using CommandLine;
using System;
using System.Runtime.InteropServices;

namespace mx_dio_ctl
{
    class Program
    {
        class Options
        {
            [Option('i', Default = null, HelpText = "-i <#DIN index> (Start from 0)")]
            public uint? DIN { get; set; }

            [Option('o', Default = null, HelpText = "-o <#DOUT index> (Start from 0)")]
            public uint? DOUT { get; set; }

            [Option('m', Default = null,
                HelpText = "-m <status>\n" +
                "0 --> LOW\n" +
                "1 --> HIGH"
                )]
            public uint? Mode { get; set; }

            [Option('c', Default = null, HelpText = "-c <#DIN:0 /DOUT:1>\n")]
            public uint? Count { get; set; }
        }

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

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

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

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

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

        public struct Action_Struct
        {
            public int diport;
            public int doport;
            public int mode;
            public int count;
        };

        private static void ShowUsage()
        {
            Console.WriteLine("Usage:");
            Console.WriteLine("	mx-dio-ctl <-i #DIN |-o #DOUT >");
            Console.WriteLine("	mx-dio-ctl <-o #DOUT > -m <status>");
            Console.WriteLine("	mx-dio-ctl <-c DIN:0 | DOUT:1 >");
            Console.WriteLine("OPTIONS:");
            Console.WriteLine("	-i <#DIN>");
            Console.WriteLine("		Get status of target DIN port");
            Console.WriteLine("		DIN index start from 0 ");
            Console.WriteLine("	-o <#DOUT>");
            Console.WriteLine("		Get status of target DOUT port");
            Console.WriteLine("		DOUT index start from 0");
            Console.WriteLine("	-m <status>");
            Console.WriteLine("		Set status for target DOUT port");
            Console.WriteLine("		0 --> LOW");
            Console.WriteLine("		1 --> HIGH");
            Console.WriteLine("	-c <count>");
            Console.WriteLine("		Get DIN/DOUT port count");
            Console.WriteLine("		0 --> DIN");
            Console.WriteLine("		1 --> DOUT\n");
            Console.WriteLine("Example:");
            Console.WriteLine("	Get value from DIN port 1");
            Console.WriteLine("	# mx-dio-ctl -i 1");
            Console.WriteLine("	Get value from DOUT port 1");
            Console.WriteLine("	# mx-dio-ctl -o 1");
            Console.WriteLine("	Set DOUT port 2 value to LOW");
            Console.WriteLine("	# mx-dio-ctl -o 2 -m 0");
            Console.WriteLine("	Get DOUT port count");
            Console.WriteLine("	# mx-dio-ctl -c 1");
        }

        static void Main(string[] args)
        {
            CommandLine.Parser.Default.ParseArguments<Options>(args)
                .WithParsed(opts =>
                {
                    if (opts.Count != null)
                    {
                        GetDIOCount(opts);
                    }
                    else if (opts.DOUT != null && opts.Mode != null)
                    {
                        SetModeAction(opts);
                    }
                    else if (opts.DOUT != null && opts.Mode == null
                            || opts.DIN != null && opts.Mode == null)
                    {
                        GetModeAction(opts);
                    }
                    else
                    {
                        ShowUsage();
                    }
                });
        }

        private static void SetModeAction(Options opts)
        {
            Action_Struct action;
            action.doport = (int)opts.DOUT;
            if (SetDoutStatus(action.doport, (int)opts.Mode) < 0)
            {
                Console.WriteLine("Failed to set DOUT port {0} value.", action.doport);
            }
            else
            {
                action.mode = GetDoutStatus(action.doport);
                if (action.mode >= 0)
                {
                    Console.WriteLine("DOUT port {0} status: {1}", action.doport, action.mode);
                }
            }
        }

        private static void GetModeAction(Options opts)
        {
            Action_Struct action;
            if (opts.DIN != null)
            {
                action.diport = (int)opts.DIN;
                action.mode = GetDinStatus(action.diport);
                if (action.mode>=0)
                {
                    Console.WriteLine(string.Format("DIN port {0} status: {1}", action.diport, action.mode));
                }
            }
            if (opts.DOUT != null)
            {
                action.doport = (int)opts.DOUT;
                action.mode = GetDoutStatus(action.doport);
                if (action.mode >= 0)
                {
                    Console.WriteLine(string.Format("DOUT port {0} status: {1}", action.doport, action.mode));
                }
            }
        }

        private static void GetDIOCount(Options opts)
        {
            if (opts.Count == 0)
            {
                Console.WriteLine(string.Format("DIN port count: {0}", GetDinCount()));
            }
            else if (opts.Count == 1)
            {
                Console.WriteLine(string.Format("DOUT port count: {0}", GetDoutCount()));
            }
            else
            {
                Console.WriteLine("Get DIN / DOUT port count\n0 --> DIN\n1 --> DOUT");
            }
        }
    }
}
