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

package cz.vutbr.feec.utko.fojtoval.krypto.sifry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Pomocne metody, napr. vytvareni nove abecedy, zasifrovani textu atd..
 * @author fojtoval
 */
public class Utils {

    private Utils(){

    }

    /**
     * Vraci pole charu - upravenou abecedu (posunutou o vstupni parametr).
     * @param abeceda mezinarodni abeceda
     * @param posun parametr posunu
     * @return mezinarodni abeceda posunuta o parametr
     */
    public static char[] posunAbecedu(char[] abeceda, int posun) {

		if (posun < 0 || posun > abeceda.length) {
            throw (new IllegalArgumentException ("Maximalni posun je " + abeceda.length + ", " + "minimalni posun je 0 (zadano: " + posun + ")"));
		}

		char[] result = new char [abeceda.length];

		for (int i = 0; i < abeceda.length; i++) {
            result[i] = abeceda [(i + posun < abeceda.length) ? (i + posun) : (i + posun - abeceda.length)];
		}

		return result;

	}


    /**
     * Zasifruje vstupni text jednoduchym posunem.
     * @param source vstupni text
     * @param nabcd sifrovaci abeceda
     * @param bdofive pomocna
     * @return zasifrovany text
     */
    public static String zmenaTextuSubs(String source, char[] nabcd, Boolean bdofive) {

        String dtext="";
		char [] sourceArr = source.toCharArray();

        for (int i = 0; i < sourceArr.length; i++) {

            if ((bdofive) && ((i%5)==0) && (i!=0)) {
                dtext+=" ";
			}

            dtext+=nabcd[(int)(sourceArr[i] - 97)];

        }

        return dtext;

    }

    /**
     * Vytvori novou abecedu afinni sifry.
     * @param abeceda mezinarodni abeceda
     * @param a parametr 'a' afinni sifry
     * @param b parametr 'b' afinni sifry
     * @return nova abeceda
     */
    public static char[] afinni(char[] abeceda, int a, int b) {

			char[] result = new char [abeceda.length];

			for (int i = 0; i < abeceda.length; i++) {
				result[i] = (char)(((((int)abeceda[i]-97) * a + b) % 26) + 97);
            }

			return result;

    }

    /**
     * Vytvori novou abecedu monoalfabeticke sifry - varianta klic.
     * @param abeceda mezinarodni abeceda
     * @param vstupniklic klic
     * @return nova abeceda
     */
    public static char[] monoalfaKlic(char[] abeceda, char[] vstupniklic) {

        char[] result = new char [abeceda.length];
        boolean[] unique = new boolean[26];
        int k=0;

        Arrays.fill(unique, false);

        for (int i=0;i<vstupniklic.length;i++){
            if (!unique[vstupniklic[i]-'a']) {
                result[k]=vstupniklic[i];
                unique[vstupniklic[i]-'a']=true;
                k++;
            }
         }

        for (int i=0;i<26;i++) {
            if (!unique[i]) {
                result[k]=(char)(i+'a');
                k++;
            }
        }

        return result;

    }

   /**
    * Vytvori novou abecedu monoalfabeticke sifry - nahodna abeceda.
    * @param abeceda mezinarodni abeceda
    * @return nova abeceda
    */
   public static char[] nahodnaAbeceda(char[] abeceda) {

        char[] result = new char [abeceda.length];

        List <Character> pomocnaabcd = new ArrayList <Character> (abeceda.length);
        for (char znak : abeceda) {
            pomocnaabcd.add(znak);
        }

        Collections.shuffle(pomocnaabcd);
        for (int i = 0; i < abeceda.length; i++) {
            result[i] = pomocnaabcd.get(i);
    	}

    	return result;

    }

   /**
    * Vytvori novou abecedu monoalfabeticke sifry - zadani abecedy.
    * @param abeceda
    * @param abcd
    * @return mezinarodni abeceda
    */
   public static char[] zadaniAbc(char[] abeceda, List abcd) {

        char[] result = new char [abeceda.length];
        String pomocnaabc = "null";

        List abc = (List)abcd;

        for (int i = 0; i < 26; i++){
            result[i] = (Character)abc.get(i);
        }

        return result;

    }

   /**
    * Zasifrovani textu (source) pomoci sifry Vigenere.
    * @param source zdrojovy text
    * @param klic klic
    * @param bdofive pomocna
    * @return zasifrovany text
    */
   public static String zmenaTextuVig(String source, String klic, Boolean bdofive) {

        String cfina="";
        int p=0;

        for (int i=0; i<source.length();i++) {
           if (p==klic.length()){
               p=0;
           }

           if ((i!=0) && ((i%5)==0)){
               cfina+=" ";
           }

           cfina+=(char)((((int)(source.charAt(i)-'a'+klic.charAt(p)-'a'))%26)+'a');
           p++;
        }

        return(cfina);
    }

   /**
    * Zasifrovani textu (source) pomoci sifry Vigenere autoklic (jeden znak).
    * @param source vstupni text
    * @param klic klic
    * @param bdofive pomocna
    * @return zasifrovany text
    */
   public static String zmenaTextuVigAuto(String source, String klic, Boolean bdofive) {

        String cfina = "";
        klic+=source;
        for (int i = 0 ;i < source.length(); i++){

            if ((i!=0) && ((i%5)==0)){
                cfina+=" ";
            }

            if (((int)source.charAt(i) + (int)klic.charAt(i))>219) {
                cfina+=(char)((int)source.charAt(i)+(int)klic.charAt(i)-123);
            } else {
                  cfina+=(char)((int)source.charAt(i)+(int)klic.charAt(i)-97);
              }
        }

        return(cfina);

    }

    /**
     * Zasifrovani textu (source) pomoci sifry jednoducha transpozice.
     * @param source vstupni text
     * @param klic klic
     * @param bdofive pomocna promenna
     * @return zasifrovany text
     */
    public static String zmenaTextuTrans(String source, String klic, Boolean bdofive) {

        //doplneni x-ek do textu na nasobek klice
        if ((source.length() % klic.length()) != 0) {
            String sappend = "";
            for (int i = 0; i < (klic.length() - (source.length() % klic.length()));i++) {
                sappend=sappend+"x";
            }
            source+= sappend;
        }

        //upraveni klice kvuli shodnym pismenum v nem
        int[] aklic = new int[klic.length()];
        for (int i=0;i<klic.length();i++) {
            aklic[i]=0;
            for (int j=0;j<i;j++) {
                if(klic.charAt(j)<=klic.charAt(i)){
                    aklic[i]++;
                }
            }
            for (int j = i + 1; j < klic.length(); j++) {
                if(klic.charAt(j) < klic.charAt(i)){
                    aklic[i]++;
                }
            }
        }

        //sifrovani a prepis do sloupecku
        String cfina = "";
        int pcounter=0;
        for (int i = 0; i < klic.length(); i++) {
            for (int j = 0; j < klic.length(); j++) {
                if (aklic[j] == i){
                    for (int kk = 0; kk < (source.length()/klic.length()); kk++) {
                        pcounter++;
                        cfina+=source.charAt(j + klic.length() * kk);
                        if (pcounter%5==0) cfina+=" ";
                    }
                }

            }
        }

        return(cfina);

    }


    /**
     * Desifrovani afinni sifry pomoci zadanych parametru.
     * @param abeceda desifrovaci abeceda
     * @param parametr1 parametr afinni sifry
     * @param parametr2 parametr afinni sifry
     * @return desifrovany text
     */
    public static char[] afinniLus(char[] abeceda, int parametr1, int parametr2) {

        char[] result = new char [abeceda.length];

        for (int i = 0; i < 26; i++) {
            int j=i-parametr2;
            if (j<0) {
                j+=26;
            }
            j=(j*parametr1)%26;
            result[i]=(char)abeceda[j];
        }

        return(result);
    }

    /**
     * Vytvoreni desifrovaci abecedy susbtituce (varianta klic)
     * @param abeceda sifrovaci abeceda
     * @param vstupniklic klicm sifry
     * @return nova abeceda
     */
    public static char[] monoalfaKlicLus(char[] abeceda, char[] vstupniklic) {

        char[] resultpom = new char [abeceda.length];
        char[] result = new char [abeceda.length];
        boolean[] unique = new boolean[26];
        int k=0;

        Arrays.fill(unique, false);

        for (int i = 0; i < vstupniklic.length; i++){
            if (!unique[vstupniklic[i]-'a']) {
                resultpom[k] = vstupniklic[i];
                unique[vstupniklic[i] - 'a'] = true;
                k++;
            }
        }
                
        for (int i = 0; i < 26; i++) {
            if (!unique[i]) {
                resultpom[k]=(char)(i+'a');
                k++;
            }
        }

        for (int i=0;i<26;i++) {
            result[(int)(resultpom[i]-'a')]=(char)(i+'a');
        }

        return(result);

    }

    /**
     * Desifrovani Vigenere sifry pomoci zadanych parametru.
     * @param source vstupni zasifrovany text
     * @param klic klic sifry
     * @param bdofive pomocna promenna
     * @return desifrovany text
     */
    public static String zmenaTextuVigLus(String source, String klic, Boolean bdofive) {

        String pfina="";
        int p=0;

        for (int i = 0; i < source.length(); i++) {

            if (p == klic.length()){
                p=0;
            }

            if ((i!=0) && ((i%5)==0)){
               pfina += " ";
            }

            if ((int)(source.charAt(i)-klic.charAt(p))<0) {
                pfina+=(char)(((int)(source.charAt(i)-klic.charAt(p)+26)%26)+'a');
            } else pfina+=(char)(((int)(source.charAt(i)-klic.charAt(p))%26)+'a');

            p++;
        }

        return(pfina);
    }

    /**
     * Desifrovani Vigenere autoklic sifry pomoci zadanych parametru.
     * @param source vstupni zasifrovany text
     * @param klic klic sifry
     * @param bdofive pomocna promenna
     * @return desifrovany text
     */
    public static String zmenaTextuVigLusA(String source, String klic, Boolean bdofive) {

        String pfina="";
        int pcounter=0;

        for (int i = 0; i < source.length(); i++) {

            if ((i!=0) && ((i%5)==0)){
               pfina += " ";
               pcounter++;
            }

            if (((int)source.charAt(i) - (int)klic.charAt(0)) < 0){
                 pfina += (char)((int)(source.charAt(i)-(int)klic.charAt(0)) + 123);
            } else {
                  pfina += (char)((int)(source.charAt(i)-(int)klic.charAt(0)) + 97);
              }
              klic = Character.toString(pfina.charAt(i + pcounter));
        }

        return(pfina);
    }

    /**
     * Desifrovani jednoduche transpozice pomoci zadanych parametru.
     * @param source vstupni zasifrovany text
     * @param klic klic sifry
     * @param bdofive pomocna promenna
     * @return desifrovany text
     */
    public static String zmenaTextuTransLus(String source, String klic, Boolean bdofive) {

        int j = 0;
        int i = 0;
        String pfina = "";

        if ((klic != null) && (klic == null ? "" != null : !klic.equals("")) && (source.length() % klic.length() == 0)) {
            int[] aklic = new int[klic.length()];
            for (i = 0; i < klic.length(); i++) {
                aklic[i] = 0;
                for (j = 0; j < i; j++) {
                    if(klic.charAt(j) <= klic.charAt(i)) {
                        aklic[i]++;
                        }
                }

                    for (j = i+1; j < klic.length(); j++) {
                        if(klic.charAt(j) < klic.charAt(i)) {
                            aklic[i]++;
                        }
                    }
                }

                int radku = source.length()/klic.length();
                int pcounter=0;
                for (i = 0; i < radku; i++){
                    for (j = 0; j < klic.length();j ++){
                        pfina += source.charAt((aklic[j]*radku)+i);
                        pcounter++;
                        if ((pcounter%5) == 0){
                            pfina += " ";
                        }
                    }
                }
            

        }

        return(pfina);

    }

    /**
     * Ze Stringu bez mezer vytvori String s mezerami.
     * @param s vstupni String abecedy
     * @return abeceda
     */
    public static String abecedaMezery(String s){
        String finalniabeceda = " ";
        for(int i = 0; i < 26; i++){
            finalniabeceda += s.charAt(i) + " ";
        }
        return(finalniabeceda);
    }

    /**
     * Vyhleda vzdalenosti mezi zadanym opakovanym retezcem v textu (ktery se vyskytuje vicekrat).
     * @param text vstupni analyzovany text
     * @param retezec hledany retezec
     * @return
     */
    public static String hledejVzdalenosti(String text, String retezec){

        String vyskyt = "";
        int pvyskyt = text.indexOf(retezec,0);
        if (pvyskyt > -1) {
            for (int i = pvyskyt+1; i < text.length(); i++) {
                if (text.indexOf(retezec,i)>0) {
                    vyskyt += Integer.toString(text.indexOf(retezec,i) - pvyskyt) + " ";
                    pvyskyt = text.indexOf(retezec,i);
                    i = pvyskyt+1;
                } else continue;
            }
        }

        return(vyskyt);
    }

    /**
     * Vytvori subtext z puvodniho textu (pismena budou ve vzdalenosti 'delka' a posunem zacatku o 'odsazeni').
     * @param text vstupni text
     * @param delka delka klice
     * @param odsazeni odsazeni od pocatku
     * @return vysledny subtext
     */
    public static String Xtice(String text, int delka, int odsazeni) {
        String ntext = "";
        for (int i = 0; (i*delka+odsazeni) < text.length(); i++) {
            ntext += text.charAt(i*delka+odsazeni);
        }
        return(ntext);
    }

}

