using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections.ObjectModel;

using SmartX;
using INT_LKD_2.DataStore;
using INT_LKD_2.Forms;

namespace INT_LKD_2.DialogForms
{
    public partial class DialogFormProgressBar : Form
    {
        #region Field
        private int Check;
        private int Code;

        private string USBPath = "";
        private string UpdateFileDisplayPath = "";
        private string UpdateFileMainboardPath = "";
        private string OldFilePath = "";
        private string RemoveFolderPath = "";
        FileInfo[] NewFiles;
        public bool IsCommunicationLogOpen;

        // 업데이트 메인보드
        public UpdateForMainBoard UpdateForMain;

        private Define.E_LanguageID m_Language;
        private Define.E_BoardMode m_BoardMode;
       
        private FormMain m_ParentForm;
        #endregion

        #region Constructor
        public DialogFormProgressBar(int code, Define.E_LanguageID language, FormMain parent)
        {
            InitializeComponent();

            this.smartGroupBox1.Text = "";
            this.labelMessage1.Text = "";
            this.labelMessage2.Text = "";

            this.ParentForm = parent;
            this.Code = code;
            this.Language = language;
            this.buttonCancel.Visible = false;

            if (language == Define.E_LanguageID.Korean)
            {
                #region 한글
                switch (code)
                {
                    case 1:
                        this.smartGroupBox1.Text = "Display Update";
                        this.labelMessage1.Text = "업데이트 중...";
                        this.labelMessage2.Text = "USB를 본체에서 분리하지 마십시오.";
                        break;
                    default:
                        this.smartGroupBox1.Text = "Error 99";
                        this.labelMessage1.Text = "제조사에 문의하세요";
                        this.labelMessage2.Text = "";
                        break;
                }
                #endregion
            }
            else if (language == Define.E_LanguageID.English)
            {
                #region 영문
                switch (code)
                {
                    case 1:
                        this.smartGroupBox1.Text = "Display update";
                        this.labelMessage1.Text = "Updating...";
                        this.labelMessage2.Text = "Do not remove the USB from the device.";
                        break;
                    default:
                        this.smartGroupBox1.Text = "Error 99";
                        this.labelMessage1.Text = "Please contact a manufacturer";
                        break;
                }
                #endregion
            }         
            else
            {

            }
        }
        public DialogFormProgressBar(int code, Define.E_LanguageID language, UpdateForMainBoard updateForMain, FormMain parent, Define.E_BoardMode board)
        {
            InitializeComponent();

            this.smartGroupBox1.Text = "";
            this.labelMessage1.Text = "";
            this.labelMessage2.Text = "";

            this.ParentForm = parent;
            this.Code = code;
            this.UpdateForMain = updateForMain;
            this.Language = language;
            this.BoardMode = board;

            if (language == Define.E_LanguageID.Korean)
            {
                #region 한글
                switch (code)
                {
                    case 2:
                        this.smartGroupBox1.Text = "Mainboard Update";
                        this.labelMessage1.Text = "업데이트 중...";
                        this.labelMessage2.Text = "USB를 본체에서 분리하지 마십시오.";
                        break;
                    default:
                        this.smartGroupBox1.Text = "Error 99";
                        this.labelMessage1.Text = "제조사에 문의하세요";
                        this.labelMessage2.Text = "";
                        break;
                }
                #endregion
            }
            else if (language == Define.E_LanguageID.English)
            {
                #region 영문
                switch (code)
                {
                    case 2:
                        this.smartGroupBox1.Text = "Mainboard update";
                        this.labelMessage1.Text = "Updating...";
                        this.labelMessage2.Text = "Do not remove the USB from the device.";
                        break;
                    default:
                        this.smartGroupBox1.Text = "Error 99";
                        this.labelMessage1.Text = "Please contact a manufacturer";
                        break;
                }
                #endregion
            }
            else
            {

            }
        }
        #endregion

        #region Property
        public Define.E_LanguageID Language
        {
            get { return this.m_Language; }
            set { this.m_Language = value; }
        }
        public Define.E_BoardMode BoardMode
        {
            get { return this.m_BoardMode; }
            private set { this.m_BoardMode = value; }
        }

        public FormMain ParentForm
        {
            get { return this.m_ParentForm; }
            private set { this.m_ParentForm = value; }
        }

        private string GetMainboardID
        {
            get
            {
                if (this.BoardMode == Define.E_BoardMode.Master)
                    return CommunicationID.MainBoardMaster;
                else
                    return CommunicationID.MainBoardSlave;
            }
        }
        #endregion

        #region Method
        private void InitializeControl()
        {
            int x = 0, y = 0;

            x = Screen.PrimaryScreen.Bounds.Width / 2 - this.Size.Width / 2;
            y = Screen.PrimaryScreen.Bounds.Height / 2 - this.Size.Height / 2;

            this.Location = new Point(x, y);

            this.Size = new Size(452, 197);
        }
        private void DefaultSetting()
        {
            if(this.Code == 2)
                this.OpenSerialPort();

            if (Directory.Exists("Hard Disk\\") == true)
                this.USBPath = "Hard Disk\\";
            else if (Directory.Exists("하드 디스크\\") == true)
                this.USBPath = "하드 디스크\\";
            else
                this.USBPath = "하드 디스크\\";

            this.UpdateFileDisplayPath = this.USBPath + "UpdateFiles\\";

            if (this.BoardMode == Define.E_BoardMode.Master)
                this.UpdateFileMainboardPath = this.USBPath + "UpdateFilesMain\\ibd902m.bin";
            else
                this.UpdateFileMainboardPath = this.USBPath + "UpdateFilesSlave\\ibd902s.bin";
            //this.OldFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase) + "\\";
            this.OldFilePath = "SD Card\\Run\\";
            this.RemoveFolderPath = "SD Card\\RemoveFile\\";
        }

        #region Display Update
        private void ProgramUpdateDisplay()
        {
            DirectoryInfo directoryFolderUpdateFiles = new DirectoryInfo(this.UpdateFileDisplayPath);
            if (directoryFolderUpdateFiles.Exists == false)
                directoryFolderUpdateFiles.Create();

            this.NewFiles = directoryFolderUpdateFiles.GetFiles();
        }
        private void TreatmentRemoveOldFile()
        {
            bool removeFolderCheck = false;
            FileInfo[] oldFiles;
            FileInfo[] removeFiles;
            DirectoryInfo directoryFolderRun = new DirectoryInfo(this.OldFilePath);
            DirectoryInfo directoryFolderRemove = new DirectoryInfo(this.RemoveFolderPath);

            removeFolderCheck = directoryFolderRemove.Exists;
            oldFiles = directoryFolderRun.GetFiles();

            if (removeFolderCheck == false)
                directoryFolderRemove.Create();
            //else
            //{
            //    removeFiles = directoryFolderRemove.GetFiles();
            //    foreach (FileInfo file in removeFiles)
            //        file.Delete();
            //}

            foreach (FileInfo subFile in oldFiles)
                subFile.MoveTo(RemoveFolderPath + DateTime.Now.ToString("yyyyMMddHHmmss") + subFile.Name.ToString());
        }
        private void TreatmentCopyNewFile(FileInfo[] newFile)
        {
            // 새 파일 복사
            foreach (FileInfo subFile in newFile)
                subFile.CopyTo(this.OldFilePath + subFile.Name.ToString());
        }
        #endregion

        #region Mainboard Update
        private void OpenSerialPort()
        {
            string fullPath = "";

            try
            {
                if (this.smartSerialPort1.IsOpen == true)
                    this.smartSerialPort1.Close();

                if (this.BoardMode == Define.E_BoardMode.Master)
                {
                    this.smartSerialPort1.PortNo = SmartSerialPort.COMPORTNO.COM2;
                    this.smartSerialPort2.PortNo = SmartSerialPort.COMPORTNO.COM3;
                }
                else
                {
                    this.smartSerialPort1.PortNo = SmartSerialPort.COMPORTNO.COM3;
                    this.smartSerialPort2.PortNo = SmartSerialPort.COMPORTNO.COM2;
                }

                this.smartSerialPort1.Open();
                this.smartSerialPort2.Open();
            }
            catch
            {
            }
            fullPath = "SD Card\\DataBackup\\UpdateLog.txt";
            this.smartFileCommunicationLog.FilePathName = fullPath;
            this.smartFileCommunicationLog.Open();
            this.IsCommunicationLogOpen = true;
        }
        public void CloseSerialPort()
        {
            if (this.IsCommunicationLogOpen == true)
            {
                this.IsCommunicationLogOpen = false;
                this.smartFileCommunicationLog.Close();
            }
            this.smartSerialPort1.Close();
            this.smartSerialPort2.Close();
        }

        public int TransferData(string command, string id)
        {
            int ret = 0;
            string chkSum = "cc";
            StringBuilder sb = new StringBuilder();

            sb.Append(command);
            sb.Append(id);

            chkSum = this.Checksumcalculator(sb.ToString());

            sb.Append(chkSum);

            if (this.smartSerialPort1.IsOpen == true)
                this.smartSerialPort1.WriteFrame(sb.ToString(), SmartSerialPort.CODETYPES.ASCIICODE);

            if (this.smartSerialPort2.IsOpen == true)
                this.smartSerialPort2.WriteFrame(sb.ToString(), SmartSerialPort.CODETYPES.ASCIICODE);

            // 통신 확인 로그
            if (this.IsCommunicationLogOpen == true)
                this.smartFileCommunicationLog.StringType.Write(string.Format("Send ({0:yyyy-MM-dd HH:mm:ss}): {1}", DateTime.Now, sb.ToString()));

            return ret;
        }
        
        private string Checksumcalculator(string strTemp)
        {
            string chkSum = "";
            byte[] temp;
            int value = 0, first = 0, second = 0;
            char char1, char2;

            if (strTemp == null || strTemp.Length == 0)
                chkSum = "cc";
            else
            {
                temp = new UTF8Encoding().GetBytes(strTemp);

                for (int i = 0; i < temp.Length; i++)
                    value += temp[i];

                first = (value & 0x00f0) >> 4;
                if (first > 9)
                    char1 = (char)(first + 0x37);
                else
                    char1 = (char)(first + 0x30);

                second = value & 0x000f;
                if (second > 9)
                    char2 = (char)(second + 0x37);
                else
                    char2 = (char)(second + 0x30);

                chkSum = char1.ToString() + char2.ToString();
            }

            return chkSum;
        }
        private string Checksumcalculator(byte[] strTemp)
        {
            string chkSum = "";
            byte[] temp;
            int value = 0, first = 0, second = 0;
            char char1, char2;

            if (strTemp == null || strTemp.Length == 0)
                chkSum = "cc";
            else
            {
                temp = strTemp;

                for (int i = 0; i < temp.Length; i++)
                    value += temp[i];

                first = (value & 0x00f0) >> 4;
                if (first > 9)
                    char1 = (char)(first + 0x37);
                else
                    char1 = (char)(first + 0x30);

                second = value & 0x000f;
                if (second > 9)
                    char2 = (char)(second + 0x37);
                else
                    char2 = (char)(second + 0x30);

                chkSum = char1.ToString() + char2.ToString();
            }

            return chkSum;
        }
        private void SetCollectionForStringToByte(ref Collection<byte> collection, string value)
        {
            byte[] byteData;

            if (collection == null)
                return;

            byteData = Encoding.UTF8.GetBytes(value);
            for (int i = 0; i < byteData.Length; i++)
                collection.Add(byteData[i]);
        }
        public int TransferDataStream(string command, string id, string address, string data)
        {
            int ret = 0;
            string chkSum = "cc";
            StringBuilder sb = new StringBuilder();

            sb.Append(command);
            sb.Append(id);
            sb.Append(Helper.StringBlankFillDigits4(data.Length.ToString()));
            sb.Append(address);
            sb.Append(data);

            chkSum = this.Checksumcalculator(sb.ToString());

            sb.Append(chkSum);

            if (this.smartSerialPort1.IsOpen == true)
                this.smartSerialPort1.WriteFrame(sb.ToString(), SmartSerialPort.CODETYPES.ASCIICODE);

            return ret;
        }
        public int TransferDataStream(string command, string id, string address, string index, byte[] datas)
        {
            int ret = 0, count = 0;
            byte[] byteData;
            string chkSum = "cc";
            Collection<byte> byteCollection = new Collection<byte>();

            // command;
            this.SetCollectionForStringToByte(ref byteCollection, command);

            // id;
            this.SetCollectionForStringToByte(ref byteCollection, id);

            // data Length
            count = datas.Length + index.Length;
            this.SetCollectionForStringToByte(ref byteCollection, Helper.StringZeroFillDigits4(count.ToString()));

            // address
            this.SetCollectionForStringToByte(ref byteCollection, address);

            // index
            this.SetCollectionForStringToByte(ref byteCollection, index);

            // datas
            for (int i = 0; i < datas.Length; i++)
                byteCollection.Add(datas[i]);

            // chkSum
            byteData = new byte[byteCollection.Count];
            for (int i = 0; i < byteCollection.Count; i++)
                byteData[i] = byteCollection[i];
            chkSum = this.Checksumcalculator(byteData);
            this.SetCollectionForStringToByte(ref byteCollection, chkSum);

            // collection -> byte[]
            byteData = new byte[byteCollection.Count];
            for (int i = 0; i < byteCollection.Count; i++)
                byteData[i] = byteCollection[i];

            if (this.smartSerialPort1.IsOpen == true)
                this.smartSerialPort1.WriteFrame(byteData);

            return ret;
        }

        private void RetryUpdateForMain(UpdateForMainBoard update)
        {
            this.TransferDataStream(CommunicationCommand.Write, CommunicationID.MainBoardMaster,
               CommunicationAddress._1651_UpdateForMain, Helper.StringZeroFillDigits4(update.Index.ToString()), update.SendData);

            this.smartTimerUpdate.Start();
        }
        public void SendUpdateForMain(byte[] datas)
        {
            int count = 0;
            string id = "";

            if (datas.Length == 0)
                return;

            count = datas.Length / 128;

            if (count != 0)
            {
                this.UpdateForMain.SendData = new byte[128];
                for (int i = 0; i < 128; i++)
                    this.UpdateForMain.SendData[i] = datas[i];
            }
            else
            {
                this.UpdateForMain.SendData = new byte[datas.Length];
                for (int i = 0; i < datas.Length; i++)
                    this.UpdateForMain.SendData[i] = datas[i];

                this.UpdateForMain.IsLastData = true;
            }

            // ID
            if (this.BoardMode == Define.E_BoardMode.Master)
                id = CommunicationID.MainBoardMaster;
            else
                id = CommunicationID.MainBoardSlave;

            this.TransferDataStream(CommunicationCommand.Write, id,
                CommunicationAddress._1651_UpdateForMain, Helper.StringZeroFillDigits4(this.UpdateForMain.Index.ToString()), this.UpdateForMain.SendData);

            if (this.UpdateForMain.ProgressBar1 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar2 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar3 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar4 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar5 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar6 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar7 == count)
                this.progressBarUpdate.Value += 10;
            else if (this.UpdateForMain.ProgressBar8 == count)
                this.progressBarUpdate.Value += 10;

            this.smartTimerUpdate.Start();
        }
        private void ProgramUpdateMainboard()
        {
            long a = 0;
            int count = 0, byteCount = 0;

            FileStream fs = new FileStream(this.UpdateFileMainboardPath, FileMode.Open, FileAccess.Read);

            BinaryReader br = new BinaryReader(fs);
            a = br.BaseStream.Length;
            byteCount = int.Parse(a.ToString());
            this.UpdateForMain.ByteData = br.ReadBytes(byteCount);

            count = byteCount / 128;
            this.UpdateForMain.SendDataCount = count;

            this.timerForMainBoard.Start();
        }

        public void UpdateMainBoardFail(Define.E_LanguageID language)
        {
            this.progressBarUpdate.Visible = false;
            this.buttonCancel.Visible = true;

            switch (language)
            {
                case Define.E_LanguageID.Korean:
                    this.labelMessage1.Text = "업데이트가 실패하였습니다.";
                    this.labelMessage2.Text = "메인보드를 체크해 주시기 바랍니다.";
                    break;
                case Define.E_LanguageID.English:
                    this.labelMessage1.Text = "Update Fail!";
                    this.labelMessage2.Text = "Please Check your MainBoard";
                    break;
                default:
                    break;
            }
        }
        private void UpdateFinish(Define.E_LanguageID language)
        {
            switch (language)
            {
                case Define.E_LanguageID.Korean:
                    this.labelMessage1.Text = "프로그램 업데이트 완료";
                    this.labelMessage2.Text = "전원을 끄고 다시 켜주세요";
                    break;
                case Define.E_LanguageID.English:
                    this.labelMessage1.Text = "Program update complete";
                    this.labelMessage2.Text = "Reset the system";
                    break;
                default:
                    break;
            }
            this.Refresh();
            if (this.Code == 1)
            {
                this.TransferData(CommunicationCommand.MainboardReboot, this.GetMainboardID);
                //this.smartTimerReboot.Start();
            }

            this.smartTimerReboot.Start();
        }
        #endregion

        #endregion

        #region Override Member
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.InitializeControl();
            this.DefaultSetting();

            this.Check = 0;
            this.timerUpdate.Start();
        }
        #endregion

        #region Event Handler
        private void smartSerialPort2_OnReadQueueEvent()
        {
            int ret = 0, index = 0;
            byte[] beforeData;
            string ack = "", data = "";
            string cmd = "", address = "", lane = "", receiveData = "", error = "";
            string strTemp = "";
            byte[] readByte;
            Define.E_ResponseData response = Define.E_ResponseData.NAK;

            SmartSerialPort.FRAMEDATAREADSTATUS receiveDataState = SmartSerialPort.FRAMEDATAREADSTATUS.EMPTY;

            try
            {
                receiveDataState = this.smartSerialPort1.ReadQueue(out readByte);
                strTemp = Encoding.Default.GetString(readByte, 0, readByte.Length);
            }
            catch
            {
                return;
            }

            if ((receiveDataState == SmartSerialPort.FRAMEDATAREADSTATUS.EMPTY) || (receiveDataState == SmartSerialPort.FRAMEDATAREADSTATUS.FAILDATA))
            {
                return;
            }

            cmd = strTemp.Substring(0, 3);

            try
            {
                switch (strTemp[0])
                {
                    case 'C':
                        error = strTemp.Substring(4, 1);

                        // 로그
                        if (this.IsCommunicationLogOpen == true)
                            this.smartFileCommunicationLog.StringType.Write(string.Format("Update Receive ({0:yyyy-MM-dd HH:mm:ss}): {1}", DateTime.Now, strTemp));

                        switch (cmd)
                        {
                            case "CBU":
                                if (error == "1")
                                    this.UpdateMainBoardFail(Language);
                                else
                                {
                                    this.CloseSerialPort();
                                    this.progressBarUpdate.Value += 100;
                                    this.UpdateFinish(Language);
                                }
                                break;
                            default:
                                break;
                        }
                        break;
                    case 'P':
                        lane = strTemp.Substring(5, 1);
                        address = strTemp.Substring(10, 4);
                        receiveData = strTemp.Substring(14, strTemp.Length - 16);

                        if (this.IsCommunicationLogOpen == true)
                            this.smartFileCommunicationLog.StringType.Write(string.Format("Update Receive ({0:yyyy-MM-dd HH:mm:ss}): {1}", DateTime.Now, strTemp.Substring(0, 14)));

                        switch (address)
                        {
                            case "1651":
                                #region 업데이트
                                #region Value Assign
                                try
                                {
                                    index = int.Parse(receiveData.Substring(0, 4));
                                }
                                catch
                                {
                                    index = 0;
                                }
                                ack = receiveData.Substring(4, 4);
                                #endregion

                                if (ack == "0001")
                                    response = Define.E_ResponseData.ACK;
                                else
                                    response = Define.E_ResponseData.NAK;

                                if (this.UpdateForMain.Index == index)
                                {
                                    this.smartTimerUpdate.Stop();
                                    if (response == Define.E_ResponseData.ACK)
                                    {
                                        beforeData = new byte[this.UpdateForMain.ByteData.Length];
                                        for (int i = 0; i < this.UpdateForMain.ByteData.Length; i++)
                                            beforeData[i] = this.UpdateForMain.ByteData[i];

                                        if (this.UpdateForMain.IsLastData == false)
                                        {
                                            this.UpdateForMain.ByteData = new byte[beforeData.Length - 128];
                                            for (int i = 0; i < beforeData.Length - 128; i++)
                                                this.UpdateForMain.ByteData[i] = beforeData[128 + i];
                                            this.UpdateForMain.Index++;

                                            this.SendUpdateForMain(this.UpdateForMain.ByteData);
                                        }
                                        else
                                        {
                                            this.progressBarUpdate.Value += 10;
                                        }
                                    }
                                    else
                                    {
                                        this.RetryUpdateForMain(this.UpdateForMain);
                                    }
                                }
                                else
                                {
                                    this.smartTimerUpdate.Stop();
                                    this.UpdateMainBoardFail(this.Language);
                                }
                                #endregion
                                break;
                            default:
                                break;
                        }
                        break;
                    case 'S':
                        break;
                    default:
                        break;
                }


            }
            catch
            {
                ret = -1;
            }
        }

        private void timerUpdate_Tick(object sender, EventArgs e)
        {
            this.Check += 1;

            if (this.Code == 1)
            {
                if (this.Check == 3)
                    this.ProgramUpdateDisplay();

                if (this.Check == 4)
                {
                    this.progressBarUpdate.Value += 30;

                    this.TreatmentRemoveOldFile();
                }

                if (this.Check == 5)
                {
                    this.progressBarUpdate.Value += 30;

                    this.TreatmentCopyNewFile(this.NewFiles);

                    this.progressBarUpdate.Value += 100;

                    this.UpdateFinish(Language);
                }
            }
            else if (this.Code == 2)
            {
                if (this.Check == 3)
                    this.ProgramUpdateMainboard();
            }

            if (this.progressBarUpdate.Value == 100)
                this.timerUpdate.Stop();
        }
        private void timerForMainBoard_Tick(object sender, EventArgs e)
        {
            this.timerForMainBoard.Stop();

            this.SendUpdateForMain(this.UpdateForMain.ByteData);
        }
        private void smartTimerUpdate_Tick(object sender, EventArgs e)
        {
            this.smartTimerUpdate.Stop();
            this.UpdateForMain.RetryCount++;

            if (this.UpdateForMain.RetryCount < 5)
                this.RetryUpdateForMain(this.UpdateForMain);
            else
                this.UpdateMainBoardFail(this.Language);
        }
        private void smartTimerReboot_Tick(object sender, EventArgs e)
        {
            this.smartTimerReboot.Stop();
            SmartX.SmartConfigs.ReBoot();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.CloseSerialPort();
            this.Close(); 
        }
        #endregion
    }
}