// Created with MonoDevelop
//
//    Copyright (C) 2023 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.Linq;
using Hiperscan.SGS.SgsNt.Protocol;
using Hiperscan.SGS.Splitter;
using Hiperscan.Unix;
using static Hiperscan.SGS.SgsNt.Protocol.BaseProtocol;
using static Hiperscan.SGS.Splitter.SplitterProtocol;

namespace Hiperscan.SGS.SerialInterface.USB
{
    public partial class RaspianCom
    {
        private void SendUsbTimeoutsCommand(int read_timeout, int write_timeout)
        {
            try
            {
                if (this.IsAskingForProtocol == true)
                    return;

                if (this.ResetIsExecuting == true)
                    return;

                Command cmd = new Command(SplitterProtocol.SetSplitterUsbTimeouts);

                SplitterProtocol.SplitterUsbTimeoutData usb_config = new SplitterUsbTimeoutData();
                usb_config.UsbReadTimeout = (uint)read_timeout;
                usb_config.UsbReadTimeout = (uint)write_timeout;

                cmd.TransferStructValue = TransferStruct.GetBytes(usb_config);
                cmd.UpdateChecksum();
                this.Write(cmd.Buffer);

                this.ReadResponse((int)RaspianCom.MIN_TIMEOUT, cmd);
            }
            catch(Exception ex)
            {
                string message = String.Format(Catalog.GetString("Cannot set USB timeout limits."), ex.Message);
                throw new Exception(message, ex);
            }

        }

        private Response ReadResponse(int timeout, Command cmd)
        {
            byte[] header_data = this.ReadBlocking(BaseProtocol.HEADER_LENGTH +
                                                   BaseProtocol.PAYLOAD_CMD_LENGTH +
                                                   BaseProtocol.PAYLOAD_LEN_LENGTH,
                                                   1000,
                                                   null);

            uint payload_data_len = BitConverter.ToUInt16(header_data, (int)BaseProtocol.PAYLOAD_LEN_OFFSET);

            if (payload_data_len > BaseProtocol.PAYLOAD_MAX_LENGTH)
                throw new Exception(string.Format(Catalog.GetString("Payload length exceeds transfer limit: {0} > {1}"),
                                                  payload_data_len,
                                                  BaseProtocol.PAYLOAD_MAX_LENGTH));

            payload_data_len = payload_data_len + BaseProtocol.CHECKSUM_LENGTH;

            int try_count = 0;
            timeout = timeout / BaseProtocol.NUMBER_OF_REPEATS;

            for (; ; )
            {
                try
                {
                    byte[] payload_data = this.ReadBlocking(payload_data_len,
                                     timeout,
                                      null);


                    Response response = new Response(header_data.Concat(payload_data).ToArray(),
                                                     cmd.ResponseDataType);

                    Errno errno = response.Check(cmd);
                    if (errno != BaseProtocol.Errno.Success)
                        throw new Exception(string.Format(Catalog.GetString("Reading response returned error {0} ({1})."), errno, (int)errno));

                    return response;
                }
                catch (Exception ex)
                {
                    if (++try_count > BaseProtocol.NUMBER_OF_REPEATS)
                        throw;

                    Console.WriteLine(string.Format(Catalog.GetString("Cannot read device response (try again): {0}"), ex.Message));
                }
            }
        }

        private bool IsAskingForProtocol { get; set; } = false;
        private bool ResetIsExecuting { get; set; }
    }
}
