using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.RecipeCenter;
using MECF.Framework.Common.Equipment;
using SciChart.Core.Extensions;

namespace MECF.Framework.Common.Jobs
{
    public enum SequenceLLInOutPath
    {
        AInBOut,
        BInAOut,
        DInDOut,
        AInAOut,
        BInBOut,
    }

    [Serializable]
    [DataContract]
    public class SequenceInfo
    {
        [DataMember]
        public List<SequenceStepInfo> Steps { get; set; }

        [DataMember]
        public string Name { get; set; }


        [DataMember]
        public string ThicknessType { get; set; }

        [DataMember]
        public Guid InnerId { get; set; }

        [DataMember]
        public SequenceLLInOutPath LLInOutPath { get; set; }
 
        public SequenceInfo(string name)
        {
            Name = name;
            InnerId = Guid.NewGuid();
            LLInOutPath =  SequenceLLInOutPath.DInDOut;
            Steps = new List<SequenceStepInfo>();
        }
    }

    public class SequenceInfoHelper
    {
        public static SequenceInfo GetInfo(string seqFile)
        {
            SequenceInfo info = new SequenceInfo(seqFile);
 
            string content = RecipeFileManager.Instance.GetSequenceAndTryAppendLL(seqFile, false);
            if (!string.IsNullOrEmpty(content))
            {
                try
                {
                    XmlDocument dom = new XmlDocument();
                    dom.LoadXml(content);

                    XmlNodeList lstStepNode = dom.SelectNodes("Aitex/TableSequenceData/Step");
                    if (lstStepNode == null)
                    {
                        //LOG.Error($"{seqFile} has no step");
                        return null;
                    }

                    var nodeData = dom.SelectSingleNode("Aitex/TableSequenceData");
                    if (nodeData != null)
                    {
                        var node = nodeData as XmlElement;
                        info.ThicknessType = node.GetAttribute("ThicknessType");
                    } 

                    foreach (var nodeModelChild in lstStepNode)
                    {
                        XmlElement nodeStep = nodeModelChild as XmlElement;
                        SequenceStepInfo stepInfo = new SequenceStepInfo();

                        foreach (XmlAttribute attr in nodeStep.Attributes)
                        {
                            stepInfo.StepParameter[attr.Name] = attr.Value;

                            if (attr.Name == "Position" || attr.Name=="LLSelection" || attr.Name == "PMSelection")
                            {
                                if (attr.Value == "LL" || attr.Value=="PM")
                                    continue;

                                string[] pos = attr.Value.Split(',');
                                if (pos.Length < 1)
                                {
                                    LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"{seqFile} Position {attr.Value} can not be empty");
                                    return null;
                                }

                                foreach (var po in pos)
                                {
                                    if (po.IsEmpty())
                                        continue;

                                    if (po == "Cooling" )
                                    { 
                                        stepInfo.StepModules.AddIfNotContains(ModuleName.Cooling1);
                                        stepInfo.StepModules.AddIfNotContains(ModuleName.Cooling2);
                                        continue;
                                    }

                                    if (po == "Aligner")
                                    {
                                        stepInfo.StepModules.AddIfNotContains(ModuleName.Aligner1);
                                        stepInfo.StepModules.AddIfNotContains(ModuleName.Aligner2);
                                        continue;
                                    }
                                    ModuleName module = ModuleHelper.Converter(po);
                                    if (module == ModuleName.System)
                                    {
                                        //LOG.Error($"{seqFile} Position {po} not valid");
                                        return null;
                                    }

                                    stepInfo.StepModules.Add(module);
                                }

                                continue;
                            }

                            if (attr.Name == "AlignerAngle")
                            {
                                if (!double.TryParse(attr.Value, out double angle))
                                {
                                    //LOG.Error($"{seqFile} AlignAngle {attr.Value} not valid");
                                    return null;
                                }

                                stepInfo.AlignAngle = angle;
                                continue;
                            }
                        }

                        info.Steps.Add(stepInfo);
                    }

                    // Loadlock Single In Single Out property check
                    var llSteps = info.Steps.FindAll(item => item.StepModules.Contains(ModuleName.LLA) || item.StepModules.Contains(ModuleName.LLB));
                    if ((llSteps.Count == 2) && 
                        (llSteps[0].StepModules.Count == 1 && llSteps[1].StepModules.Count == 1))
                    {
                        if (llSteps[0].StepModules[0] != llSteps[1].StepModules[0])
                        {
                            info.LLInOutPath = llSteps[0].StepModules[0] == ModuleName.LLA ? SequenceLLInOutPath.AInBOut : SequenceLLInOutPath.BInAOut;
                        }
                        else
                        {
                            info.LLInOutPath = llSteps[0].StepModules[0] == ModuleName.LLA ? SequenceLLInOutPath.AInAOut : SequenceLLInOutPath.BInBOut;
                        }
                    }
                }
                catch (Exception ex)
                {
                    LOG.WriteExeption(ex);
                    return null;
                }
            }

            return info;
        }
    }
}