using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;

namespace Verifier
{
    public partial class Form1 : Form
    {
        //Proměnné pro výpočet
        private string q;
        private string g;
        private string p;
        private string publicKeyPA;             //Veřejný klíč PA
        private string publicKeyAS;             //Veřejný klíč AS

        private string status;                  //Proměnná pro ukládání informací
        private int uplynulyCas;                //Proměnná pro počítání doby práce programu

        Thread testovaciVlakno;                 //Vytvoření nového vlákna       

        private void setQ(string q)
        {
            this.q = q;
        }
        private string getQ()
        {
            return this.q;
        }
        private void setG(string g)
        {
            this.g = g;
        }
        private string getG()
        {
            return this.g;
        }
        private void setP(string p)
        {
            this.p = p;
        }
        private string getP()
        {
            return this.p;
        }
        private void setPublicKeyPA(string publicKeyPA)
        {
            this.publicKeyPA = publicKeyPA;
        }
        private string getPublicKeyPA()
        {
            return this.publicKeyPA;
        }
        private void setPublicKeyAS(string publicKeyAS)
        {
            this.publicKeyAS = publicKeyAS;
        }
        private string getPublicKeyAS()
        {
            return this.publicKeyAS;
        }

        private void setStatus(string status)
        {
            this.status += status;
        }
        private string getStatus()
        {
            return this.status;
        }

        public Form1()
        {
            InitializeComponent();
        }



        //----------------------------------------------------------------------------
        // Metoda sloužící pro ověření tokenu
        //---------------------------------------------------------------------------- 
        private void SpustTest()
        {
            setStatus("---  Začátek\n");

            pbStav.BackColor = Color.Yellow;        //Barva určující - průběh testováni

            //Inicializace proměných
            bool overeno = false;
            bool errorSpojeni = false;
            bool errorVypocet = false;
            bool platnyPodpis = false;
            bool errorToken = false;
            string c = "";
            string a = "";
            string sigPA = "";
            string z = "";
        
            //Vytvoření instance třídy, která slouží pro komunikaci s kartou
            MyCompany.Client.ClientApp ca = new MyCompany.Client.ClientApp();

            //Vytvoření instance třídy pro operace ověření
            Verify vrf = new Verify();

            try
            {
                //Faze 1:
                //   token je v pořadí: 'c' 'a' 'sigPA' :oddělovačem je mezera

                //Informování o stavu tokenu z karty
                setStatus("Smartkarta: Probíhá odesílání tokenu\n");

                //Přijetí tokenu
                string token = ca.TransferZKarty_token();
                setStatus("Smartkarta: Token odeslán\n");

                //Získání jednotlivých parametrů
                string[] tokenSplit = token.Split(' ');
                c = tokenSplit[0];
                a = tokenSplit[1];
                sigPA = tokenSplit[2];
            }
            catch (Exception)
            {
                //Došlo k chybě spojení s kartou
                errorSpojeni = true;
            }

            //Ověření, zda nedošly z karty jen prázdné hodnoty
            if (c == "" || a == "" || sigPA == "")
            {
                errorToken = true;

                if (errorSpojeni == true)
                {
                    MessageBox.Show("Selhalo spojení se smartkartou. Smartkarta byla pravděpodobně vyjmuta a nelze obnovit spojení. Zkuste restartovat program.",
                        "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    setStatus("Chyba!      Selhalo spojení s kartou\n");
                }
                else
                {
                    MessageBox.Show("Obdrženy prázdné hodnoty tokenu.",
                       "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    setStatus("Chyba!      Obdrženy prázdné hodnoty tokenu\n");
                }               
            }

            //Jestliže nedošlo k chybě při spojení ani k přijetí neplatného tokenu ..
            if (errorToken == false && errorSpojeni == false)
            {
                //Faze 2.1:
                //   Overeni podpisu přijatého tokenu
                vrf.RSAimportVK(getPublicKeyPA());
                string zprava = c + " " + a + " " + getPublicKeyAS();
                setStatus("Verifier  : Probíhá ověřování podpisu tokenu..\n");
                platnyPodpis = vrf.RSAoveritPodpis(zprava, sigPA);

                if (platnyPodpis == true)
                {
                    //Faze 2 a 3: 
                    //   vygenerování náhodného čísla 'e'
                    //   výpočet odezvy na 'e' z karty
                    int[] rndE = vrf.generujE(getQ());
                    setStatus("Verifier  : Vygenerována náhodná hodnota 'e'\n");

                    try
                    {
                        setStatus("Smartkarta: Probíhá výpočet odezvy 'z'\n");
                        z = IntToString(ca.TransferZKarty_eResponse(rndE));
                        setStatus("Smartkarta: Vypočtena odezva 'z'\n");
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("Smartkarta ukončila spojení nebo spojení se smartkartou nelze navázat.",
                            "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        setStatus("Chyba!      Smartkarta ukončila spojení nebo spojení se smartkartou nelze navázat\n");

                        errorVypocet = true;
                    }

                    //Jestliže karta vrátila platnou hondnotu a nedošlo k chybě při výpočtu na kartě..
                    if (errorVypocet == false)
                    {
                        try
                        {
                            //Faze 4:
                            //   overeni:
                            overeno = vrf.overeni(z, getG(), a, c, IntToString(rndE), getP());
                            setStatus("Verifier  : Probíhá ověřování tokenu..\n");

                            //Faze 5:
                            //   výsledek:
                            if (overeno == true)
                            {
                                setStatus("Verifier  : Smartkarta byla úspěšně ověřena\n");
                                pbStav.BackColor = Color.Green;
                            }
                            else
                            {
                                setStatus("Verifier  : Neplatný token\n");
                                pbStav.BackColor = Color.Red;
                            }
                            loguj(overeno, c, a, IntToString(rndE), z);
                        }
                        catch (Exception)
                        {
                            MessageBox.Show("Selhal proces ověřování.",
                                "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            setStatus("Chyba!      Selhal proces ověřování\n");
                        }
                    }
                }
                else
                {
                    //Jestliže je neplatný podpis - informuj o této skutečnosti a udělej záznam do logu
                    setStatus("Verifier  : Neplatný podpis tokenu\n");
                    pbStav.BackColor = Color.Red;
                    loguj(false, c, a, " ", " ");
                }
            }

            //this.btnOtestuj.Enabled = true;
            setStatus("---  Konec\n");

            //Ukončení měření času
            this.tmCasovac.Stop();

            //Zrušení vlákna
            testovaciVlakno.Abort();
        }

        //----------------------------------------------------------------------------
        // Metoda sloužící pro převedení pole intů na string
        //---------------------------------------------------------------------------- 
        private string IntToString(int[] a)
        {
            string result = "";
            for (int i = 0; i <= a.Length - 1; i++)
            {
                result = result + a[i].ToString();
            }
            return result;
        }

        //----------------------------------------------------------------------------
        // Metoda sloužící pro logování úspěšných i neúspěšných pokusů
        //---------------------------------------------------------------------------- 
        private void loguj(bool overeno, string c, string a, string e, string z)
        {
            string log = "";
            string aktCas = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");

            if (overeno == true)
            {
                log = aktCas + " " + " 1 " + " " + c + " " + a + " " + e + " " + z + "\n";
            }
            else
            {
                log = aktCas + " " + " 0 " + " " + c + " " + a + "\n";
            }

            try
            {
                //Jestli neexistuje soubor TokenList.xml 
                if (!File.Exists("Verifier_log.txt"))
                {
                    //vytvoří soubor Verifier_log.txt
                    FileStream file = new FileStream("Verifier_log.txt", FileMode.OpenOrCreate, FileAccess.Write);
                    StreamWriter sw = new StreamWriter(file);

                    //Vytvoření a zapsání úvodních informací a logu
                    sw.WriteLine("-----------------------\n");                   
                    sw.WriteLine("Log je ve formátu:");
                    sw.WriteLine(" ");
                    sw.WriteLine("rrrr.mm.dd hh:mm:ss  x  C A E Z");
                    sw.WriteLine(" ");
                    sw.WriteLine("V případě úspěšného ověření (x = 1) jsou uvedeny všechny výše uvedené hodnoty (C A E Z),");
                    sw.WriteLine("v případě neúspěšného ověření (x = 0) jsou uvedeny pouze některé hodnoty (C A).");
                    sw.WriteLine("-----------------------");
                    sw.WriteLine(" ");
                    sw.WriteLine(log);                    

                    sw.Close();
                    file.Close();
                }
                else        //Jestliže je soubor vytvořený
                {
                    //Otevře soubor a přida nový log za poslední log v souboru
                    FileStream file = new FileStream("Verifier_log.txt", FileMode.Append, FileAccess.Write);
                    StreamWriter sw = new StreamWriter(file);

                    //Zapsání dalšího logu 
                    sw.WriteLine(log);

                    sw.Close();
                    file.Close();
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Došlo k chybě při ukládání logu.",
                    "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        //----------------------------------------------------------------------------
        // Ošetření stisknutí tlačítka "Ověřit" - spoušté ověřovací proces
        //----------------------------------------------------------------------------
        private void button1_Click(object sender, EventArgs e)
        {
            //Spuštění časovače pro měření uplynulého času
            this.tmCasovac.Enabled = true;              
            this.uplynulyCas = 0;
            this.tmCasovac.Start();

            //Spuštění nového vlákna, ve kterém bude probíhat operace ověřování
            testovaciVlakno = new Thread(SpustTest);
            testovaciVlakno.Start();

            //Smazání předchozích informativních výpisů z programu
            this.status = "";
         }

        //----------------------------------------------------------------------------
        // Časovač měřící uběhlý čas od započetí ověřování
        //----------------------------------------------------------------------------
        private void tmCasovac_Tick(object sender, EventArgs e)
        {
            uplynulyCas ++;
            lblCas.Text = "Uplynulý čas: " + uplynulyCas.ToString()+"s";            
        }

        //----------------------------------------------------------------------------
        // Slouží pro import parametrů nutných pro výpočet
        //----------------------------------------------------------------------------
        private void btnImport_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                FileStream fs = new FileStream(openFileDialog.FileName, FileMode.Open);
                TextReader tr = new StreamReader(fs);

                string parametry = tr.ReadLine();

                tr.Close();
                fs.Close();

                //Načtení parametrů do příslušných proměných, parametry
                //   jsou v pořadí 'p q g1 g2 publicKeyPA publicKeyAS'
                string[] param = parametry.Split(' ');

                try
                {
                    setP(param[0].ToString());
                    setQ(param[1].ToString());
                    setG(param[2].ToString());
                    setPublicKeyPA(param[4].ToString());
                    setPublicKeyAS(param[5].ToString());

                    btnOtestuj.Enabled = true;

                    //Výpis informací
                    setStatus("Verifier  : Načteny parametry 'p', 'q', 'g', 'VK_PA' a 'VK_AS'\n");
                }
                catch (Exception)
                {
                    MessageBox.Show("Pokusili ste se načíst neplatný soubor s parametry.",
                        "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            else 
            {
                MessageBox.Show("Je potřeba načíst soubory.",
                    "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        //----------------------------------------------------------------------------
        // Časovač pravidelně vypisující stav aktuálně probíhaných operací
        //----------------------------------------------------------------------------
        private void tmStatus_Tick(object sender, EventArgs e)
        {
            lblStatus.Text = status;
        }
    }
}
