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

namespace Hiperscan.Extensions.ApoIdentCommon.PerformanceQualification
{
    [DataContract(Name = "ReferenceSet", Namespace = "http://www.hiperscan.com/apoidentcommon/pqtool")]
    public partial class ReferenceSet : System.Runtime.Serialization.IExtensibleDataObject
    {
        public const string RB = "B";
        public const string R1 = "1";
        public const string R2 = "2";
        public const string R5 = "5";
        public const string R8 = "8";
        public const string RW = "W";
        public const string RX = "X";
        
        public const string X1132_9 = "1132_9";
        public const string X1261_8 = "1261_8";
        public const string X1320_2 = "1320_2";
        public const string X1534_6 = "1534_6";
        public const string X1681_4 = "1681_4";
        public const string X1757_6 = "1757_6";
        public const string X1847_3 = "1847_3";
        

        public ReferenceSet ()
        {
            this.InitializeSets();
            this.Id = -1;
            this.AcquistionDate = DateTime.MinValue;
        }
            
        public void InitializeSets()
        {
            this.SingleSets = new SingleSetDictionary();
            this.SingleSets.Add(ReferenceSet.RB, new SingleSet());
            this.SingleSets.Add(ReferenceSet.R1, new SingleSet());
            this.SingleSets.Add(ReferenceSet.R2, new SingleSet());
            this.SingleSets.Add(ReferenceSet.R5, new SingleSet());
            this.SingleSets.Add(ReferenceSet.R8, new SingleSet());
            this.SingleSets.Add(ReferenceSet.RW, new SingleSet());
            this.SingleSets.Add(ReferenceSet.RX, new SingleSet());
        }

        public SingleSet this[string indexer]
        {
            get
            {
                if (this.SingleSets.ContainsKey(indexer) == false)
                    return null;
                else
                    return this.SingleSets[indexer];
            }
        }

        private bool IsSingleSetComplete(string index)
        {
            bool is_complete = true;
            if (string.IsNullOrEmpty(this[index].Id) == true)
                is_complete = false;
            if (string.IsNullOrEmpty(this[index].ScannerId) == true)
                is_complete = false;
            if (index != ReferenceSet.RB && index != ReferenceSet.RX)
            {
                if (this[index].Reflectance < 0)
                    is_complete = false;
            }                
            return is_complete;
        }
        
        private bool IsSingleSetValid(string index)
        {
            string id = this[index].Id;
            string id_pattern = @"^(\d\d((0[1-9])|([1-4]\d)|(5[0-3])))" + index + @"-\d{3}$";
            Regex id_regex = new Regex(id_pattern);
            if (id_regex.Match(id ?? string.Empty).Success == false)
                return false;
            
            string scanner_id = this[index].ScannerId;
            string scanner_id_pattern = @"^" + index + @"\d{3}$";
            Regex scanner_idregex = new Regex(scanner_id_pattern);
            if (scanner_idregex.Match(scanner_id ?? string.Empty).Success == false)
                return false;
            
            return id.Substring(4).Replace("-", string.Empty) == scanner_id;
        }
        
        private bool IsSingleSetUniqueLocal(string index)
        {
            string id = this[index].Id;
            string scanner_id = this[index].ScannerId;
            foreach (string other_index in this.SingleSets.Keys)
            {
                if (other_index != index)
                {
                    if (this[other_index].Id == id || this[other_index].ScannerId == scanner_id)
                        return false;
                }    
            }            
            return true;
        }
        
        public bool SetsValidAndComplete
        {
            get
            {
                foreach (string index in this.SingleSets.Keys)
                {
                    if (this.IsSingleSetComplete(index) == false)
                        return false;
                    if (this.IsSingleSetValid(index) == false)
                        return false;
                }
                return true;
            }
        }
        
        public bool CanBeAdded
        {
            get
            {
                foreach (string index in this.SingleSets.Keys)
                {
                    if (this.IsSingleSetComplete(index) == false)
                        return false;
                    if (this.IsSingleSetValid(index) == false)
                        return false;
                    if (this.IsSingleSetUniqueLocal(index) == false)
                        return false;
                    if (this.Id < 0)
                        return false;
                }
                return true;
            }
        }
        
        public double[] AbsorbanceValues
        {
            get
            {
                double[] absorbance_values = new double[5];
                double max_reflecetion = this[ReferenceSet.RW].Reflectance; 
                absorbance_values[0] =  Math.Log10(max_reflecetion / this[ReferenceSet.RW].Reflectance); 
                absorbance_values[1] =  Math.Log10(max_reflecetion / this[ReferenceSet.R8].Reflectance); 
                absorbance_values[2] =  Math.Log10(max_reflecetion / this[ReferenceSet.R5].Reflectance); 
                absorbance_values[3] =  Math.Log10(max_reflecetion / this[ReferenceSet.R2].Reflectance); 
                absorbance_values[4] =  Math.Log10(max_reflecetion / this[ReferenceSet.R1].Reflectance); 
                return (absorbance_values);
            }
        }

        public double[] AbsorptionValues
        {
            get
            {
                double[] absorbtion_values = new double[5];
                absorbtion_values[0] = 1 - this[ReferenceSet.RW].Reflectance;
                absorbtion_values[1] = 1 - this[ReferenceSet.R8].Reflectance;
                absorbtion_values[2] = 1 - this[ReferenceSet.R5].Reflectance;
                absorbtion_values[3] = 1 - this[ReferenceSet.R2].Reflectance;
                absorbtion_values[4] = 1 - this[ReferenceSet.R1].Reflectance;
                return (absorbtion_values);
            }
        }

        public double[] ReflectanceValues
        {
            get
            {
                double[] reflectance_values = new double[5];
                reflectance_values[0] =  this[ReferenceSet.RW].Reflectance; 
                reflectance_values[1] =  this[ReferenceSet.R8].Reflectance; 
                reflectance_values[2] =  this[ReferenceSet.R5].Reflectance; 
                reflectance_values[3] =  this[ReferenceSet.R2].Reflectance; 
                reflectance_values[4] =  this[ReferenceSet.R1].Reflectance; 
                return (reflectance_values);
            }
        }

        public ExtensionDataObject ExtensionData { get; set; }

        [DataMember(Order = 0)] public int Id { get; set; }
        [DataMember(Order = 1)] public DateTime AcquistionDate { get; set; }
        [DataMember(Order = 2)] public SingleSetDictionary SingleSets { get; private set; }
    }
}

