// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2017 Thomas Klose & Torsten Schache, Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.IO;
using System.Threading;
using System.Xml;

using Hiperscan.Unix;


namespace Hiperscan.Extensions.ApoIdent
{
	public class Configurations
	{
        public const string BACKUP_FILE_EXTENSION       = "_backup";

		private const string APO_IDENT_TAG 				= "ApoIdentConfig";
		private const string CONFIG_FILE_NAME			= "ApoIdent.config.xml";

		private Configurations()
		{
			this.Profiles 				= new Profiles();
			this.AcquisitionSettings	= new AcquisitionSettings();
			this.PrinterSettings		= new LabelPrinterSettings();
			this.GuiSettings			= new GuiSettings();           
		}

		public Configurations(string path) : this ()
		{
            this.ConfigFile         = Path.Combine(path, Configurations.CONFIG_FILE_NAME);
            this.BackupConfigFile   = this.ConfigFile + Configurations.BACKUP_FILE_EXTENSION;

            bool can_read_from_xml = File.Exists(this.ConfigFile) || File.Exists(this.BackupConfigFile);
 
            if (can_read_from_xml == true)
            {
                for (int i = 0; i < 5; i++)
                {
                    try
                    {
                        this.ReadFromXmlFile(this.ConfigFile);
                        break;
                    }
                    catch(Exception ex)
                    {
                        Console.WriteLine("An error occurred while first readeing apo-ident-config-file: {0}", ex);
                        System.Threading.Thread.Sleep(50);                                          
                    }

                    try
                    {
                        this.ReadFromXmlFile(this.BackupConfigFile);
                        break;
                    }
                    catch(Exception ex)
                    {
                        Console.WriteLine("An error occurred while second readeing apo-ident-config-file: {0}", ex);
                        System.Threading.Thread.Sleep(50);  
                        if (i == 4)
                        {
                            this.Profiles               = new Profiles();
                            this.AcquisitionSettings    = new AcquisitionSettings();
                            this.PrinterSettings        = new LabelPrinterSettings();
                            this.GuiSettings            = new GuiSettings();

                        }
                    }
                }
            }


            this.OldHashCode = this.GetXmlDoc().InnerXml.GetHashCode();
		}

        private void ReadFromXmlFile(string file)
        {
            XmlDocument  doc = new XmlDocument();
            using (StreamReader sr = new StreamReader(file, System.Text.Encoding.UTF8))
            {
                doc.Load(sr);
            }

            XmlNode root_node = doc.DocumentElement;

            try
            {
				XmlNode profiles_node = root_node.SelectNodes(Profiles.PROFILES_TAG)[0];
				this.Profiles = new Profiles(profiles_node);
                
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while reading profiles: {0}", ex);
                this.Profiles = new Profiles();
            }

            try
            {
                XmlNode acqusisition_node = root_node.SelectNodes(AcquisitionSettings.ACQUISITION_SETTINGS_TAG)[0];
                this.AcquisitionSettings = new AcquisitionSettings(acqusisition_node);
            }
            catch (Exception)
			{
				this.AcquisitionSettings = new AcquisitionSettings();
			}

            try
            {
                XmlNode printer_node = root_node.SelectNodes(LabelPrinterSettings.PRINTER_SETTINGS_TAG)[0];
                this.PrinterSettings = new LabelPrinterSettings(printer_node);
            }
            catch (Exception)
			{
				this.PrinterSettings = new LabelPrinterSettings();
			}

            try
            {
                XmlNode gui_node = root_node.SelectNodes(GuiSettings.GUI_SETTINGS_TAG)[0];
                this.GuiSettings = new GuiSettings(gui_node);
            }
            catch (Exception)
			{
				this.GuiSettings = new GuiSettings();
			}

            this.OldHashCode = this.GetXmlDoc().InnerXml.GetHashCode();
        }

        public void WriteToXmlFile()
        {
            XmlDocument doc = GetXmlDoc();

            if (this.OldHashCode == doc.InnerXml.GetHashCode())
                return;

            for (int i = 0; i < 5; i++)
            {
                try
                {
                    using (StreamWriter sw = new StreamWriter(this.ConfigFile, false, System.Text.Encoding.UTF8))
                    {
                        doc.Save(sw);
                    }

                    Configurations tmp = new Configurations();
                    tmp.ReadFromXmlFile(this.ConfigFile);
                    break;
                }
                catch (Exception ex)
                {
                    if (i == 4)
                    {
                        Console.WriteLine("Error while saving substance extension: {0}", ex);
                        throw;
                    }
                    Thread.Sleep(50);
                }
            }

            try
            {
                File.Copy(this.ConfigFile, this.BackupConfigFile, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while saving apo-ident-config (second try): {0}", ex);
            }

            this.OldHashCode = doc.InnerXml.GetHashCode();
        }

        private XmlDocument GetXmlDoc()
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(String.Format("<{0}></{0}>", Configurations.APO_IDENT_TAG));
            XmlNode root = doc.DocumentElement;

			this.Profiles.WriteToXml(doc, root);
            this.AcquisitionSettings.WriteToXml(doc, root);
            this.PrinterSettings.WriteToXml(doc, root);
            this.GuiSettings.WriteToXml(doc, root);

            return doc;
        }
      
		public void Stash()
		{
			this.Profiles.Stash();
			this.AcquisitionSettings.Stash();
            this.PrinterSettings.Stash();
		}

		public void Unstash()
		{
			this.Profiles.Unstash(true);
			this.AcquisitionSettings.Unstash();
            this.PrinterSettings.Unstash();
		}

		public Profiles Profiles 						{get; private set;}
		public AcquisitionSettings AcquisitionSettings	{get; private set;}
		public LabelPrinterSettings PrinterSettings		{get; private set;}
		public GuiSettings GuiSettings					{get; private set;}
 
		public string ConfigFile        {get; private set;}
        public string BackupConfigFile  {get; private set;}
       
        private int OldHashCode         {get; set;}       
	}
}

