// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2018 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.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;

using Hiperscan.Spectroscopy.IdentModule;


namespace Hiperscan.Extensions.ApoIdent
{
	public class AdditionalTestEntries : Dictionary<string, string>
    {
		private const string COMPLETION_ENTRY_TAG = "CompletionEntry";
        private const string ID_ATTRIBUTE = "Id";
        private const string ROOT_TAG = "AdditionalTest";
          
		public AdditionalTestEntries()
		{			
		}

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

            XmlNode root = doc.DocumentElement;

            XmlNodeList completion_nodes = root.SelectNodes(AdditionalTestEntries.COMPLETION_ENTRY_TAG);
            if (completion_nodes != null && completion_nodes.Count > 0)
            {
                foreach (XmlNode completion_node in completion_nodes)
                {
                    string id = null;
                    if (completion_node.Attributes[AdditionalTestEntries.ID_ATTRIBUTE] != null)
                        id = completion_node.Attributes[AdditionalTestEntries.ID_ATTRIBUTE].Value;

                    if (String.IsNullOrEmpty(id) == true)
                        continue;

                    if (String.IsNullOrEmpty(completion_node.InnerText) == true)
                        continue;

                    this.Add(id, completion_node.InnerText);
                }
            }      
        }
      
        public void Save()
        {
            for (int i = 0; i < 5; i++)
            {
                try
                {
                    AdditionalTestEntries.WriteToXml(FilesAndDirs.AdditionalTestAutoCompletionFile, this);
                    Thread.Sleep(50);
                    new AdditionalTestEntries(FilesAndDirs.AdditionalTestAutoCompletionFile);
                    break;

                }
                catch (Exception ex)
                {
                    Thread.Sleep(50);
                    if (i == 4)
					{
						Console.WriteLine("Error while saving auto completion additional tests: {0}", ex);
						return;
					}
                }
            }
         
            try
            {
				File.Copy(FilesAndDirs.AdditionalTestAutoCompletionFile, FilesAndDirs.AdditionalTestAutoCompletionBackupFile);
            }
            catch (Exception)
            {
            }
        }

		public static AdditionalTestEntries Read()
        {
            for (int i = 0; i < 5; i++)
            {
                try
                {
					if (File.Exists(FilesAndDirs.AdditionalTestAutoCompletionFile) == true)
                    {
                        Console.WriteLine("AdditionalTestEntries: file exists");
                        return new AdditionalTestEntries(FilesAndDirs.AdditionalTestAutoCompletionFile);
                    }                     
                }
                catch (Exception ex)
                {
                    Console.WriteLine("AdditionalTestEntries: loading file failed {0}", ex.ToString());
                    Thread.Sleep(50);
                }
            }

            for (int i = 0; i < 5; i++)
            {
                try
                {
                    if (File.Exists(FilesAndDirs.AdditionalTestAutoCompletionBackupFile) == true)
                    {
                        Console.WriteLine("AdditionalTestEntries: backup file exists");
                        return new AdditionalTestEntries(FilesAndDirs.AdditionalTestAutoCompletionBackupFile);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("AdditionalTestEntries: loading backup file failed {0}", ex.ToString());
                    Thread.Sleep(50);
                }
            }

            Console.WriteLine("AdditionalTestEntries: empty instance created");
            return new AdditionalTestEntries();
        }
      
		private static void WriteToXml(string file, AdditionalTestEntries additional_entries)
        {         
            try
            {            
                XmlDocument doc = new XmlDocument();

				doc.LoadXml(String.Format("<{0}></{0}>", AdditionalTestEntries.ROOT_TAG));
                XmlNode root = doc.DocumentElement;

				foreach (string id in additional_entries.Keys)
                {
					XmlNode completion_element = doc.CreateElement(AdditionalTestEntries.COMPLETION_ENTRY_TAG);
					completion_element.InnerText = additional_entries[id];
                    root.AppendChild(completion_element);

					XmlAttribute id_attribute = doc.CreateAttribute(AdditionalTestEntries.ID_ATTRIBUTE);
                    id_attribute.Value = id;
                    completion_element.Attributes.Append(id_attribute);
                }

                using (StreamWriter sw = new StreamWriter(file, false, Encoding.UTF8))
                {
                    doc.Save(sw);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while writing auto completion data: {0}", ex.Message);
            }
        }

        public static void Merge(AdditionalTestEntries entries)
		{
            Console.WriteLine("Merge additional test entries ....");
			if (File.Exists(FilesAndDirs.OldAdditionalTestAutoCompletionFile) == false)
			{
                Console.WriteLine("Merge additional test entries -> there is not fount an merging file.");
				entries.Save();
				return;
			}

			try
			{
                Regex regex = new Regex(@"\d+$");
				AdditionalTestEntries old_entries = new AdditionalTestEntries(FilesAndDirs.OldAdditionalTestAutoCompletionFile);
                foreach (string old_key in old_entries.Keys)
				{                   
                    string new_key = regex.Match(old_key).Value;
                    if (String.IsNullOrEmpty(new_key) == true)
                        continue;
                    
                    if (entries.ContainsKey(new_key) == false)
                        entries.Add(new_key, String.Empty);

                    entries[new_key] = old_entries[old_key];
				}
				entries.Save();

                Console.WriteLine("Merge additional test entries success.");
			}
			catch(Exception ex)
			{
				Console.WriteLine("Error while merging auto completion additional tests: {0}", ex.Message);
			}
		}






		public bool CustomerEvaluation(FinderWindow finder_window)
        {
			if (this.InsertIntoProtocol == false)
            {
                if (finder_window.InitState == ServerDeviceState.Success &&
                    finder_window.SubstanceManagement.CurrentClassification.IsNirMeasurable == true &&
                    finder_window.IdentServerClient.HasValidResult == true &&
                    finder_window.SubstanceManagement.CurrentClassification.ClassificationType != ClassificationType.Multiple)
                {
                    return finder_window.IdentServerClient.IsTruePositive;
                }
            }
            
            if (this.InsertIntoProtocol == true)
				return this.CustomerIdentificationResult;

            return false;
        }

        public void Reset()
		{
			this.CustomerText = String.Empty;
			this.InsertIntoProtocol = false;
			this.CustomerIdentificationResult = false;
			this.SubstanceUniqueIdentifed = false;
			this.Key = String.Empty;
		}

		public void LoadCustomerText(string id)
        {            
			this.CustomerText = String.Empty;
			this.Key = id;

			if (this.ContainsKey(id) == true)
				this.CustomerText = this[id];         
        }

        public void SetCustomerText(string text)
		{
			this.CustomerText = (text ?? String.Empty).Trim();         
			if (this.ContainsKey(this.Key) == false)
			    this.Add(this.Key, String.Empty);

			this[this.Key] = this.CustomerText;
		}
              
        public string ProtocolText
        {
			get
			{
				string text = String.Empty;
				if (this.ContainsKey(this.Key) == true && this.InsertIntoProtocol == true)
					text = this[this.Key];

				return text;
			}
        }


		public string CustomerText { get; private set; }
		public bool InsertIntoProtocol { get; set; } = false;
		public bool CustomerIdentificationResult { get; set; } = false;

		public bool SubstanceUniqueIdentifed { get; set; } = false;
		private string Key { get; set; } = String.Empty;   
	}
}
