/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pnandmd;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.util.logging.Level;
import java.util.logging.Logger;
import pnandmd.Point1.TworzPDB;

/**
 *
 * @author Ania
 */
public class PDBgeneration {

    private File dir;
    private int[] marking;
    private int[] last;
    private int[] lastM;
    private double[][] miejsca;

    private int liczM;
    private int ilosc;
    private int przes;

    private int typSieci;

    private BufferedReader wyst;

    //jakie dlugosci maja macierze ze "wspolrzednymi" - atom + x,y,z
    private int dl = 4;

    private BufferedReader mNazwy;
    private BufferedReader mPlik;

    public PDBgeneration(File d, int place) {
        dir = d;
        try {
            wyst = new BufferedReader(new FileReader(dir.getAbsolutePath() + File.separator + "wystapienia.txt"));
            String linia = wyst.readLine();
            typSieci = Integer.parseInt(linia);
            linia = wyst.readLine();
            String[] tab = linia.split(" ");
            liczM = Integer.parseInt(tab[3]);
            liczM++;
            marking = new int[liczM];
            if ((typSieci == 1) || (typSieci == 2)) {
                przes = Integer.parseInt(tab[5]);
                ilosc = Integer.parseInt(tab[5]);
                ilosc /= 2;
            }
            if ((typSieci == 2)) {
                last = new int[ilosc];
                lastM = new int[ilosc];
            }
            mPlik = new BufferedReader(new FileReader(dir.getAbsolutePath() + File.separator + "markingPN.txt"));
            mNazwy = new BufferedReader(new FileReader(dir.getAbsolutePath() + File.separator + "mNazwy.txt"));
            boolean markingSet;
            if (place != -1) {
                setMarking(place);
                markingSet = true;
            } else {
                markingSet = false;
            }

            if (typSieci == 1) {
                czytajMiejsca1();
                generujPdb(markingSet);
            } else if (typSieci == 2) {
                czytajMiejsca2();
                generujPdb(markingSet);
            } else if (typSieci == 3) {
                generujPdb3(markingSet);
            }
        } catch (IOException ex) {
            Logger.getLogger(PDBgeneration.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private void setMarking(int place) {
        for (int i = 0; i < liczM; i++) {
            if (i == place) {
                marking[i] = 1;
            } else {
                marking[i] = 0;
            }
        }
    }

    public final void generujPdb(boolean markingSet) {
        BufferedWriter pdb = null;
        String linia, pom;
        char[] czesc;
        int index;
        double pomM[] = new double[dl - 1];
        String line = "AAA";
        try {
            pdb = new BufferedWriter(new FileWriter(dir.getAbsolutePath() + File.separator + "generated.pdb"));
            if (!markingSet) {
                line = czytajMarking(mPlik);
            }
            while (line.compareTo("STOP") != 0) {
                for (int i = 0; i < ilosc; i++) {
                    linia = "";

                    if (typSieci == 2) {
                        pomM[0] = miejsca[lastM[i]][0];
                        pomM[1] = miejsca[lastM[i]][1];
                        pomM[2] = miejsca[lastM[i]][2];
                    } else if (typSieci == 1) {
                        index = przes + 1;
                        while (!((miejsca[index][0] == (1.0 * i)) && (marking[index] == 1))) {
                            index++;
                            if (index >= liczM) {
                                index = i;
                                break;
                            }
                        }
                        pomM[0] = miejsca[index][1];
                        pomM[1] = miejsca[index][2];
                        pomM[2] = miejsca[index][3];
                    }
                    czesc = new char[6];
                    pom = "ATOM  ";
                    linia = pomocnicza(linia, czesc, pom);
                    czesc = new char[5];
                    pom = Integer.toString(i);
                    linia = pomocnicza(linia, czesc, pom);
                    linia = linia + " ";
                    czesc = new char[4];
                    pom = "O";
                    linia = pomocnicza(linia, czesc, pom);
                    linia = linia + " ";
                    czesc = new char[3];
                    pom = "VAL";
                    linia = pomocnicza(linia, czesc, pom);
                    linia = linia + " A";
                    czesc = new char[4];
                    pom = Integer.toString(i);
                    linia = pomocnicza(linia, czesc, pom);
                    linia = linia + "    ";
                    czesc = new char[8];
                    pom = Double.toString(pomM[0]);
                    linia = pomocnicza(linia, czesc, pom);
                    czesc = new char[8];
                    pom = Double.toString(pomM[1]);
                    linia = pomocnicza(linia, czesc, pom);
                    czesc = new char[8];
                    pom = Double.toString(pomM[2]);
                    linia = pomocnicza(linia, czesc, pom);
                    czesc = new char[6];
                    pom = "1.00";
                    linia = pomocnicza(linia, czesc, pom);
                    czesc = new char[6];
                    pom = "0.00";
                    linia = pomocnicza(linia, czesc, pom);
                    linia = linia + "      ";
                    czesc = new char[4];
                    pom = "A";
                    czesc = wpiszLewa(czesc, pom);
                    linia = linia + new String(czesc);
                    linia = linia + "    ";

                    pdb.write(linia);
                    pdb.newLine();

                }
                for (int i = 0; i < ilosc - 1; i++) {
                    linia = "CONECT ";
                    czesc = new char[4];
                    pom = Integer.toString(i);
                    czesc = wpiszLewa(czesc, pom);
                    linia = linia + new String(czesc);

                    czesc = new char[5];
                    pom = Integer.toString(i + 1);
                    czesc = wpiszLewa(czesc, pom);
                    linia = linia + new String(czesc);

                    for (int j = 0; j < 15; j++) {
                        linia = linia + " ";
                    }

                    pdb.write(linia);
                    pdb.newLine();
                }
                if (line.compareTo("END") == 0) {
                    pdb.write("END");
                    pdb.newLine();
                }
                if (!markingSet) {
                    line = czytajMarking(mPlik);
                } else {
                    line = "STOP";
                }
            }

            pdb.close();
            mPlik.close();
        } catch (IOException ex) {
            Logger.getLogger(TworzPDB.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                pdb.close();
            } catch (IOException ex) {
                Logger.getLogger(TworzPDB.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Wpisuje tekst ze stringa do tablicy znakow na jej koniec - tzn wyrownanie
     * do prawej
     *
     * @param tab tablica do kotrej wpisuje tekst
     * @param tekst tekst do wpisania
     * @return tablica z wpisanym tekstem
     */
    private char[] wpisz(char[] tab, String tekst) {
        int n = tab.length;
        int m = tekst.length();
        int i, j;
        for (i = n - 1, j = m - 1; i >= 0; i--, j--) {
            if (j >= 0) {
                tab[i] = tekst.charAt(j);
            } else {
                tab[i] = ' ';
            }
        }
        return tab;
    }

    /**
     * to co wyzej ale wpisuje wyrownujac do lewej
     *
     * @param tab
     * @param tekst
     * @return
     */
    private char[] wpiszLewa(char[] tab, String tekst) {
        int n = tab.length;
        int m = tekst.length();
        int i, j;
        for (i = 0, j = 0; i < n; i++, j++) {
            if (j < m) {
                tab[i] = tekst.charAt(j);
            } else {
                tab[i] = ' ';
            }
        }

        return tab;
    }

    /**
     * Dopisuje tablice tab do stringa linia, ktorego zwraca.
     *
     * @param linia
     * @param tab
     * @return
     */
    private String pomocnicza(String linia, char[] tab, String pom) {
        tab = wpisz(tab, pom);
        linia = linia + new String(tab);
        return linia;
    }

    private String czytajMarking(BufferedReader mPlik) throws IOException {
        String linia;
        linia = mPlik.readLine();
        if (linia == null) {
            return "STOP";
        }
        String[] tab = linia.split(" ");
        int n = tab.length;
        for (int i = 0; i < n; i++) {
            marking[i] = Integer.parseInt(tab[i]);
        }
        if (typSieci == 2) {
            linia = mPlik.readLine();
            tab = linia.split(" ");
            n = tab.length;
            for (int i = 0; i < n; i++) {
                last[i] = Integer.parseInt(tab[i]);
            }
        }
        linia = mPlik.readLine();
        if (linia == null) {
            linia = "END";
        }
        return linia;
    }

    private void czytajMiejsca1() {
        try {
            String linia;
            String[] tab;
            String[] tab2;
            miejsca = new double[liczM][dl];
            double[] wsp = new double[4];
            int a, p;
            while ((linia = mNazwy.readLine()) != null) {

                tab = linia.split(" ");
                p = Integer.parseInt(tab[1]);
                a = Integer.parseInt(tab[4]);

                wsp[0] = 1.0 * a;
                tab2 = tab[6].split(",");
                wsp[1] = Double.parseDouble(tab2[0]);
                wsp[2] = Double.parseDouble(tab2[1]);
                wsp[3] = Double.parseDouble(tab2[2]);
                przepiszMiejsca(p, wsp, dl);
            }
            /*for(int i = 0; i < lmiejsc; i++){
             System.out.println("nr: "+i+" atom: "+miejsca[i][0]+" wsp: "+miejsca[i][1]+", "+miejsca[i][2]+", "+miejsca[i][3]);
             }*/
            mNazwy.close();
        } catch (IOException ex) {
            Logger.getLogger(TworzPDB.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Przepisuje informacje z tablicy tab do macierzy miejsca do indeksu nr.
     *
     * @param nr indeks pod ktory wpisac informacje z malej tablicy
     * @param tab mala tablica do wpisania do miejsca
     * @param n ilosc elementow w tablicy do przepisania
     */
    private void przepiszMiejsca(int nr, double[] tab, int n) {
        System.arraycopy(tab, 0, miejsca[nr], 0, n);
    }

    private void czytajMiejsca2() {
        try {
            String linia;
            String tab[];
            String tab2[];
            int p, nn, tr, i;
            nn = dl - 1;
            miejsca = new double[liczM][nn];
            double wsp[] = new double[nn];
            BufferedReader tNazwy = new BufferedReader(new FileReader(new File(dir.getAbsolutePath() + File.separator + "tNazwy.txt")));
            while ((linia = mNazwy.readLine()) != null) {
                tab = linia.split(" : ");
                tab2 = tab[1].split(",");
                wsp[0] = Double.parseDouble(tab2[0]);
                wsp[1] = Double.parseDouble(tab2[1]);
                wsp[2] = Double.parseDouble(tab2[2]);
                tab2 = tab[0].split(" ");
                p = Integer.parseInt(tab2[1]);
                przepiszMiejsca(p, wsp, nn);
            }
            i = 0;
            while (((linia = tNazwy.readLine()) != null) && (i < ilosc)) {
                tab = linia.split(" ");
                tr = Integer.parseInt(tab[1]);
                tab[8] = tab[8].replace("p", "");
                p = Integer.parseInt(tab[8]);
                for (int j = 0; j < ilosc; j++) {
                    if (tr == last[j]) {

                        i++;
                        lastM[j] = p;
                        break;
                    }
                }

            }
            mNazwy.close();
            tNazwy.close();
        } catch (IOException ex) {
            Logger.getLogger(PDBgeneration.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Generuje plik pdb dla alg 3. Znajduje miejsce w markingu ktore ma zeton,
     * szuka go w pliku i wspolrzedne z niego wpisuje do pdb.
     */
    private void generujPdb3(boolean markingSet) {
        try {
            String linia, pom, linia2;
            char[] czesc;
            String tab[];
            String tab2[];
            BufferedWriter pdb;
            double pomM[] = new double[dl - 1];
            int nr;
            String line = "AAA";

            pdb = new BufferedWriter(new FileWriter(dir.getAbsolutePath() + File.separator + "poSieci.pdb"));

            if (!markingSet) {
                line = czytajMarking(mPlik);
            }
            while (line.compareTo("STOP") != 0) {
                for (int i = 0; i < liczM; i++) {
                    if (marking[i] != 0) {
                        while ((linia2 = mNazwy.readLine()) != null) {

                            tab = linia2.split(":");
                            tab[0] = tab[0].replace(" ", "");
                            tab[0] = tab[0].replace("p", "");
                            nr = Integer.parseInt(tab[0]);
                            if (nr == i) {
                                int dlg = tab.length;
                                for (int j = 2; j < dlg; j++) {
                                    linia = "";
                                    tab2 = tab[j].split(",");
                                    pomM[0] = Double.parseDouble(tab2[0]);
                                    pomM[1] = Double.parseDouble(tab2[1]);
                                    pomM[2] = Double.parseDouble(tab2[2]);

                                    czesc = new char[6];
                                    pom = "ATOM  ";
                                    linia = pomocnicza(linia, czesc, pom);
                                    czesc = new char[5];
                                    pom = Integer.toString(j - 2);
                                    linia = pomocnicza(linia, czesc, pom);
                                    linia = linia + " ";
                                    czesc = new char[4];
                                    pom = "O";
                                    linia = pomocnicza(linia, czesc, pom);
                                    linia = linia + " ";
                                    czesc = new char[3];
                                    pom = "VAL";
                                    linia = pomocnicza(linia, czesc, pom);
                                    linia = linia + " A";
                                    czesc = new char[4];
                                    pom = Integer.toString(j - 2);
                                    linia = pomocnicza(linia, czesc, pom);
                                    linia = linia + "    ";
                                    czesc = new char[8];
                                    pom = Double.toString(pomM[0]);
                                    linia = pomocnicza(linia, czesc, pom);
                                    czesc = new char[8];
                                    pom = Double.toString(pomM[1]);
                                    linia = pomocnicza(linia, czesc, pom);
                                    czesc = new char[8];
                                    pom = Double.toString(pomM[2]);
                                    linia = pomocnicza(linia, czesc, pom);
                                    czesc = new char[6];
                                    pom = "1.00";
                                    linia = pomocnicza(linia, czesc, pom);
                                    czesc = new char[6];
                                    pom = "0.00";
                                    linia = pomocnicza(linia, czesc, pom);
                                    linia = linia + "      ";
                                    czesc = new char[4];
                                    pom = "A";
                                    czesc = wpiszLewa(czesc, pom);
                                    linia = linia + new String(czesc);
                                    linia = linia + "    ";

                                    pdb.write(linia);
                                    pdb.newLine();
                                }
                                int pp = dlg - 3;
                                for (int j = 0; j < pp; j++) {
                                    linia = "CONECT ";
                                    czesc = new char[4];
                                    pom = Integer.toString(j);
                                    czesc = wpiszLewa(czesc, pom);
                                    linia = linia + new String(czesc);

                                    czesc = new char[5];
                                    pom = Integer.toString(j + 1);
                                    czesc = wpiszLewa(czesc, pom);
                                    linia = linia + new String(czesc);

                                    for (int k = 0; k < 15; k++) {
                                        linia = linia + " ";
                                    }

                                    pdb.write(linia);
                                    pdb.newLine();
                                }
                                break;

                            }

                        }
                        break;

                    }
                }
                if (line.compareTo("END") == 0) {
                    pdb.write("END");
                    pdb.newLine();
                }
                if (!markingSet) {
                    line = czytajMarking(mPlik);
                } else {
                    line = "STOP";
                }
                mNazwy.close();
                mNazwy = new BufferedReader(new FileReader(dir.getAbsolutePath() + File.separator + "mNazwy.txt"));
            }
            pdb.close();
            mPlik.close();
        } catch (IOException ex) {
            Logger.getLogger(PDBgeneration.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void zapiszMarking() {
        int n = marking.length;
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(new File(dir.getAbsolutePath() + File.separator + "markingPN.txt")));
            for (int i = 0; i < n; i++) {
                bw.write("" + marking[i] + " ");
            }
            bw.newLine();
            bw.close();
        } catch (IOException ex) {
            Logger.getLogger(Simulation.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
