// 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.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Reflection;

using Hiperscan.Spectroscopy;
using Hiperscan.PdfLib;

using System.Globalization;
using Hiperscan.Unix;
using Hiperscan.I18n;
using Hiperscan.PdfPrint;

namespace Hiperscan.Extensions.ApoIdent.Report
{   
	public abstract class Generic
	{
		public const double DEFAULT_TAB_INDENT 		= 130;
		public const double DEFAULT_FONT_SIZE 		= 10;
		public const double DEFAULT_LINE_DISTANCE	= 1.5;
		public const double DEFAULT_RIGHT_MARGIN	= 60;
        public const double DEFAULT_LOWER_MARGIN    = 60;
        public const double DEFAULT_FEED            = 10;

		public Generic(ReportInfo report_info)
		{
			Console.WriteLine("Creating report...");

			 this.ReportInfo			= report_info;
			this.Layout 			    = null;
                    
            this.NumberOfAdditionalTextLines    = this.ReportInfo.IsMeasurable ? 3 : 15;
            this.Text                           = String.Empty;

			this.State = new PdfCreationState();
            this.SetDefaultValues();

			for(;;)
			{	
				try
				{
                    if (this.State.IsSet(PdfCreationStates.TryMode) == true &&
                        this.State.IsSet( PdfCreationStates.Init) == false)
					{
						if (this.ReferenceFontSize < 7.9)
						{
                            if (this.State.IsSet(PdfCreationStates.CreateTwoSides) == false)
							{
                                this.State.Set(PdfCreationStates.CreateTwoSides, true);
								this.SetDefaultValues();
							}
                            else if (this.State.IsSet(PdfCreationStates.CreateTwoSides) == true)
							{
								this.Delete();
                                throw new PdfLayoutException(Catalog.GetString("There is not enough space for creating protocol."));
							}                     
						}
                        else
						{
                            double scale = (this.ReferenceFontSize - 0.5) / this.ReferenceFontSize;
                            this.ReferenceFontSize *= scale;
                            this.ReferenceLineDistance *= scale;
                            this.ReferenceTabIndent *= scale;
                            this.ReferenceParagraphFeed *= scale;							
						}
					}

                    if (this.CreatePageOne() == true)
                    {
                        if (this.State.IsSet(PdfCreationStates.CreateTwoSides) == false)
                        {
                            if (this.State.IsSet(PdfCreationStates.TryMode) == false)
                            {
                                break;
                            }
                            else
                            {
                                this.State.Set(PdfCreationStates.TryMode, false);
                                continue;
                            }
                        }
                    }
                    else
                    {
                        continue;
                    }

                    if (this.CreatePageTwo() == true)
                    {
                        if (this.State.IsSet(PdfCreationStates.TryMode) == false)
                        {
                            break;
                        }
                        else
                        {
                            this.State.Set(PdfCreationStates.TryMode, false);
                            continue;
                        }     
                    }
                    else
                    {
                        continue;
                    }    
				}
				catch(Exception ex)
				{
					this.Delete();
					throw ex;
				}
			}

			this.Layout.Save();
			Console.WriteLine("Done.");
		}

        private void SetDefaultValues()
		{
            this.ReferenceTabIndent = Generic.DEFAULT_TAB_INDENT;
            this.ReferenceFontSize = Generic.DEFAULT_FONT_SIZE;
            this.ReferenceLineDistance = Generic.DEFAULT_LINE_DISTANCE;
            this.ReferenceParagraphFeed = Generic.DEFAULT_FEED;
        }

        protected virtual bool CreatePageOne()
        {
            if (this.State.IsSet(PdfCreationStates.Init) == true)
            {
                this.Layout = new Layout(PdfPageSizes.A4_PORTRAIT, this.ReportInfo.PdfFileFullName);
                this.Layout.PDF.SetAuthor(this.ReportInfo.Company);
                this.Layout.PDF.SetTitle(this.ReportInfo.Label.Header);
                this.Layout.PDF.SetSubject(this.ReportInfo.Label.Header);
				this.State.Set(PdfCreationStates.Init, false);
            }
            
			this.State.CurrentPage = 1;

            this.Layout.SimulateDrawing = this.State.IsSet(PdfCreationStates.TryMode) == true;
            this.Layout.YPosition = 0;
            this.Layout.XPosition = 0;
            this.Layout.RightMargin = Generic.DEFAULT_RIGHT_MARGIN;
            this.Layout.LowerMargin = Generic.DEFAULT_LOWER_MARGIN;
            this.Layout.LineDistance = this.ReferenceLineDistance;

            this.CreateHeader();
            if (this.CreateAddressHeader() == false)
                return false;

            if (this.CreateSubstanceProperties() == false)
                return false;
         
            if (this.CreateNirProperties() == false)
                return false;

            if (this.CreateCommentProperties() == false)
                return false;

            if (this.CreateGraphics() == false)
                return false;

            if (this.CreateNirResultSection() == false)
                return false;

            if (this.CreateAdditionalTest() == false)
                return false;

            if (this.CreateFinalResult() == false)
                return false;

            if (this.CreateTestCertificateSection() == false)
                return false;

            if (this.CreateSignature() == false)
                return false;

            this.CreateFooter();


            return true;
        }

        protected virtual bool CreatePageTwo()
        {
			this.Layout.AddNewPage();
            
			this.State.CurrentPage = 2;

            this.Layout.YPosition = 0;
            this.Layout.XPosition = 0;

            this.CreateHeader();
            if (this.CreateAddressHeader() == false)
                return false;

            if (this.CreateSubstanceProperties() == false)
                return false;
            
            if (this.CreateAdditionalTest() == false)
                return false;
            
            if (this.CreateFinalResult() == false)
                return false;
            
            if (this.CreateTestCertificateSection() == false)
                return false;

            this.CreateFooter();
            return true;
        }

		protected abstract void CreateHeader();
		protected abstract bool CreateAddressHeader();
		protected abstract bool CreateSubstanceProperties();
		protected abstract bool CreateNirProperties();
		protected abstract bool CreateCommentProperties();
		protected abstract bool CreateGraphics();
		protected abstract bool CreateNirResultSection();
		protected abstract bool CreateSingleNegativeResult();
		protected abstract bool CreateSinglePositiveResult();
		protected abstract bool CreateMultipleNegativeResult();
		protected abstract bool CreateMultiplePositiveResult();
		protected abstract bool CreateNonMultipleNegativeResult();
		protected abstract bool CreateNonMultiplePositiveResult();
		protected abstract bool AddNirEvaluation();
		protected abstract bool CreateAdditionalTest();
		protected abstract bool CreateFinalResult();
        protected abstract bool CreateTestCertificateSection();
		protected abstract bool CreateSignature();
		protected abstract void CreateFooter();

        public static void Print(string file)
        {
            PdfPrinting.Print(file);
        }

        protected string GetSubstanceName()
        {
            return new SubstanceNameResolver(this.ReportInfo.SubstanceClass, this.ReportInfo.DefaultName).SubstanceName;
        }

        protected string GetLatinName()
        {
            return new SubstanceNameResolver(this.ReportInfo.SubstanceClass, this.ReportInfo.LatinName).SubstanceName;
        }

		public void Show()
		{
            if (!string.IsNullOrEmpty(this.ReportInfo.PdfFileFullName))
			{
                System.IO.FileInfo file = new System.IO.FileInfo(this.ReportInfo.PdfFileFullName);
					
				if (file.Exists)
				{
                    System.Diagnostics.Process.Start(this.ReportInfo.PdfFileFullName);
					return;
				}
			}
				
			throw new Exception(Catalog.GetString("No report available."));
		}

		public void Print()
		{
            Generic.Print(this.ReportInfo.PdfFileFullName);
		}

		private void Delete()
		{
			try
			{
				this.Layout.Save();
                File.Delete(this.ReportInfo.PdfFileFullName);
			}
			catch(Exception)
			{
			}
		}
        
        protected abstract CultureInfo Culture  {get; set;}

        protected PdfCreationState State        {get; set;}
		protected Layout Layout					{get; set;}
		protected double ReferenceTabIndent		{get; set;}
		protected double ReferenceFontSize 		{get; set;}
		protected double ReferenceLineDistance 	{get; set;}
		protected double ReferenceParagraphFeed	{get; set;}
		protected string Text 					{get; set;}

        protected ReportInfo ReportInfo             {get; set;}
        protected int NumberOfAdditionalTextLines   {get; set;}
        protected abstract string SubstanceTestType { get; }
	}
}

