// Created with MonoDevelop
//
//    Copyright (C) 2017 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.Xml;
using System.IO;
using System.Text;
using System.Runtime.Serialization;


namespace Hiperscan.Pdf.SubstanceOverview
{
	[DataContract][Serializable ()]
	public class PdfModelStructure
	{
		public PdfModelStructure()
		{
			this.ModelClasses				= new List<PdfModelClassEntry>();
			this.ShowClassificationColumn	= true;
			this.ListOfContentsHeader		= String.Empty;
			this.Version 					= String.Empty;
		}


		public void Sort()
		{
			this.ModelClasses.Sort();
			foreach (PdfModelClassEntry class_entry in this.ModelClasses)
			{
				foreach (PdfSubstanceEntry substance_entry in class_entry.Substances)
				{
					substance_entry.DefaultNames.Sort();
					substance_entry.LatinNames.Sort();
				}

				class_entry.Substances.Sort();
			}
		}

		public bool IsEmpty
		{
			get
			{
				return this.ModelClasses.Count == 0;
			}
		}

		public static PdfModelStructure operator - (PdfModelStructure a, PdfModelStructure b)
		{
			if (a == null || b == null)
				return null;

			if (a.IsEmpty == true || b.IsEmpty == true)
				return null;

			a.Sort();
			b.Sort();
			
			//a - b = c
			PdfModelStructure c = new PdfModelStructure();

			foreach (PdfModelClassEntry a_class_entry in a.ModelClasses)
			{
				if (b.ModelClasses.Contains(a_class_entry) == false)
				{
					c.ModelClasses.Add(a_class_entry.Clone(true));
					continue;
				}

				PdfModelClassEntry b_class_entry = b.ModelClasses.Find(x => x.ModelClassName.Contains(
					a_class_entry.ModelClassName));

				foreach (PdfSubstanceEntry a_substance_entry in a_class_entry.Substances)
				{
					if (b_class_entry.Substances.Contains(a_substance_entry) == false)
					{
						PdfModelClassEntry c_class_entry = c.ModelClasses.Find(x => x.ModelClassName.Contains(
							a_class_entry.ModelClassName));

						if(c_class_entry == null)
						{
							c_class_entry = a_class_entry.Clone(false);
							c.ModelClasses.Add(c_class_entry);
						}

						c_class_entry.Substances.Add(a_substance_entry.Clone());
					}
				}
			}

			return c;
		}

		public static void Write(PdfModelStructure model_structure, string file_name)
		{
			using (Stream stream = new FileStream (file_name, FileMode.Create)) 
			{
				DataContractSerializer serializer = new DataContractSerializer (typeof (PdfModelStructure));
				serializer.WriteObject (stream, model_structure);
			}
		}

		public static PdfModelStructure Read(string file_name)
		{
			using (Stream stream = new FileStream (file_name, FileMode.Open)) 
			{
				using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader (stream, new XmlDictionaryReaderQuotas ())) 
				{
					DataContractSerializer serializer = new DataContractSerializer (typeof (PdfModelStructure));
					PdfModelStructure model = (PdfModelStructure)serializer.ReadObject (reader, true);

					if (model == null)
						throw new Exception ("Cannot deserialize model.");

					return model;
				}
			}
		}

		[DataMember (Name = "ModelClasses")]
		public List<PdfModelClassEntry> ModelClasses	{get; set;}
		[DataMember(Name = "Version")]
		public string Version { get; set;}
		[IgnoreDataMember]
		public bool ShowClassificationColumn		{get; set;}
		[IgnoreDataMember]
		public string ListOfContentsHeader			{get; set;}
	}
}

