/*
 * Programa-exemplo para a miniaula introdutória de Computação para a Turma 34 do Curso de Ciências Moleculares.
 * Processa uma entrada de texto no formato FASTA e retorna as (potenciais) sequências codificantes dentro do código.
 * Uma sequência codificante é uma sequência de trincas (códons) tal que a primeira trinca é um códon de início (para nós, ATG)
 * e a última trinca é um códon de parada (para nós, TAA, TAG ou TGA).
 */

public class FindCodingSequences {

    // A função main() é a única rodada quando executamos o programa.
    // Outras funções só são rodadas se forem chamadas no main().
    public static void main(String[] args) {

        // Tratamento da entrada. Transformamos a entrada que recebemos pro programa (em geral alguma forma de texto)
        // na representação que achamos mais conveniente para o nosso problema.
        String[] sequence_codons = parseSequence();

        // Implementação do algoritmo. Tendo a nossa representação do problema em código, fazemos as manipulações necessárias
        // para chegar no nosso fim desejado.
        findCodingSequences(sequence_codons);
    }

    // Problemas que essa função precisa resolver:
    // 1. Receber os dados de entrada
    // 2. Limpar esses dados de coisas desnecessárias (header, linebreaks)
    // 3. Transformar os dados limpos na nossa representação (sequência de códons)
    public static String[] parseSequence() {
        String input = StdIn.readAll(); 
        input = removeHeader(input);
        input = removeNewlines(input);
        String[] sequence = splitIntoCodons(input);
        return sequence;
    }

    // Problema que essa função precisa resolver:
    // 1. Remover o header
    public static String removeHeader(String fasta) {
        return fasta.substring(fasta.indexOf('\n')+1);
    }

    // Remover linebreaks
    public static String removeNewlines(String fasta) {
        return fasta.replace("\n", "");
    }

    // Transformar string de sequência de DNA em sequência de códons
    public static String[] splitIntoCodons(String fasta) {
        // número de códons é o número de bases dividido por três
        int codon_count = fasta.length()/3;
        String[] codons = new String[codon_count];
        for (int i = 0; i < codons.length; i++) {
            codons[i] = fasta.substring(3*i, 3*(i+1));
        }
        return codons;
    }

    // Função precisa implementar o algoritmo abstrato que pensamos:
    // 1. Andar do começo ao fim da sequência até achar um códon de início
    // 2. Começando do códon de início, achar um códon de parada
    // 3. Imprimir para o usuário a sequência que inicia no códon de início e termina no de parada
    // 4. Continuar 1., começando do códon de parada
    public static void findCodingSequences(String[] codons) {
        // loop que busca um codon de inicio
        for (int i = 0; i < codons.length; i++) {
            String possible_start_codon = codons[i];
            // se achamos um codon de inicio, entramos no loop que busca um codon de parada
            if (isStartCodon(possible_start_codon)) {
                for (int j = i+1; j < codons.length; j++) {
                    String possible_stop_codon = codons[j];
                    if (isStopCodon(possible_stop_codon)) {
                        // se achamos o codon de parada,
                        // imprimimos a sequência que começa
                        // no índice do códon de início e termina
                        // no índice do códon de parada
                        printSequence(codons, i, j);
                        i = j;
                        break;
                    }
                }
            }
        }
    }

    // Checar se algum códon é de início
    public static boolean isStartCodon(String codon) {
        return codon.equals("ATG");
    }

    // Checar se algum códon é um dos códons de parada
    public static boolean isStopCodon(String codon) {
        String[] STOP_CODONS = {"TAA", "TAG", "TGA"};
        for (int i = 0; i < STOP_CODONS.length; i++) {
            if (codon.equals(STOP_CODONS[i])) {
                return true;
            }
        }
        return false;
    }

    // Imprimir os candidatos a sequência codificante
    public static void printSequence(String[] codons, int start, int end) {
        StdOut.print("Candidato achado: ");
        for (int i = start; i <= end; i++) {
            StdOut.print(codons[i]);
        }
        StdOut.println();
    }
}
