using CommandLine;
using CommandLine.Text;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace mx_uart_ctl
{
    class Program
    {
        class Options
        {
            [Option('p', Required = true, HelpText = "-p <#port index> (Start from 0)")]
            public uint Port { get; set; }

            [Option('m', Default = null, Required = false,
                HelpText = "-m <#uart mode>\n" +
                " 		0 --> set to RS232 mode\n" +
                "		1 --> set to RS485-2W mode\n" +
                "		2 --> set to RS422/RS485-4W mode"
                )]
            public uint? Mode { get; set; }

            [Usage(ApplicationAlias = "mx-uart-ctl")]
            public static IEnumerable<Example> Examples
            {
                get
                {
                    yield return new Example("Get uart mode from port 2", new Options { Port = 2});
                    yield return new Example("Set port 1 to mode RS-422", new Options { Port = 1, Mode = 2 });
                }
            }
        }

        [DllImport("mxsp.dll", EntryPoint = "GetUartMode", CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern int GetUartMode(int port);

        [DllImport("mxsp.dll", EntryPoint = "SetUartMode", CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern int SetUartMode(int port, int mode);

        enum Uart_Mode
        {
            UART_MODE_RS232 = 0,
            UART_MODE_RS485_2W = 1,
            UART_MODE_RS422_RS485_4W = 2,
            NOTSUPPORT = 4
        };

        enum Action_Type
        {
            GET_MODE = 0,
            SET_MODE = 1
        };

        enum UART_STATUS
        {
            LIB_INITIALIZE_FAIL = -1,
            PORT_OUTOF_INDEX = -2,
            SET_STATUS_ERR = -3,
            NO_FT260_DEVICE = -4,
            SET_FT260_DEVICE_FAIL = -5
        };

        public struct Action_Struct
        {
            public int type;
            public uint port;
            public int mode;
        };

        static void ShowUartModeMessage(int mode)
        {
            switch (mode)
            {
                case (int)Uart_Mode.UART_MODE_RS232:
                    Console.WriteLine("Current uart mode is RS232 interface.");
                    break;
                case (int)Uart_Mode.UART_MODE_RS485_2W:
                    Console.WriteLine("Current uart mode is RS485-2W interface.");
                    break;
                case (int)Uart_Mode.UART_MODE_RS422_RS485_4W:
                    Console.WriteLine("Current uart mode is RS422 / RS485-4W interface.");
                    break;
                case (int)Uart_Mode.NOTSUPPORT:
                    Console.WriteLine("Not Support.");
                    break;
                default:
                    Console.WriteLine("Unknown interface is set.");
                    break;
            }
        }

        static void DoAction(Action_Struct action)
        {
            int ret;
            switch (action.type)
            {
                default:
                    ret = -1;
                    break;
                case (int)Action_Type.GET_MODE:
                    ret = GetUartMode((int)action.port);
                    if (ret < 0)
                    {
                        Environment.Exit(Environment.ExitCode);
                    }
                    break;
                case (int)Action_Type.SET_MODE:
                    ret = SetUartMode((int)action.port, action.mode);
                    if (ret < 0)
                    {                        
                        Environment.Exit(Environment.ExitCode);
                    }
                    Console.WriteLine("Set OK.\n");

                    ret = GetUartMode((int)action.port);
                    if (ret < 0)
                    {
                        Environment.Exit(Environment.ExitCode);
                    }
                    break;
            }
            ShowUartModeMessage(ret);
        }

        static void Main(string[] args)
        {
            Action_Struct action;
            CommandLine.Parser.Default.ParseArguments<Options>(args)
                .WithParsed<Options>(opts =>
                {
                    action.port = opts.Port;
                    if (opts.Mode == null)
                    {
                        action.type = (int)Action_Type.GET_MODE;
                        action.mode = -1;
                    }
                    else
                    {
                        action.type = (int)Action_Type.SET_MODE;
                        action.mode = (int)opts.Mode;
                    }
                    DoAction(action);
                });
        }
    }
}
