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

package ggh;

import flanagan.math.Matrix;

/**
 *
 * @author Admin
 *
 * Datovy model - zpracovat vsechna data zadana uzivatelem a vypocitat
 * vsechny vysledky.
 *
 */
public class GGHData {
    private static GGHData instance;

    public static int MIN_DIMENSION = 2;
    public static int MAX_DIMENSION = 5;

    private int dimension = 2;

    private Matrix u_vector;
    private Matrix v_vector;
    private Matrix w_vector;
    
    private Matrix m_vector;
    private Matrix r_vector;
    private Matrix e_vector;

    private Matrix t_vector;
    private Matrix m_decrypted;
    private Matrix v_grid;

    private GGHData() {

    };

    public static GGHData getInstance(){
        if (instance == null) {
            instance = new GGHData();
        }

        return instance;
    }

    public int getDimension() {
        return dimension;
    }

    public void setDimension(int dimension) {
        this.dimension = dimension;
    }

    public Matrix getU_vector() {
        if (u_vector == null)
            u_vector = new Matrix(MAX_DIMENSION, MAX_DIMENSION);
        return u_vector;
    }

    public void setU_vector(Matrix u_vector) {
        this.u_vector = u_vector;
    }

    public Matrix getV_vector() {
        if (v_vector == null)
            v_vector = new Matrix(MAX_DIMENSION, MAX_DIMENSION);
        return v_vector;
    }

    public void setV_vector(Matrix v_vector) {
        this.v_vector = v_vector;
    }

    public Matrix getW_vector() {
        if (w_vector == null)
            w_vector = new Matrix(MAX_DIMENSION, MAX_DIMENSION);
        return w_vector;
    }

    public void setW_vector(Matrix w_vector) {
        this.w_vector = w_vector;
    }

    public Matrix getE_vector() {
        if (e_vector == null)
            e_vector = new Matrix(1, MAX_DIMENSION);
        return e_vector;
    }

    public void setE_vector(Matrix e_vector) {
        this.e_vector = e_vector;
    }

    public Matrix getM_vector() {
        if (m_vector == null)
            m_vector = new Matrix(1, MAX_DIMENSION);
        return m_vector;
    }

    public void setM_vector(Matrix m_vector) {
        this.m_vector = m_vector;
    }

    public Matrix getR_vector() {
        if (r_vector == null)
            r_vector = new Matrix(1, MAX_DIMENSION);
        return r_vector;
    }

    public void setR_vector(Matrix r_vector) {
        this.r_vector = r_vector;
    }

    public Matrix getT_vector() {
        if (t_vector == null)
            t_vector = new Matrix(1, MAX_DIMENSION);
        return t_vector;
    }

    public void setT_vector(Matrix t_vector) {
        this.t_vector = t_vector;
    }

    public Matrix getM_decrypted() {
        if (m_decrypted == null)
            m_decrypted = new Matrix(1, MAX_DIMENSION);
        return m_decrypted;
    }

    public void setM_decrypted(Matrix m_decrypted) {
        this.m_decrypted = m_decrypted;
    }

    public Matrix getV_grid() {
        if (v_grid == null)
            v_grid = new Matrix(1, MAX_DIMENSION);
        return v_grid;
    }

    public void setV_grid(Matrix v_grid) {
        this.v_grid = v_grid;
    }

    public Matrix generate_u_vector(int dimension) {
        u_vector = new Matrix(dimension, dimension);

        for (int i = 0; i < dimension; i++) {
            for (int j = 0; j < dimension; j++)

               if (dimension == 2) {
               u_vector.setElement(0, 0, -1118); //GENEROVAT VEKTOR U pro dimenzi 2
               u_vector.setElement(0, 1, -525); //
               u_vector.setElement(1, 0, 707);
               u_vector.setElement(1, 1, 332); }
               if (dimension == 3) {
               u_vector.setElement(0, 0, 4327); //GENEROVAT VEKTOR U pro dimenzi 3
               u_vector.setElement(0, 1, -15447);
               u_vector.setElement(0, 2, 23454);
               u_vector.setElement(1, 0, 3297);
               u_vector.setElement(1, 1, -11770);
               u_vector.setElement(1, 2, 17871);
               u_vector.setElement(2, 0, 5464);
               u_vector.setElement(2, 1, -19506);
               u_vector.setElement(2, 2, 29617); }
               if (dimension == 4) {
               u_vector.setElement(0, 0, 4327); //GENEROVAT VEKTOR U pro dimenzi 4
               u_vector.setElement(0, 1, 3297);
               u_vector.setElement(0, 2, 5464);
               u_vector.setElement(0, 3, 4327);
               u_vector.setElement(1, 0, -15447);
               u_vector.setElement(1, 1, -11770);
               u_vector.setElement(1, 2, -19506);
               u_vector.setElement(1, 3, -15447);
               u_vector.setElement(2, 0, 23454);
               u_vector.setElement(2, 1, 17871);
               u_vector.setElement(2, 2, 29617);
               u_vector.setElement(2, 3, 23454);
               u_vector.setElement(3, 0, -15447);
               u_vector.setElement(3, 1, -11770);
               u_vector.setElement(3, 2, -19506);
               u_vector.setElement(3, 3, -15448);}
               if (dimension == 5) {
               u_vector.setElement(0, 0, 4327); //GENEROVAT VEKTOR U pro dimenzi 5
               u_vector.setElement(0, 1, 3297);
               u_vector.setElement(0, 2, 5464);
               u_vector.setElement(0, 3, 4327);
               u_vector.setElement(0, 4, 3297);
               u_vector.setElement(1, 0, -15447);
               u_vector.setElement(1, 1, -11770);
               u_vector.setElement(1, 2, -19506);
               u_vector.setElement(1, 3, -15447);
               u_vector.setElement(1, 4, -11770);
               u_vector.setElement(2, 0, 23454);
               u_vector.setElement(2, 1, 17871);
               u_vector.setElement(2, 2, 29617);
               u_vector.setElement(2, 3, 23454);
               u_vector.setElement(2, 4, 17871);
               u_vector.setElement(3, 0, -15447);
               u_vector.setElement(3, 1, -11770);
               u_vector.setElement(3, 2, -19506);
               u_vector.setElement(3, 3, -15448);
               u_vector.setElement(3, 4, -11770);
               u_vector.setElement(4, 0, 23454);
               u_vector.setElement(4, 1, 17871);
               u_vector.setElement(4, 2, 29617);
               u_vector.setElement(4, 3, 23454);
               u_vector.setElement(4, 4, 17872);}
 }
       return u_vector;
  
   }

    public Matrix generate_v_vector(int dimension) {
        v_vector = new Matrix(dimension, dimension);

        for (int i = 0; i < dimension; i++) {
            for (int j = 0; j < dimension; j++)
                
               if (dimension == 2) {
                   v_vector.setElement(0, 0, 4); //GENEROVAT VEKTOR V pro dimenzi 2
                   v_vector.setElement(0, 1, 13);
                   v_vector.setElement(1, 0, -57);
                   v_vector.setElement(1, 1, -45); 
               }
               if (dimension == 3) {
               v_vector.setElement(0, 0, -97); //GENEROVAT VEKTOR V pro dimenzi 3
               v_vector.setElement(0, 1, 19);
               v_vector.setElement(0, 2, 19);
               v_vector.setElement(1, 0, -36);
               v_vector.setElement(1, 1, 30);
               v_vector.setElement(1, 2, 86);
               v_vector.setElement(2, 0, -184);
               v_vector.setElement(2, 1, -64);
               v_vector.setElement(2, 2, 78); }
               if (dimension == 4) {
               v_vector.setElement(0, 0, -72); //GENEROVAT VEKTOR V pro dimenzi 4
               v_vector.setElement(0, 1, 44);
               v_vector.setElement(0, 2, 44);
               v_vector.setElement(0, 3, -47);
               v_vector.setElement(1, 0, -11);
               v_vector.setElement(1, 1, 55);
               v_vector.setElement(1, 2, 111);
               v_vector.setElement(1, 3, 77);
               v_vector.setElement(2, 0, -159);
               v_vector.setElement(2, 1, -39);
               v_vector.setElement(2, 2, 103);
               v_vector.setElement(2, 3, 107);
               v_vector.setElement(3, 0, -45);
               v_vector.setElement(3, 1, 75);
               v_vector.setElement(3, 2, 43);
               v_vector.setElement(3, 3, 128);}
               if (dimension == 5) {
               v_vector.setElement(0, 0, -47); //GENEROVAT VEKTOR V pro dimenzi 5
               v_vector.setElement(0, 1, 69);
               v_vector.setElement(0, 2, 69);
               v_vector.setElement(0, 3, -22);
               v_vector.setElement(0, 4, -132);
               v_vector.setElement(1, 0, 14);
               v_vector.setElement(1, 1, 80);
               v_vector.setElement(1, 2, 136);
               v_vector.setElement(1, 3, 102);
               v_vector.setElement(1, 4, 28);
               v_vector.setElement(2, 0, -134);
               v_vector.setElement(2, 1, -14);
               v_vector.setElement(2, 2, 128);
               v_vector.setElement(2, 3, 132);
               v_vector.setElement(2, 4, -138);
               v_vector.setElement(3, 0, -20);
               v_vector.setElement(3, 1, 50);
               v_vector.setElement(3, 2, 18);
               v_vector.setElement(3, 3, 103);
               v_vector.setElement(3, 4, 111);
               v_vector.setElement(4, 0, -120);
               v_vector.setElement(4, 1, -17);
               v_vector.setElement(4, 2, 142);
               v_vector.setElement(4, 3, 99);
               v_vector.setElement(4, 4, 225);}
        }
        return v_vector;
    }

    public Matrix generate_w_vector(int dimension) {
        w_vector = new Matrix(dimension, dimension);

        for (int i = 0; i < dimension; i++) {
            for (int j = 0; j < dimension; j++) {
                w_vector = u_vector.times(v_vector);
            }
        }

        return w_vector;
    }
    
    public Matrix generate_m_vector(int dimension) {
        m_vector = new Matrix(1, dimension);

        //for (int i = 0; i < dimension; i++) {
            
               if (dimension == 2) {
                   m_vector.setElement(0, 0, 8); //GENEROVAT VEKTOR M pro dimenzi 2
                   m_vector.setElement(0, 1, 3);
               }
               if (dimension == 3) {
                   m_vector.setElement(0, 0, 86); //GENEROVAT VEKTOR M pro dimenzi 3
                   m_vector.setElement(0, 1, -35);
                   m_vector.setElement(0, 2, -32);
               }
               if (dimension == 4) {
                   m_vector.setElement(0, 0, 61); //GENEROVAT VEKTOR M pro dimenzi 4
                   m_vector.setElement(0, 1, -60);
                   m_vector.setElement(0, 2, -57);
                   m_vector.setElement(0, 3, -71);
               }
               if (dimension == 5) {
                   m_vector.setElement(0, 0, 37); //GENEROVAT VEKTOR M pro dimenzi 5
                   m_vector.setElement(0, 1, 85);
                   m_vector.setElement(0, 2, -45);
                   m_vector.setElement(0, 3, 72);
                   m_vector.setElement(0, 4, 57);
               }
       // }

        return m_vector;
    }
    
    public Matrix generate_r_vector(int dimension) {
        r_vector = new Matrix(1, dimension);

        for (int i = 0; i < dimension; i++) {
            if (dimension == 2) {
               r_vector.setElement(0, 0, 4); //GENEROVAT VEKTOR R pro dimenzi 2
               r_vector.setElement(0, 1, 2);}
               if (dimension == 3) {
               r_vector.setElement(0, 0, -4); //GENEROVAT VEKTOR R pro dimenzi 3
               r_vector.setElement(0, 1, -3);
               r_vector.setElement(0, 2, 2);}
               if (dimension == 4) {
               r_vector.setElement(0, 0, -9); //GENEROVAT VEKTOR R pro dimenzi 4
               r_vector.setElement(0, 1, -8);
               r_vector.setElement(0, 2, -3);
               r_vector.setElement(0, 3, 5);}
               if (dimension == 5) {
               r_vector.setElement(0, 0, 1); //GENEROVAT VEKTOR R pro dimenzi 5
               r_vector.setElement(0, 1, 2);
               r_vector.setElement(0, 2, 7);
               r_vector.setElement(0, 3, -5);
               r_vector.setElement(0, 4, -7);}
        }

        return r_vector;
    }
    
    public Matrix generate_e_vector(int dimension) {
        e_vector = new Matrix(1, dimension);

        e_vector = m_vector.times(w_vector).plus(r_vector);

        return e_vector;
    }

    public boolean check_vector_u() {
        if (u_vector == null) //vektor nebyl nastaven
            return false;

        if (Math.abs(Math.round(u_vector.determinant() * 100)/100.0) == 1.0)
            return true;
        else
            return false;
    }

    public boolean check_vector_v() {
        if (v_vector == null) //vektor nebyl nastaven
            return false;

        double size_v = 1;

        for (int i = 0; i < dimension; i++) {
             double temp_v = 0;
             for (int j = 0; j < dimension; j++) {
                temp_v += Math.pow(v_vector.getElement(i, j), 2); //soucet druhych mocnin
             }
           
             size_v *= Math.pow(temp_v, 0.5); //druha odmocnina
        }

        if (Math.pow(Math.abs(v_vector.determinant())/size_v, 1.0/dimension) >= 0.70 &&
            Math.pow(Math.abs(v_vector.determinant())/size_v, 1.0/dimension) <= 0.95)

            return true;
        else
            return false;
    }

    public Matrix compute_t_vector() {
        if (v_vector == null || e_vector == null)
            return null;

        t_vector = new Matrix(1, MAX_DIMENSION);

        double a[][] = v_vector.transpose().getArrayCopy();
        double b[] = e_vector.getRowCopy(0);

        MatrixUtil.gaussJordan(a, b);

        for (int i = 0; i < dimension; i++) {           
            t_vector.setElement(0, i, Math.round(b[i]));
        }

        return t_vector;
    }

    public Matrix computer_v_grid() {
        if (t_vector == null)
            return null; //vektor t nebyl nastaven

        if (v_grid == null)
            v_grid = new Matrix(1, MAX_DIMENSION);

        for (int i = 0; i < dimension; i++) {
            double sum = 0.0;

            for (int j = 0 ; j < dimension; j++) {
                sum += v_vector.getElement(j, i) * t_vector.getElement(0, j);
            }
            v_grid.setElement(0, i, sum);
        }
        
        return v_grid;
    }

    public Matrix compute_m_decrypted() {
        if (v_grid == null || w_vector == null)
            return null;

        if (m_decrypted == null)
            m_decrypted = new Matrix(1, MAX_DIMENSION);


        double a[][] = w_vector.transpose().getArrayCopy();
        double b[] = v_grid.getRowCopy(0);

        MatrixUtil.gaussJordan(a, b);

        for (int i = 0; i < dimension; i++) {
            m_decrypted.setElement(0, i, Math.round(b[i]));
        }

        return m_decrypted;
    }



}
