using System;
using System.Linq;
using System.Threading;
using ICC4cPwmSdk.Device;
using ICC4cPwmSdk.Dtos;

namespace Icc4cExample
{
    internal class Example
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Stating basic ECC-1C example...");
            ICC4cPwmSdkDeviceController controller;

            while (true)
            {
                Console.WriteLine("Select connection: C = COM, E = ETHERNET");
                var key = Console.ReadKey();
                Console.WriteLine();
                //COM connection
                if (key.Key == ConsoleKey.C)
                {
                    controller = new ICC4cPwmSdkDeviceController();

                    Console.WriteLine("What is the COM number of the ICC-4c?");
                    var comport = Console.ReadLine();
                    if (int.TryParse(comport, out var comInt))
                    {
                        if (controller.Connect(comInt))
                        {
                            break;
                        }
                        Console.WriteLine("Connection failed.");
                    }
                }

                //Ethernet connection
                if (key.Key == ConsoleKey.E)
                {
                    controller = new ICC4cPwmSdkDeviceController(true);

                    Console.WriteLine("Static IP or automatic search? A = auto, S = static");
                    key = Console.ReadKey();
                    Console.WriteLine();

                    //Automatic ethernet search (DHCP has to be enabled in the board EEPROM (default))
                    if (key.Key == ConsoleKey.A)
                    {
                        var devices = EthernetSearcher.SearchEthernetIcc4cBoards();
                        if (devices.Count == 0)
                        {
                            Console.WriteLine("No ethernet boards found.");
                        }
                        else
                        {
                            Console.WriteLine($"Boards found({devices.Count}):");

                            var index = 0;
                            foreach (var device in devices)
                            {
                                Console.WriteLine($"Index: {index}, Serial number: {device.SerialNumber}, IP: {device.Ip}, Port: {device.Port}");
                                index++;
                            }
                            Console.WriteLine("Select index of the device you want to connect.");
                            var selectedIndex = Console.ReadLine();
                            if (int.TryParse(selectedIndex, out var indexInt) && indexInt >=0 && indexInt < devices.Count)
                            {
                                if (controller.Connect(devices[indexInt].Ip, devices[indexInt].Port))
                                {
                                    break;
                                }
                                Console.WriteLine("Connection failed.");
                            }
                        }
                       
                    }

                    //Static IP connection (static IP must be configured in the board EEPROM (using Optotune Cockpit application), also DHCP has to be switched of in the board EEPROM)
                    if (key.Key == ConsoleKey.S)
                    {
                        Console.WriteLine("Specify IP address of the board:");
                        var ipAddress = Console.ReadLine();

                        if (controller.Connect(ipAddress, 5000))
                        {
                            break;
                        }
                        Console.WriteLine("Connection failed.");
                    }
                }
            }


            //Connecting to board

            //Set board to PRO mode
            controller.ChangeModeToPro();

            //Getting board info
            Console.WriteLine("Board info");
            var serialNumber = controller.GetElectronicSerialNumber();
            var fwVersion =
                $"{controller.Status.GetBoardFirmwareMajorVersion()}.{controller.Status.GetBoardFirmwareMinorVersion()}.{controller.Status.GetBoardFirmwareRevisionVersion()}";

            Console.WriteLine($"Board serial number: {serialNumber}");
            Console.WriteLine($"Board firmware version: {fwVersion}");

            // In order to drive the connected product, device type of the product has to be obtained (this is not needed if
            // automatic detection is allowed)
            var connectedDevices = controller.GetConnectedDeviceTypes();
            Console.WriteLine();
            Console.WriteLine(
                $"Connected devices: {string.Join(", ", connectedDevices.Select(deviceType => Enum.GetName(typeof(EConnectedDeviceType), deviceType)))}");
            Console.WriteLine();

            //Supported lens types
            var lensesTypes = new[]
            {
                EConnectedDeviceType.EL1030C,
                EConnectedDeviceType.EL1030TC,
                EConnectedDeviceType.EL1230TC,
                EConnectedDeviceType.EL1640TC_5D
            };
            //Finding first connected lens
            var firstLensFound = connectedDevices.Select((device, index) => (type: device, channel: index))
                .FirstOrDefault(deviceIndexPair => lensesTypes.Contains(deviceIndexPair.type));

            if (firstLensFound == default(ValueTuple<EConnectedDeviceType, int>))
            {
                Console.WriteLine("No lens connected");
            }
            else
            {
                //Each channel can also be accessed directly as EChannel.Channel0, EChannel.Channel1, ...
                var lensChannel = (EChannel)firstLensFound.channel;
                var lensSerialNumber = controller.GetProductSerialNumberOnChannel(lensChannel);
                Console.WriteLine(
                    $"Lens {Enum.GetName(typeof(EConnectedDeviceType), firstLensFound.type)} ({lensSerialNumber}) found on channel {lensChannel}");

                var lensTemperature = controller.TemperatureManager.GetDeviceTemperature(lensChannel);

                Console.WriteLine($"Lens temperature: {lensTemperature}°C");

                var minCurrent = controller.DeviceEeprom.GetMaxNegativeCurrent(lensChannel);
                var maxCurrent = controller.DeviceEeprom.GetMaxPositiveCurrent(lensChannel);

                Console.WriteLine($"Minimum current is {minCurrent} mA, maximum current is {maxCurrent} mA");

                Console.WriteLine();
                Console.WriteLine("Setting static current");
                //Setting input system to static input
                controller.InputStage.ChangeActiveSystem(lensChannel, EInputSignalStageSystem.StaticInput);

                for (var current = minCurrent; current <= maxCurrent; current += (maxCurrent - minCurrent) / 5)
                {
                    //Value has to be converted from mA to A
                    var currentInA = current / 1000;
                    Console.WriteLine($"Current {currentInA} A");
                    controller.InputStage.StaticValue.SetCurrent(lensChannel, currentInA);
                    //Diopter can be set similarly
                    //controller.InputStage.StaticValue.SetDiopter(lensChannel, diopterInDpt);
                    Thread.Sleep(1000);
                }

                Console.WriteLine("Setting static current to 0 A");
                controller.InputStage.StaticValue.SetCurrent(lensChannel, 0);

                Console.WriteLine();
                Console.WriteLine("Running signal generator");

                controller.InputStage.ChangeActiveSystem(lensChannel, EInputSignalStageSystem.SignalGenerator);
                controller.InputStage.SignalGenerator.SetUnitType(lensChannel, EICC4cPwmUnitType.Current);
                controller.InputStage.SignalGenerator.SetShape(lensChannel, ESignalGeneratorShape.Sinusoidal);
                controller.InputStage.SignalGenerator.SetAmplitude(lensChannel, 0.2f);
                controller.InputStage.SignalGenerator.SetFrequency(lensChannel, 5);
                controller.InputStage.SignalGenerator.SwitchRunning(lensChannel, true);

                for (var i = 0; i < 5; i++)
                {
                    Console.Write(".");
                    Thread.Sleep(1000);
                }

                controller.InputStage.SignalGenerator.SwitchRunning(lensChannel, false);

                Console.WriteLine();
                Console.WriteLine("Signal generator stopped");

                Console.WriteLine();
                Console.WriteLine("Device EEPROM");

                var eepromVersion =
                    $"{controller.DeviceEeprom.GetEepromVersion(lensChannel)}.{controller.DeviceEeprom.GetEepromSubVersion(lensChannel)}";
                Console.WriteLine($"EEPROM version: {eepromVersion}");

                var eepromBytes = controller.DeviceEeprom.GetBytes(lensChannel, 0, 10);
                var eepromSize = controller.DeviceEeprom.GetDeviceEepromSize(lensChannel);

                Console.WriteLine(
                    $"Printing {eepromBytes.Length}/{eepromSize} bytes saved in EEPROM: {string.Join(", ", eepromBytes)}");
            }

            Console.WriteLine();
            Console.WriteLine("Example finished.");
            Console.ReadLine();

        }
    }
}
