using AR;
using arCtl;
using SATOPrinterAPI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Project.Device
{
    public class SATOPrinterAPI : IDisposable
    {
        private bool disposed = false;
        Printer SATOPrinter = null;
        public string LastPrintZPL = string.Empty;
        public string qrData = string.Empty;
        public string PortName { get; set; }
        public int BaudRate { get; set; }

        public string ZPLFileName { get; set; } = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "zpl.txt");
        public string baseZPL
        {
            get
            {
                var fi = new System.IO.FileInfo(ZPLFileName);
                if (fi.Exists == false || fi.Length == 0)
                {
                    PUB.log.AddE($"{ZPLFileName} does not exist or has no data. Changed to default zpl.txt");
                    fi = new System.IO.FileInfo(UTIL.MakePath("Data", "zpl.txt"));
                    if (fi.Exists == false) PUB.log.AddE("Print template file (zpl.txt) does not exist");
                }
                if (fi.Exists && fi.Length > 1)
                    return System.IO.File.ReadAllText(fi.FullName, System.Text.Encoding.Default);
                else
                {
                    PUB.log.AddAT("No ZPL file found, using ZPL code from settings");
                    return string.Empty;
                }

            }
        }

        public SATOPrinterAPI()
        {
            SATOPrinter = new Printer();
            SATOPrinter.Timeout = 2500;
            SATOPrinter.Interface = Printer.InterfaceType.COM;
            SATOPrinter.ByteAvailable += SATOPrinter_ByteAvailable;
        }


        bool _isopen = false;
        public bool Open()
        {
            try
            {
                SATOPrinter.COMPort = this.PortName;
                SATOPrinter.COMSetting.Baudrate = this.BaudRate;
                SATOPrinter.Connect();
                _isopen = true;
                return _isopen;
            }
            catch(Exception ex) { _isopen = false; return false; }

        }
        private string ControlCharReplace(string data)
        {
            Dictionary<string, char> chrList = ControlCharList();
            foreach (string key in chrList.Keys)
            {
                data = data.Replace(key, chrList[key].ToString());
            }
            return data;
        }
        private Dictionary<string, char> ControlCharList()
        {
            Dictionary<string, char> ctr = new Dictionary<string, char>();
            ctr.Add("[NUL]", '\u0000');
            ctr.Add("[SOH]", '\u0001');
            ctr.Add("[STX]", '\u0002');
            ctr.Add("[ETX]", '\u0003');
            ctr.Add("[EOT]", '\u0004');
            ctr.Add("[ENQ]", '\u0005');
            ctr.Add("[ACK]", '\u0006');
            ctr.Add("[BEL]", '\u0007');
            ctr.Add("[BS]", '\u0008');
            ctr.Add("[HT]", '\u0009');
            ctr.Add("[LF]", '\u000A');
            ctr.Add("[VT]", '\u000B');
            ctr.Add("[FF]", '\u000C');
            ctr.Add("[CR]", '\u000D');
            ctr.Add("[SO]", '\u000E');
            ctr.Add("[SI]", '\u000F');
            ctr.Add("[DLE]", '\u0010');
            ctr.Add("[DC1]", '\u0011');
            ctr.Add("[DC2]", '\u0012');
            ctr.Add("[DC3]", '\u0013');
            ctr.Add("[DC4]", '\u0014');
            ctr.Add("[NAK]", '\u0015');
            ctr.Add("[SYN]", '\u0016');
            ctr.Add("[ETB]", '\u0017');
            ctr.Add("[CAN]", '\u0018');
            ctr.Add("[EM]", '\u0019');
            ctr.Add("[SUB]", '\u001A');
            ctr.Add("[ESC]", '\u001B');
            ctr.Add("[FS]", '\u001C');
            ctr.Add("[GS]", '\u001D');
            ctr.Add("[RS]", '\u001E');
            ctr.Add("[US]", '\u001F');
            ctr.Add("[DEL]", '\u007F');
            return ctr;
        }


        private bool Query(string cmd, out string errmsg)
        {
            errmsg = string.Empty;
            if (string.IsNullOrEmpty(cmd))
            {
                errmsg = "No Command";
                return false;
            }

            try
            {
                byte[] cmddata = Utils.StringToByteArray(ControlCharReplace(cmd));
                byte[] receiveData = SATOPrinter.Query(cmddata);

                if (receiveData != null)
                {
                    errmsg = ControlCharConvert(Utils.ByteArrayToString(receiveData));
                }
                return true;
            }
            catch (Exception ex)
            {
                errmsg = ex.Message;
                return false;
            }

        }
        private string ControlCharConvert(string data)
        {
            Dictionary<char, string> chrList = ControlCharList().ToDictionary(x => x.Value, x => x.Key);
            foreach (char key in chrList.Keys)
            {
                data = data.Replace(key.ToString(), chrList[key]);
            }
            return data;
        }


        ~SATOPrinterAPI()
        {
            Dispose(disposing: false);
        }
        public void Dispose()
        {
            Dispose(disposing: true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SuppressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    //component.Dispose();

                }
                SATOPrinter.Disconnect();
                // Note disposing has been done.
                disposed = true;
            }
        }

        public bool IsOpen
        {
            get
            {

                if (_isopen == false || SATOPrinter == null) return false;
                try
                {
                    return true;// return SATOPrinter.IsBusy;
                    //var prn = this.SATOPrinter.GetPrinterStatus();
                    //return prn.IsOnline;
                }
                catch { return false; }

            }
        }
        private void SATOPrinter_ByteAvailable(object sender, Printer.ByteAvailableEventArgs e)
        {
            byte[] rawData = e.Data;
            var msg = Utils.ByteArrayToString(rawData);// System.Text.Encoding.Default.GetString(rawData);
            PUB.log.Add($"SATO Recv : " + msg);
        }


        //      private void SATOPrinter_ReceiveData_Raw(object sender, ReceiveDataEventArgs e)
        //{
        //	PUB.log.Add($"SATO Recv(RAW) : " + e.StrValue);
        //}

        //private void SATOPrinter_ReceiveData(object sender, ReceiveDataEventArgs e)
        //{
        //	PUB.log.Add($"SATO Recv : " + e.StrValue);
        //}

        public (Boolean result, string errmessage) TestPrint(Boolean drawbox, string manu = "", string mfgdate = "")
        {
            var dtstr = DateTime.Now.ToShortDateString();
            var printcode = "103077807;Z577603504;105-35282-1105;15000;RC00004A219001W;20210612";
            var reel = new Class.Reel(printcode);
            //reel.id = "RLID" + DateTime.Now.ToString("MMHHmmssfff");
            reel.SID = "103000000";
            reel.PartNo = "PARTNO".PadRight(20, '0'); //20자리

            if (mfgdate == "") reel.mfg = dtstr;
            else reel.mfg = mfgdate;

            reel.venderLot = "LOT000000000";
            if (manu == "") reel.venderName = "ATK4EET1";
            else reel.venderName = manu;

            reel.qty = 15000;
            var rlt = Print(reel, true, drawbox);
            var fi = new System.IO.FileInfo(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "temp_zpl.txt"));
            System.IO.File.WriteAllText(fi.FullName, LastPrintZPL, System.Text.Encoding.Default);
            return rlt;
        }


        public (Boolean result, string errmessage) Print(Class.Reel reel, Boolean display1drid, Boolean drawOUtBox)
        {
            string prtData;
            prtData = makeZPL_210908(reel, drawOUtBox, out qrData);

            return Print(prtData);
        }

        public (Boolean result, string errmessage) Print(string _zpl)
        {
            this.LastPrintZPL = _zpl;
            try
            {
                byte[] cmddata = Utils.StringToByteArray(ControlCharReplace(_zpl));
                SATOPrinter.Send(cmddata);
                return (true,"");
            }
            catch (Exception ex)
            {
                return (false,ex.Message);
            }
        }

        public string makeZPL_210908(Class.Reel reel, Boolean drawbox, out string qrData)
        {
            string m_strSend = string.Empty;

            if(reel.PartNo.isEmpty())
                qrData = string.Format("{0};{1};{2};{3};{4};{5}", reel.SID, reel.venderLot, reel.venderName, reel.qty, reel.id, reel.mfg);
            else
            qrData = string.Format("{0};{1};{2};{3};{4};{5};{6}", reel.SID, reel.venderLot, reel.venderName, reel.qty, reel.id, reel.mfg, reel.PartNo);

            var reeid = reel.id;
            if (reeid.Length > 20)
                reeid = "..." + reeid.Substring(reeid.Length - 20);

            m_strSend = this.baseZPL;
            m_strSend = m_strSend.Replace("{qrdata}", qrData);
            m_strSend = m_strSend.Replace("{sid}", reel.SID);
            m_strSend = m_strSend.Replace("{lot}", reel.venderLot);
            m_strSend = m_strSend.Replace("{partnum}", reel.PartNo);
            m_strSend = m_strSend.Replace("{rid}", reeid);
            m_strSend = m_strSend.Replace("{qty}", reel.qty.ToString());
            m_strSend = m_strSend.Replace("{mfg}", reel.mfg);

            var supply1 = reel.venderName;
            string supply2 = "";
            if (supply1.Length > 30)
            {
                supply2 = supply1.Substring(30);
                supply1 = supply1.Substring(0, 30);
            }   

            m_strSend = m_strSend.Replace("{supply}", supply1);
            m_strSend = m_strSend.Replace("{supply2}", supply2);

            //줄바꿈제거
            m_strSend = m_strSend.Replace("\r", "").Replace("\n", "");
            return m_strSend;
        }
    }
}