using System;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using System.Data;
using Oracle.ManagedDataAccess.Client;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Controls;
using co_zpracování;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Documents;
using System.Windows.Media;
using Microsoft.Win32;

namespace co_zpracování
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        DispatcherTimer timer = new DispatcherTimer();
        //System.Timers.Timer timer;
        bool dokoncit;
        public Soubor s1 { get; set; }
        CancellationTokenSource zastavit;
        Progress<Status> Status;
        bool aktualizacePrvku;
        int interval = 0;

        public MainWindow()
        {
            InitializeComponent();
            stopButton.IsEnabled = false;
            finishButton.IsEnabled = false;
            dokoncit = false;
            aktualizacePrvku = false;
            timer.Tick += new EventHandler(TimerClick);
            timer.Interval = new TimeSpan(0, 0, 0);

            if (!IsolatedStorage.ExistujeSoubor("MDB"))
            {
                try
                {
                    var w = new HesloMDB();
                    if (w.ShowDialog() == true)
                    {
                        IsolatedStorage.ZapisSoubor("MDB", Krypt.Kryptuj(w.Heslo));
                    }
                }
                catch(Exception ex)
                {
                    MessageBox.Show(string.Format("Nepodařilo se vytvořit zašifrovaný soubor s heslem pro DB kontaktů: {0}{1}", Environment.NewLine, ex.Message));
                }
            }
        }

        /// <summary>
        /// Timer pro automatické zpracování. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void TimerClick(object sender, EventArgs e)
        {
            if(timer.Interval == new TimeSpan(0,0,0))
            {
                timer.Interval = new TimeSpan(0, 5, 0);
            }       
            s1 = new Soubor(TextBox_Zdroj.Text, TextBox_Zpracovani.Text, TextBox_Zpracovane.Text, TextBox_Nezpracovane.Text);
            zastavit = new CancellationTokenSource();
            TextBox_PocetAsync.IsReadOnly = true;
            startButton.IsEnabled = false;
            stopButton.IsEnabled = true;
            CycleButton.IsEnabled = false;
            finishButton.IsEnabled = true;
            Status = new Progress<Status>(stat => AppendLine(Log1, stat.message, stat.color));
            string id = TextBox_Id.Text;
            string psw = passwordBox.Password;
            int pocetAsync;
            if (TextBox_PocetAsync.Text == "" || Convert.ToInt32(TextBox_PocetAsync.Text) == 0)
                pocetAsync = 5;
            else
                pocetAsync = Convert.ToInt32(TextBox_PocetAsync.Text);
            try
            {
                timer.Stop();   // Zastavuje timer aby neběžel paralelně se zpracováním a nezačínal se tak druhý soubor.
                s1.AdrSouboru = s1.HledejSoubor();  // Hledá slo soubor v adresářích
                var task = Zpracovani.ZpracujSoubor(zastavit.Token, Status, s1, id, psw, pocetAsync);
                await Task.WhenAll(task);
                if (dokoncit == false)  // Po dokončení zpracování opět spustí timer, pokud nebylo zmáčknuto dokončení momentárně běžícího souboru.
                {                    
                    timer.Start();                    
                }                    
            }
            catch (OperationCanceledException ex)
            {

            }
            catch (FileNotFoundException ex)
            {
                AppendLine(Log1, String.Format("Nebyl nalezen žádný soubor ke zpracování {0}.", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss")), "black");
                if(dokoncit == false)
                    timer.Start();
            }
            catch (Exception ex)
            {
                if(s1.AdrSouboru != "")
                    s1.NedokončenoChyba(s1.AdrSouboru, Status, ex);
                if(dokoncit == false)
                    timer.Start();
                //AppendLine(Log1, s1.AdrSouboru);
            }
            finally
            {
                if (Directory.Exists(s1.AdrTemp))
                    Directory.Delete(s1.AdrTemp, true);
                zastavit.Dispose();
                if (s1.AdrSouboru != "")
                    timer.Interval = new TimeSpan(0, 0, 0);
                TextBox_PocetAsync.IsReadOnly = false;
                dokoncit = false;
                if (aktualizacePrvku == true)
                {
                    startButton.IsEnabled = true;
                    stopButton.IsEnabled = false;
                    finishButton.IsEnabled = false;
                    CycleButton.IsEnabled = true;
                }                
                AppendLine(Log1, string.Format("Interval timeru: {0}", interval), "orange");
                interval++;
            }
        }
            
        #region AppendLine

        /// <summary>
        /// Metoda sloužící k odřádkování logu v případě, že je na aktuálním řádku napsát text
        /// </summary>
        /// <param name="source">TextBox do kterého se zapisuje.</param>
        /// <param name="value">Hodnota která se zapisuje.</param>
        public static void AppendLine(TextBox source, string value)
        {
            if (source.Text.Length == 0)
                source.Text = value;
            else
            {
                source.AppendText("\r\n" + value);
                source.ScrollToEnd();
            }                
        }
        public static void AppendLine(RichTextBox source, string value)
        {
            string str = new TextRange(source.Document.ContentStart, source.Document.ContentEnd).Text;
            if (str.Length == 0)
                source.AppendText(value);
            else
            {
                source.AppendText("\r" + value);
                source.ScrollToEnd();
            }
        }
        /// <summary>
        /// Slouží k zápisu Logu tak, aby nové řádky byly odřádkovány a automaticky byl Log scrollovaný, plus výběr barvy.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="text"></param>
        /// <param name="color"></param>
        public static void AppendLine(RichTextBox source, string text, string color)
        {
            string str = new TextRange(source.Document.ContentStart, source.Document.ContentEnd).Text;
            if (str.Length == 0)
            {
                BrushConverter bc = new BrushConverter();
                TextRange tr = new TextRange(source.Document.ContentEnd, source.Document.ContentEnd);
                tr.Text = text;
                try
                {
                    tr.ApplyPropertyValue(TextElement.ForegroundProperty, bc.ConvertFromString(color));
                }
                catch (FormatException) { }
            }
            else
            {
                BrushConverter bc = new BrushConverter();
                TextRange tr = new TextRange(source.Document.ContentEnd, source.Document.ContentEnd);
                tr.Text = "\r"+text;
                try
                {
                    tr.ApplyPropertyValue(TextElement.ForegroundProperty, bc.ConvertFromString(color));

                    source.ScrollToEnd();
                }
                catch (FormatException) { }
            }
        }

        #endregion
        
                       

        /// <summary>
        /// Zastaví zpracování slo souboru (jednoho nebo automaticky zpracovávaného).
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stopButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (timer.IsEnabled)
                {
                    timer.Interval = new TimeSpan(0, 0, 0);
                    timer.Stop();                    
                    stopButton.IsEnabled = false;
                    finishButton.IsEnabled = false;
                    startButton.IsEnabled = true;
                    CycleButton.IsEnabled = true;
                }
                aktualizacePrvku = true;
                zastavit.Cancel();                
            }            
            catch(Exception ex) { }       
        }

        /// <summary>
        /// Spustí zpracování jednoho slo souborů
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            s1 = new Soubor(TextBox_Zdroj.Text, TextBox_Zpracovani.Text, TextBox_Zpracovane.Text, TextBox_Nezpracovane.Text);
            zastavit = new CancellationTokenSource();
            startButton.IsEnabled = false;
            stopButton.IsEnabled = true;
            CycleButton.IsEnabled = false;
            TextBox_PocetAsync.IsReadOnly = true;
            Status = new Progress<Status>(stat => AppendLine(Log1, stat.message, stat.color));
            string id = TextBox_Id.Text;
            string psw = passwordBox.Password;
            int pocetAsync;
            if (TextBox_PocetAsync.Text == "" || Convert.ToInt32(TextBox_PocetAsync.Text) == 0)
                pocetAsync = 5;
            else
                pocetAsync = Convert.ToInt32(TextBox_PocetAsync.Text);
            try
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Title = "Vyber slo soubor";
                ofd.Filter = "Slo soubory|*.slo|Slog soubory|*.slog|Slogcr soubory|*.slogcr";
                ofd.InitialDirectory = s1.AdrZdroj;
                if (ofd.ShowDialog() == true)
                {
                    s1.AdrSouboru = ofd.FileName;
                    await Task.Run(() => Zpracovani.ZpracujSoubor(zastavit.Token, Status, s1, id, psw, pocetAsync));
                }
            }
            catch (OperationCanceledException ex)
            {

            }
            catch (FileNotFoundException ex)
            {
                AppendLine(Log1, String.Format("Nebyl nalezen žádný soubor ke zpracování {0}.", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss")), "black");
            }
            catch (Exception ex)
            {
                s1.NedokončenoChyba(s1.AdrSouboru, Status, ex);
            }            
            finally
            {
                if(Directory.Exists(s1.AdrTemp))
                    Directory.Delete(s1.AdrTemp, true);
                zastavit.Dispose();
                TextBox_PocetAsync.IsReadOnly = false;
                stopButton.IsEnabled = false;
                startButton.IsEnabled = true;
                CycleButton.IsEnabled = true;
            }
        }       

        private void TextBox_Zpracovani_TextChanged(object sender, TextChangedEventArgs e)
        {

        }

        private void Log_TextChanged(object sender, TextChangedEventArgs e)
        {

        }
        /// <summary>
        /// Testuje čísla psané do text boxu pro počet zpracovávaných audittrailů.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox_PocetAsync_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            CheckIfNumber(e);
        }
        /// <summary>
        /// Zamezuje psaní písmen a symbolů.
        /// </summary>
        /// <param name="e"></param>
        private void CheckIfNumber(TextCompositionEventArgs e)
        {
            int result;
            if(!(int.TryParse(e.Text, out result)))
            {
                e.Handled = true;
            }
        }
        /// <summary>
        /// Zamezuje psaní mezery do text boxu pro počet zpradcovávaných audittrailů.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox_PocetAsync_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space)
            {
                e.Handled = true;
            }
            base.OnPreviewKeyDown(e);
        }
        private void NastavitHesloMDB()
        {
            try
            {
                    var w = new HesloMDB();
                    if (w.ShowDialog() == true)
                    {
                        IsolatedStorage.ZapisSoubor("MDB", Krypt.Kryptuj(w.Heslo));
                    }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Chyba: {0}{1}", Environment.NewLine, ex.Message));
            }
        }
        /// <summary>
        /// Testování
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void test_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (!IsolatedStorage.ExistujeSoubor("MDB"))
                {

                    var w = new HesloMDB();
                    if (w.ShowDialog() == true)
                    {
                        IsolatedStorage.ZapisSoubor("MDB", Krypt.Kryptuj(w.Heslo));
                    }
                    else
                        throw new System.IO.FileNotFoundException("Soubor s heslem 'MDB' nebyl nalezen.");                
                }
                else
                {
                    MessageBox.Show("Soubor již existuje.");
                }
                MessageBox.Show(Krypt.Dekryptuj(IsolatedStorage.CtiSoubor("MDB")));
            }
            catch(Exception ex)
            {
                MessageBox.Show(string.Format("Chyba: {0}{1}", Environment.NewLine, ex.Message));
            }
        }
        /// <summary>
        /// Automatické zpracování, spouští timer a upravuje UI.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CycleButton_Click(object sender, RoutedEventArgs e)
        {
            if(!timer.IsEnabled)
            {
                timer.Start();
                dokoncit = false;
                aktualizacePrvku = false;
                CycleButton.IsEnabled = false;
                finishButton.IsEnabled = true;
                startButton.IsEnabled = false;
                stopButton.IsEnabled = true;
            }                
        }

        /// <summary>
        /// Ukládá momentální log do textového nebo RTF formátu.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveLogButton_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            if (CheckboxLogFormat.IsChecked == true)
                sfd.Filter = "rtf files (*.rtf)|*.rtf";
            else
                sfd.Filter = "txt files (*.txt)|*.txt";

            if(sfd.ShowDialog() == true)
            {
                if(CheckboxLogFormat.IsChecked == true)
                {
                    TextRange t = new TextRange(Log1.Document.ContentStart, Log1.Document.ContentEnd);
                    using (FileStream file = new FileStream(sfd.FileName, FileMode.Create))
                    {
                        t.Save(file, DataFormats.Rtf);
                    }
                }
                else
                {
                    TextRange t = new TextRange(Log1.Document.ContentStart, Log1.Document.ContentEnd);
                    using (FileStream file = new FileStream(sfd.FileName, FileMode.Create))
                    {
                        t.Save(file, DataFormats.Text);
                    }
                }
            }
        }

        private void finishButton_Click(object sender, RoutedEventArgs e)
        {
            dokoncit = true;
            aktualizacePrvku = true;
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            NastavitHesloMDB();
        }
    }

    /// <summary>
    /// Třída Status slouží k předávání dat IProgress<Status> k reportu
    /// </summary>
    public class Status
    {
        public string message { get; set; }
        public string color { get; set; }
        public Status(string text, string color)
        {
            this.message = text;
            this.color = color;
        }
    }
}
