using System;
using System.Collections.Generic;
using System.Text;
using everdrive3x.Hardware;
using System.Threading;
using System.IO;
using everdrive3x.Rom;

namespace everdrive3x
{
    class Prog
    {

        Form1 main_form;
        Thread prog_thread;
        Thread state_control_thread;
        bool thread_state;
        Device device;
        long bytes_transmit;
        RomInterface rom;
        DateTime start_prog_time;
        String speed = "";
        DateTime last_prog_time;

        public Prog(Form1 main)
        {
            main_form = main;
        }

        public void start(String file)
        {
            last_prog_time = DateTime.Now;
            start_prog_time = DateTime.Now;
            bytes_transmit = 0;
            rom = RomTools.loadrRom(file);
            rom.Region = main_form.comboBox_region_sega.Text;
            thread_state = true;
            prog_thread = new Thread(initProg);
            prog_thread.Start();
            state_control_thread = new Thread(stateUpdate);
            state_control_thread.Start();
        }

        public void stop()
        {
            if (!thread_state) return;
            try
            {
                Thread.Sleep(50);
                thread_state = false;
                device.close();
                device = null;

            }
            catch (Exception) { }
        }

        void initProg()
        {
            try
            {
                main_form.lockInterface(true);
                main_form.addToConsole("---------------------------------------------------");
                main_form.addToConsole("ROM platform: " + rom.Platform);
                main_form.addToConsole("ROM name: " + rom.Name);
                main_form.addToConsole("ROM type: " + rom.RomType);
                main_form.addToConsole("ROM region: " + rom.Region);
                main_form.addToConsole("ROM size: " + rom.BinData.Length / 1024 + "kb");
                main_form.addToConsole("search device...");
                device = Device.searchDevice();
                main_form.addToConsole("OK: device detected");
                main_form.addToConsole("DEVICE name: " + device.Profile.Name);
                device.Control.resetByPass();
                main_form.addToConsole("erase...");
                device.Control.eraseAuto(rom.BinData.Length);
                device.Control.unlockByPass();
                device.Control.setAddr(0);
                main_form.addToConsole("start programming...");
                programming();
                for (int i = 0; i < rom.Config.Length; i++) device.Control.writeEeprom(i + 1, rom.Config[i]);
                main_form.addToConsole("OK: programming done");
                if (main_form.checkBox_verification.Checked)
                {
                    ToolBox tool = new ToolBox(main_form);
                    tool.checkCRC(device, rom.BinData, 0, rom.BinData.Length);
                }
            }
            catch (Exception x)
            {
                if (thread_state)
                {
                    main_form.addToConsole("ERROR: " + x.Message);
                }
            }
            if (thread_state)
            {
                Thread.Sleep(600);
                stop();
                main_form.lockInterface(false);
            }
        }

        void programming()
        {
            int block_size;
            start_prog_time = DateTime.Now;

            while (thread_state && bytes_transmit < rom.BinData.Length)
            {
                try
                {
                    block_size = Math.Min(Communication.BUFF_SIZE, rom.BinData.Length - (int)bytes_transmit);
                    device.Control.writeBlock(rom.BinData, (int)bytes_transmit, block_size);
                    bytes_transmit += block_size;
                    last_prog_time = System.DateTime.Now;
                }
                catch (TimeoutException)
                {
                    main_form.addToConsole("WARNING: timeout");
                }

            }
        }

        void stateUpdate()
        {

            
            DateTime start_time = System.DateTime.Now;
            
            String time = "";
            String traff = "";
            long speed_time = 1;
            int progress = 0;

            while (thread_state)
            {

                try
                {
                    progress = (int)bytes_transmit * 100 / (rom.BinData.Length + 1);

                    speed_time = (last_prog_time - start_prog_time).Ticks / 10000;
                    if (speed_time < 1) speed_time = 1;
                    speed = "" + bytes_transmit * 1000 / speed_time / 1024;

                    time = "" + (System.DateTime.Now - start_time).Minutes + ":" + (System.DateTime.Now - start_time).Seconds;
                    traff = "" + bytes_transmit / 1024 + "kb";
                    if (thread_state) main_form.stateUpdate(progress + 1, speed, time, traff);
                    Thread.Sleep(200);
                }
                catch (Exception) { }
            }

        }
    }
}
