// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2024. Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections;
using System.Collections.Generic;

namespace Hiperscan.SGS.Benchtop.TouchBoard
{
    public class TouchBoardLEDs
    {
        public enum DeviceLEDs
        {
            None = 0,
            FinderX = 5,
            Finder2 = 4
        }

        public TouchBoardLEDs(DeviceLEDs device_led_type)
        {
            this.DeviceLEDType = device_led_type;
            this.ClickedLEDButtons = new List<int>();

            switch (this.DeviceLEDType)
            {
                case DeviceLEDs.Finder2:
                    this.LED1.IsSupported = true;
                    this.LED2.IsSupported = true;
                    this.LED3.IsSupported = true;
                    this.LED4.IsSupported = true;
                    break;

                case DeviceLEDs.FinderX:
                    this.LED1.IsSupported = true;
                    this.LED2.IsSupported = true;
                    this.LED3.IsSupported = true;
                    this.LED4.IsSupported = true;
                    this.LED5.IsSupported = true;

                    this.LED3.IsButton = false;
                    this.LED4.IsButton = false;
                    this.LED5.IsButton = false;
                    break;
            }
        }

        public bool SetClickedTouchButtonIDs(byte clicked_buttons)
        {
            Console.WriteLine(clicked_buttons);
            BitArray bits = new BitArray(new byte[] { clicked_buttons });

            if (this.LED1.IsSupported && bits.Get(0) == true)
                this.ClickedLEDButtons.Add(this.LED1.ID);

            if (this.LED2.IsSupported && bits.Get(1) == true)
                this.ClickedLEDButtons.Add(this.LED2.ID);

            if (this.LED3.IsSupported && bits.Get(2) == true)
                this.ClickedLEDButtons.Add(this.LED3.ID);

            if (this.LED4.IsSupported && bits.Get(3) == true)
                this.ClickedLEDButtons.Add(this.LED4.ID);

            return this.ClickedLEDButtons.Count > 0;
        }

        public void SetTouchBoardLights(byte button_lights)
        {

            BitArray bits = new BitArray(new byte[] { button_lights });
            if (bits.Length > 8)
                throw new Exception("Cannot handle more than 8 bit");

            this.LED1.LightWhite = bits.Get(0);
            this.LED2.LightWhite = bits.Get(1);
            this.LED3.LightWhite = bits.Get(2);
            this.LED4.LightWhite = bits.Get(3);
            this.LED1.LightRed = bits.Get(4);
            this.LED2.LightRed = bits.Get(5);

            switch (this.DeviceLEDType)
            {
                case DeviceLEDs.Finder2:
                    this.LED3.LightRed = bits.Get(6);
                    this.LED4.LightRed = bits.Get(7);
                    break;
                case DeviceLEDs.FinderX:
                    this.LED5.LightWhite = bits.Get(7);
                    break;
                default:
                    break;
            }

        }

        public byte ConvertTouchButtonLightsToByte()
        {
            bool[] lights = null;
            switch (this.DeviceLEDType)
            {
                case DeviceLEDs.Finder2:
                    lights = new bool[]
                    {
                        this.LED1.LightWhite,
                        this.LED2.LightWhite,
                        this.LED3.LightWhite,
                        this.LED4.LightWhite,
                        this.LED1.LightRed,
                        this.LED2.LightRed,
                        this.LED3.LightRed,
                        this.LED4.LightRed,
                    };
                    break;
                case DeviceLEDs.FinderX:
                    lights = new bool[]
                    {
                        this.LED1.LightWhite,
                        this.LED2.LightWhite,
                        this.LED3.LightWhite,
                        this.LED4.LightWhite,
                        this.LED1.LightRed,
                        this.LED2.LightRed,
                        false,
                        this.LED5.LightWhite,
                    };
                    break;
            }

            return this.GetByteFromBoolArray(lights);
        }

        public byte SetHwLinked(bool hardware_managed)
        {
            bool[] light_on =
            {
                this.LED1.HardwareManaged = hardware_managed,
                this.LED2.HardwareManaged = hardware_managed,
                this.LED3.HardwareManaged = hardware_managed,
                this.LED4.HardwareManaged = hardware_managed,

                false,
                false,
                false,
                this.LED5.HardwareManaged = hardware_managed,
            };
            return this.GetByteFromBoolArray(light_on);
        }

        private byte GetByteFromBoolArray(bool[] bits, bool little_endian = true)
        {
            byte b = 0;

            if (little_endian == true)
            {
                for (int i = 0; i < bits.Length; i++)
                {
                    if (bits[i])
                    {
                        b |= (byte)(1 << i);
                    }
                }
            }
            else
            {
                for (int i = bits.Length - 1; i > 0; i--)
                {
                    if (bits[i])
                    {
                        b |= (byte)(1 << i);
                    }
                }
            }

            return b;
        }

        private DeviceLEDs DeviceLEDType { get; set; }

        public LED LED1 { get; private set; } = new LED(1);
        public LED LED2 { get; private set; } = new LED(2);
        public LED LED3 { get; private set; } = new LED(3);
        public LED LED4 { get; private set; } = new LED(4);
        public LED LED5 { get; private set; } = new LED(5);

        /// <summary>
        /// Gets the clicked LED Buttons.
        /// These List would never be Cleared in this Class.
        /// The caller must take care of the removinging and clearing.
        /// </summary>
        public List<int> ClickedLEDButtons { get; private set; }
    }
}
