using Microscopic_Traffic_Simulator.Properties;
using Microscopic_Traffic_Simulator.ViewModels;
using Microscopic_Traffic_Simulator.Views;
using Microscopic_Traffic_Simulator.Views.MainWindowView;
using System;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Markup;

namespace Microscopic_Traffic_Simulator
{
    /// <summary>
    /// GUIInteractions logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// Directory of localization resources.
        /// </summary>
        private String localizationDirectory;

        /// <summary>
        /// Event handler of changing language.
        /// </summary>
        internal event EventHandler LanguageChangedEvent;

        /// <summary>
        /// Index of localization resources in resource dictionaries.
        /// </summary>
        private int langDictId = -1;

        /// <summary>
        /// Static initialization of App when OS culture is passed to the current culture.
        /// </summary>
        static App()
        {
            // This code is used to test the app when using other cultures.
            //
            //System.Threading.Thread.CurrentThread.CurrentCulture =
            //    System.Threading.Thread.CurrentThread.CurrentUICulture =
            //        new System.Globalization.CultureInfo("sk-SK");

            // Ensure the current culture passed into bindings is the OS culture.
            // By default, WPF uses en-US as the culture, regardless of the system settings.            
            FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
              new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(
                  CultureInfo.CurrentCulture.IetfLanguageTag)));
        }

        /// <summary>
        /// Initialization of app.
        /// </summary>
        public App()
            : base()
        {
            //set event handler for unhandled exceptions
            Dispatcher.UnhandledException += Dispatcher_UnhandledException;            
            localizationDirectory = System.IO.Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\Localization";
        }

        /// <summary>
        /// Occurs on startup of application.
        /// </summary>
        /// <param name="e">Event args of startup.</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            //initialize languages
            InitializeLanguageResource();
            //initialize main window
            MainWindow window = new MainWindow();
            //set main viewmodel to main window data context
            MainViewModel mainViewModel = new MainViewModel(new GUIInteractions(this),
                new Settings(), new Action<string>(i => { SwitchLanguage(i); }));
            mainViewModel.Initialize(FindStringResource("new"),
                Resources.MergedDictionaries[langDictId]["ResourceDictionaryName"].ToString().Substring(4));
            window.DataContext = mainViewModel;            
            //show window
            window.Show();
        }

        /// <summary>
        /// Method for finding string resource based on key. Useful for searching for translations
        /// of strings in current language.
        /// </summary>
        /// <param name="key">Key of string resource.</param>
        /// <returns>String in current language.</returns>
        internal string FindStringResource(string key)
        {
            return FindResource(key).ToString().Trim();            
        }

        /// <summary>
        /// Initialize language resource based on the current application culture or culture stored
        /// in application settings.
        /// </summary>
        private void InitializeLanguageResource()
        {
            string UICulture = Microscopic_Traffic_Simulator.Properties.Settings.Default.UICulture
                == string.Empty ?
                CultureInfo.CurrentUICulture.Name :
                Microscopic_Traffic_Simulator.Properties.Settings.Default.UICulture;

            SetLanguageResourceDictionary(GetLocXAMLFilePath(UICulture));
        }

        /// <summary>
        /// Returns the path to the ResourceDictionary file based on the language character string.
        /// </summary>
        /// <param geometricTopologyName="inFiveCharLang"></param>
        /// <returns>Path to the ResourceDictionary file.</returns>
        private string GetLocXAMLFilePath(string inFiveCharLang)
        {
            string locXamlFile = "LocalizationDictionary." + inFiveCharLang + ".xaml";
            return Path.Combine(localizationDirectory, inFiveCharLang, locXamlFile);
        }

        /// <summary>
        /// Dynamically load a Localization ResourceDictionary from a file of given culture string.
        /// </summary>               
        /// <param name="inFiveCharLang">Culture string of language to change to.</param>
        private void SwitchLanguage(string inFiveCharLang)
        {
            //check if language is not already set as current language.
            if (Resources.MergedDictionaries[langDictId]["ResourceDictionaryName"]
                    .ToString().Substring(4).Equals(inFiveCharLang))
                return;

            //set new culture, save culture string to application settings and save it.
            var ci = new CultureInfo(inFiveCharLang);
            Thread.CurrentThread.CurrentUICulture = ci;
            Microscopic_Traffic_Simulator.Properties.Settings.Default.UICulture = inFiveCharLang;
            Microscopic_Traffic_Simulator.Properties.Settings.Default.Save();

            //set new language resource according to new culture
            SetLanguageResourceDictionary(GetLocXAMLFilePath(inFiveCharLang));
            //send event signal about changing of language
            if (LanguageChangedEvent != null)
            {
                LanguageChangedEvent(this, new EventArgs());
            }
        }

        /// <summary>
        /// Sets or replaces the ResourceDictionary by dynamically loading
        /// a Localization ResourceDictionary from the file path passed in.
        /// </summary>
        /// <param name="inFile">File with localization resource laneTypeToRenderer.</param>        
        private void SetLanguageResourceDictionary(String inFile)
        {
            //check if the language is supported. If not use English (or exceptionally Slovak in
            //case that czech language is given
            if (!File.Exists(inFile))
            {
                if (inFile.Contains("cs-CZ"))
                    inFile = inFile.Replace("cs-CZ", "sk-SK");
                else
                    inFile = inFile.Replace(inFile.Substring(inFile.Length - 10, 5), "en-US");
            }

            // Read in ResourceDictionary File
            var languageDictionary = new ResourceDictionary();
            languageDictionary.Source = new Uri(inFile);

            // Remove any previous Localization dictionaries loaded
            langDictId = -1;
            for (int i = 0; i < Resources.MergedDictionaries.Count; i++)
            {
                var md = Resources.MergedDictionaries[i];
                // Make sure your Localization ResourceDictionarys have the ResourceDictionaryName
                // key and that it is set to a value starting with "Loc-".
                if (md.Contains("ResourceDictionaryName"))
                {
                    if (md["ResourceDictionaryName"].ToString().StartsWith("Loc-"))
                    {
                        langDictId = i;
                        break;
                    }
                }
            }
            if (langDictId == -1)
            {
                // Add in newly loaded Resource Dictionary
                Resources.MergedDictionaries.Add(languageDictionary);
                langDictId = Resources.MergedDictionaries.Count - 1;
            }
            else
            {
                // Replace the current langage laneTypeToRenderer with the new one
                Resources.MergedDictionaries[langDictId] = languageDictionary;
            }
        }

        /// <summary>
        /// Handle unhandled exceptions.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event args of unhandled exception.</param>
        private void Dispatcher_UnhandledException(object sender,
            System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message, "Error",
                MessageBoxButton.OK, MessageBoxImage.Error);
            string path = System.IO.Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly().Location);
            path += @"\err.log";
            using (StreamWriter streamWriter = new StreamWriter(path, true))
            {
                Exception ex = e.Exception;
                streamWriter.WriteLine(DateTime.Now);
                for (int i = 0; ex != null; i++)
                {
                    streamWriter.Write(i == 0 ? "Exception " :
                        "\r\nInner Exception " + i + ": ");
                    streamWriter.WriteLine(e.Exception.Message);
                    streamWriter.WriteLine("Call stack:");
                    streamWriter.WriteLine(e.Exception.StackTrace);
                    ex = ex.InnerException;
                }
                streamWriter.WriteLine("----------------------------");
            }
            e.Handled = true;            
        }
    }
}
