using System.Collections;
using System.IO.Ports;
using VisionBuilder.UI.IOCommander.Interfaces;

namespace VisionBuilder.UI.IOCommander;

public class IOCommander : IIOCommander
{

    SerialPort _port;
    public IOCommander(string COMPort)
    {
        _port = new SerialPort(COMPort);
        _port.BaudRate = 57600;
        _port.ReadTimeout = 100;
        _port.WriteTimeout = 100;
        _port.Open();
        Task.Factory.StartNew(CheckPins, TaskCreationOptions.LongRunning);
    }

    private int _currentPinsState = 0;
    public BitArray PinState { get; private set; }
    private void CheckPins()
    {
        while (true)
        {
            lock (this)
            {
                if (!_port.IsOpen) return;
                try
                {
                    var req = new byte[] { 1, 0 };
                    _port.Write(req, 0, req.Length);
                    var readState = ~(_port.ReadByte());
                    BitArray arrreadState = new BitArray(new byte[] { (byte)readState });
                    PinState = new BitArray(new byte[] { (byte)readState }); ;
                    string buf = "";
                    foreach (bool b in arrreadState)
                    {
                        buf += b ? 1 : 0;
                    }
                    //Console.WriteLine(buf);
                    if (_currentPinsState != readState)
                    {


                        BitArray arrcurrentPinsState = new BitArray(new byte[] { (byte)_currentPinsState });



                        for (int i = 0; i < 8; i++)
                        {
                            if (arrcurrentPinsState[i] != arrreadState[i])
                                OnPinChanged(i+1, arrreadState[i]);
                        }
                    }

                    _currentPinsState = readState;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }

            }
            Thread.Sleep(100);
        }
    }


    public void Dispose()
    {
        if (_port.IsOpen) _port.Close();
    }

    public event Action<int, bool> OnPinChanged = delegate { };
    List<int> _readPins = new List<int>();
    private int _pinsState = 0;
    

    public void SetPins(int pin, bool state)
    {
        pin -= 1;
        lock (this)
        {
            //Log.Logger.ForContext<IOCommander>().Verbose("Setting pin {pin} to {state}", pin, state);
            
            if (state)
                _pinsState |= (1 << pin);
            else
                _pinsState &= ~(1 << pin);
            var data = new byte[] { 0x00, (byte)_pinsState };
            try
            {
                _port.Write(data, 0, data.Length);
            }
            catch (Exception ex)
            {
                
            }


        }
    }

    public void SetPins(int pin)
    {
        lock (this)
        {
            if (!_readPins.Contains(pin))
            {
                _readPins.Add(pin);
                _port.WriteLine("$pinmo:" + pin + ";");

            }

            _port.WriteLine("$pinh:" + pin + ";");
        }
    }
}