// Created with MonoDevelop
//
//    Copyright (C) 2019 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 Hiperscan.Unix;

namespace Hiperscan.SGS.SgsNt.Protocol
{

    abstract partial class BaseProtocol
    {
        public enum Errno : UInt16
        {
            Success = 0,
            NotPermitted = 1,
            NoSuchFileOrDirectory = 2,
            InputOutput = 5,
            Access = 13,
            Busy = 16,
            NoSuchDevice = 19,
            InvalidArgument = 22,
            NotImplemented = 38,
            NoData = 61,
            Timeout = 62,

            NotSupportedOperation = 95, //OPNOTSUPP = 95,   //!< Operation not supported on transport endpoint.
            RemoteInputOutput = 121, //REMOTEIO              = 121,  //!< Remote I/O error.

            Unknown = 1000,
            LightSourceDamaged = 1001,
            InvalidRecalibrationSpectrum = 1002,
            InvalidDarkReference = 1003,
            InvalidWhiteReference = 1004,
            InvalidTransflectReference = 1005,
            MissingReference = 1006,
            ReferencingTimeout = 1007,
            UnknownDeviceStatus = 1008,
            InvalidReferenceData = 1009,
            InvalidSpectrumType = 1010,
            InvalidSpectrumFormat = 1011,
            MissingChecksum = 1012,
            InvalidCheckSum = 1013,

            FailedSelfTest = 1014, //SELFTEST = 1014, //!< Self-test failed.
            NotInitializedDevice = 1015, //NOTINIT = 1015, //!< Device not initialized.
            UnexpectedValue = 1016, //UNEXPECTEDVALUE = 1016, //!< Unexpected value.
            NoStableSpectrum = 1017, //SPECTRUMNOTSTABLE = 1017, //!< Spectrum not stable.

            //! Errors in the mechanical system
            LockedLiftMagnet = 1018, //DEVICELOCKED = 1018, //!< Device is transport locked, no movement requests permitted
            ResetNeededForPeriphery = 1019, //PERIPHERY = 1019, //!< Periphery IC is unresponsive and needs reset

            //! Errors relating to the builtin ADC
            FailedAdcAcquisition = 1020, //ADCACQUISITION = 1020, //!< Error during ADC data aquisition
            LockedAdcAcquisition = 1021, //ADCLOCK = 1021, //!< Error in aquiring an ADC lock
            OverrunAdc = 1022, //ADCOVERRUN = 1022, //!< ADC overrun error

            //! Errors relating to the builtin Non-Volatile-Memory
            FailedFlashErease = 1023, //FLASHERASE = 1023, //!< Can't erase a flash region
            FailedFlashWriteControl = 1024, //FLASHWRITINGCTRL = 1024,
            FailedFlashWriting = 1025, //FLASHWRITING = 1025, //!< Can't write to flash region
            FailedFlashProtection = 1026, //FLASHPROTECTION = 1026,
            FailedFlashAccess = 1027, //FLASH = 1027, //!< Unknown error while accessing flash
            FailedNvmAccess = 1028, //NVMCRC = 1028, //!< CRC Error when accessing NVM

            //! Errors relating to the MEMS control
            InvalidMSA = 1029, //MEMSINVALIDMSA = 1029, //!< Invalid MSA
            UnknownMemsType = 1030, //MEMSUNKNOWNTYPE = 1030, //!< Unknown MEMS type
            TimeoutAtMemsStabilisation = 1031, //MEMSSTABILIZETIMEOUT = 1031, //!< MEMS stabilisation timeout
            InvalidMemsAmplitude = 1032, //MEMSINVALIDAMPLITUDE = 1032, //!< Invalid MEMS amplitude
            InvalidMemsStep = 1033, //MEMSUNKNOWNSEQSTEP = 1033, //!< Invalis MEMS sequencer step

            //! Errors relating to the Peripheral EEPROM
            FailedEepromReading = 1034, //EEPROMREAD = 1034, //!< Failed to read from EEPROM
            FailedEepromWriting = 1035, //EEPROMWRITE = 1035, //!< Failed to write to EEPROM
            InvalidEepromAddress = 1036,//EEPROMINVALIDADDRESS = 1036, //!< Invalid Adress for EEPROM
            TimeoutAtEepromAccess = 1037, //EEPROMTIMEOUT = 1037, //!< Timeout when accessing EEPROM

            FailedToEnableMotor = 1038, //MOTORENABLE = 1038, //!< Failed to enable Motor
            TimeoutAtMotorMovement = 1039, //MOTORTIMEOUT = 1039, //!< Timeout when waiting for a movement

            //! Errors in Periphery IC communication 
            FailedMotorCommunication = 1040, //MOTORCOM = 1040, //!< Error when communicating with motor drivers
            FaledTemperatureCommunication = 1041,//TEMPSENSORCOM = 1041, //!< Error when communicating with temperature sensors
            FailedTouchCommunication = 1042, //TOUCHSENSORCOM = 1042, //!< Error when communicating with touch sensors
            FailedGpioExpanderComunication = 1043, //GPIOEXPANDERCOM = 1043, //!< Error when communicating with GPIO expanders
            FailedPeripheryComunication = 1044, //PERIPHERYCOM = 1044, //!< Error when communicating with periphery (ie. SGSNT-Protocol "Periphery"!)
            FailedDSESComunication = 1045, //DSESCOM = 1045, //!< Error when communicating with DSES
            FailedHallSensorComunication = 1046, //HALLSENSORCOM = 1046, //!< Error when communicating with hall sensors
            FailedLightComunication = 1047, //LIGHTSENSORCOM = 1047, //!< Error when communicating with light sensors
            FailedExternalAdcComunication = 1048, //EXTADCCOM = 1048, //!< Error when communicating with external ADCs

            FailedMotorReferenceSearch = 1353, //EMOTORREFSEARCH = 1353, //!< Refsearch using the motor driver failed

            ThermalCutOutError = 1450, //ETHERMALCUTOUT = 1450, //!< Device is in thermal cutout mode (overheated)

            UnknownMemsError = 1049,

            NullPointerReference = 10000//NULLPTR = 10000, //!< Got null pointer as reference
        }

        public enum AddressType : byte
        {
            Master = 0,
            Peripheral = 1,
            Splitter = 2,
            XYTable = 3,
        }

        public enum HeaderStartType : byte
        {
            FrameStart = 0xAA
        }

        [Flags]
        public enum ChannelType : byte
        {
            Channel1 = 0b0000_0001,
            Channel2 = 0b0000_0010,
            Channel3 = 0b0000_0100,
            Channel4 = 0b0000_1000,
            ReverseScan = 0b1000_0000
        }

        public enum KeyIndex : byte
        {
            General = 0,
            Individual = 1
        }

        public enum TriggerMode : byte
        {
            Software = 0,
            Edge = 1,
            Gate = 2,
        }

        internal static void CheckErrnoIsSuccessOrThrowEx(bool throw_on_error,
                                                          BaseProtocol.Errno errno,
                                                          string exception_message,
                                                          IDevice device = null)
        {
            if (throw_on_error == false)
                return;

            switch (errno)
            {
                case Errno.Success:
                    return;
                case Errno.NotImplemented:
                    throw new NotImplementedException(Catalog.GetString("Not implemented by firmware"));
                case Errno.NotSupportedOperation:
                    throw new NotSupportedException(Catalog.GetString("Not supported by firmware"));
                default:
                    if (device == null)
                        throw new Exception(exception_message);

                    throw new SgsException(exception_message, device);
            }
        }
    }
}