import java.util.List;
import java.util.Scanner;
import java.util.InputMismatchException;

//
public class UserInterface {

    final static Scanner sc = new Scanner(System.in);
    static int input;
    static boolean quit = false;

    public static void main(String args[]) {
        while(!quit) {
            System.out.println("\nALPHA/BETA T-CELL RECEPTOR MATCHING SIMULATOR");
            System.out.println("Please select an option:");
            System.out.println("1) Generate a population of distinct cells");
            System.out.println("2) Generate a sample plate of T cells");
            System.out.println("3) Simulate CDR3 alpha/beta T cell matching");
            System.out.println("4) Simulate CDR3/CDR1 T cell matching");
            System.out.println("5) Acknowledgements");
            System.out.println("0) Exit");
            try {
                input = sc.nextInt();
                switch(input){
                    case 1 -> makeCells();
                    case 2 -> makePlate();
                    case 3 -> matchCells();
                    case 4 -> matchCellsExpanded();
                    case 5 -> acknowledge();
                    case 0 -> quit = true;
                    default -> throw new InputMismatchException("Invalid input.");
                }
            }catch(InputMismatchException ex){
                System.out.println(ex);
                sc.next();
            }
        }
        sc.close();
    }

    private static void makeCells() {
        String filename = null;
        Integer numCells = 0;
        Integer cdr1Freq = 1;
        try {
            System.out.println("\nSimulated T-Cells consist of integer values representing:\n" +
                    "* a pair of alpha and beta CDR3 peptides (unique within simulated population)\n" +
                    "* a pair of alpha and beta CDR1 peptides (not necessarily unique).");
            System.out.println("\nThe cells will be written to a file.");
            System.out.print("Please enter a file name: ");
            filename = sc.next();
            System.out.println("CDR3 sequences are more diverse than CDR1 sequences.");
            System.out.println("Please enter the factor by which distinct CDR3s outnumber CDR1s: ");
            cdr1Freq = sc.nextInt();
            System.out.print("Please enter the number of T-cells to generate: ");
            numCells = sc.nextInt();
            if(numCells <= 0){
                throw new InputMismatchException("Number of cells must be a positive integer.");
            }
        } catch (InputMismatchException ex) {
            System.out.println(ex);
            sc.next();
        }
        CellSample sample = Simulator.generateCellSample(numCells, cdr1Freq);
        CellFileWriter writer = new CellFileWriter(filename, sample);
        writer.writeCellsToFile();
    }

    //method to output a CSV of
    private static void makePlate() {
        String cellFile = null;
        String filename = null;
        Double stdDev = 0.0;
        Integer numWells = 0;
        Integer numSections = 0;
        Integer[] concentrations = {1};
        Double dropOutRate = 0.0;
        boolean poisson = false;
        try {
            System.out.println("\nMaking a sample plate requires a population of distinct cells");
            System.out.println("Please enter name of an existing cell sample file: ");
            cellFile = sc.next();
            System.out.println("\nThe sample plate will be written to file");
            System.out.print("Please enter a name for the output file: ");
            filename = sc.next();
            System.out.println("Select T-cell frequency distribution function");
            System.out.println("1) Poisson");
            System.out.println("2) Gaussian");
            System.out.println("(Note: wider distributions are more memory intensive to match)");
            System.out.print("Enter selection value: ");
            input = sc.nextInt();
            switch(input) {
                case 1:
                    poisson = true;
                    break;
                case 2:
                    System.out.println("How many distinct T-cells within one standard deviation of peak frequency?");
                    System.out.println("(Note: wider distributions are more memory intensive to match)");
                    stdDev = sc.nextDouble();
                    if(stdDev <= 0.0){
                        throw new InputMismatchException("Value must be positive.");
                    }
                    break;
                default:
                    System.out.println("Invalid input. Defaulting to Poisson.");
                    poisson = true;
            }
            System.out.print("Number of wells on plate: ");
            numWells = sc.nextInt();
            if(numWells < 1){
                throw new InputMismatchException("No wells on plate");
            }
            System.out.println("The plate can be evenly sectioned to allow multiple concentrations of T-cells/well");
            System.out.println("How many sections would you like to make (minimum 1)?");
            numSections = sc.nextInt();
            if(numSections < 1) {
                throw new InputMismatchException("Too few sections.");
            }
            else if (numSections > numWells) {
                throw new InputMismatchException("Cannot have more sections than wells.");
            }
            int i = 1;
            concentrations = new Integer[numSections];
            while(numSections > 0) {
                System.out.print("Enter number of T-cells per well in section " + i +": ");
                concentrations[i - 1] = sc.nextInt();
                i++;
                numSections--;
            }
            System.out.println("Errors in amplification can induce a well dropout rate for peptides");
            System.out.print("Enter well dropout rate (0.0 to 1.0): ");
            dropOutRate = sc.nextDouble();
            if(dropOutRate < 0.0 || dropOutRate > 1.0) {
                throw new InputMismatchException("The well dropout rate must be in the range [0.0, 1.0]");
            }
        }catch(InputMismatchException ex){
            System.out.println(ex);
            sc.next();
        }
        CellFileReader cellReader = new CellFileReader(cellFile);
        if(poisson) {
            stdDev = Math.sqrt(cellReader.getCellCount()); //gaussian with square root of elements approximates poisson
        }
        Plate samplePlate = new Plate(numWells, dropOutRate, concentrations, stdDev);
        samplePlate.fillWells(cellReader.getCells());
        PlateFileWriter writer = new PlateFileWriter(filename, samplePlate);
        writer.writePlateFile();
    }

    private static void matchCells() {
        String filename = null;
        String cellFile = null;
        String plateFile = null;
        Integer lowThreshold = 0;
        Integer highThreshold = Integer.MAX_VALUE;
        try {
            System.out.println("\nSimulated experiment requires a cell sample file and a sample plate file.");
            System.out.print("Please enter name of an existing cell sample file: ");
            cellFile = sc.next();
            System.out.print("Please enter name of an existing sample plate file: ");
            plateFile = sc.next();
            System.out.println("The matching results will be written to a file.");
            System.out.print("Please enter a name for the output file: ");
            filename = sc.next();
            System.out.println("What is the minimum number of alpha/beta overlap wells to attempt matching?");
            lowThreshold = sc.nextInt();
            if(lowThreshold < 1){
                throw new InputMismatchException("Minimum value for low threshold is 1");
            }
            System.out.println("What is the maximum number of alpha/beta overlap wells to attempt matching?");
            highThreshold = sc.nextInt();
        } catch (InputMismatchException ex) {
            System.out.println(ex);
            sc.next();
        }
        CellFileReader cellReader = new CellFileReader(cellFile);
        PlateFileReader plateReader = new PlateFileReader(plateFile);
        Plate plate = new Plate(plateReader.getWells());
        if (cellReader.getCells().size() == 0){
            System.out.println("No cell sample found.");
            System.out.println("Returning to main menu.");
        }
        else if(plate.getWells().size() == 0){
            System.out.println("No sample plate found.");
            System.out.println("Returning to main menu.");

        }
        else{
            if(highThreshold >= plate.getSize()){
                highThreshold = plate.getSize() - 1;
            }
            List<Integer[]> cells = cellReader.getCells();
            MatchingResult results = Simulator.matchCDR3s(cells, plate, lowThreshold, highThreshold);
            //result writer
            MatchingFileWriter writer = new MatchingFileWriter(filename, results.getComments(),
                    results.getHeaders(), results.getAllResults());
            writer.writeResultsToFile();
        }
    }

    public static void matchCellsExpanded(){
    /*
    The idea here is that we'll get the CDR3 alpha/beta matches first. Then we'll try to match CDR3s to CDR1s by
    looking at the top two matches for each CDR3. If CDR3s in the same cell simply swap CDR1s, we assume a correct
    match
     */
        String filename = null;
        String cellFile = null;
        String plateFile = null;
        Integer lowThresholdCDR3 = 0;
        Integer highThresholdCDR3 = Integer.MAX_VALUE;
        Integer lowThresholdCDR1 = 0;
        Integer highThresholdCDR1 = Integer.MAX_VALUE;
        try {
            System.out.println("\nSimulated experiment requires a cell sample file and a sample plate file.");
            System.out.print("Please enter name of an existing cell sample file: ");
            cellFile = sc.next();
            System.out.print("Please enter name of an existing sample plate file: ");
            plateFile = sc.next();
            System.out.println("The matching results will be written to a file.");
            System.out.print("Please enter a name for the output file: ");
            filename = sc.next();
            System.out.println("What is the minimum number of CDR3 alpha/beta overlap wells to attempt matching?");
            lowThresholdCDR3 = sc.nextInt();
            if(lowThresholdCDR3 < 1){
                throw new InputMismatchException("Minimum value for low threshold is 1");
            }
            System.out.println("What is the maximum number of CDR3 alpha/beta overlap wells to attempt matching?");
            highThresholdCDR3 = sc.nextInt();
            System.out.println("What is the minimum number of CDR3/CDR1 overlap wells to attempt matching?");
            lowThresholdCDR1 = sc.nextInt();
            if(lowThresholdCDR1 < 1){
                throw new InputMismatchException("Minimum value for low threshold is 1");
            }
            System.out.println("What is the maximum number of CDR3/CDR1 overlap wells to attempt matching?");
            highThresholdCDR1 = sc.nextInt();
        } catch (InputMismatchException ex) {
            System.out.println(ex);
            sc.next();
        }
        CellFileReader cellReader = new CellFileReader(cellFile);
        PlateFileReader plateReader = new PlateFileReader(plateFile);
        Plate plate = new Plate(plateReader.getWells());
        if (cellReader.getCells().size() == 0){
            System.out.println("No cell sample found.");
            System.out.println("Returning to main menu.");
        }
        else if(plate.getWells().size() == 0){
            System.out.println("No sample plate found.");
            System.out.println("Returning to main menu.");

        }
        else{
            if(highThresholdCDR3 >= plate.getSize()){
                highThresholdCDR3 = plate.getSize() - 1;
            }
            if(highThresholdCDR1 >= plate.getSize()){
                highThresholdCDR1 = plate.getSize() - 1;
            }
            List<Integer[]> cells = cellReader.getCells();
            MatchingResult preliminaryResults = Simulator.matchCDR3s(cells, plate, lowThresholdCDR3, highThresholdCDR3);
            MatchingResult[] results = Simulator.matchCDR1s(cells, plate, lowThresholdCDR1,
                    highThresholdCDR1, preliminaryResults.getMatchMap(), preliminaryResults.getTime());

            //result writer
            MatchingFileWriter writer = new MatchingFileWriter(filename + "First", results[0].getComments(),
                    results[0].getHeaders(), results[0].getAllResults());
            writer.writeResultsToFile();
            writer = new MatchingFileWriter(filename + "Dual", results[1].getComments(),
                    results[1].getHeaders(), results[1].getAllResults());
            writer.writeResultsToFile();
        }
    }

    private static void acknowledge(){
        System.out.println("Simulation based on:");
        System.out.println("Howie, B., Sherwood, A. M., et. al.");
        System.out.println("High-throughput pairing of T cell receptor alpha and beta sequences.");
        System.out.println("Sci. Transl. Med. 7, 301ra131 (2015)");
        System.out.println("");
        System.out.println("Simulation by Eugene Fischer, 2021");
    }
}
