/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package pnandmd.Conformation;

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

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

    //mapa dla sin i cos aby nie obliczac ich za kazdym razem
    private Map<Double, Double> sinMap = new HashMap<Double, Double>();
    private Map<Double, Double> cosMap = new HashMap<Double, Double>();

    private double podstawaKat = 0.1;

    private int massC = 12;

    public ConformationUtils() {
        calculateSinCos();
    }

    public double calcRmsd(List wspPrzes, List wsp) {
        int n = wsp.size();
        double tabNowe[];
        double[] tabMiejsce = new double[3];
        double wynik = 0, pom = 0;
        for (int i = 0; i < n; i++) {
            tabNowe = (double[]) wsp.get(i);
            tabMiejsce[0] = (double) wspPrzes.get(i * 3);
            tabMiejsce[1] = (double) wspPrzes.get(i * 3 + 1);
            tabMiejsce[2] = (double) wspPrzes.get(i * 3 + 2);
            pom = tabMiejsce[0] - tabNowe[1];
            pom *= pom;
            wynik += pom;
            pom = tabMiejsce[1] - tabNowe[2];
            pom *= pom;
            wynik += pom;
            pom = tabMiejsce[2] - tabNowe[3];
            pom *= pom;
            wynik += pom;
        }
        return wynik;
    }

    public List<Double> obroc(List<Double> wsp, double kat, boolean osX, boolean osY, boolean osZ) {
        int m = wsp.size();
        double x, y, z, tmpX, tmpY, tmpZ;
        double cos, sin;
        if (!cosMap.containsKey(kat)) {
            cos = Math.cos(kat);
            sin = Math.sin(kat);
        } else {
            cos = cosMap.get(kat);
            sin = sinMap.get(kat);
        }
        if (osX) {
            for (int k = 0; k < m; k += 3) {
                x = wsp.get(k);
                y = wsp.get(k + 1);
                z = wsp.get(k + 2);
                tmpX = x;
                tmpY = cos * y + sin * z;
                tmpZ = -1.0 * sin * y + cos * z;
                wsp.set(k, tmpX);
                wsp.set(k + 1, tmpY);
                wsp.set(k + 2, tmpZ);
            }
        }
        if (osY) {
            for (int k = 0; k < m; k += 3) {
                x = wsp.get(k);
                y = wsp.get(k + 1);
                z = wsp.get(k + 2);
                tmpX = cos * x + sin * z;
                tmpY = y;
                tmpZ = -1.0 * sin * x + cos * z;
                wsp.set(k, tmpX);
                wsp.set(k + 1, tmpY);
                wsp.set(k + 2, tmpZ);
            }
        }
        if (osZ) {
            for (int k = 0; k < m; k += 3) {
                x = wsp.get(k);
                y = wsp.get(k + 1);
                z = wsp.get(k + 2);
                tmpX = cos * x + (-1.0) * sin * y;
                tmpY = sin * x + cos * y;
                tmpZ = z;
                wsp.set(k, tmpX);
                wsp.set(k + 1, tmpY);
                wsp.set(k + 2, tmpZ);
            }
        }
        return wsp;
    }

    private void calculateSinCos() {
        List<Double> katy = new ArrayList<>();
        int n = 3;
        for (int i = 0; i <= n; i++) {
            katy.add(i * podstawaKat);
            katy.add(i * podstawaKat * -1);
        }
        for (Double a : katy) {
            sinMap.put(a * 1.0, Math.sin(a));
            cosMap.put(a * 1.0, Math.cos(a));
        }
    }

    public double getPodstawaKat() {
        return podstawaKat;
    }

    public double[] centerOfMass(List<double[]> wsp) {
        double[] tab = new double[4];
        double sumX = 0, sumY = 0, sumZ = 0;
        int m = wsp.size();
        for (int i = 0; i < m; i++) {
            double tabNowe[] = (double[]) wsp.get(i);
            sumX = sumX + massC * tabNowe[1];
            sumY = sumY + massC * tabNowe[2];
            sumZ = sumZ + massC * tabNowe[3];
        }
        double sumM = massC * m;
        tab[0] = 0;
        tab[1] = sumX / sumM;
        tab[2] = sumY / sumM;
        tab[3] = sumZ / sumM;
        return tab;
    }

    public double[] centerOfMassList(List<Double> wsp) {
        double[] tab = new double[3];
        double sumX = 0, sumY = 0, sumZ = 0;
        int m = wsp.size();
        for (int i = 0; i < m; i = i + 3) {
            double x1 = wsp.get(i);
            double x2 = wsp.get(i + 1);
            double x3 = wsp.get(i + 2);
            sumX = sumX + massC * x1;
            sumY = sumY + massC * x2;
            sumZ = sumZ + massC * x3;
        }
        double sumM = massC * m / 3;
        tab[0] = sumX / sumM;
        tab[1] = sumY / sumM;
        tab[2] = sumZ / sumM;
        return tab;
    }
}
