package pnandmd.Point1;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Klasa ktora czyta plik pdb (jeden, podany jako arg w konstruktorze), powstaly
 * na podstawie dcda. Zwraca ona pozycje atomow CA w kolejnych klatkach. Moze
 * zwrocic pojedycznego atomu lub wszytskich na raz. Zwraca rowniez aktualna
 * klatke, pozycje wybranego atomu CA jesli juz zostala wczytana w aktualnej
 * klatce. Mozna zmienic zeby czytala wszystkie atomy, nie tylko CA.
 *
 * @author Ania
 */
public class CzytaniePdb {

    private ArrayList atoms;
    private ArrayList oldAtoms;
    private boolean endFrame;
    private boolean endFile;
    private int catom;
    private int cframe;
    private String retAtom = "CA";
    private BufferedReader bw;
    private int dl = 4;
    private float oko = (float) 5;
    private Konwerter kon;
    private boolean firstFrame;
    private int atomsShift;
    //private static int stalaZero = 100000;

    /**
     * Konstuktor klasy. Ustawienie poczatkowych wartosci dla parametrow.
     *
     * @param name plik pdb wejscowy
     */
    public CzytaniePdb(String name, File dir, float o) {
        try {
            oko = o;
            kon = new Konwerter(oko);
            atoms = new ArrayList();
            oldAtoms = new ArrayList();
            endFrame = false;
            endFile = false;
            cframe = 0;
            File input = new File("" + dir.getAbsolutePath() + File.separator + name);
            bw = new BufferedReader(new FileReader(input));
            firstFrame = true;
            atomsShift = 0;
        } catch (FileNotFoundException ex) {
            Logger.getLogger(CzytaniePdb.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Metoda ktora czyta plik pdb, az nie trafi na koniec klatki lub linie
     * zawierajaca wspolrzedne kolejnego ataomu CA (mozna to zmienic). Jesli
     * trafi na koniec klatki lub pliku to ustawia odpowiednie flagi i
     * parametry. Jesli trafi na linie ze wspolrzednymi zczytuje numer
     * aminokwasu i pozycje atomu CA, zwraca je jako tablica oraz dodaje je do
     * listy. Metoda uzywana przez inne metoedy z klasy do czytania. Jesli
     * wczytano koniec pliku lub klatki to zwrocona tablica zawiera same -1.
     *
     * @return tablica zawierajaca nr atomu oraz jego wspolrzedne
     */
    public double[] ZwrocJeden() {
        double[] poz = new double[dl];
        double[] tmp = new double[dl];
        boolean read = true;
        String linia, kawalek, kawalek3, kawalek2;
        while (read) {
            try {
                linia = bw.readLine();
                if (linia == null) {
                    endFile = true;
                    bw.close();
                    endFrame = true;
                    atoms.clear();
                    for (int i = 0; i < dl; i++) {
                        poz[i] = -1;
                    }
                    read = false;
                } else {
                    kawalek = linia.substring(0, 3);
                    kawalek = kawalek.replace(" ", "");
                    if ((kawalek.compareTo("END") == 0)) {
                        endFrame = true;
                        for (int i = 0; i < dl; i++) {
                            poz[i] = -1;
                        }
                        read = false;
                    } else if ((kawalek.compareTo("ATO") == 0)) {
                        kawalek2 = linia.substring(21);
                        kawalek3 = linia.substring(12, 16);
                        kawalek3 = kawalek3.replace(" ", "");
                        char lancuch = linia.charAt(21);
                        //if ((kawalek3.compareTo(retAtom) == 0) && kawalek2.compareTo("I") != 0) {
                        if ((kawalek3.compareTo(retAtom) == 0) && (kawalek2.compareTo("I") != 0) && (lancuch == 'A')) {
                            //if(kawalek2.compareTo("I") != 0){
                            read = false;
                            if (endFrame) {
                                endFrame = false;
                                oldAtoms = atoms;
                                atoms.clear();
                                cframe++;
                            }
                            kawalek = linia.substring(22, 26);
                            kawalek = kawalek.replace(" ", "");
                            catom = Integer.parseInt(kawalek);
                            if (firstFrame) {
                                firstFrame = false;
                                if (catom != 0) {
                                    atomsShift = catom;
                                }
                            }
                            poz[0] = catom - atomsShift;
                            kawalek = linia.substring(30, 38);
                            kawalek = kawalek.replace(" ", "");
                            poz[1] = kon.konwertuj(Double.parseDouble(kawalek));
                            tmp[1] = Double.parseDouble(kawalek);

                            kawalek = linia.substring(38, 46);
                            kawalek = kawalek.replace(" ", "");
                            poz[2] = kon.konwertuj(Double.parseDouble(kawalek));
                            tmp[2] = Double.parseDouble(kawalek);

                            kawalek = linia.substring(46, 54);
                            kawalek = kawalek.replace(" ", "");
                            poz[3] = kon.konwertuj(Double.parseDouble(kawalek));
                            tmp[3] = Double.parseDouble(kawalek);

                            if ((poz[1] == poz[2]) && (poz[2] == poz[3]) && (poz[1] == 0.0)) {

                                poz[1] = 0.5 * Math.signum(tmp[1]);
                                poz[2] = 0.5 * Math.signum(tmp[2]);
                                poz[3] = 0.5 * Math.signum(tmp[3]);

                                //System.out.println("" + poz[1] + " " + poz[2] + " " + poz[3]);
                                //System.out.println("jestem");
                            }

                            atoms.add(poz);

                            //System.out.println("atom: " + catom + " x: " + poz[1] + " y: " + poz[2] + " z: " + poz[3]);
                        }

                    }
                }
            } catch (IOException ex) {
                Logger.getLogger(CzytaniePdb.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        return poz;
    }

    /**
     * Zwraca aktulany numer klatki przerabianej.
     *
     * @return numer klatki
     */
    public int getKlatka() {
        return cframe;
    }

    /**
     * Zwraca aktualnie (czyli ostatnio wczytany) numer aminikwasu/atomu.
     *
     * @return numer atomu/aminokwasu
     */
    public int getCAtom() {
        return catom;
    }

    /**
     * Zwraca pozycje i numery wszystkich atomow CA wczytanych w poprzedniej
     * klatce - poprzedniej wzgledem obecnie czytnej, obecnie czytana nie musi
     * byc wczytana w calosci.
     *
     * @return numery i pozycje atomow w poprzedniej klatce
     */
    public ArrayList getOldAtoms() {
        return oldAtoms;
    }

    /**
     * Zwraca numery i pozycje atomow CA z obecnie czytanej klatki, do atomu
     * aktulanie wczytanego jako ostatni, czyli lista nie musi zawierac
     * wszystkich atomow z klatki.
     *
     * @return numery i pozycje atomow jak dotad wczytanych w obecnej klatce
     */
    public ArrayList getAtoms() {
        return atoms;
    }

    /**
     * Zwraca wartosc true jesli ostatnio wczytano koniec klatki lub false jesli
     * jest w trakcie czytania klatki. Jesli zwrocona wartosc jest true to
     * metoda getAtoms() zwroci liste zawierajaca wszytskie atomu w klatce.
     *
     * @return flaga oznaczajaca koniec klatki
     */
    public boolean koniecKlatki() {
        return endFrame;
    }

    /**
     * Zwraca flage oznaczajaca koniec pliku (rowniez koniec klatki).
     *
     * @return flaga oznaczajaca koniec pliku
     */
    public boolean koniecPliku() {
        return endFile;
    }

    /**
     * Zwraca liste zawierajaca numery i pozycje wszystkich atomow z obecnie
     * przerabianej klatki - jesli wszystkie atomy z klatki nie zostaly jeszcze
     * wczytane doczytuje je. Jesli obecnie czytanie zatrzymalo sie na koncu
     * klatki (poprzez wywolanie innych metod!) metoda wczyta atomy z nastepnej
     * klatki, dlatego warto sprawdzic czy nie jest sie na koncu klatki przed
     * wywolaniem tej metody. Jesli czyta sie tylko ta metoda nie trzeba
     * sprawdzac czy znalazlo sie na koncu klatki przed wywolaniem, w takiej
     * sytuacji metoda bedzie czytac tak jak powinna.
     *
     * @return lista zawierajaca numery i pozycje wszytskich atomow w danej
     * klatce
     */
    public ArrayList zwrocWszystkie() {
        do {
            ZwrocJeden();
        } while (endFrame == false);
        return atoms;
    }

    /**
     * Zwraca tablice zawierajaca numer i pozycje n-tego atomu jesli zostal on
     * juz wczytany do listy w biezacej klatce. Jesli nie tablica bedzie
     * zawierac same -1.
     *
     * @param n numer atomu ktorego pozycje nalezy zwrocic
     * @return tablica zawierajaca numer atomu i jego wspolrzedne
     */
    public double[] zwrocWczytane(int n) {
        double[] wart;
        if (catom < n) {
            wart = new double[dl];
            for (int i = 0; i < dl; i++) {
                wart[i] = -1;
            }
        } else {
            wart = (double[]) atoms.get(n);
        }
        return wart;
    }

    /**
     * Metoda ktora zwraca numer i pozycje wybranego atomu. Jesli zostal on juz
     * wczytany w danej klatce to zwraca jego pozycje odczytujac ja z listy.
     * Jesli nie zostal wczytany to metoda doczytuje plik az nie wczyta danych
     * dotyczacych wybranego atomu. Informacje o atomach "po drodze" trafiaja do
     * listy, ktora mozna zwrocic innymi metodami.
     *
     * @param n numer wybranego atomu
     * @return tablica zawierajaca numer atomu i jego wspolrzedne
     */
    public double[] zwrocWczytane2(int n) {
        double[] wart;
        if (catom < n) {
            while (catom != n) {
                ZwrocJeden();
            }
        }
        wart = (double[]) atoms.get(n);
        return wart;
    }

    /**
     * Zwraca wielkosc oczka siatki - jaka konwersja jest.
     *
     * @return wielkosc oka siatki punktow
     */
    public float zwrocOko() {
        return oko;
    }

}
