using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.ComponentModel;
using System.IO;

using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;

using MVVM;

using sdkdef = YoseenPTZ.SDKDef;
using YoseenPTZ.CoreDef;
using YoseenPTZ.ResourceDef;

namespace YoseenPTZ.ConfigDef
{
    public class ConfigService
    {
        #region static
        const int ConstBinHead_FileVersion = BinHead.ConstBinHead_FileVersion;

        //Head, DeviceConfig, ImageConfig
        const int ConstHead_Size = 4096;
        public const int ConstDeviceConfig_Size = 4096;
        public const int ConstImageConfig_Size = 4096;
        const int ConstFileSize = ConstHead_Size + ConstDeviceConfig_Size + ConstImageConfig_Size;

        //
        readonly int[] ConstSize_Array;
        readonly int[] ConstOffset_Array;

        #endregion

        IntPtr _ptrFile;
        IntPtr _ptrBuffer;

        void resetConfig()
        {
            IntPtr ptr = _ptrBuffer;
            sdkdef.Win32Helper.memset(ptr, 0, ConstFileSize);

            //head
            _clsHead._bin.Reset();
            ptr = _ptrBuffer + ConstOffset_Array[(int)ConfigPartType.Head];
            Marshal.StructureToPtr(_clsHead._bin, ptr, false);

            //deviceConfig
            _clsDeviceConfig._bin.Reset();
            ptr = _ptrBuffer + ConstOffset_Array[(int)ConfigPartType.DeviceConfig];
            Marshal.StructureToPtr(_clsDeviceConfig._bin, ptr, false);

            //imageConfig
            _clsImageConfig._bin.Reset();
            ptr = _ptrBuffer + ConstOffset_Array[(int)ConfigPartType.ImageConfig];
            Marshal.StructureToPtr(_clsImageConfig._bin, ptr, false);

            //
            sdkdef.Win32Helper.fwrite(_ptrBuffer, ConstFileSize, 1, _ptrFile);
        }

        void initConfig()
        {
            string dir = _clsHead.Data_SaveDir;
            try
            {
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.Message);
            }
        }

        public ConfigService()
        {
            //
            const int ConstPartCount = (int)ConfigPartType.PartCount;
            ConstSize_Array = new int[ConstPartCount]{
                ConstHead_Size, ConstDeviceConfig_Size,ConstImageConfig_Size
            };
            ConstOffset_Array = new int[ConstPartCount];
            ConstOffset_Array[0] = 0;
            int i;
            for (i = 1; i < ConstPartCount; i++)
            {
                ConstOffset_Array[i] = ConstOffset_Array[i - 1] + ConstSize_Array[i - 1];
            }

            //
            _ptrBuffer = sdkdef.Win32Helper.calloc(1, ConstFileSize);
            _ptrFile = sdkdef.Win32Helper._wfopen(AppStatic.FileBin, "rb+");
            if (IntPtr.Zero == _ptrFile)
            {
                _ptrFile = sdkdef.Win32Helper._wfopen(AppStatic.FileBin, "wb+");
            }
            if (IntPtr.Zero == _ptrBuffer || IntPtr.Zero == _ptrFile)
            {
                throw new Exception(string.Format("_wfopen, calloc, error"));
            }
            sdkdef.Win32Helper.fread(_ptrBuffer, ConstFileSize, 1, _ptrFile);
            sdkdef.Win32Helper.fseek(_ptrFile, 0, 0);

            //
            IntPtr ptr;
            _clsHead = new ClsHead();
            _clsDeviceConfig = new ClsDeviceConfig();
            _clsImageConfig = new ClsImageConfig();

            _clsHead._bin = Marshal.PtrToStructure<BinHead>(_ptrBuffer);
            if (_clsHead._bin.FileVersion != ConstBinHead_FileVersion)
            {
                resetConfig();
            }

            //Head, DeviceConfig
            ptr = _ptrBuffer + ConstOffset_Array[(int)ConfigPartType.DeviceConfig];
            _clsDeviceConfig.Ptr2Cls(ptr);

            ptr = _ptrBuffer + ConstOffset_Array[(int)ConfigPartType.ImageConfig];
            _clsImageConfig.Ptr2Cls(ptr);


            //
            initConfig();
        }

        internal readonly ClsHead _clsHead;
        internal readonly ClsDeviceConfig _clsDeviceConfig;
        internal readonly ClsImageConfig _clsImageConfig;

        public void ConfigPart(ConfigPartType partType)
        {
            //
            int partIndex = (int)partType;
            int offset = ConstOffset_Array[partIndex];
            int size = ConstSize_Array[partIndex];

            IntPtr ptr = _ptrBuffer + offset;
            sdkdef.Win32Helper.memset(ptr, 0, size);

            //
            if (partType == ConfigPartType.Head)
            {
                Marshal.StructureToPtr(_clsHead._bin, ptr, false);
            }
            else if (partType == ConfigPartType.DeviceConfig)
            {
                Marshal.StructureToPtr(_clsDeviceConfig._bin, ptr, false);
            }
            else if (partType == ConfigPartType.ImageConfig)
            {
                Marshal.StructureToPtr(_clsImageConfig._bin, ptr, false);
            }
            //
            if (0 == sdkdef.Win32Helper.fseek(_ptrFile, offset, 0))
            {
                sdkdef.Win32Helper.fwrite(ptr, (uint)size, 1, _ptrFile);
                sdkdef.Win32Helper.fflush(_ptrFile);
            }
        }

        public void SaveConfig()
        {
            if (IntPtr.Zero == _ptrFile) return;
            sdkdef.Win32Helper.fclose(_ptrFile); _ptrFile = IntPtr.Zero;
            sdkdef.Win32Helper.free(_ptrBuffer); _ptrBuffer = IntPtr.Zero;
        }
    }

    public enum ConfigPartType
    {
        //
        Head = 0,
        DeviceConfig,
        ImageConfig,

        //
        PartCount,
    }

    #region Head
    [StructLayout(LayoutKind.Sequential)]
    public struct BinHead
    {
        public const int ConstBinHead_FileVersion = 20230116;

        public int FileVersion;

        //data
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
        public string Data_SaveDir;

        public bool IR_TempStream;

        public void Reset()
        {
            FileVersion = ConstBinHead_FileVersion;

            //
            Data_SaveDir = "d:\\YoseenPTZ-Data";

            IR_TempStream = true;
        }
    }

    public class ClsHead : BaseModel
    {
        internal BinHead _bin;

        [PropertyOrder(1), DisplayName(Loc.Data_SaveDir), Description()]
        public string Data_SaveDir
        {
            get
            {
                return _bin.Data_SaveDir;
            }
            set
            {
                bool b = value != _bin.Data_SaveDir && value.Length < 1024;
                b = b && Directory.Exists(value);
                if (b)
                {
                    _bin.Data_SaveDir = value;
                    OnPropertyChanged("Data_SaveDir");
                }
            }
        }

        [PropertyOrder(1), DisplayName(Loc.IR_TempStream), Description()]
        public bool IR_TempStream
        {
            get
            {
                return _bin.IR_TempStream;
            }
            set
            {
                bool b = value != _bin.IR_TempStream;
                if (b)
                {
                    _bin.IR_TempStream = value;
                    OnPropertyChanged("IR_TempStream");
                }
            }
        }

        public ClsHead()
        {
            _bin.Reset();
        }

        public void Bin2Cls(ref BinHead bin)
        {
            //
            _bin.FileVersion = bin.FileVersion;

            //
            Data_SaveDir = bin.Data_SaveDir;

            IR_TempStream = bin.IR_TempStream;
        }
    }
    #endregion
}
