import java.util.*;

public class Spy
{
    /*******************************************************
     ** Attributes:
     * name, serialID, rank, enPass, secretPortion, phoenix
     ******************************************************/
    
    //A spy's name
    private String name;
    
    // A Spy's serial ID 
    private long serialID;
    
    // A spy's rank (ranging from 1 to 5)
    private int rank;
    
    // A spy's encoded Secret
    private String enPass;
    
    //A spy's share of the secret
    private String secretPortion;
    
    // Encoding of the concatenation of all spies' passwords
    private static String phoenix = "";
    
    /*********************************************************************
     ** Methods
     *********************************************************************/
    
    // Constructor
    
    public Spy(String inputName, String password, int inputRank)
    {
        //Set name and rank appropriately
        name = inputName;
        rank = inputRank;
        
        enPass = encode(password.toUpperCase());
        
        //SerialID:  202**r where ** can be any * digit between 0 and 9 and r is the spy's rank
        
        Random gen = new Random();
        serialID = 202*1000 + gen.nextInt(100)*10 + rank;
        
        
        // secretPortion should be set to the spy's share of the secret.
        secretPortion = chopMsg();    
        
    }
    
    /******************************************
     * Accessor Methods: "Getters" and "Setters"
     *****************************************/
    
    public String getName()
    {
        return name;
    }
    
    public long getID()
    {
        return serialID;    
    }
    
    public String getSecretPortion()
    {
        return secretPortion;
        
    }
    
    public String getEnPass()
    {
        return enPass;    
    }
    
    // Create a string that is the concatenation of spies' passwords and then encodes it 
    public static void setPhoenix(String[] input)
    {
        for(int i = 0; i < input.length; i++)
            {
                phoenix +=  input[i];
            }
        phoenix = encode(phoenix);
    }
    
    /**************************************
     ** Cryptography
     ***************************************/
    
    /**
     * Pre: None
     * Post: The input string is encoded using the following simple purmutation 
     * 
     * Encoding scheme:
     * 
     * Divide input into blocks of length six and permute as follows:
     * (where i--> j means that character at position i is swaped with character at 
     * position j)
     *  0 --> 1
     *  1 --> 3
     *  2 --> 5
     *  3 --> 4
     *  4 --> 0
     *  5 --> 2
     *  If a string is not a multiple of six, then append it at the end with character #.
     *  Add the number of padded characters at the beginning of each (permuted) block.
     * */
    
    public static String encode(String input)
    {
        String temp = input, loopTemp = "";
        int length = input.length();
        //int blockNums = (int) Math.ceil(length / 6);
        String result = "";
        int poundCount = 0, iterations = 6 - length%6;
        
        //Append #'s at the end to make the length of the input a multiple of 6
        for (int i = 0; i < iterations; i++)
            {
                temp += "#";
                poundCount++;
            }
        
        int blockNums = temp.length() / 6;
        
        for (int i = 0; i < blockNums - 1 ; i++)
            {
                loopTemp  = temp.substring(6*i, 6*i + 6);
                result += "0" + loopTemp.charAt(4) + loopTemp.charAt(0) + loopTemp.charAt(5) + loopTemp.charAt(1) + loopTemp.charAt(3) + loopTemp.charAt(2);
            }
        
        //Encode the last block
        loopTemp = temp.substring(temp.length() - 6);
        result += "" + poundCount + loopTemp.charAt(4) + loopTemp.charAt(0) + loopTemp.charAt(5) + loopTemp.charAt(1) + loopTemp.charAt(3) + loopTemp.charAt(2);
        return result;
    }
    
    /**
     * Pre: None
     * Post: The input string is decoded using the above permutation scheme:
     * (permutation(permutation msg)) = msg
     * 
     * Decoding scheme:
     *  
     * Divide input into blocks of length seven. The first character of the block will indicate
     * how many padded characters were added. Remove the first character (inicating the number of #'s added), 
     * and then permute as follows:
     * (where i--> j means that character at position i is swaped with character at 
     * position j)
     *  0 --> 4
     *  1 --> 0
     *  2 --> 5
     *  3 --> 1
     *  4 --> 3
     *  5 --> 2
     *  At the last step, remove the #'s from the decoding and append the blocks together.
     * */  
    
    public static String decode(String input)
    {
        // We assume that the input is of proper format and therefore has a multiple of 7 characters
        int blockNums = input.length() / 7;
        String temp = "", result = "";
        char pound;
        
        for (int i = 0 ; i < blockNums-1 ; i++)
            {
                temp = input.substring(7*i + 1, 7*i + 7);
                result += "" + temp.charAt(1) + temp.charAt(3) + temp.charAt(5) + temp.charAt(4) + temp.charAt(0) + temp.charAt(2);
            }
        // Decoding the Last block
        temp = input.substring(input.length() -  7);
        pound = temp.charAt(0);
        temp = temp.substring(1);
        result += "" + temp.charAt(1) + temp.charAt(3) + temp.charAt(5) + temp.charAt(4) + temp.charAt(0) + temp.charAt(2);
        
        switch(pound)
            {
            case '1':
                result = result.substring(0, result.length() - 1);
                break;
            case '2':
                result = result.substring(0, result.length() - 2);
                break;
            case '3':
                result = result.substring(0, result.length() - 3);
                break;
            case '4':
                result = result.substring(0, result.length() - 4);
                break;
            case '5':
                result = result.substring(0, result.length() - 5);
                break;
            }
        return result;
    }
    
    // Chop the Master secret into five portions and output the encoding of the spy's corresponding portion 
    
    public String chopMsg()
    {
        String secret = encode(Secret.secret);
        int blockSize = (int) Math.ceil(secret.length() / 5);
        String result = "";
        
        if (rank != 5)
            result = secret.substring((rank-1)*blockSize, (rank*blockSize));    
        
        else
            result = secret.substring(4*blockSize);
        return result;
    }
    
    // This method will be called in SpyTest.java to enveil the secret by calling the decode method
    public static String unveilSecret(String input)
    {
        return decode(input);
    }
    
    public static String getPhoenix()
    {
        return phoenix;
    }
}
