// Created with MonoDevelop
//
//    Copyright (C) 2020 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.Threading;

using Hiperscan.SGS.Benchtop;
using Hiperscan.SGS.Common;
using Hiperscan.SGS.SerialInterface;
using Hiperscan.SGS.SgsNt.Protocol;
using Hiperscan.Unix;


namespace Hiperscan.SGS.SgsNt
{
    internal partial class DeviceNt1_1 : Sgs1900.BaseDevice
    {
        public override FinderWheelPosition FinderWheelPosition { get; protected set; }
        public override bool FinderLightSourceState { get; protected set; }

        public override void SetFinderLightSource(bool state, IdleTaskHandler idle_task)
        {
            if (this.IsFinder == false || this.GetState() == Spectrometer.State.Unknown)
                return;

            Protocol.Command command = new Protocol.Command(Protocol.PeripheralSetLightSource)
            {
                ByteValue = state ? (byte)1 : (byte)0
            };

            this.SetState(Spectrometer.State.Waiting);
            Protocol.Response response = this.WriteCommand(command, TIMOUT_LONGCOMMAND_MS);

            if (response == null)
                throw new SgsException(Catalog.GetString("Cannot set light source."), this);

            this.FinderLightSourceState = state;

            lock (this)
                this.state_changed = true;

            idle_task?.Invoke();

            if (state == true)
                Thread.Sleep((int)this.LightSourceDelay);

            this.FinderLightSourceState = state;

            this.SetState(Spectrometer.State.Idle);
        }

        public override void SetFinderWheel(FinderWheelPosition position, IdleTaskHandler idle_task, bool no_wait = false)
        {
            if (!this.IsFinder)
                return;

            Protocol.Command command = new Protocol.Command(Protocol.PeripheralSetWheelPosition)
            {
                ByteValue = (byte)position
            };

            this.FinderWheelPosition = FinderWheelPosition.Moving;
            lock (this)
                this.state_changed = true;

            int timeout = (position == FinderWheelPosition.Initial) ? 20000 : 5000;
            Protocol.Response response = this.WriteCommand(command, timeout);

            if (response == null)
                throw new SgsException(Catalog.GetString("Cannot set Reference Wheel."), this);

            this.FinderWheelPosition = position;
            idle_task?.Invoke();
        }

        public override void SetFinderFanSpeed(bool on)
        {

        }

        public override double ReadFinderTemperature()
        {
            Protocol.Response response = this.WriteCommand(new Protocol.Command(Protocol.ReadFinderStatus), TIMOUT_COMMAND_MS);

            if (response == null)
                throw new SgsException(Catalog.GetString("Cannot read status."), this);

            StatusReadData stat = (StatusReadData)Protocol.TransferStruct.FromBuffer(response.TransferStructValue, typeof(StatusReadData));

            //SGSFirmwareStatusType finder_firmware_status = (SGSFirmwareStatusType)stat.ErrorFlag;

            return (double)stat.Temperature / 100.0;
        }

        public override byte[] ReadFinderHardwareVersion()
        {
            throw new NotSupportedException("Not supported by hardware.");
        }

        public override byte ReadDimmerParameter()
        {
            return 0;
        }

        public override void WriteDimmerParameter(byte[] key, byte val)
        {
            return;
        }

        public override bool FinderButtonPressed()
        {
            if (this.is_finder == false || this.IsIdle == false)
                return false;

            return (this.ReadByteParameter(new Protocol.Command(Protocol.FinderButton), TIMOUT_COMMAND_MS) == 1);
        }

        public override void SwitchFinderStatusLED(bool green)
        {
            if (this.IsFinder == false || this.AssumedFinderLEDState == green)
                return;

            Protocol.Command command = new Protocol.Command(Protocol.FinderStatusLED)
            {
                ByteValue = green ? (byte)1 : (byte)0
            };

            Protocol.Response response = this.WriteCommand(command, TIMOUT_COMMAND_MS);

            this.assumed_finder_led_state = green;
        }

        private PeripheralInfoReadData? ReadPeripheralInfo()
        {
            Protocol.Response response = this.WriteCommand(Protocol.DetectPeripheral, this.current_config.Timeout, null, false);

            if (response == null)
                throw new SgsException(Catalog.GetString("Cannot read peripheral info."), this);

            if (response.HeaderErrno == BaseProtocol.Errno.Success)
                return (PeripheralInfoReadData)Protocol.TransferStruct.FromBuffer(response.TransferStructValue, typeof(PeripheralInfoReadData));
            else if (response.HeaderErrno == BaseProtocol.Errno.NoSuchDevice)
                return null;
            throw new SgsException(Catalog.GetString("Cannot read peripheral info."), this);
        }

        public override void WriteFinderPcbHardwareVersion(byte[] key, byte[] versions)
        {
            if (versions == null || versions.Length != 4)
                throw new ArgumentException(Catalog.GetString("Invalid finder hardware version information."));

            this.SetMaintenanceMode(key);

            Protocol.Command command = new Protocol.Command(Protocol.WriteFinderPcbHardwareVersion)
            {
                ByteArrayValue = versions
            };

            Protocol.Response response = this.WriteCommand(command, TIMOUT_COMMAND_MS);

            if (response == null)
                throw new SgsException(Catalog.GetString("Cannot write serial number."), this);
        }

        public override void WriteFinderOverrideHardwareVersion(byte[] key, byte[] versions)
        {
            WriteFinderPcbHardwareVersion(key, versions);
        }
    }
}