// 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 Hiperscan.SGS.Common;
using Hiperscan.SGS.SerialInterface;
using Hiperscan.SGS.SerialInterface.USB;
using Hiperscan.Unix;
using LibUsbDotNet;
using LibUsbDotNet.Main;
using static Hiperscan.SGS.SerialInterface.SerialInterfaceConfig;

namespace Hiperscan.SGS.Splitter
{
    public class SplitterSgsInterface
    {
        public static readonly SerialInterfaceConfig ES22_SENSOR_FINDER2 =
            new SerialInterfaceConfig(VendorId.HIPERSCAN,
                                      ProductId.ES22_SENSOR_FINDER2,
                                      BackendType.STM32,
                                      DeviceType.ApoIdent2X);


        public static SplitterSgsInterface GetSgsInterface(SerialInterfaceConfig config)
        {
            return new SplitterSgsInterface(config);
        }

        private SplitterSgsInterface(SerialInterfaceConfig config)
        {
            this.DeviceInfo = this.GetDeviceInfo(config.VendorId, config.ProductId);
            this.Backend = config.Backend;

            switch(this.Backend)
            {
                case BackendType.STM32:
                    this.SpectrometerSerialInterface = new STM32(config.VendorId, config.ProductId);
                    this.Versions = STM32.GetVersionInfo(this.DeviceInfo, false);
                    break;

                case BackendType.CP2130:
                    this.SpectrometerSerialInterface = new CP2130(config.VendorId, config.ProductId);
                    this.Versions = CP2130.GetVersionInfo(this.DeviceInfo, false);
                    break;

                case BackendType.FT245BL:
                    this.SpectrometerSerialInterface = new FT245BL(config.VendorId, config.ProductId);
                    this.Versions = FT245BL.GetVersionInfo(this.DeviceInfo, false);
                    break;

                default:
                    string message = String.Format(Catalog.GetString("Unknown Backend type {0}"),this.Backend);
                    throw new Exception(message);
            }
        }

        private DeviceInfo GetDeviceInfo(uint vid, uint pid)
        {
            UsbRegDeviceList usb_regs = UsbDevice.AllDevices;
            UsbRegistry usb_registry = usb_regs.Find((dev => dev.Vid == vid && dev.Pid == pid));


            if (usb_registry == null)
            {
                string message = String.Format(Catalog.GetString("Cannot determine USB device by vendor id {0} and product id {1}"), vid, pid);
                throw new Exception(message);
            }

            string manufacturer = usb_registry.DeviceProperties["Mfg"]?.ToString() ?? Catalog.GetString("Unknown");
            string description = usb_registry.DeviceProperties["DeviceDesc"]?.ToString() ?? Catalog.GetString("Unknown");
            string serial = LibUsbDevice.GetSerialNumber(usb_registry);

            if (String.IsNullOrEmpty(serial))
            {
                string message = Catalog.GetString("Cannot determine serial number of device");
                throw new Exception(message);
            }

            return new DeviceInfo(manufacturer,
                                  serial,
                                  description,
                                  (uint)usb_registry.Vid,
                                  (uint)usb_registry.Pid);
        }

        public VersionInfo Versions { get; private set; }
        public DeviceInfo DeviceInfo { get; private set; }
        public ISerialInterface SpectrometerSerialInterface { get; private set; }
        public BackendType Backend { get; private set; }
    }
}
