// 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 System.Text.RegularExpressions;

using Hiperscan.Extensions.ApoIdentCommon;
using Hiperscan.Unix;
using Hiperscan.I18n;
using System.IO;

namespace Hiperscan.Extensions.ApoIdent
{
    public enum FilenameStartTypes
    {
        SubstanceName,
        LatinName,
    }  

	public enum ReportCountryType
	{
		Germany,
		Austria,
		GreatBritain,
		Switzerland
	}

	public class Profile
	{
		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 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 NAME_ATTRIBUTE = "Name";

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

		public static bool AutoConvertToBase64 = false;
      
		public Profile()
		{
			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();

            switch (Locale.Language)
			{
            case "de":
                switch (Locale.Country)
				{

				case "at":
					this.ReportCountry = ReportCountryType.Austria;
					break;

				case "ch":
					this.ReportCountry = ReportCountryType.Switzerland;
					break;

				default:
					this.ReportCountry = ReportCountryType.Germany;
					break;

				}
				break;

			default:
				this.ReportCountry = ReportCountryType.GreatBritain;
				break;
			}

			this.ShowDifference			= false;
			this.IgnoreMissingArchive	= false;
		}

		public Profile(XmlNode profile_node) : this()
		{
            this.MergedAdditionalData = false;

			try
			{
				this.Name = profile_node.Attributes[Profile.NAME_ATTRIBUTE].Value;
			}
			catch (Exception) { return; }

			string[] decoded_address_data = null;
			try
			{
				XmlNode base64_address_node = profile_node.SelectNodes(Profile.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] = Profile.DEFAULT_CUSTOMER_NUMBER;
				decoded_address_data[1] = Profile.DEFAULT_COMPANY;
				decoded_address_data[2] = Profile.DEFAULT_STREET;
				decoded_address_data[3] = Profile.DEFAULT_TOWN;
				decoded_address_data[4] = Plugin.name + " " + Plugin.version;
				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 (Profile.AutoConvertToBase64 == false)
					return;
				
				this.CustomerNumber = Profile.DEFAULT_CUSTOMER_NUMBER;

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

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

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

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

			try
			{
				XmlNode country_node = profile_node.SelectNodes(Profile.COUNTRY_TAG)[0];
				this.ReportCountry = (ReportCountryType) Enum.Parse(typeof(ReportCountryType), country_node.InnerText, true);
			}
			catch (Exception) {}

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

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

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

            try
            {
                XmlNode merged_additional_data_node = profile_node.SelectNodes(Profile.MERGED_ADDITIONAL_DATA_TAG)[0];
                this.MergedAdditionalData = Boolean.Parse(merged_additional_data_node.InnerText);
            }
            catch (Exception) { }

            try
            {
                XmlNode archive_created = profile_node.SelectNodes(Profile.ARCHIVE_CREATED_TAG)[0];
                this.ArchiveCreated = Boolean.Parse(archive_created.InnerText);
            }
            catch (Exception) 
            {
                this.ArchiveCreated = true;
            }
		}

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

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

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

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

			XmlNode town_node = doc.CreateElement(Profile.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 ?? Plugin.name + " " + Plugin.version;
			entries[5] = this.Base64ConversionTimestamp?.ToString(System.Globalization.CultureInfo.InvariantCulture) ?? DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture);
			XmlNode base64_address_node = doc.CreateElement(Profile.BASE64_ADDRESS_DATA_TAG);
			base64_address_node.InnerText = Base64AddressData.Encode(entries);
			profile_node.AppendChild(base64_address_node);

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

            this.ExchangeData.WriteToXml(doc, profile_node);

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

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

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

            XmlNode merged_additional_date_node = doc.CreateElement(Profile.MERGED_ADDITIONAL_DATA_TAG);
            merged_additional_date_node.InnerText = this.MergedAdditionalData.ToString();
            profile_node.AppendChild(merged_additional_date_node);

            XmlNode archive_created_node = doc.CreateElement(Profile.ARCHIVE_CREATED_TAG);
            archive_created_node.InnerText = this.ArchiveCreated.ToString();
            profile_node.AppendChild(archive_created_node);
		}
      
		public Profile Clone()
		{
			Profile tmp 				  = new Profile();
			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.AdditionalCompletionEntries = this.AdditionalCompletionEntries;
			tmp.SubstanceExtension = this.SubstanceExtension;
            tmp.MergedAdditionalData = this.MergedAdditionalData;
          
			return tmp;
		}

		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 string Archive						{ get; set; }
        public string OldArchive                    { get; set; }
        public DataExchange ExchangeData            { get; set; }
		public ReportCountryType ReportCountry		{ get; set;	}
		public bool ShowDifference					{ get; set; }
		public bool IgnoreMissingArchive            { get; set; }
		public AdditionalTestEntries AdditionalCompletionEntries { get; set; } = new AdditionalTestEntries();
		public SubstanceExtension SubstanceExtension { get; set; } = null;
        public bool MergedAdditionalData { get; set; } = true;
        public bool ArchiveCreated { get; set; } = false;
	}
}

