// 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.Xml;

using Hiperscan.Common.I18n;
using Hiperscan.Unix;
using Hiperscan.ApoIdentCommon.ApoConfig.Enums;
using Hiperscan.ApoIdentCommon.ApoConfig.ThirdPartyDataExchange;
using Hiperscan.ApoIdentCommon.ApoConfig.Internationalization;

#pragma warning disable RECS0022 // catch-Klausel, die System.Exception abfängt und keinen Text aufweist

namespace Hiperscan.ApoIdentCommon.ApoConfig
{
    public partial class ProfileSettings : SettingsTemplate<ProfileSettings>
    {
        public const string PROFILE_TAG = "Profile";
        private const string COMPANY_TAG = "Company";
        private const string STREET_TAG = "Street";
        private const string TOWN_TAG = "Town";
        private const string FILE_NAMES_TAG = "FileNameStartsWith";
        private const string ARCHIVE_TAG = "Archive";
        private const string COUNTRY_TAG = "Country";
        private const string BAK_MARKING_ACTIVATED_TAG = "BAKMarkingActivated";
        private const string DIFFERENCE_TAG = "Difference";
        private const string BASE64_ADDRESS_DATA_TAG = "Base64AddressData";
        private const string MERGED_ADDITIONAL_DATA_TAG = "MergedAdditionalData";
        private const string ARCHIVE_CREATED_TAG = "ArchiveCreated";
        private const string DONT_SHOW_NOT_MEASURABLE_DIALOG_TAG = "DontShowNotMeasurableDialog";
        private const string MANDATORY_FOR_ADD_TEST_TAG = "MandatoryForAddTest";
        private const string PRINT_VALIDATION_WITHIN_PROTOCOL_TAG = "PrintValidationWithinProtocol";
        private const string CERTIFICATION_CONTROL_TAG = "CertificationControl";


        private const string NAME_ATTRIBUTE = "Name";

        public static readonly string DEFAULT_CUSTOMER_NUMBER = "00000";
        public static string DEFAULT_NAME => Catalog.GetString("Demo profile");
        public static string DEFAULT_COMPANY => Catalog.GetString("Unknown organisation");
        public static string DEFAULT_STREET => Catalog.GetString("Unknown street");
        public static string DEFAULT_TOWN => Catalog.GetString("Unknown location");

        public static bool AutoConvertToBase64 = false;

        public ProfileSettings() : base()
        {

        }

        public ProfileSettings(XmlNode profile_node) : base(profile_node)
        {

        }

        protected override void Init(XmlNode parent_node = null)
        {
            this.Name = String.Empty;
            this.CustomerNumber = String.Empty;
            this.Company = String.Empty;
            this.Street = String.Empty;
            this.Town = String.Empty;
            this.Archive = String.Empty;

            this.FileNameStart = FilenameStartTypes.SubstanceName;
            this.ExchangeData = new DataExchangeApoIdent();
            this.ReportCountry = I18n.GetDefaultReportCountry();
            this.BakMarking.IsActive = false;
            this.ShowDifference = false;
            this.IgnoreMissingArchive = false;

            base.Init(parent_node);
        }

        protected override void Read(XmlNode parent_node)
        {
            try
            {
                this.Name = parent_node.Attributes[ProfileSettings.NAME_ATTRIBUTE].Value;
            }
            catch (Exception) { return; }

            string[] decoded_address_data = null;
            try
            {
                XmlNode base64_address_node = parent_node.SelectNodes(ProfileSettings.BASE64_ADDRESS_DATA_TAG)[0];
                if (base64_address_node != null)
                {
                    decoded_address_data = Base64AddressData.Decode(base64_address_node.InnerText);
                    if (decoded_address_data.Length < 6)
                        throw new Exception(Catalog.GetString("Invalid number of entries in decoded address data."));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("Using default address data.");
                decoded_address_data = new string[6];
                decoded_address_data[0] = ProfileSettings.DEFAULT_CUSTOMER_NUMBER;
                decoded_address_data[1] = ProfileSettings.DEFAULT_COMPANY;
                decoded_address_data[2] = ProfileSettings.DEFAULT_STREET;
                decoded_address_data[3] = ProfileSettings.DEFAULT_TOWN;
                decoded_address_data[4] = ProfileManager.APO_IDENT_NAME;
                decoded_address_data[5] = DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture);
            }

            if (decoded_address_data != null)
            {
                try
                {
                    this.CustomerNumber = decoded_address_data[0];
                    this.Company = decoded_address_data[1];
                    this.Street = decoded_address_data[2];
                    this.Town = decoded_address_data[3];
                    this.Base64ConversionCreator = decoded_address_data[4];
                    this.Base64ConversionTimestamp = DateTime.Parse(decoded_address_data[5], System.Globalization.CultureInfo.InvariantCulture);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Cannot decode address data: " + ex.Message);
                }
            }
            else
            {
                if (ProfileSettings.AutoConvertToBase64 == false)
                    return;

                this.CustomerNumber = ProfileSettings.DEFAULT_CUSTOMER_NUMBER;

                try
                {
                    XmlNode company_node = parent_node.SelectNodes(ProfileSettings.COMPANY_TAG)[0];
                    this.Company = company_node.InnerText;
                }
                catch (Exception) { }

                try
                {
                    XmlNode street_node = parent_node.SelectNodes(ProfileSettings.STREET_TAG)[0];
                    this.Street = street_node.InnerText;
                }
                catch (Exception) { }


                try
                {
                    XmlNode town_node = parent_node.SelectNodes(ProfileSettings.TOWN_TAG)[0];
                    this.Town = town_node.InnerText;
                }
                catch (Exception) { }
            }

            try
            {
                XmlNode archive_node = parent_node.SelectNodes(ProfileSettings.ARCHIVE_TAG)[0];
                this.Archive = archive_node.InnerText;
            }
            catch (Exception) { }

            try
            {
                XmlNode country_node = parent_node.SelectNodes(ProfileSettings.COUNTRY_TAG)[0];
                this.ReportCountry = (ReportCountryTypes)Enum.Parse(typeof(ReportCountryTypes), country_node.InnerText, true);
                this.ReportCountry = I18n.GetCountrySpecificReportCountry(this.ReportCountry);
            }
            catch (Exception) { }

            try
            {
                XmlNode bak_node = parent_node.SelectNodes(ProfileSettings.BAK_MARKING_ACTIVATED_TAG)[0];
                this.BakMarking.IsActive = Boolean.Parse(bak_node.InnerText);
            }
            catch (Exception) { }

            try
            {
                XmlNode difference_node = parent_node.SelectNodes(ProfileSettings.DIFFERENCE_TAG)[0];
                this.ShowDifference = Boolean.Parse(difference_node.InnerText);
            }
            catch (Exception) { }

            try
            {
                XmlNode management_node = parent_node.SelectNodes(DataExchange.MANAGEMENT_TAG)[0];
                this.ExchangeData = DataExchange.ReadFromConfig(management_node);
            }
            catch (Exception) { }

            try
            {
                XmlNode file_name_node = parent_node.SelectNodes(ProfileSettings.FILE_NAMES_TAG)[0];
                this.FileNameStart = (FilenameStartTypes)Enum.Parse(typeof(FilenameStartTypes), file_name_node.InnerText, true);
            }
            catch (Exception) { }

            try
            {
                XmlNode dont_show_not_measurable_node = parent_node.SelectNodes(ProfileSettings.DONT_SHOW_NOT_MEASURABLE_DIALOG_TAG)[0];
                this.DontShowNotMeasurableDialogAgain = Boolean.Parse(dont_show_not_measurable_node.InnerText);
            }
            catch (Exception) { }

            try
            {
                XmlNode deactivate_add_tests_node = parent_node.SelectNodes(ProfileSettings.MANDATORY_FOR_ADD_TEST_TAG)[0];
                this.AdditionalTest.IsMandatoryForComplementaryTest = Boolean.Parse(deactivate_add_tests_node.InnerText);
            }
            catch (Exception) { }

            try
            {
                XmlNode print_validation_node = parent_node.SelectNodes(ProfileSettings.PRINT_VALIDATION_WITHIN_PROTOCOL_TAG)[0];
                this.PrintValidationWhitinProtocol = Boolean.Parse(print_validation_node.InnerText);
            }
            catch (Exception) { }

            try
            {
                XmlNode certification_control_node = parent_node.SelectNodes(ProfileSettings.CERTIFICATION_CONTROL_TAG)[0];
                this.CertificationControl = Boolean.Parse(certification_control_node.InnerText);
            }
            catch (Exception) { }
        }

        public override void WriteToXml(XmlDocument doc, XmlNode parent)
        {
            XmlNode profile_node = doc.CreateElement(ProfileSettings.PROFILE_TAG);
            parent.AppendChild(profile_node);

            XmlAttribute name_attribute = doc.CreateAttribute(ProfileSettings.NAME_ATTRIBUTE);
            name_attribute.Value = this.Name;
            profile_node.Attributes.Append(name_attribute);

            XmlNode company_node = doc.CreateElement(ProfileSettings.COMPANY_TAG);
            company_node.InnerText = this.Company;
            profile_node.AppendChild(company_node);

            XmlNode street_node = doc.CreateElement(ProfileSettings.STREET_TAG);
            street_node.InnerText = this.Street;
            profile_node.AppendChild(street_node);

            XmlNode town_node = doc.CreateElement(ProfileSettings.TOWN_TAG);
            town_node.InnerText = this.Town;
            profile_node.AppendChild(town_node);

            string[] entries = new string[6];
            entries[0] = this.CustomerNumber;
            entries[1] = this.Company;
            entries[2] = this.Street;
            entries[3] = this.Town;
            entries[4] = this.Base64ConversionCreator ?? ProfileManager.APO_IDENT_NAME;
            entries[5] = this.Base64ConversionTimestamp?.ToString(System.Globalization.CultureInfo.InvariantCulture) ?? DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture);
            XmlNode base64_address_node = doc.CreateElement(ProfileSettings.BASE64_ADDRESS_DATA_TAG);
            base64_address_node.InnerText = Base64AddressData.Encode(entries);
            profile_node.AppendChild(base64_address_node);

            XmlNode archive_node = doc.CreateElement(ProfileSettings.ARCHIVE_TAG);
            archive_node.InnerText = this.Archive;
            profile_node.AppendChild(archive_node);

            this.ExchangeData.WriteToXml(doc, profile_node);

            XmlNode country_node = doc.CreateElement(ProfileSettings.COUNTRY_TAG);
            country_node.InnerText = this.ReportCountry.ToString();
            profile_node.AppendChild(country_node);

            XmlNode bak_node = doc.CreateElement(ProfileSettings.BAK_MARKING_ACTIVATED_TAG);
            bak_node.InnerText = this.BakMarking.IsActive.ToString();
            profile_node.AppendChild(bak_node);

            XmlNode difference_node = doc.CreateElement(ProfileSettings.DIFFERENCE_TAG);
            difference_node.InnerText = this.ShowDifference.ToString();
            profile_node.AppendChild(difference_node);

            XmlNode file_name_node = doc.CreateElement(ProfileSettings.FILE_NAMES_TAG);
            file_name_node.InnerText = this.FileNameStart.ToString();
            profile_node.AppendChild(file_name_node);

            XmlNode dont_show_not_meaurable_node = doc.CreateElement(ProfileSettings.DONT_SHOW_NOT_MEASURABLE_DIALOG_TAG);
            dont_show_not_meaurable_node.InnerText = this.DontShowNotMeasurableDialogAgain.ToString();
            profile_node.AppendChild(dont_show_not_meaurable_node);

            XmlNode deactivate_add_tests_node = doc.CreateElement(ProfileSettings.MANDATORY_FOR_ADD_TEST_TAG);
            deactivate_add_tests_node.InnerText = this.AdditionalTest.IsMandatoryForComplementaryTest.ToString();
            profile_node.AppendChild(deactivate_add_tests_node);

            XmlNode print_validation_node = doc.CreateElement(ProfileSettings.PRINT_VALIDATION_WITHIN_PROTOCOL_TAG);
            print_validation_node.InnerText = this.PrintValidationWhitinProtocol.ToString();
            profile_node.AppendChild(print_validation_node);

            XmlNode certification_control_node = doc.CreateElement(ProfileSettings.CERTIFICATION_CONTROL_TAG);
            certification_control_node.InnerText = this.CertificationControl.ToString();
            profile_node.AppendChild(certification_control_node);
        }


        public override ProfileSettings Clone()
        {
            ProfileSettings tmp = new ProfileSettings();
            tmp.Name = this.Name;
            tmp.CustomerNumber = this.CustomerNumber;
            tmp.Company = this.Company;
            tmp.Street = this.Street;
            tmp.Town = this.Town;
            tmp.Base64ConversionCreator = this.Base64ConversionCreator;
            tmp.Base64ConversionTimestamp = this.Base64ConversionTimestamp;
            tmp.FileNameStart = this.FileNameStart;
            tmp.Archive = this.Archive;
            tmp.ExchangeData = this.ExchangeData.Clone(this.ExchangeData.ProtocolType);
            tmp.ReportCountry = this.ReportCountry;;
            tmp.ShowDifference = this.ShowDifference;
            tmp.IgnoreMissingArchive = this.IgnoreMissingArchive;
            tmp.DontShowNotMeasurableDialogAgain = this.DontShowNotMeasurableDialogAgain;
            tmp.PrintValidationWhitinProtocol = this.PrintValidationWhitinProtocol;
            tmp.ArchiveMissing = this.ArchiveMissing;
            tmp.DontShowHintMessageAgain = this.DontShowHintMessageAgain;
            tmp.CertificationControl = this.CertificationControl;

            tmp.ModelExtension = this.ModelExtension;
            tmp.BakMarking = this.BakMarking.Clone();
            tmp.AdditionalTest = this.AdditionalTest.Clone();
            tmp.GracePeriod = this.GracePeriod;

            return tmp;
        }

        protected override bool SettingsChanged()
        {
            this.ArchiveChanged = false;

            if (this.Stashed == null)
            {
                this.ArchiveChanged = true;
                return true;
            }

            if (this.Stashed.Archive != this.Archive)
            {
                this.ArchiveChanged = true;
                return true;
            }

            if (this.Stashed.Name != this.Name)
                return true;

            if (this.Stashed.ExchangeData.ProtocolType != this.ExchangeData.ProtocolType)
                return true;

            if (this.Stashed.ExchangeData.IsActivated != this.ExchangeData.IsActivated)
                return true;

            if (this.Stashed.ExchangeData.WorkingDir != this.ExchangeData.WorkingDir)
                return true;

            if (this.Stashed.ReportCountry != this.ReportCountry)
                return true;

            if ((this.Stashed.IsBakMarkingUsable && this.Stashed.BakMarking.IsActive) != (this.IsBakMarkingUsable && this.BakMarking.IsActive))
                return true;

            if (this.Stashed.AdditionalTest.IsMandatoryForComplementaryTest != this.AdditionalTest.IsMandatoryForComplementaryTest)
                return true;

            return false;
        }

        public bool IsBakMarkingUsable
        { 
            get
            {
                if (this.ReportCountry != ReportCountryTypes.Germany)
                    return false;

                if (this.ExchangeData.ProtocolType != ProtocolType.ApoIdent)
                    return false;

                return true;
            }
        }

        public string Name { get; set; }
        public string CustomerNumber { get; set; }
        public string Company { get; set; }
        public string Street { get; set; }
        public string Town { get; set; }
        public string Base64ConversionCreator { get; set; }
        public DateTime? Base64ConversionTimestamp { get; set; }
        public FilenameStartTypes FileNameStart { get; set; }
        public DataExchange ExchangeData { get; set; }
        public ReportCountryTypes ReportCountry { get; set; }
        public bool ShowDifference { get; set; }
        public bool IgnoreMissingArchive { get; set; }
        public bool DontShowNotMeasurableDialogAgain { get; set; } = false;
        public bool PrintValidationWhitinProtocol { get; set; } = true;
        public bool ArchiveMissing { get; set; } = true;
        public bool ArchiveChanged { get; set; } = false;
        public bool DontShowHintMessageAgain { get; set; } = false;
        public bool CertificationControl { get; set; } = true;
    }
}

#pragma warning restore RECS0022 // catch-Klausel, die System.Exception abfängt und keinen Text aufweist
