using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Ports;
using System.ComponentModel;

using Cosmos.UserFrame;
using Cosmos.Common;

namespace Cosmos.OLEDevice
{
    public class DeviceScale : IScaleUs
    {
        /// <summary>
        /// StateServer Object (StateServer 객체)
        /// </summary>
        public StateServer StateObject = (StateServer)StateServer.GetInstance();

        /// <summary>
        /// Device 상태 정보 객체
        /// </summary>
        public DeviceStatus devStatus = null;

        /// <summary>
        /// Pos 상태 정보 객체
        /// </summary>
        public PosStatus m_cPosStatus = null;

        /// <summary>
        /// RS232통신을 위한 시리얼포트 객체
        /// </summary>
        private SerialPort m_serialPort = null;

        private BackgroundWorker bw = null;

        private string m_sReceivedData = string.Empty;

        #region 초기화
        /// <summary>
        /// 생성자
        /// </summary>
        public DeviceScale()
        {
            try
            {
                m_cPosStatus = (PosStatus)StateObject.POS;
                devStatus = (DeviceStatus)StateObject.DEVICE;

                DeviceStatusInit();
                bw = new BackgroundWorker();
            }
            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);
            }
        }

        private void DeviceStatusInit()
        {
            devStatus.Scale.Open = false;
            devStatus.Scale.Data = string.Empty;
            devStatus.Scale.Status = string.Empty;
        }
        #endregion

        #region OPEN/CLOSE 처리 함수
        /// <summary>
        /// 디바이스 OPEN시 처리 함수
        /// </summary>
        /// <returns></returns>
        public bool OpenDevice(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.Scale.Open = false;
                        devStatus.Scale.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.Scale.Status);
                        return bRet;
                    }

                    m_serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
                    //m_serialPort.PinChanged += new SerialPinChangedEventHandler(serialPort_PinChanged);
                    //m_serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(serialPort_ErrorReceived);

                    m_serialPort.NewLine = "\r\n";
                    m_serialPort.Encoding = Encoding.ASCII;

                    m_serialPort.WriteBufferSize = 512;
                    m_serialPort.PortName = sSerialPort;
                    m_serialPort.BaudRate = (int)lBaudrate;
                    m_serialPort.DataBits = 7;
                    m_serialPort.StopBits = StopBits.One;
                    m_serialPort.Parity = Parity.Even;
                    m_serialPort.Handshake = Handshake.None;
                    m_serialPort.ReadTimeout = 500;
                    m_serialPort.WriteTimeout = 2000;

                    m_serialPort.Open();
                    if (m_serialPort.IsOpen == false)
                    {
                        devStatus.Scale.Open = false;
                        devStatus.Scale.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.Scale.Status);
                        return bRet;
                    }

                    devStatus.Scale.Open = true;
                    devStatus.Scale.Status = "SUCCESS";

                    bw.DoWork += OlePosHandler;
                    bRet = true;
                }
                else
                {
                    devStatus.Scale.Open = false;
                    devStatus.Scale.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.Scale.Status);
                    return bRet;
                }
            }
            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);
            }

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

            try
            {
                if (m_serialPort == null)
                {
                    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 (함수명))
                                         "Close fail(m_serialPort == null)");
                    return bRet;
                }

                m_serialPort.Close();
                bRet = true;
                m_serialPort = null;
                devStatus.Scale.Status = "CLOSE";
                devStatus.Scale.Open = false;
                bw.DoWork -= OlePosHandler;
            }
            catch (Exception ex)
            {
                devStatus.Printer.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 (함수명))
                                     ex.Message);
            }

            return bRet;
        }
        #endregion

        #region 이벤트 처리
        private void OlePosHandler(object sender, DoWorkEventArgs e)
        {
            try
            {
                if (PosOLEDevice.m_delegateOlePos != null)
                    PosOLEDevice.m_delegateOlePos(PosConst.OPOS_DEVICE.SCALE, devStatus.Scale.Data, string.Empty, string.Empty);
                else
                {
                    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 (함수명))
                                         "이벤트 전송 대상 없음");
                }
            }
            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);
            }
        }

        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort serialPort = (SerialPort)sender;
            string sHeader = string.Empty;
            string sWeight = string.Empty;
            string sUnit = string.Empty;

            try
            {
                if(!bw.IsBusy)
                {
                    // 데이터의 Terminator는 개행문자(\r\n) 이므로 개행문자 까지 값을 읽는 ReadLine으로 수신
                    string sBuf = serialPort.ReadLine();
                    sHeader = sBuf.Substring(0, 2);

                    // 계량모드에서의 데이터만 처리.
                    // ST:계량모드, QT:계수모드, US:데이터가 안정되지 않다., OL:데이터가 오버되어 있다.(계량범위를 넘었다.)
                    if (sHeader.Equals("ST"))
                    {
                        sWeight = sBuf.Substring(3, 9);
                        sUnit = sBuf.Substring(12, 3).Trim();

                        //devStatus.Scale.Data = sWeight;
                        devStatus.Scale.Data = sBuf;
                        devStatus.Scale.Unit = sUnit;
                    }

                    bw.RunWorkerAsync();
                }
                else
                {
                    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 (함수명))
                                         "저울 이벤트 처리 전 이벤트 발생 불가");
                }
            }
            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);
            }
        }

        private void serialPort_PinChanged(object sender, SerialPinChangedEventArgs e)
        {

        }

        private void serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {

        }
        #endregion

        #region 저울 0점 조정
        /// <summary>
        /// 저울 0점 조정
        /// </summary>
        public void ScaleCalibration()
        {
            byte[] bytCalibrationCmd = new byte[] { (byte)0x54, (byte)0x0A };

            if(devStatus.Scale.Open == true)
            {
                m_serialPort.Write(bytCalibrationCmd, 0, bytCalibrationCmd.Length);
            }
        }
        #endregion

        #region 무게 전송 요청
        /// <summary>
        /// 무게 전송 요청
        /// </summary>
        public void ScaleWeigh()
        {
            byte[] bytWeighCmd = new byte[] { (byte)0x53, (byte)0x0A };

            if (devStatus.Scale.Open == true)
            {
                m_serialPort.Write(bytWeighCmd, 0, bytWeighCmd.Length);
            }
        }
        #endregion
    }
}
