// Created with MonoDevelop
//
//    Copyright (C) 2012 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.SGS.Common;
using Hiperscan.SGS.SerialInterface;
using Hiperscan.Unix;


namespace Hiperscan.SGS.Sgs1900
{
    internal class Device0_21 : Device0_20
    {
        protected new class Protocol : Device0_20.Protocol
        {
            public static readonly Parameter StartSampleSpinner           = new Parameter('R', 'S', typeof(byte),   sizeof(byte));
            public static readonly Parameter StopSampleSpinner            = new Parameter('R', 'P', typeof(byte),   0);
            public static readonly Parameter RotateSampleSpinner          = new Parameter('R', 'D', typeof(byte[]), 3*sizeof(byte));
            public static readonly Parameter WriteSampleSpinnerCorrection = new Parameter('R', 'C', typeof(byte[]), 4*sizeof(byte));
            public static readonly Parameter ReadSampleSpinnerCorrection  = new Parameter('R', 'E', typeof(byte[]), 0);
            public static readonly Parameter WriteScanEngineMSAFactor     = new Parameter('S', 'X', typeof(ushort), sizeof(ushort));
            public static readonly Parameter ReadScanEngineMSAFactor      = new Parameter('S', 'Y', typeof(ushort), 0);
            public static readonly Parameter ResetSampleSpinnerCounter    = new Parameter('R', 'X', typeof(byte),   0);
            public static readonly Parameter ReadSampleSpinnerCounter     = new Parameter('R', 'W', typeof(uint),   0);
        }

        public Device0_21(DeviceInfo info, VersionInfo version_info) : base (info, version_info)
        {
        }
         
        public override void StartSampleSpinner(sbyte velocity)
        {
            if (this.IsFinder == false)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));

            Protocol.Parameter parameter = new Protocol.Parameter(Protocol.StartSampleSpinner)
            {
                ByteValue = (byte)velocity
            };

            if (this.WriteParameter(parameter) == false)
                throw new SgsException(Catalog.GetString("Operation failed."), this);
        }

        public override void StopSampleSpinner()
        {
            if (this.IsFinder == false)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));
            
            Protocol.Parameter parameter = new Protocol.Parameter(Protocol.StopSampleSpinner);
            if (this.WriteParameter(parameter) == false)
                throw new SgsException(Catalog.GetString("Operation failed."), this);
        }

        public override void RotateSampleSpinner(sbyte velocity, ushort angle)
        {
            if (this.IsFinder == false)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));
            
            Protocol.Parameter parameter = new Protocol.Parameter(Protocol.RotateSampleSpinner);
            byte[] tx_buf = new byte[3];
            tx_buf[0] = (byte)velocity;
            Array.Copy(BitConverter.GetBytes(angle), 0, tx_buf, 1, sizeof(ushort));
            parameter.ByteArray = tx_buf;
            if (this.WriteParameter(parameter, 25000) == false) // 25s timeout for max angle at min velocity
                throw new SgsException(Catalog.GetString("Operation failed."), this);
        }

        public override void WriteSampleSpinnerCorrections(double slope, double offset)
        {
            if (this.IsFinder == false)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));
            
            Protocol.Parameter parameter = new Protocol.Parameter(Protocol.WriteSampleSpinnerCorrection);
            byte[] tx_buf = new byte[4];
            Array.Copy(BitConverter.GetBytes((UInt16)(slope*10000.0)), 0, tx_buf, 0, sizeof(UInt16));
            Array.Copy(BitConverter.GetBytes((Int16)(offset*10000.0)), 0, tx_buf, 2, sizeof(Int16));
            parameter.ByteArray = tx_buf;
            if (this.WriteParameter(parameter) == false)
                throw new SgsException(Catalog.GetString("Operation failed."), this);
        }

        public override void ReadSampleSpinnerCorrections(out double slope, out double offset)
        {
            if (this.IsFinder == false)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));

            byte[] rx_buf = this.ReadByteArrayParameter(Protocol.ReadSampleSpinnerCorrection);

            slope  = BitConverter.ToUInt16(rx_buf, 0) / 10000.0;
            offset = BitConverter.ToInt16(rx_buf,  2) / 10000.0;
        }

        public override void WriteScanEngineMsaFactor(byte[] key, double msa_factor)
        {
            if (this.ScanEngineVersion.Major < 12)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));

            this.SetMaintenanceMode(key);

            Protocol.Parameter parameter = new Protocol.Parameter(Protocol.WriteScanEngineMSAFactor)
            {
                UShortValue = (ushort)(msa_factor * 10000)
            };

            if (this.WriteParameter(parameter) == false)
                throw new SgsException(Catalog.GetString("Operation failed."), this);
        }

        public override double ReadScanEngineMsaFactor()
        {
            if (this.ScanEngineVersion.Major == 0)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));

            if (this.ScanEngineVersion.Major < 12)
                return double.NaN;
            
            return (double)(this.ReadUShortParameter(Protocol.ReadScanEngineMSAFactor) / 10000.0);
        }

        public override void ResetSampleSpinnerCounter()
        {
            if (this.IsFinder == false)
                throw new NotSupportedException(Catalog.GetString("Not supported by hardware."));

            Protocol.Parameter parameter = new Protocol.Parameter(Protocol.ResetSampleSpinnerCounter);
            if (this.WriteParameter(parameter) == false)
                throw new SgsException(Catalog.GetString("Operation failed."), this);
        }

        public override uint ReadSampleSpinnerCounter()
        {
            return this.ReadUIntParameter(Protocol.ReadSampleSpinnerCounter);
        }
    }
}
