using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using SystemX.Net.Platform.Common.Util;
using static SystemX.PLC.Model.ModelSetupTemplate;

namespace SystemX.PLC.Model
{
    public class ModelCtrl
    {
        public Dictionary<string, ModelSetupTemplate> ModelDataResult { get; set; } = null;
        public ModelSetupTemplate ModelTmpStd { get; set; }
        public DataTable TemplateTable { get; set; } = null;
        public DataTable ModelTable { get; set; } = null;
        public string ModelPath { get; set; }

        public ModelCtrl(string strModelTmpPath, string strModelPath)
        {
            ModelTmpStd = new ModelSetupTemplate(strModelTmpPath);
            TemplateTable = CreateDescDataTable(ModelTmpStd);
            ModelTable = OpenModelData(strModelPath);
            ModelPath = strModelPath;
        }

        #region Initialization
        DataTable OpenModelData(string strModelPath)
        {
            DataTable dtSetup = new DataTable();
            List<string> vReadData = null;

            CreateDTTemplate(dtSetup, ModelTmpStd);

            if (File.Exists(strModelPath))
                vReadData = OpenModelFile(strModelPath);

            ModelDataResult = ReadModelData(vReadData, ModelTmpStd);

            CreateModelDatatable(dtSetup, ModelDataResult);

            return dtSetup;
        }

        DataTable CreateDescDataTable(ModelSetupTemplate model_tmpstd)
        {
            DataTable dtSetup = new DataTable();

            dtSetup.Columns.Add(ModelTemplateDefinition.DescTableName);
            dtSetup.Columns.Add(ModelTemplateDefinition.DescTableValue);

            foreach (string strKey in model_tmpstd.ModelDescriptionDictionary.Keys)
            {
                DataRow dtRow = dtSetup.NewRow();
                dtRow[ModelTemplateDefinition.DescTableName] = model_tmpstd.ModelDescriptionDictionary[strKey].Name;
                dtRow[ModelTemplateDefinition.DescTableValue] = model_tmpstd.ModelDescriptionDictionary[strKey].Desc;
                dtSetup.Rows.Add(dtRow);
            }

            return dtSetup;
        }

        void CreateDTTemplate(DataTable dtResult, ModelSetupTemplate model_tmpstd)
        {
            foreach (string strKey in model_tmpstd.ModelDataDictionary.Keys)
            {
                DataRow dtRow = dtResult.NewRow();
                Type typeTarget = CommonUtil.GetType(model_tmpstd.ModelDataDictionary[strKey].DataType);

                if (typeTarget == null) return;

                dtResult.Columns.Add(model_tmpstd.ModelDataDictionary[strKey].Name, typeTarget, model_tmpstd.ModelDataDictionary[strKey].Desc);

                if (model_tmpstd.ModelDataDictionary[strKey].IsIDKey)
                    dtResult.Columns[model_tmpstd.ModelDataDictionary[strKey].Name].Unique = true;
            }
        }

        void CreateModelDatatable(DataTable dtResult, Dictionary<string, ModelSetupTemplate> vModelData)
        {
            try
            {
                if (vModelData == null)
                    return;

                foreach (ModelSetupTemplate vModel in vModelData.Values)
                {
                    DataRow dtRow = dtResult.NewRow();

                    foreach (string strKey in vModel.ModelDataDictionary.Keys)
                    {
                        ModelElementData elemData = vModel.ModelDataDictionary[strKey];
                        object objValue = elemData.RValue;

                        if (objValue == null)
                            continue;

                        dtRow[strKey] = objValue;
                    }

                    dtResult.Rows.Add(dtRow);
                }
            }
            catch (Exception ex)
            {
                LogMessage.MessageOutput.ConsoleWrite($"Error in CreateModelDatatable. Error Message: {ex.Message}", ConsoleColor.Red, LogMessage.LogMessageLevel.FATAL);
            }
        }

        public void UpdateModelDataTable()
        {
            ModelTable.Clear();

            CreateModelDatatable(ModelTable, ModelDataResult);
        }

        Dictionary<string, ModelSetupTemplate> ReadModelData(List<string> vstrModel, ModelSetupTemplate model_tmpstd)
        {
            if (vstrModel == null || vstrModel.Count <= 0)
                return null;
            Dictionary<string, ModelSetupTemplate> dicResultModel = new Dictionary<string, ModelSetupTemplate>();
            List<string> vstrColumn = vstrModel[0].Split(ModelTemplateDefinition.ModelFileDelimiter.ToCharArray()).Where(x => x != string.Empty).ToList();

            vstrModel.RemoveAt(0);

            try
            {
                foreach (string strModel in vstrModel)
                {
                    List<string> vstrModelLine = strModel.Split(ModelTemplateDefinition.ModelFileDelimiter.ToCharArray()).ToList();
                    ModelSetupTemplate modelstr = model_tmpstd.GetNewModelStructure();

                    if (!CreateModelData(vstrColumn, vstrModelLine, modelstr))
                        continue;

                    dicResultModel.Add(modelstr.GetPrimaryKey().Value, modelstr);
                }
            }
            catch (Exception ex)
            {
                LogMessage.MessageOutput.ConsoleWrite($"Error occured in ModelCtrl.ReadModelData. Error Message: {ex.Message}", ConsoleColor.Red, LogMessage.LogMessageLevel.FATAL);
            }
            return dicResultModel;
        }

        bool CreateModelData(List<string> vstrColumn, List<string> vstrModelLine, ModelSetupTemplate modelstr)
        {
            string strColumnName = string.Empty;

            try
            {
                for (int i = 0; i < vstrColumn.Count; i++)
                {
                    strColumnName = vstrColumn[i];
                    modelstr.ModelDataDictionary[strColumnName].Value = vstrModelLine[i];
                }

                return true;
            }
            catch (Exception ex)
            {
                LogMessage.MessageOutput.ConsoleWrite("Error to find a column or a value. Column Name: " + strColumnName + "\n - Error Message: " + ex.Message, ConsoleColor.Red, LogMessage.LogMessageLevel.FATAL);

                return false;
            }
        }

        List<string> OpenModelFile(string strPath)
        {
            List<string> vstrData = new List<string>();
            //IntPtr safeADSHandle = NativeMethods.CreateFile(strPath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
            FileStream fs = new FileStream(strPath, FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(fs);

            while (!sr.EndOfStream)
                vstrData.Add(sr.ReadLine());

            sr.Close();
            fs.Close();

            return vstrData;
        }
        #endregion

        public ModelSetupTemplate FindElement(string strKey)
        {
            return ModelDataResult[strKey];
        }

        public void SaveModel(string strPath)
        {
            string strSavePath = string.IsNullOrEmpty(strPath) ? ModelPath : strPath;
            //IntPtr safeADSHandle = NativeMethods.CreateFile(strSavePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
            FileStream fs = new FileStream(strSavePath, FileMode.Truncate, FileAccess.ReadWrite);
            StreamWriter sr = new StreamWriter(fs);

            sr.WriteLine(ModelTmpStd.GetSaveModelColName());

            foreach (ModelSetupTemplate model in ModelDataResult.Values)
            {
                string strLine = model.GetSaveModelValue();

                sr.WriteLine(strLine);
            }

            sr.Close();
            fs.Close();
        }
    }
}
