using Jdas_Mbic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Windows.Forms;


namespace Jdas_Mbic
{
    class Update_Serial
    {
        public byte[] Firmware_byte_load;
        byte Data_Request_Val = 0;
        int FirmTotalcnt = 0;
        int FirmCurrcnt = 0;
        int PreFirmSendingcnt = 0;
        int FirmSendingcnt = 0;
        int pretempupdateret = 0;
        bool update_ready = false;
        const byte blucell_stx = 0xbe;
        const byte blucell_etx = 0xeb;
        const byte Termianl_Controller_Update_Ack = 0x11;
        const byte Termianl_Controller_Update_Nak = 0x22;
        const byte Termianl_Controller_FirmwareUpdateLen = 250;
        const byte Termianl_Reset = 0x0A;
        const byte Termianl_BootStart = 0x0B;
        const int POLYNOMIAL = 0x131; // P(x) = x^8 + x^5 + x^4 + 1 = 100110001
        Bluecell_BootProtocol Bluecell_BootProtocol = new Bluecell_BootProtocol();
        Download_bar download_Bar = new Download_bar();
        private delegate void StringSend(string Text);
        private delegate void VoidSend();
        OpenFileDialog ofd;
        Serial serial;


        private byte Data_Request_Func
        {
            get
            { return Data_Request_Val; }
            set
            { Data_Request_Val = value; }

        }

        public bool Update_ready { get => update_ready; set => update_ready = value; }


        /***
*Data File open
***/
        public string ShowFileOpenDialog(ref Serial serial, object ofd)
        {
            byte[] tempdata = new byte[5];
            this.ofd = (OpenFileDialog)ofd;
            this.serial = (Serial)serial;
            //파일오픈창 생성 및 설정
            this.ofd.Title = "업데이터 파일 탐색기";
            this.ofd.FileName = "*.bin";
            this.ofd.Filter = "binary 파일 (*.binary,*.bin) | *.binary;, *.bin; | 모든 파일 (*.*) | *.*";

            //파일 오픈창 로드
            DialogResult dr = this.ofd.ShowDialog();

            //OK버튼 클릭시
            if (dr == DialogResult.OK)
            {
                //File명과 확장자를 가지고 온다.
                string fileName = this.ofd.SafeFileName;
                //File경로와 File명을 모두 가지고 온다.
                string fileFullName = this.ofd.FileName;
                //File경로만 가지고 온다.
                string filePath = fileFullName.Replace(fileName, "");
                this.serial.debug_hextoasciiConvert();

                //출력 예제용 로직
                //  label1.Text = "File Name  : " + fileName;
                // label2.Text = "Full Name  : " + fileFullName;
                // label3.Text = "File Path  : " + filePath;`
                //File경로 + 파일명 리턴
                this.serial.FileDownloadClass_Set(this);
                Data_Request_Func = 1;

                Firmware_byte_load = File.ReadAllBytes(this.ofd.FileName);
                FirmTotalcnt = Firmware_byte_load.Length / Termianl_Controller_FirmwareUpdateLen;

                FirmCurrcnt = 0;
                PreFirmSendingcnt = 0;
                FirmSendingcnt = 0;
                Update_ready = true;
                Bluecell_BootProtocol.Bluecell_Reset(this.serial);
            /*    
                tempdata[0] = 0xbe;
                tempdata[1] = Termianl_Reset;
                tempdata[2] = 0x02;
                tempdata[3] = STH30_CreateCrc(tempdata, tempdata[2]);
                tempdata[4] = 0xeb;
               
                this.serial.Serial_DataSend(tempdata, 5);*/
                try
                {
                   // Controller_Debug.Controller_TX_TextLoad(tempdata);
                }
                catch { }
                download_Bar.ShowDialog();
                /*Update_label.Visible = true;
                progressBar1.Visible = true;*/
                return fileFullName;
            }
            //취소버튼 클릭시 또는 ESC키로 파일창을 종료 했을경우
            else if (dr == DialogResult.Cancel)
            {
                return "";
            }

            return "";
        }
        private int Current_step = 0;
        public void FirmwareUpdateCheck(byte check)
        {

            byte[] temp_data = new byte[Termianl_Controller_FirmwareUpdateLen + 5];
            byte cnt = 3;
            int lastlen = 0;
            // FirmTotalcnt = Firmware_byte_load.Length / Termianl_Controller_FirmwareUpdateLen;
            lastlen = Firmware_byte_load.Length % Termianl_Controller_FirmwareUpdateLen;
            temp_data[0] = blucell_stx;
            temp_data[1] = 0xDD;
            if (check == Termianl_BootStart)
            {
                System.Threading.Thread.Sleep(2000);
            }
            if (Termianl_Controller_Update_Ack == check || Termianl_BootStart == check)
            {
                PreFirmSendingcnt = FirmSendingcnt;
                if (FirmCurrcnt != FirmTotalcnt)
                {
                    temp_data[2] = Termianl_Controller_FirmwareUpdateLen + 2;
                    for (int i = 0; i < Termianl_Controller_FirmwareUpdateLen; i++)
                    {
                        temp_data[cnt++] = Firmware_byte_load[FirmSendingcnt++];
                    }
                    FirmCurrcnt++;
                    temp_data[Termianl_Controller_FirmwareUpdateLen + 3] = STH30_CreateCrc(temp_data, temp_data[2]);
                    temp_data[Termianl_Controller_FirmwareUpdateLen + 4] = blucell_etx;
                }
                else
                {
                    Current_step = 0;
                    Update_ready = false;
                    temp_data[1] = 0xEE;
                    temp_data[2] = Convert.ToByte(lastlen + 2);
                    for (int i = 0; i < lastlen; i++)
                    {
                        temp_data[cnt++] = Firmware_byte_load[FirmSendingcnt++];
                    }
                    temp_data[temp_data[2] + 1] = STH30_CreateCrc(temp_data, temp_data[2]);
                    temp_data[temp_data[2] + 2] = blucell_etx;
                    /*ownload_Bar.ShowDialog();*/
                    this.download_Bar.Invoke(new StringSend(this.download_Bar.Progressbar), "0 %");
                    //download_Bar.Progressbar("0 %");
                    this.download_Bar.Progressbar_gauge_zero();
                    this.download_Bar.FormClosed(this.download_Bar);
                    this.serial.debug_asciitohexConvert();
                    FirmSendingcnt = PreFirmSendingcnt = FirmCurrcnt = FirmTotalcnt = pretempupdateret = Data_Request_Val = 0;
      
                    /*Update_label.Text = "0%";
                    Update_label.Visible = false;
                    progressBar1.Visible = false;
                    progressBar1.Value = 0;*/
                    //  MessageBox.Show("Update Complete !!");
                }

            }
            else
            {
                FirmSendingcnt = PreFirmSendingcnt;
                if (FirmCurrcnt != FirmTotalcnt)
                {
                    temp_data[2] = Termianl_Controller_FirmwareUpdateLen + 2;
                    for (int i = 0; i < Termianl_Controller_FirmwareUpdateLen; i++)
                    {
                        temp_data[cnt++] = Firmware_byte_load[FirmSendingcnt++];

                    }
                    FirmCurrcnt++;
                    temp_data[Termianl_Controller_FirmwareUpdateLen + 3] = STH30_CreateCrc(temp_data, temp_data[2]);
                    temp_data[Termianl_Controller_FirmwareUpdateLen + 4] = blucell_etx;
                }
                else
                {
                    Update_ready = false;
                    temp_data[1] = 0xEE;
                    temp_data[2] = Convert.ToByte(lastlen + 2);
                    for (int i = 0; i < lastlen; i++)
                    {
                        temp_data[cnt++] = Firmware_byte_load[FirmSendingcnt++];
                    }
                    temp_data[temp_data[2] + 1] = STH30_CreateCrc(temp_data, temp_data[2]);
                    temp_data[temp_data[2] + 2] = blucell_etx;
                    /* Update_label.Visible = false;
                     progressBar1.Visible = false;*/
                    download_Bar.Close();
                }
            }
            int tempupdateret = Firmware_byte_load.Length / 100;
            tempupdateret = FirmSendingcnt / tempupdateret;
            //CheckForIllegalCrossThreadCalls = false;
            this.download_Bar.Update_Percent(Convert.ToString(tempupdateret));
            if (pretempupdateret != tempupdateret)
            {

                for(int i = Current_step; i < tempupdateret; i++)
                {
                    this.download_Bar.PerformStepup(this.download_Bar);
                    Current_step++;
                    //this.download_Bar.PerformStepinc(tempupdateret);
                    // progressBar1.PerformStep();
                }

                pretempupdateret = tempupdateret;
            }

            //serialPort1.Write(temp_data, 0, temp_data[2] + 3);
            this.serial.Serial_DataSend(temp_data, temp_data[2] + 3);
            try
            {
               // Controller_Debug.Controller_TX_TextLoad(temp_data);
            }
            catch { }
        }


        public void Termianl__Operate(byte[] Text)
        {
            byte Type = 0;
            Type = Text[(int)Bluecell_ProtIndex_p.Bluecell_Type];
            switch (Type)
            {
               
                case Termianl_BootStart:
                case Termianl_Controller_Update_Ack:
                case Termianl_Controller_Update_Nak:
                    if (Update_ready == true)
                        FirmwareUpdateCheck(Type);
                    break;
               
                default:
                    // MessageBox.Show("다시 시도 해주세요.");
                    break;
            }
        }
       // private JdasMbic JdasMbic = new JdasMbic();    // Teminal Text Wnd Open
       
        Crc16 crc = new Crc16();
       // static public int MBIC_SendingCnt = 0;
        static int MBIC_SendingIndex = 0;
        public void MBIC_FirmwareUpdateSend(ref Serial serial,byte[] data)
        {
            int SendDataLength = 0;
            int Length = data.Length;// + 128;
            int cnt = data.Length / 1024;
            int reminder = data.Length % 1024;
            byte[] SendArray = new byte[1061];//1024 + 22 + 3 + 12
            int Totalframe = data.Length / 1024;
            int CurrFrame = 0;
            UInt16 CrcRet = 0;
            if (Totalframe % 1024 > 0)
            {
                Totalframe += 1;
            }

            //MBIC_SendingCnt++;

            //if (MBIC_SendingCnt <= cnt)
            
            if (Length - MBIC_SendingIndex >= 1024)
            {
                Array.Copy(data, MBIC_SendingIndex, SendArray, 12, 1024);
                MBIC_SendingIndex += 1024 ;
                CurrFrame = MBIC_SendingIndex / 1024;
                //SendArray = 
                SendArray[0] = Convert.ToByte((Totalframe & 0xFF000000) >> 24);
                SendArray[1] = Convert.ToByte((Totalframe & 0x00FF0000) >> 16);
                SendArray[2] = Convert.ToByte((Totalframe & 0x0000FF00) >> 8);
                SendArray[3] = Convert.ToByte((Totalframe & 0x000000FF));


               
                SendArray[4] = Convert.ToByte((CurrFrame - 1& 0xFF000000) >> 24);
                SendArray[5] = Convert.ToByte((CurrFrame - 1& 0x00FF0000) >> 16);
                SendArray[6] = Convert.ToByte((CurrFrame - 1& 0x0000FF00) >> 8);
                SendArray[7] = Convert.ToByte((CurrFrame - 1& 0x000000FF));


                SendArray = Bluecell_BootProtocol.MBIC_HeaderMergeFunction(SendArray, SendArray.Length);
                SendArray[(int)MBICProt_st.MBIC_CMD_0] = 0x11;

                SendDataLength = 1024 + 22 + 12 + 3;
                SendArray[(int)MBICProt_st.MBIC_LENGTH_0] = (Byte)(((SendDataLength - 25) & 0xFF00) >> 8);
                SendArray[(int)MBICProt_st.MBIC_LENGTH_1] = (Byte)((SendDataLength - 25) & 0x00FF);
                SendArray[(int)MBICProt_st.MBIC_HEADERCHECKSUM_0] = crc.Chksum_Create(SendArray);
                CrcRet = crc.MBIC_CRC16_Generate(SendArray, SendDataLength - 25); //Length = Total Length - Header Length - Taile Length
                SendArray[SendDataLength - 3] = Convert.ToByte((CrcRet & 0xFF00) >> 8); 
                SendArray[SendDataLength - 2] = Convert.ToByte(CrcRet & 0x00FF);
                SendArray[SendDataLength - 1] = 0x03;
                serial.Serial_DataSend(SendArray, SendDataLength);
                /*
                 * 1024byte : data ,
                 * 22byte : Header  
                 * 12byte : Subdata Header , 
                 * 3byte : Tail
                 */
            }
            else
            {
                Array.Copy(data, MBIC_SendingIndex, SendArray, 12, reminder);
                MBIC_SendingIndex += reminder;
                CurrFrame = MBIC_SendingIndex / 1024;
                //SendArray = 
                SendArray[0] = Convert.ToByte((Totalframe & 0xFF000000) >> 24);
                SendArray[1] = Convert.ToByte((Totalframe & 0x00FF0000) >> 16);
                SendArray[2] = Convert.ToByte((Totalframe & 0x0000FF00) >> 8);
                SendArray[3] = Convert.ToByte((Totalframe & 0x000000FF));


                SendArray[4] = Convert.ToByte((CurrFrame & 0xFF000000) >> 24);
                SendArray[5] = Convert.ToByte((CurrFrame & 0x00FF0000) >> 16);
                SendArray[6] = Convert.ToByte((CurrFrame & 0x0000FF00) >> 8);
                SendArray[7] = Convert.ToByte((CurrFrame & 0x000000FF));


                SendArray = Bluecell_BootProtocol.MBIC_HeaderMergeFunction(SendArray, SendArray.Length);
                SendArray[(int)MBICProt_st.MBIC_CMD_0] = 0x11;

                SendDataLength = reminder + 22 + 12 + 3;
                SendArray[(int)MBICProt_st.MBIC_LENGTH_0] = (Byte)(((SendDataLength - 25) & 0xFF00) >> 8);
                SendArray[(int)MBICProt_st.MBIC_LENGTH_1] = (Byte)((SendDataLength - 25) & 0x00FF);
                SendArray[(int)MBICProt_st.MBIC_HEADERCHECKSUM_0] = crc.Chksum_Create(SendArray);

                CrcRet = crc.MBIC_CRC16_Generate(SendArray, SendDataLength - 25); //Length = Total Length - Header Length - Taile Length
                SendArray[SendDataLength - 3] = Convert.ToByte((CrcRet & 0xFF00) >> 8);
                SendArray[SendDataLength - 2] = Convert.ToByte(CrcRet & 0x00FF);
                SendArray[SendDataLength - 1] = 0x03;
                serial.Serial_DataSend(SendArray, SendDataLength);
               // MBIC_SendingCnt = 0;
                MBIC_SendingIndex = 0;
            }
        }
        byte STH30_CreateCrc(byte[] data, byte nbrOfBytes)
        {
            byte bit;        // bit mask
            int crc = 0xFF; // calculated checksum
            byte byteCtr;    // byte counter
            byte index = 1;
            // calculates 8-Bit checksum with given polynomial
            for (byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++)
            {
                crc ^= (data[index++]);
                for (bit = 8; bit > 0; --bit)
                {
                    if (Convert.ToBoolean(crc & 0x80)) { crc = (crc << 1) ^ POLYNOMIAL; }
                    else crc = (crc << 1);
                }
            }
            return (byte)crc;
        }
        
    }
}
