package a7;

public class HillCypher
{
    private DynamicArray2 d = new DynamicArray2();
    
    HillCypher()
    {
        
    }
    
    public HillCypher(String a, String b, String c, String d, String phrase) 
    {
        this.d.add(a);
        this.d.add(b);
        this.d.add(c);
        this.d.add(d);
        
        this.d.add(phrase);
        
        
    }
    public static String getLetterAt(int val) 
    {
        String[] alpha = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r",
                "s","t","u","v","w","x","y","z"};
        return alpha[val];
    }
    public static double getLetterVal(String a) 
    {
        
        String[] alpha = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r",
               "s","t","u","v","w","x","y","z"};
        double returnDouble = -1;
    
    
    
        for(int i = 0; i < alpha.length; i++) 
        {
            String tempChar = alpha[i];
            if(tempChar.equals(a)) 
            {
                return ((double)i);
            }
        }
        
        return returnDouble;
       
    }
    
    public String getKeyAt(int index) 
    {
        return this.d.get(index);
    }
    
    public String getKey() 
    {
        String returnString = "(" + this.d.get(0) + ", " + this.d.get(2) + ")" + "\n";
        returnString = returnString + "(" + this.d.get(1) + ", " + this.d.get(3) + ")" + "\n";
        
        return returnString;
    }
    
    
    /**
     * 
     * @return returnDouble    returns the double value calculated for the Determinant 
     *                             
     *                   A    =    (a, b) 
     *                             (c, d)
     * 
     * where the value is calculated by a*d - b*c;
     */
    public double detA() 
    {
        double returnDouble = -1;
        
        String a = getKeyAt(0); 
        String b = getKeyAt(1);
        String c = getKeyAt(2);
        String d = getKeyAt(3);
        
        double aVal = getLetterVal(a);
        double bVal = getLetterVal(b);
        double cVal = getLetterVal(c);
        double dVal = getLetterVal(d);
        
        returnDouble = aVal * dVal - bVal * cVal;
        
        
        return returnDouble;
    }
    
    public void inverseMatrix() 
    {

        String a = getKeyAt(0); 
        String b = getKeyAt(1);
        String c = getKeyAt(2);
        String d = getKeyAt(3);
        
        double aVal = getLetterVal(a);
        double bVal = getLetterVal(b);
        double cVal = getLetterVal(c);
        double dVal = getLetterVal(d);
        double kInverse = -1;
        
        Double determinant = this.detA() % 26;
        
        if(determinant < 0) 
        {
            determinant += 26;
        }
        
        for(int i = 0; i < 26; i++) 
        {
            Double checkVal = (determinant * i);
            if((checkVal % 26) == 1.0) 
            {
                kInverse = i;
            }
        }
       
        double inverseA = (dVal * kInverse) % 26;
        if(inverseA < 0) 
        {
            inverseA += 26;
        }
        
        double inverseB = (-bVal * kInverse) % 26;
        if(inverseB < 0) 
        {
            inverseB += 26;
        }
        double inverseC = (-cVal * kInverse) % 26;
        if(inverseC < 0) 
        {
            inverseC += 26;
        }
        double inverseD = (aVal * kInverse) % 26;
        if(inverseD < 0) 
        {
            inverseD += 26;
        }
        
        String inverseAChar = getLetterAt((int)Math.round(inverseA));
        String inverseBChar = getLetterAt((int)Math.round(inverseB));
        String inverseCChar = getLetterAt((int)Math.round(inverseC));
        String inverseDChar = getLetterAt((int)Math.round(inverseD));
        this.d.add(inverseAChar);
        this.d.add(inverseBChar);
        this.d.add(inverseCChar);
        this.d.add(inverseDChar);
    }
    
    public String scramble() 
    {
        
        String returnString = "";
        String a = getKeyAt(0); 
        String b = getKeyAt(1);
        String c = getKeyAt(2);
        String d = getKeyAt(3);
        
        double aVal = getLetterVal(a);
        double bVal = getLetterVal(b);
        double cVal = getLetterVal(c);
        double dVal = getLetterVal(d);
        String phrase = getKeyAt(4);
        
        Double newVal1 = -1.0;
        Double newVal2 = -1.0;
        
        for(int i = 0; i < phrase.length(); i+=2) 
        {
            String tempChar = (String)Character.toString(phrase.charAt(i));
          
            Double tempVal = getLetterVal(tempChar);
       
            String tempChar2 = (String)Character.toString(phrase.charAt(i+1));
            Double tempVal2 = getLetterVal(tempChar2);
            newVal1 = (tempVal * aVal + tempVal2 * bVal) % 26;
            String newChar = getLetterAt((int)Math.round(newVal1));
            
            newVal2 = (tempVal*cVal + tempVal2 * dVal) % 26;
            String newChar2 = getLetterAt((int)Math.round(newVal2));
            
            
           returnString = returnString + newChar + newChar2;
        }
        
        return returnString;
            
    }
    
    public String unscramble(String hidden) 
    {
        String returnString = "";
        String a = getKeyAt(this.d.size()-4); 
        String b = getKeyAt(this.d.size()-3);
        String c = getKeyAt(this.d.size()-2);
        String d = getKeyAt(this.d.size()-1);
        
        double aVal = getLetterVal(a);
        double bVal = getLetterVal(b);
        double cVal = getLetterVal(c);
        double dVal = getLetterVal(d);
        String phrase = hidden;
        
        Double newVal1 = -1.0;
        Double newVal2 = -1.0;
        
        for(int i = 0; i < phrase.length(); i+=2) 
        {
            String tempChar = (String)Character.toString(phrase.charAt(i));
          
            Double tempVal = getLetterVal(tempChar);
       
            String tempChar2 = (String)Character.toString(phrase.charAt(i+1));
            Double tempVal2 = getLetterVal(tempChar2);
            newVal1 = (tempVal * aVal + tempVal2 * bVal) % 26;
            String newChar = getLetterAt((int)Math.round(newVal1));
            
            newVal2 = (tempVal*cVal + tempVal2 * dVal) % 26;
            String newChar2 = getLetterAt((int)Math.round(newVal2));
            
            
           returnString = returnString + newChar + newChar2;
        }
        
        return returnString;
    }
    
    
   
    
    public static void main(String[] args) 
    {
        String a = "h";
        String b = "i";
        String c = "l";
        String d = "l";
        
        HillCypher test1 = new HillCypher(a, b, c, d, "cats");
        test1.inverseMatrix();
        
        System.out.println("The key entered is: " + "\n" + test1.getKey());
        System.out.println("The phrase entered is: " + "\n" + test1.getKeyAt(4));
        System.out.println();
        
        System.out.println("The scrambled phrase is: " + "\n" + test1.scramble());
        
        System.out.println("The unscrambled phrase is: " + "\n" + test1.unscramble("owrr"));
           
    }
    
    
    
    
    
    
  
    

}
