using System;
using System.Runtime.InteropServices;
using System.Text;

namespace ltrModulesNet
{
    public class ltr41api
    {
        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_Init(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_Open(ref TLTR41 module, int net_addr, ushort net_port,
                                                     string crate_sn, int slot_num);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_IsOpened(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_Close(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_Config(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_ReadPort(ref TLTR41 module, out ushort InputData);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_StartStreamRead(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_StopStreamRead(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern int LTR41_Recv(ref TLTR41 module, uint[] data, uint[] tmark, uint size, uint timeout);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_ProcessData(ref TLTR41 module, uint[] src, ushort[] dest, ref int size);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_StartSecondMark(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_StopSecondMark(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_MakeStartMark(ref TLTR41 module);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_WriteEEPROM(ref TLTR41 module, int Address, byte val);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_ReadEEPROM(ref TLTR41 module, int Address, out byte val);

        [DllImport("ltr41api.dll")]
        static extern _LTRNative.LTRERROR LTR41_SetStartMarkPulseTime(ref TLTR41 module, uint time_mks);

        [DllImport("ltr41api.dll")]
        static extern IntPtr LTR41_GetErrorString(int ErrorCode);


        public const int LTR41_EEPROM_SIZE  = 512;
        public const double LTR41_STREAM_READ_RATE_MIN = 100;
        public const double LTR41_STREAM_READ_RATE_MAX = 100000;

        public enum MarkMode : int
        {
            INTERNAL = 0,
            MASTER = 1,
            EXTERNAL = 2
        }

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        public struct INFO
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            char[] Name_;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
            char[] Serial_;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            char[] FirmwareVersion_;// Версия БИОСа
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            char[] FirmwareDate_;  // Дата создания данной версии БИОСа

            public string Name { get { return new string(Name_).Split('\0')[0]; } }
            public string Serial { get { return new string(Serial_).Split('\0')[0]; } }
            public string FirmwareVersionStr { get { return new string(FirmwareVersion_).Split('\0')[0]; } }
            public string FirmwareDateStr { get { return new string(FirmwareDate_).Split('\0')[0]; } }
        };

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        public struct MarksCfg
        {
            MarkMode SecondMark_Mode_; // Режим меток. 0 - внутр., 1-внутр.+выход, 2-внешн
            MarkMode StartMark_Mode_; // 

            public MarkMode SecondMark_Mode { get { return SecondMark_Mode_; } set { SecondMark_Mode_ = value; } }
            public MarkMode StartMark_Mode { get { return StartMark_Mode_; } set { StartMark_Mode_ = value; } }
        };  // Структура для работы с временными метками		

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        struct TLTR41
        {
            int size;   // размер структуры    
            public _LTRNative.TLTR Channel;

            double StreamReadRate_;
            MarksCfg Marks_;

            INFO ModuleInfo_;

            public double StreamReadRate { get { return StreamReadRate_; } set { StreamReadRate_ = value; } }            
            public MarksCfg Marks { get { return Marks_; } set { Marks_ = value; } }
            public INFO ModuleInfo { get { return ModuleInfo_; } }
        }; // Структура описания модуля


        TLTR41 module;

        public ltr41api() 
        {
            LTR41_Init(ref module);	
        }

        ~ltr41api()
        {
            LTR41_Close(ref module);
        }

		
		public virtual _LTRNative.LTRERROR Init()
		{
			return LTR41_Init(ref module);
		}

        public virtual _LTRNative.LTRERROR Open (uint saddr, ushort sport, string csn, ushort cc)
		{
			return LTR41_Open(ref module, (int)saddr, sport, csn, cc);
		}

        public virtual _LTRNative.LTRERROR Open(string csn, ushort cc)
        {
            return Open(_LTRNative.SADDR_DEFAULT, _LTRNative.SPORT_DEFAULT, csn, cc);
        }

        public virtual _LTRNative.LTRERROR Open(ushort cc)
        {
            return Open("", cc);
        }

        public virtual _LTRNative.LTRERROR Close ()
		{
			return LTR41_Close(ref module);
		}        

        public virtual _LTRNative.LTRERROR IsOpened ()
		{
			return LTR41_IsOpened(ref module);
		}

        public virtual _LTRNative.LTRERROR Config()
        {
            return LTR41_Config(ref module);
        }

        public virtual _LTRNative.LTRERROR ReadPort(out ushort InputData)
        {
            return LTR41_ReadPort(ref module, out InputData);
        }

        public virtual _LTRNative.LTRERROR StartStreamRead()
        {
            return LTR41_StartStreamRead(ref module);
        }

        public virtual _LTRNative.LTRERROR StopStreamRead()
        {
            return LTR41_StopStreamRead(ref module);
        }

        public virtual int Recv(uint[] Data, uint[] tstamp, uint size, uint timeout)
        {
            return LTR41_Recv(ref module, Data, tstamp, size, timeout);
        }

        public virtual int Recv(uint[] Data, uint size, uint timeout)
        {
            return LTR41_Recv(ref module, Data, null, size, timeout);
        }

        public virtual _LTRNative.LTRERROR ProcessData(uint[] src, ushort[] dest, ref int size)
        {
            return LTR41_ProcessData(ref module, src, dest, ref size);
        }

        public virtual _LTRNative.LTRERROR StartSecondMark()
        {
            return LTR41_StartSecondMark(ref module);
        }

        public virtual _LTRNative.LTRERROR StopSecondMark()
        {
            return LTR41_StopSecondMark(ref module);
        }

        public virtual _LTRNative.LTRERROR MakeStartMark()
        {
            return LTR41_MakeStartMark(ref module);
        }

        public virtual _LTRNative.LTRERROR WriteEEPROM(int Address, byte val)
        {
            return LTR41_WriteEEPROM(ref module, Address, val);
        }

        public virtual _LTRNative.LTRERROR ReadEEPROM(int Address, out byte val)
        {
            return LTR41_ReadEEPROM(ref module, Address, out val);
        }

        public virtual _LTRNative.LTRERROR SetStartMarkPulseTime(uint time_ms)
        {
            return LTR41_SetStartMarkPulseTime(ref module, time_ms);
        }

        public virtual _LTRNative.LTRERROR SetDefaultTimeout(uint timeout)
        {
            return _LTRNative.LTR_SetTimeout(ref module.Channel, timeout);
        }


        public static string GetErrorString(_LTRNative.LTRERROR err)
        {
            IntPtr ptr = LTR41_GetErrorString((int)err);
            string str = Marshal.PtrToStringAnsi(ptr);
            Encoding srcEncodingFormat = Encoding.GetEncoding("windows-1251");
            Encoding dstEncodingFormat = Encoding.UTF8;
            return dstEncodingFormat.GetString(Encoding.Convert(srcEncodingFormat, dstEncodingFormat, srcEncodingFormat.GetBytes(str)));
        }

        public double StreamReadRate { get { return module.StreamReadRate; } set { module.StreamReadRate = value; } }
        public MarksCfg Marks { get { return module.Marks; } set { module.Marks = value; } }
        public INFO ModuleInfo { get { return module.ModuleInfo; } }

    }
}
