using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using BankTVUpdater.Helpers.Service;
using System.Xml;
using BankTVUpdater.AppUpdaterService;
using BankTVUpdater.Exceptions;
using BankTVUpdater.Logger;
using BankTVUpdater.Model.Service;
using BankTVUpdater.Consts;
using BankTVUpdater.Helpers;
using BankTVUpdater.Helpers.Config.Local;
using BankTVUpdater.Helpers.BottomBarNews;
using System.IO;
using System.Windows.Threading;
using System.Threading;

namespace BankTVUpdater
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void UpdateProgressBarLabel(string text)
        {
            this.ResetDetailedProgressBar();
            if (String.IsNullOrEmpty(text))
            {
                lblDetailedProgressBarInfo.Visibility = Visibility.Hidden;
                return;
            }   //if
            lblDetailedProgressBarInfo.Content = text;
            lblDetailedProgressBarInfo.Visibility = Visibility.Visible;            
        }

        private void ResetDetailedProgressBar()
        {            
            pbDetailedProgress.Value = 0;
            pbDetailedProgress.Visibility = Visibility.Visible;
            this.DoEvents();
        }

        private void SetControlsOnError(string errorMsg)
        {
            pbAllProgress.Value = 100;
            pbDetailedProgress.Visibility = Visibility.Hidden;            
            this.UpdateProgressBarLabel(errorMsg);
            this.DoEvents();
        }

        private bool CheckUpdaterUpdateNeeded(ServiceHelper service)
        {
            if (service == null)
            {
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return true;
            }   //if
            try
            {
                pbDetailedProgress.Value = 50;
                this.DoEvents();
                if (service.IsUpdaterUpdateNeeded(GlobalConsts.UPDATER_VERSION))
                {
                    pbDetailedProgress.Value = 100;
                    this.SetControlsOnError("Wersja aktualizatora jest nieaktualna. Proszę skontaktować się z administratorem systemu.");
                    return true;
                }   //if
                pbDetailedProgress.Value = 100;
                this.DoEvents();
                return false;
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
                return true;
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return true;
            }
        }

        private bool CheckAppUpdateNeeded(ServiceHelper service)
        {
            if (service == null)
            {
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return true;
            }   //if
            try
            {
                pbDetailedProgress.Value = 50;
                this.DoEvents();
                bool result = service.IsAppUpdateNeeded();
                pbDetailedProgress.Value = 100;
                this.DoEvents();
                return result;
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
                return true;
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return true;
            }
        }

        private void btnUpdate_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                pbAllProgress.Value = 0;
                btnUpdate.IsEnabled = false;
                ServiceHelper service = new ServiceHelper();
                this.UpdateProgressBarLabel("Sprawdzanie zgodności wersji aktualizatora...");
                this.DoEvents();
                if (this.CheckUpdaterUpdateNeeded(service))
                {
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if
                pbAllProgress.Value = pbAllProgress.Value + 5;
                this.UpdateProgressBarLabel("Pobieranie walut...");
                this.DoEvents();
                if (!this.StoreCurrencyConfiguration(service))
                {
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if
                pbAllProgress.Value = pbAllProgress.Value + 5;
                this.UpdateProgressBarLabel("Pobieranie ikonek pogodowych...");
                this.DoEvents();
                List<WeatherIcon> weatherIcons = service.GetWeatherIcons();
                if (weatherIcons == null)
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if
                pbAllProgress.Value = pbAllProgress.Value + 5;
                int progressInterval = 5 / weatherIcons.Count;
                int filesProgressInterval = 100 / weatherIcons.Count;
                foreach (WeatherIcon icon in weatherIcons)
                {
                    FilesHelper.DownloadWeatherIcon(icon);
                    pbAllProgress.Value = pbAllProgress.Value + progressInterval;
                    pbDetailedProgress.Value = pbDetailedProgress.Value + filesProgressInterval;
                    this.DoEvents();
                }   //for                
                this.UpdateProgressBarLabel("Sprawdzanie zgodności wersji aplikacji...");
                this.DoEvents();
                if (!this.CheckAppUpdateNeeded(service))
                {
                    this.SetControlsOnError("Aplikacja jest aktualna.");
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if
                pbAllProgress.Value = pbAllProgress.Value + 5;
                this.UpdateProgressBarLabel("Pobieranie nowej konfiguracji aplikacji...");
                this.DoEvents();
                if (!this.StoreAppConfiguration(service))
                {
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if

                pbAllProgress.Value = pbAllProgress.Value + 5;
                this.UpdateProgressBarLabel("Pobieranie nowej konfiguracji aplikacji dla placówek...");
                this.DoEvents();
                if (!this.StoreAppConfigurationForDepartments(service))
                {
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if

                pbAllProgress.Value = pbAllProgress.Value + 5;
                this.UpdateProgressBarLabel("Pobieranie aktualności na dolny pasek...");
                this.DoEvents();
                if (!this.StoreBottomBarNewsConfiguration(service))
                {
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return;
                }   //if
                pbAllProgress.Value = pbAllProgress.Value + 5;
                this.UpdateProgressBarLabel("Pobieranie plików...");
                this.DoEvents();
                List<SingleFile> images = service.GetImageFiles();                
                if (images == null)
                {
                    images = new List<SingleFile>();
                }   //if
                pbDetailedProgress.Value = pbDetailedProgress.Value + 4;
                pbAllProgress.Value = pbAllProgress.Value + 4;
                this.DoEvents();
                List<SingleFile> videos = service.GetVideoFiles();
                if (videos == null)
                {
                    videos = new List<SingleFile>();
                }   //if
                pbDetailedProgress.Value = pbDetailedProgress.Value + 6;
                pbAllProgress.Value = pbAllProgress.Value + 4;
                this.DoEvents();
                List<SingleNews> news = service.GetNewsFiles();
                if (news == null)
                {
                    news = new List<SingleNews>();
                }   //if
                pbDetailedProgress.Value = pbDetailedProgress.Value + 4;
                pbAllProgress.Value = pbAllProgress.Value + 4;
                this.DoEvents();
                List<SingleFile> flash = service.GetFlashFiles();
                if (flash == null)
                {
                    flash = new List<SingleFile>();
                }   //if
                pbDetailedProgress.Value = pbDetailedProgress.Value + 4;
                pbAllProgress.Value = pbAllProgress.Value + 3;
                this.DoEvents();
                int weatherProgressInterval = 45 / (images.Count + videos.Count + news.Count + flash.Count);
                int weatherFilesProgressInterval = 82 / (images.Count + videos.Count + flash.Count);
                foreach (SingleFile image in images)
                {
                    FilesHelper.DownloadImageFile(image);
                    pbAllProgress.Value = pbAllProgress.Value + weatherProgressInterval;
                    pbDetailedProgress.Value = pbDetailedProgress.Value + weatherFilesProgressInterval;
                    this.DoEvents();
                }   //for                
                foreach (SingleFile video in videos)
                {
                    FilesHelper.DownloadVideoFile(video);
                    pbAllProgress.Value = pbAllProgress.Value + weatherProgressInterval;
                    pbDetailedProgress.Value = pbDetailedProgress.Value + weatherFilesProgressInterval;
                    this.DoEvents();
                }   //for                
                foreach (SingleFile singleFlash in flash)
                {
                    FilesHelper.DownloadFlashFile(singleFlash);
                    pbAllProgress.Value = pbAllProgress.Value + weatherProgressInterval;
                    pbDetailedProgress.Value = pbDetailedProgress.Value + weatherFilesProgressInterval;
                    this.DoEvents();
                }   //for                
                pbDetailedProgress.Value = 100;
                this.UpdateProgressBarLabel("Pobieranie aktualności...");
                this.DoEvents();
                int newsProgressInterval = 100 / news.Count;
                foreach (SingleNews singleNews in news)
                {
                    FilesHelper.DownloadNewsFile(singleNews);
                    pbAllProgress.Value = pbAllProgress.Value + weatherProgressInterval;
                    pbDetailedProgress.Value = pbDetailedProgress.Value + newsProgressInterval;
                    this.DoEvents();
                }   //for
                pbAllProgress.Value = 100;
                this.SetControlsOnError("Aplikacja została zaktualizowana.");
                pbDetailedProgress.Visibility = Visibility.Hidden;
                this.DoEvents();
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
            }
            finally
            {
                btnUpdate.IsEnabled = true;
            }
        }

        private bool StoreAppConfiguration(ServiceHelper service)
        {
            if (service == null)
            {
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //if
            try
            {
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                string appConfigFolder = GlobalHelper.GetUserAppDataFolder();
                if (String.IsNullOrEmpty(appConfigFolder))
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                string xmlConfig = service.GetAppConfiguration();
                pbDetailedProgress.Value = pbDetailedProgress.Value + 40;
                this.DoEvents();
                if (String.IsNullOrEmpty(xmlConfig))
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                string appConfigFile = System.IO.Path.Combine(appConfigFolder, GlobalConsts.APP_CONFIG_FILE);
                if (File.Exists(appConfigFile))
                {
                    File.Delete(appConfigFile);
                }   //if                
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                File.WriteAllText(appConfigFile, xmlConfig);
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                return true;
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //catch
        }

        private bool StoreAppConfigurationForDepartments(ServiceHelper service)
        {
            if (service == null)
            {
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //if
            try
            {
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                string appConfigFolder = GlobalHelper.GetUserAppDataFolder();
                if (String.IsNullOrEmpty(appConfigFolder))
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                Departments departments = service.GetDepartments();
                if (departments == null)
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                List<Department> configDepartments = FilesHelper.ConvertWSDepartmentsToList(departments);
                if (configDepartments == null)
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                if (configDepartments.Count > 0)
                {
                    int progressInterval = 80 / (configDepartments.Count * 3);                
                    foreach (Department department in configDepartments)
                    {
                        string xmlConfig = service.GetAppConfigurationForDepartments(department.Parameter);
                        pbDetailedProgress.Value = pbDetailedProgress.Value + progressInterval;
                        this.DoEvents();
                        if (String.IsNullOrEmpty(xmlConfig))
                        {
                            this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                            return false;
                        }   //if
                        string appConfigFile = System.IO.Path.Combine(appConfigFolder, String.Format("{0}-{1}{2}", GlobalConsts.APP_CONFIG_FILE_PREFIX, department.GetFormattedParameter(), GlobalConsts.APP_CONFIG_FILE_SUFFIX));
                        if (File.Exists(appConfigFile))
                        {
                            File.Delete(appConfigFile);
                        }   //if                
                        XmlLocalConfigHelper.SetLocalConfigObject(department.City, department.GetFormattedParameter());
                        pbDetailedProgress.Value = pbDetailedProgress.Value + progressInterval;
                        this.DoEvents();
                        File.WriteAllText(appConfigFile, xmlConfig);
                        pbDetailedProgress.Value = pbDetailedProgress.Value + progressInterval;
                        this.DoEvents();
                    }   //for
                }   //if
                return true;
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //catch
        }

        private bool StoreCurrencyConfiguration(ServiceHelper service)
        {
            if (service == null)
            {
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //if
            try
            {
                pbDetailedProgress.Value = pbDetailedProgress.Value + 10;
                this.DoEvents();
                string currencyConfigFolder = GlobalHelper.GetCurrencyFolder();
                if (String.IsNullOrEmpty(currencyConfigFolder))
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                string currencyConfig = service.GetCurrencyConfiguration();
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                if (String.IsNullOrEmpty(currencyConfig))
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                string currencyConfigFile = System.IO.Path.Combine(currencyConfigFolder, GlobalConsts.CURRENCY_CONFIG_FILE);
                if (File.Exists(currencyConfigFile))
                {
                    File.Delete(currencyConfigFile);
                }   //if                
                pbDetailedProgress.Value = pbDetailedProgress.Value + 10;
                this.DoEvents();
                File.WriteAllText(currencyConfigFile, currencyConfig);
                pbDetailedProgress.Value = pbDetailedProgress.Value + 10;
                this.DoEvents();
                List<CurrencyItem> currencyFiles = service.GetCurrencyFiles();
                if (currencyFiles == null)
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    pbDetailedProgress.Visibility = Visibility.Hidden;
                    return false;
                }   //if
                if (currencyFiles.Count > 0)
                {
                    int progressInterval = 100 / currencyFiles.Count;
                    foreach (CurrencyItem currencyFile in currencyFiles)
                    {
                        FilesHelper.DownloadCurrencyImage(currencyFile);
                        pbDetailedProgress.Value = pbDetailedProgress.Value + progressInterval;
                        this.DoEvents();
                    }   //for
                }   //if
                return true;
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //catch
        }

        private bool StoreBottomBarNewsConfiguration(ServiceHelper service)
        {
            if (service == null)
            {
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //if
            try
            {
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                string bottomBarNewsFolder = GlobalHelper.GetBottomBarNewsFolder();
                if (String.IsNullOrEmpty(bottomBarNewsFolder))
                {
                    this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                    return false;
                }   //if
                List<string> bottomBarNews = service.GetBottomBarNews();
                pbDetailedProgress.Value = pbDetailedProgress.Value + 40;
                this.DoEvents();
                if (bottomBarNews == null)
                {
                    bottomBarNews = new List<string>();
                }   //if
                string bottomBarNewsFile = System.IO.Path.Combine(bottomBarNewsFolder, GlobalConsts.BOTTOM_BAR_NEWS_FILE);
                if (File.Exists(bottomBarNewsFile))
                {
                    File.Delete(bottomBarNewsFile);
                }   //if                
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                BottomBarNewsXmlHelper.SetBottomBarNews(bottomBarNews);
                pbDetailedProgress.Value = pbDetailedProgress.Value + 20;
                this.DoEvents();
                return true;
            }   //try
            catch (UpdaterConnectionException ex)
            {
                this.SetControlsOnError(ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                MyLogger.Log(ex);
                this.SetControlsOnError("Wystąpił niespodziewany błąd w trakcie aktualizacji. Proszę skontaktować się z administratorem systemu.");
                return false;
            }   //catch
        }

        public void DoEvents()
        {
            DispatcherFrame frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
                new DispatcherOperationCallback(ExitFrame), frame);
            Dispatcher.PushFrame(frame);
        }

        public object ExitFrame(object f)
        {
            ((DispatcherFrame)f).Continue = false;
            return null;
        }

        private void btnSetCity_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string city = XmlLocalConfigHelper.GetCurrentCity();
                if (!String.IsNullOrEmpty(city))
                {
                    inputBox.InputTextBox.Text = city;
                }   //if
                else
                {
                    inputBox.InputTextBox.Text = String.Empty;
                }   //else
                inputBox.InputBoxGrid.Visibility = Visibility.Visible;
            }   //try
            catch (Exception ex)
            {                
                MessageBox.Show("Przepraszamy, wystąpił błąd w trakcie określania nazwy miasta dla aplikacji.");
                MyLogger.Log(ex);
            }   //catch
            
        }
        
    }
}
