// 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.Common.I18n;
using Hiperscan.Spectroscopy.IdentModule;
using Hiperscan.Unix;

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()
        {
            if (this.Count == 0)
                return;

            try
            {
                FilesAndDirs.CreateMetaDataDir();
            }
            catch(Exception ex)
            {
                Console.WriteLine("Cannot create .meta directory: {0}", ex);
                return;
            }

            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, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot create auto completion backup: {0}", ex);
            }
        }

        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.");
                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(SubstanceManagement substance_db, bool true_positive)
        {
            if (this.InsertIntoProtocol == false)
            {
                if (substance_db.CurrentClassification.IsNirMeasurable == true &&
                    substance_db.CurrentClassification.ClassificationType != ClassificationType.Multiple)
                {
                    return true_positive;
                }
            }

            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 static string LabelName(ApoIdentApplication app)
        {
            if (app.Config.Profiles.Current == null)
                return Catalog.GetString("Additional\ntests");

            if (app.SubstanceManagement.CurrentSubstance == null)
                return Catalog.GetString("Additional\ntests");


            string text = Catalog.GetString("Additional\ntests");
            bool is_additional_test = true;

            if (app.Control.CreateNotMeasurableReport)
            {
                text = Catalog.GetString("Identity\ntests");
                is_additional_test = false;
            }
            else if (app.SubstanceManagement.CurrentSubstanceCategory == SubstanceCategory.Classifiaction)
            {
                text = Catalog.GetString("Complementary\ntests");
                is_additional_test = false;
            }

            if (app.Control.ProtocolState.HasFlag(ProtocolStates.IdentificationResultExists))
            {
                if (app.IdentServerClient.IsTruePositive == false)
                {
                    text = Catalog.GetString("Identity\ntests");
                    is_additional_test = false;
                }
            }

            if (AdditionalTestEntries.IsMandatory(app) && is_additional_test == false)
                text += "*";

            return text;
        }

        public static bool  IsMandatory(ApoIdentApplication app)
        {
            if (app.Config.Profiles.Current == null)
                return false;

            if (app.Config.Profiles.Current.MandatoryForComplementaryTest == false)
                return false;

            if (app.SubstanceManagement.CurrentSubstance == null)
                return false;

            if (app.Config.Profiles.Current.ExchangeData.IsActivated)
            {
                if (Locale.Language == "de")
                    return false;
            }

            if (app.Control.CreateNotMeasurableReport == true)
                    return true;

            if (app.SubstanceManagement.CurrentSubstanceCategory == SubstanceCategory.Classifiaction)
                return true;

            if (app.Control.ProtocolState.HasFlag(ProtocolStates.IdentificationResultExists))
            {
                if (app.IdentServerClient.IsTruePositive)
                    return false;
                else
                    return true;
            }

            return false;
        }


        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;   
    }
}
