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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *Klasa ktora przyjmuje jako argument wspolrzedne atomow - pozniej mozna nadpisac obecne wspolrzedne
 * i zwraca ona pary atomow bedace w kontakcie - na podstawie wgrannych wspolrzednych
 * @author Ania
 */
public class Kontakty {
    
    //tablica zawierajaca listy zawierajace numery atomow bedacych razem w danej komorce
    //numer komorki to indeks tablicy
    //numer komorki to int[3] - aby to mogl byc numer tablicy to mapowanie na int poprzez mapy
    //mapy mapuja w obie strony
    private ArrayList[] sasiedzi;
    private Map<Integer, String> indexNumerS = new HashMap();
    private Map<String, Integer> numerIndeksS = new HashMap();
    
    //tablica zawierajaca listy zawierajace numery atomow mozliwych sasiadow dla danej komorki
    //numer komorki to indeks tablicy
    //numer komorki to int[3] - aby to mogl byc numer tablicy to mapowanie na int poprzez mapy
    //mapy mapuja w obie strony
    private ArrayList[] mozliwi;
    private Map<Integer, String> indexNumerM = new HashMap();
    private Map<String, Integer> numerIndeksM= new HashMap();
    
    //lista zawierajaca pary bedace w kontakcie
    private List<Integer> wynik = new ArrayList();
    
    //ilosc atomow
    int n;
    
    //ilosc mozliwych sasiadow 
    int ms = 26;
    
    //indeksy w tablicach sasiedzi i mozliwi
    int i1 = 0;
    int i2 = 0;
    
    ArrayList wsp;
    ArrayList org;
    
    int oko = 8;
    
    
    /**
     * Podanie nowych wspolrzednych - oraz czyszczenie poprzednich danych
     * @param wspol 
     */
    public void noweWsp(ArrayList wspol, ArrayList oo, int o){
        wsp = wspol;
        oko = o;
        org = oo;
        czysc();
    }
    
    /**
     * Metoda czyszczaca dane z poprzednich wspolrzednych. Czysci wszystkei listy itd.
     */
    public void czysc(){
        indexNumerS.clear();
        numerIndeksS.clear();
        indexNumerM.clear();
        numerIndeksM.clear();
        sasiedzi = null;
        mozliwi = null;
        sasiedzi = new ArrayList[n];
        mozliwi = new ArrayList[n * ms];
        wynik.clear();
    }
    
    private boolean czyZawiera(int a, int b){
        boolean zawiera = false;
        int s = wynik.size();
        int w1, w2;
        for(int i = 0; i < s; i += 2){
            w1 = wynik.get(i);
            w2 = wynik.get(i + 1);
            if(((w1 == a) && (w2 == b)) || ((w1 == b) && (w2 == a))){
                zawiera = true;
                break;
            }
        }
        return zawiera;
    }
    
    /**
     * Glowna metoda zwracajaca pary w kontakcie z aktualnych wspolrzednych podanych jako argument
     * @return 
     */
    public List<Integer> zwrocKonkaty(ArrayList wspol){
        wsp = wspol;
        n = wsp.size();
        czysc();
        wypelnijTablice();
        //System.out.println("i1 "+i1+" i2: "+i2);
        /*for(int i = 0; i < i1; i++){
            int kk = sasiedzi[i].size();
            System.out.println("lista sasiedzi: "+i);
            for(int j = 0; j < kk; j++){
                System.out.println(sasiedzi[i].get(j));
            }
        }*/
        dodajWynikiSasiedzi();
        /*int nn = wynik.size();
        int a, b;
        for(int i = 0; i < nn; i+=2){
            a = (int) wynik.get(i);
            b = (int) wynik.get(i+1);
            System.out.println("sasiedzi kontakt: "+a+" i "+b);
        }*/
        dodajWynikiMozliwi();   
        /*nn = wynik.size();
        for(int i = 0; i < nn; i++){
            tab = (int[]) wynik.get(i);
            System.out.println("mozliwi kontakt: "+tab[0]+" i "+tab[1]);
        }*/
        return wynik;
    }
    
    
    private void dodajWynikiMozliwi(){
        int s, a, b;
        for(int ii = 0; ii < i2; ii++){
            s = mozliwi[ii].size();
            for(int i = 0; i < s; i++){
                for(int j = i + 1; j < s; j++){
                    a = (int) mozliwi[ii].get(i);
                    b = (int) mozliwi[ii].get(j);
                    //System.out.println(""+a + ", "+b+" odl "+odleglosc(a, b));
                    if(odleglosc(a, b) <= oko ){
                        if(!czyZawiera(a, b)){
                            wynik.add(a);
                            wynik.add(b);
                        }
                    }
                }
            }
        }
    }
    
    private float odleglosc(int a, int b){
        float odl;
        double[] tab1;
        double[] tab2;
        //System.out.println("odl: "+a+" i " + b);
        tab1 = (double[]) org.get(a);
        tab2 = (double[]) org.get(b);
        //System.out.println("wsp: "+a+": " + tab1[1] + ","+tab1[2]+","+tab1[3]);
        //System.out.println("wsp: "+b+": " + tab2[1] + ","+tab2[2]+","+tab2[3]);
        odl = (float) (( tab1[1] - tab2[1]) * ( tab1[1] - tab2[1]));
        odl += (float) (( tab1[2] - tab2[2]) * ( tab1[2] - tab2[2]));
        odl += (float) (( tab1[3] - tab2[3]) * ( tab1[3] - tab2[3]));
        odl = (float) Math.sqrt(odl);
        return odl;
    }
    
    /**
     * Dodaj do wynikow elementy z kazdej listy sasiadow. Dla kazdej listy - jednego elemetu tablicy
     * zrob pary kazdy w kazdym i dodaj je do wynikow.
     */
    private void dodajWynikiSasiedzi(){
        int s;
        int tab[] = new int[2];
        for(int ii = 0; ii < i1; ii++){
            s = sasiedzi[ii].size();
            for(int i = 0; i < s - 1; i++){
                for(int j = i + 1; j < s; j++){
                    tab[0] = (int) sasiedzi[ii].get(i);
                    tab[1] = (int) sasiedzi[ii].get(j);
                    wynik.add(tab[0]);
                    wynik.add(tab[1]);
                }
            }
        }
    }
    
    
    /**
     * Wypelnia tablice sasiedzi i mozliwe
     */
    private void wypelnijTablice(){
        int[] komorka = new int[3];
        int[] sasiad = new int[3];
        double[] tab;
        String klucz;
        i1 = 0;
        i2 = 0;
        int nr;
        int atom;
        for(int i = 0; i < n; i++){
            //uzyskiwanie numeru komorki i-tego atomu
            tab = (double[]) wsp.get(i);
            komorka[0] = (int)tab[1];
            komorka[1] = (int)tab[2];
            komorka[2] = (int)tab[3];
            atom = (int) tab[0];
            klucz = komorka[0] + "," + komorka[1] + "," + komorka[2];
            //System.out.println("atom: "+i+" komorka: "+komorka[0] + ","+komorka[1]+","+komorka[2]);
            //czy na liscie atomow w danych komorkach jest juz ta komorka - tak
            if(numerIndeksS.containsKey(klucz)){
                nr = numerIndeksS.get(klucz);   //nr w tablicy dla listy dla danej komorki
                sasiedzi[nr].add(atom);
            }
            else{//nie ma tej komorki - dodaj do tablicy - dodaj do nastepnej i wpisz tam atom
                sasiedzi[i1] = new ArrayList();
                indexNumerS.put(i1, klucz);
                numerIndeksS.put(klucz, i1);
                sasiedzi[i1].add(atom);
                i1++;  
            }
            
            //teraz dodaj do list mozliwych sasiadow
            //System.out.println("komorka: "+komorka[0]+", "+komorka[1] +", "+komorka[2]);
            for(int j = 0; j <  3; j++){
                for(int k = 0; k < 3; k++){
                    for(int l = 0; l < 3; l++){
                        //numery wszystkich mozliwych sasiadow (odleglych o +-1)
                        if(!((j == 1) && (k == 1) == (l == 1))){
                            sasiad[0] = komorka[0] - 1 + j;
                            sasiad[1] = komorka[1] - 1 + k;
                            sasiad[2] = komorka[2] - 1 + l;
                            
                            //jesli komorka mialam numer 1 lub -1 to teraz dostaniemy numer 0
                            //a nie ma takich - po -1 jest od razu 1
                            //System.out.println("sasiad: "+sasiad[0]+", "+sasiad[1] +", "+sasiad[2]);
                            for(int m = 0; m < 3; m++){
                                if(sasiad[m] == 0){
                                    if(komorka[m] == 1){
                                        sasiad[m] = -1;
                                    }
                                    else if(komorka[m] == -1){
                                        sasiad[m] = 1;
                                    }
                                }
                            }
                            
                            klucz = sasiad[0] + "," + sasiad[1] + "," + sasiad[2];
                            if(numerIndeksM.containsKey(klucz)){
                                nr = numerIndeksM.get(klucz);   //nr w tablicy dla listy dla danej komorki
                                mozliwi[nr].add(atom);
                            }
                            else{//nie ma tej komorki - dodaj do tablicy - dodaj do nastepnej i wpisz tam atom
                                mozliwi[i2] = new ArrayList();
                                indexNumerM.put(i2, klucz);
                                numerIndeksM.put(klucz, i2);
                                mozliwi[i2].add(atom);
                                i2++;  
                            }
                        }
                    }
                }
            }
        }
    }
    
    
    
    
}
