using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO.Ports;

using Cosmos.UserFrame;
using Cosmos.Common;
using Cosmos.ServiceProvider;

using Microsoft.PointOfService;

/*-----------------------------------------------------------------------------------------------*/
// 설      명 : CahsDrawer 제어
// 작  성  자 : 
// 변경  이력 : 
/*-----------------------------------------------------------------------------------------------*/
namespace Cosmos.OLEDevice
{
    /// <summary>
    /// CASHDRAWER 제어 CLASS
    /// </summary>
    public class DeviceCashdrawer : ICashdrawerUs
    {
        #region VctDraw2kSs.dll 제어 함수
        [DllImport("VctDraw2kSs.dll", EntryPoint = "OpenDrawPort")]
        public static extern int OpenDrawPortFor9700();

        [DllImport("VctDraw2kSs.dll", EntryPoint = "CloseDrawPort")]
        public static extern int CloseDrawPortFor9700();

        [DllImport("VctDraw2kSs.dll", EntryPoint = "OpenDraw")]
        public static extern void OpenDrawFor9700();
        #endregion

        #region TgDrawA.dll 제어 함수
        [DllImport("TgDrawA.dll", EntryPoint = "OpenDrawPort")]
        public static extern int OpenDrawPortForTg();

        [DllImport("TgDrawA.dll", EntryPoint = "CloseDrawPort")]
        public static extern int CloseDrawPortForTg();

        [DllImport("TgDrawA.dll", EntryPoint = "OpenDraw")]
        public static extern void OpenDrawForTg();
        #endregion
        /// <summary>
        /// StateServer Object (StateServer 객체)
        /// </summary>
        public StateServer StateObject = (StateServer)StateServer.GetInstance();
        /// <summary>
        /// Device 상태 정보 객체
        /// </summary>
        public DeviceStatus devStatus = new DeviceStatus();
        /// <summary>
        /// POS 기본 정보
        /// </summary>
        public PosStatus m_cPosStatus = null;
        /// <summary>
        /// Pos for .Net CashDrawer 객체
        /// </summary>
        private CashDrawer cashdrawer = null;
        /// <summary>
        /// Pos for .Net의 Device 정보를 가져오기 위한 객체
        /// </summary>
        private PosExplorer posExplorer = null;
        /// <summary>
        /// RS232통신을 위한 시리얼포트 객체
        /// </summary>
        private SerialPort m_serialPort = null;

        private IPosPrinterUs objPosPrinter = null;
        /// <summary>
        /// 
        /// </summary>g
        private int m_sUpdateStatus = 0;

        /// <summary>
        /// 0:OPOS, 1:RS232(프린터에 연결), 2:IBM본체에 연결하는 돈통
        /// <para>DRAWER_TYPE 참고</para>
        /// </summary>
        private int drawerType = 0;

        #region 초기화
        /// <summary>
        /// 생성자
        /// </summary>
        public DeviceCashdrawer()
        {
            try
            {
                try
                {
                    posExplorer = new PosExplorer();
                }
                catch (Exception ex) { }
                devStatus = (DeviceStatus)StateObject.DEVICE;
                m_cPosStatus = (PosStatus)StateObject.POS;
                objPosPrinter = (IPosPrinterUs)(new SManager()).InitServiceInstance(ServiceLists.AGENT_OLEDEVICE.DLL, ServiceLists.AGENT_OLEDEVICE.DEVICE_POSPRINTER);
                DeviceStatusInit();
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }
        }

        /// <summary>
        /// 초기화
        /// </summary>
        private void DeviceStatusInit()
        {
            devStatus.Cashdrawer.Status = "";
            devStatus.Cashdrawer.DeviceName = "";
            devStatus.Cashdrawer.Open = false;
        }
        #endregion

        #region 디바이스 OPEN/CLOSE 처리
        /// <summary>
        /// 디바이스 Open시 처리함수
        /// </summary>
        /// <param name="sDeviceType">장비종류(ex- "Msr","PosPrinter","Scanner"...)</param>
        /// <param name="sLogicalName">레지스트리 항목(ex- "DefaultMsr","DefaultPosPrinter","DefaultScanner"...)</param>
        /// <returns></returns>
        public bool OpenDevice(string sDeviceType, string sLogicalName)
        {
            bool bRet = false;

            try
            {
                if(devStatus.Cashdrawer.UseYn == false)
                {
                    return false;
                }

                if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._1_PRINTER)
                {
                    if(devStatus.Printer.UseYn == false)
                    {
                        return false;
                    }
                    devStatus.Cashdrawer.Open = true;
                    devStatus.Cashdrawer.Status = "SUCCESS";
                }
                else if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._2_OPOS_IBM)
                {
                    OpenDeviceByOPOS(sDeviceType, sLogicalName);
                }
                else if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._3_DLL_TPS8700)
                {
                    OpenDrawForTg();
                    bRet = true;
                }
                else if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._4_DLL_VPS9700)
                {
                    OpenDrawFor9700();
                    bRet = true;
                }
                else if (m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._5_IBM_MAIN)
                {
                    OpenDeviceByRS232(m_cPosStatus.Base.OlePosCashDrawerSerialPortNumber, m_cPosStatus.Base.OlePosCashDrawerBaudRate);
                }
                
                bRet = true;
            }
            catch (Exception ex)
            {
                devStatus.Cashdrawer.Open = false;
                devStatus.Cashdrawer.Status = "CashDrawer Device Open Exception";

                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     devStatus.Cashdrawer.Status + "/" + ex.Message);
                return bRet;
            }
            return bRet;
        }

        public bool OpenDeviceByOPOS(string sDeviceType, string sLogicalName)
        {
            bool bRet = false;

            try
            {
                DeviceInfo devInfo = null;

                if (sDeviceType == DeviceType.CashDrawer && sLogicalName == PosConst.OPOS_LDN.CASHDRAWER)
                {
                    devInfo = posExplorer.GetDevice(DeviceType.CashDrawer, PosConst.OPOS_LDN.CASHDRAWER);
                }
                else
                {
                    devStatus.Cashdrawer.Open = false;
                    devStatus.Cashdrawer.Status = "DEVICE INFO ERROR";
                    UserLog.WriteLogFile(UserCom.LOG_IOS, UserCom.ERROR_LEVEL, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                        "DeviceCashdrawer.OpenDeviceByOPOS()", devStatus.Printer.Status);
                    return bRet;
                }

                if(devInfo == null)
                {
                    devStatus.Cashdrawer.Open = false;
                    devStatus.Cashdrawer.Status = "DEVICE INFO ERROR";
                    UserLog.WriteLogFile(UserCom.LOG_IOS, UserCom.ERROR_LEVEL, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                        "DeviceCashdrawer.OpenDeviceByOPOS()", devStatus.Printer.Status);
                    return bRet;
                }

                cashdrawer = (CashDrawer)posExplorer.CreateInstance(devInfo);

                if(cashdrawer != null)
                {
                    cashdrawer.StatusUpdateEvent += new StatusUpdateEventHandler(CashDrawer_StatusUpdateEventDataEvent);

                    try
                    {
                        cashdrawer.Open();
                    }
                    catch(Exception ex)
                    {
                        devStatus.Cashdrawer.Status = "OPEN FAIL";
                        UserLog.WriteLogFile(UserCom.LOG_IOS, UserCom.ERROR_LEVEL, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                        "DeviceCashdrawer.OpenDeviceByOPOS()", devStatus.Printer.Status);
                        return bRet;
                    }

                    try
                    {
                        cashdrawer.Claim(1000);
                    }
                    catch(Exception ex)
                    {
                        devStatus.Cashdrawer.Status = "CLAIM FAIL";
                        UserLog.WriteLogFile(UserCom.LOG_IOS, UserCom.ERROR_LEVEL, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                        "DeviceCashdrawer.OpenDeviceByOPOS()", devStatus.Printer.Status);
                        return bRet;
                    }

                    try
                    {
                        cashdrawer.DeviceEnabled = true;
                    }
                    catch(Exception ex)
                    {
                        devStatus.Cashdrawer.Status = "DEVICE ENABLED FAIL";
                        UserLog.WriteLogFile(UserCom.LOG_IOS, UserCom.ERROR_LEVEL, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                        "DeviceCashdrawer.OpenDeviceByOPOS()", devStatus.Printer.Status);
                        return bRet;
                    }

                    devStatus.Cashdrawer.DeviceName = devInfo.ServiceObjectName;
                    devStatus.Cashdrawer.Open = true;
                    devStatus.Cashdrawer.Status = "Success";
                    bRet = true;
                }
            }
            catch (Exception ex)
            {
                devStatus.Cashdrawer.Open = false;
                devStatus.Cashdrawer.Status = "CashDrawer Device Open Exception";

                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     devStatus.Cashdrawer.Status + "/" + ex.Message);
            }

            return bRet;
        }

        public bool OpenDeviceByRS232(string sSerialPort, long lBaudrate)
        {
            bool bRet = false;

            try
            {
                if(m_serialPort != null)
                {
                    m_serialPort.Close();
                    System.Threading.Thread.Sleep(50);
                    m_serialPort = null;
                }

                if(m_serialPort == null)
                {
                    m_serialPort = new SerialPort();
                    if(m_serialPort == null)
                    {
                        devStatus.Cashdrawer.Open = false;
                        devStatus.Cashdrawer.Status = "SERIAL PORT ERROR";
                        UserLog.WriteLogFile(UserCom.LOG_IOS,
                                             UserCom.WARNING_LEVEL,
                                             System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                             System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                             System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                             devStatus.Cashdrawer.Status);
                        return bRet;
                    }

                    m_serialPort.NewLine = "\r\n";
                    m_serialPort.Encoding = System.Text.Encoding.GetEncoding("ks_c_5601-1987");

                    m_serialPort.WriteBufferSize = 1024 * 3;
                    m_serialPort.PortName = sSerialPort;
                    m_serialPort.BaudRate = (int)lBaudrate;
                    m_serialPort.DataBits = 8;
                    m_serialPort.StopBits = StopBits.One;
                    m_serialPort.Parity = Parity.None;

                    m_serialPort.Open();
                    if(m_serialPort.IsOpen == false)
                    {
                        devStatus.Cashdrawer.Open = false;
                        devStatus.Cashdrawer.Status = "SERIAL PORT OPEN ERROR";
                        UserLog.WriteLogFile(UserCom.LOG_IOS,
                                             UserCom.WARNING_LEVEL,
                                             System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                             System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                             System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                             devStatus.Cashdrawer.Status);
                        return bRet;
                    }

                    devStatus.Cashdrawer.Open = true;
                    devStatus.Cashdrawer.Status = "SUCCESS";
                    bRet = true;
                }
            }
            catch (Exception ex)
            {
                devStatus.Cashdrawer.Open = false;
                devStatus.Cashdrawer.Status = "CashDrawer Device Open Exception";

                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }

            return bRet;
        }

        /// <summary>
        /// 디바이스 Close시 처리함수</para>
        /// </summary>
        /// <returns></returns>
        public bool CloseDevice()
        {
            bool bRet = false;

            try
            {
                if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._2_OPOS_IBM)
                {
                    if (cashdrawer == null)
                        return bRet;
                    
                    cashdrawer.DeviceEnabled = false;
                    cashdrawer.Release();
                    cashdrawer.Close();
                    cashdrawer = null;
                }
                else if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._3_DLL_TPS8700)
                {
                    CloseDrawPortForTg();
                }
                else if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._4_DLL_VPS9700)
                {
                    CloseDrawPortFor9700();
                }
                else if(m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._5_IBM_MAIN)
                {
                    if(m_serialPort == null)
                    {
                        UserLog.WriteLogFile(UserCom.LOG_IOS, UserCom.WARNING_LEVEL, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                         "DeviceCashdrawer.CloseDevice()", "m_serialPort == null");
                        return bRet;
                    }

                    m_serialPort.Close();
                    m_serialPort = null;
                }
                bRet = true;

                devStatus.Cashdrawer.Status = "CLOSE";
                devStatus.Cashdrawer.Open = false;
            }
            catch (Exception ex)
            {
                devStatus.Cashdrawer.Status = "CLOSE EXCEPTION";
                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     devStatus.Cashdrawer.Status + "/" + ex.Message);
            }

            return bRet;
        }
        #endregion

        #region POS for .NET 이벤트 처리
        /// <summary>
        /// Cashdrawer 상태 변경에 따른 이벤트 처리
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CashDrawer_StatusUpdateEventDataEvent(object sender, StatusUpdateEventArgs e)
        {
            try
            {
                m_sUpdateStatus = e.Status;

                switch (m_sUpdateStatus)
                {
                    case CashDrawer.StatusOpen:
                        devStatus.Cashdrawer.Status = "DRAWER OPENED";
                        break;
                    case CashDrawer.StatusClosed:
                        devStatus.Cashdrawer.Status = "DRAWER CLOSED";
                        break;
                }

                if (PosOLEDevice.m_delegateOlePos != null)
                    PosOLEDevice.m_delegateOlePos(PosConst.OPOS_DEVICE.CASHDRAWER, devStatus.Cashdrawer.Status, string.Empty, string.Empty);
            }
            catch (Exception ex)
            {
                devStatus.Cashdrawer.Status = "STATUS UPDATE EVENT ERROR";
                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     devStatus.Cashdrawer.Status + "-" + ex.Message);
            }
        }
        #endregion

        #region 돈통 개방 처리
        /// <summary>
        /// 돈통 개방
        /// </summary>
        public void OpenCashDrawer()
        {
            bool bRet = false;

            try
            {
                if (devStatus.Cashdrawer.Open == false)
                {
                    OpenDevice(DeviceType.CashDrawer, PosConst.OPOS_LDN.CASHDRAWER);
                }

                if (devStatus.Cashdrawer.Open == true)
                {
                    if (m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._1_PRINTER)
                    {
                        objPosPrinter.OpenCashDrawer();
                        bRet = true;
                    }
                    else if (m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._2_OPOS_IBM)
                    {
                        cashdrawer.OpenDrawer();
                        bRet = true;
                    }
                    else if (m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._3_DLL_TPS8700)
                    {
                        OpenDrawForTg();
                        bRet = true;
                    }
                    else if (m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._4_DLL_VPS9700)
                    {
                        OpenDrawFor9700();
                        bRet = true;
                    }
                    else if (m_cPosStatus.Base.OlePosCashDrawerType == PosConst.POS_DEVICE_LIST.CASHDRAWER._5_IBM_MAIN)
                    {
                        TransmitCommand(PosConst.ESCP_COMMAND.CASHDRAWER_OPEN_IBMHOST, true);
                        bRet = true;
                    }
                    else
                    {
                        devStatus.Cashdrawer.Status = "DRAWER TYPE ERROR";
                        UserLog.WriteLogFile(UserCom.LOG_IOS,
                                             UserCom.WARNING_LEVEL,
                                             System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                             System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                             System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                             devStatus.Cashdrawer.Status);
                    }
                    devStatus.Cashdrawer.Status = "DRAWER OPEN";
                }
            }
            catch (Exception ex)
            {
                devStatus.Cashdrawer.Status = "DRAWER OPEN ERROR";

                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     devStatus.Cashdrawer.Status + "/" + ex.Message);
            }

            UserLog.WriteLogFile(UserCom.LOG_IOS,
                                 UserCom.INFO_LEVEL,
                                 System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                 System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                 System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                 "Open Drawer=" + (bRet ? "SUCCESS" : "FAIL"));
        }
        #endregion

        #region SerialPort 전송
        private void TransmitCommand(byte[] aCmd, bool bSleepOn = true)
        {
            if (m_serialPort.IsOpen == true)
            {
                int iOffset = 0;
                //int iReadBuf = 2048;
                int iReadBuf = m_serialPort.WriteBufferSize;

                while (true)
                {
                    if (iOffset >= aCmd.Length)
                    {
                        break;
                    }
                    if (iReadBuf + iOffset > aCmd.Length)
                    {
                        iReadBuf = aCmd.Length - iOffset;
                    }
                    m_serialPort.Write(aCmd, iOffset, iReadBuf);

                    iOffset += iReadBuf;
                    System.Threading.Thread.Sleep(10);
                }
                //m_serialPort.Write(Encoding.Default.GetString(aCmd, 0, aCmd.Length));

                if (bSleepOn == true) System.Threading.Thread.Sleep(30);
            }
        }
        #endregion
    }
}
