
using System;
using System.Collections.Generic;
using System.Linq;
using OPSSDK;
using OPSSDKCommon.Model.Config;

namespace PBXConfiguration
{
    class Program
    {
        static OpsClient client;
        static string prompt = string.Empty;

        static void Main(string[] args)
        {
            ShowGreetingMessage();
            ReadLoginInfos();
            ReadCommands();
        }

        private static void ShowGreetingMessage()
        {
            Console.WriteLine("This is a simple Ozeki Phone System XE demo written in C#.");
            Console.WriteLine("It can be used to configure extensions on Ozeki Phone System XE.");
            Console.WriteLine("-------------------------------------------------------------------------------");
            Console.WriteLine();
        }

        private static void ReadLoginInfos()
        {
            Console.WriteLine("Please enter the IP address of Ozeki Phone System XE.");

            var serverAddress = Read("Server address (default: 127.0.0.1)", false);

            if (string.IsNullOrEmpty(serverAddress))
                serverAddress = "127.0.0.1";

            Console.WriteLine("Please enter the username and password of the user created in Ozeki Phone System XE");
            var username = Read("Username (default: admin)", false);

            if (string.IsNullOrEmpty(username))
                username = "admin";

            var password = Read("Password", true);
            Login(serverAddress, username, password);
        }

        private static void Login(string serverAddress, string username, string password)
        {
            client = new OpsClient();
            Console.WriteLine("Connecting...");
            client.ErrorOccurred += client_ErrorOccurred;
            var result = client.Login(serverAddress, username, password);

            if (result)
            {
                Console.WriteLine("Successfully connected to {0} with username: {1}.", serverAddress, username);
            }
            else
            {
                Console.WriteLine("Connection fail try again.");
                Console.WriteLine("Please check whether the IP address is correct and the given user has right to use OPS SDK. This can be checked under PBX features/Preferences/User access profile.");
                ReadLoginInfos();
            }

        }

        static void client_ErrorOccurred(object sender, ErrorInfo e)
        {
            Console.WriteLine(e.Message);
        }

        private static void ReadCommands()
        {
            Console.WriteLine("This demo features the following commands.");
            Console.WriteLine("The first word specifies the name of the command followed by the mandatory command parameters.");

            ShowHelp();

            while (true)
            {
                Console.Write(prompt);
                var command = Console.ReadLine();

                if (string.IsNullOrEmpty(command))
                    continue;

                var parameters = GetStringParts(command);

                var commandName = parameters[0].ToLower();

                parameters.RemoveAt(0);

                var paramValuePairs = CreateParamValuePairs(parameters);
                switch (commandName)
                {
                    case "addsip":
                        AddSIPAccount(paramValuePairs);
                        break;
                    case "addcallqueue":
                        AddCallQueue(paramValuePairs);
                        break;
                    case "showsip":
                        ShowSIP(paramValuePairs);
                        break;
                    case "showcallqueue":
                        ShowCallQueue(paramValuePairs);
                        break;
                    case "deleteconfig":
                        DeleteConfig(paramValuePairs);
                        break;
                    case "exit":
                        Exit();
                        break;
                    case "help":
                        ShowHelp();
                        break;
                    default:
                        Console.WriteLine("Invalid command.");
                        break;
                }

            }
        }

        private static void DeleteConfig(List<KeyValuePair<string, string>> paramValuePairs)
        {
            string id = null;

            foreach (var paramValuePair in paramValuePairs)
            {
                switch (paramValuePair.Key)
                {
                    case "-id":
                        id = paramValuePair.Value;
                        break;
                }
            }

            if(string.IsNullOrWhiteSpace(id))
            {
                Console.WriteLine("Id is not valid.");
                return;
            }

            var conf = client.GetConfigs<BaseConfig>().FirstOrDefault(item => item.ID == id);

            if(conf == null)
            {
                Console.WriteLine("Configuration does not exists.");
                return;
            }


            client.DeleteConfig(conf);
            Console.WriteLine("Configuration successfully removed.");
        }

        private static void ShowCallQueue(List<KeyValuePair<string, string>> paramValuePairs)
        {
            string id = null;

            foreach (var paramValuePair in paramValuePairs)
            {
                switch (paramValuePair.Key)
                {
                    case "-id":
                        id = paramValuePair.Value;
                        break;
                }
            }

            var configs = client.GetConfigs<CallQueueConfig>();
            
            if(string.IsNullOrWhiteSpace(id))
            {
                foreach (var config in configs)
                {
                    ShowCallQueueDetails(config);
                }
            }
            else
            {
                var config = configs.FirstOrDefault(item => item.ID == id);

                if(config == null)
                {
                    Console.WriteLine("Configuration does not exists.");
                    return;
                }

                ShowCallQueueDetails(config);

            }

        }

        private static void ShowCallQueueDetails(CallQueueConfig callQueueConfig)
        {
            Console.WriteLine("id: {0}, strategy: {1}, members: {2}", callQueueConfig.ID, callQueueConfig.RingingStrategy, string.Join(",", callQueueConfig.Members));
        }

        private static void ShowSIP(List<KeyValuePair<string, string>> paramValuePairs)
        {
            string id = null;

            foreach (var paramValuePair in paramValuePairs)
            {
                switch (paramValuePair.Key)
                {
                    case "-id":
                        id = paramValuePair.Value;
                        break;
                }
            }

            var configs = client.GetConfigs<SIPAccountConfig>();

            if (string.IsNullOrWhiteSpace(id))
            {
                foreach (var config in configs)
                {
                    ShowSIPDetails(config);
                }
            }
            else
            {
                var config = configs.FirstOrDefault(item => item.ID == id);

                if (config == null)
                {
                    Console.WriteLine("Configuration does not exists.");
                    return;
                }

                ShowSIPDetails(config);

            }
        }

        private static void ShowSIPDetails(SIPAccountConfig config)
        {
            Console.WriteLine("username: {0}, authName: {1}, password: {2}", config.ID, config.AuthorizationName, config.Password);
        }

        private static void AddCallQueue(List<KeyValuePair<string, string>> paramValuePairs)
        {
            var strategy = CallQueueRingingStrategyType.RingAll;
            string id = null;
            List<string> members = null;


            foreach (var keyValuePair in paramValuePairs)
            {
                switch (keyValuePair.Key)
                {
                    case "-id":
                        id = keyValuePair.Value;
                        break;
                    case "-members":
                        if(!string.IsNullOrWhiteSpace(keyValuePair.Value))
                            members = new List<string>(keyValuePair.Value.Split(','));
                        break;
                    case "-strategy":
                        switch (keyValuePair.Value.ToLower())
                        {
                            case "all":
                                strategy = CallQueueRingingStrategyType.RingAll;
                                break;
                            case "random":
                                strategy = CallQueueRingingStrategyType.Random;
                                break;
                            case "prioritised":
                                strategy = CallQueueRingingStrategyType.PrioritisedHunt;
                                break;
                        }
                        break;
                }
            }


            if(members == null)
            {
                Console.WriteLine("Members is not valid.");
                return;
            }

            if(string.IsNullOrWhiteSpace(id))
            {
                Console.WriteLine("Id is not valid.");
                return;
            }

            if (client.AddConfig(new CallQueueConfig(id, strategy, members, true)))
                Console.WriteLine("Successfully added.");
            else
                Console.WriteLine("Account already exists.");
        }

        private static void AddSIPAccount(List<KeyValuePair<string, string>> parameters)
        {
            string username = null;
            string password = null;
            string authName = null;

            foreach (var keyValuePair in parameters)
            {
                switch (keyValuePair.Key)
                {
                    case "-u":
                        username = keyValuePair.Value;
                        break;
                    case "-p":
                        password = keyValuePair.Value;
                        break;
                    case "-a":
                        authName = keyValuePair.Value;
                        break;
                }  
            }

            if(string.IsNullOrWhiteSpace(username))
            {
                Console.WriteLine("Username is not valid.");
                return;
            }
            if(string.IsNullOrWhiteSpace(password))
            {
                Console.WriteLine("Password is not valid.");
                return;
            }
            if(string.IsNullOrWhiteSpace(authName))
            {
                Console.WriteLine("Authorization name is not valid.");
                return;
            }

            if(client.AddConfig(new SIPAccountConfig(username, true, username, authName, null, password, true)))
                Console.WriteLine("Successfully added.");
            else
                Console.WriteLine("Account already exists.");
        }

        private static void ShowHelp()
        {
            Console.WriteLine();
            Console.WriteLine("Available commands:");
            Console.WriteLine();

            Console.WriteLine("addSIP -u username -a authorization_name -p password");
            Console.WriteLine("example: addSIP -u 200 -a 200 -p 200");
            Console.WriteLine();

            Console.WriteLine("addCallQueue -id id -members member1,member2,member3,... [-strategy all|random|prioritised]");
            Console.WriteLine("example: addCallQueue -id 199 -members 200,201,202");
            Console.WriteLine();

            Console.WriteLine("showSIP [id]");
            Console.WriteLine("example: showSIP 200 or showSIP");
            Console.WriteLine();

            Console.WriteLine("showCallQueue [id]");
            Console.WriteLine("example: showCallQueue 200 or showCallQueue");
            Console.WriteLine();

            Console.WriteLine("deleteConfig -id");
            Console.WriteLine("example: delete -id 200");
            Console.WriteLine();

            Console.WriteLine("help");
            Console.WriteLine("exit");
            Console.WriteLine();
        }

        private static void Exit()
        {
            Environment.Exit(0);
        }

       
        private static string Read(string inputName, bool readWhileEmpty)
        {
            Console.Write(prompt + "" + inputName + ": ");
            while (true)
            {
                var input = Console.ReadLine();

                if (!readWhileEmpty)
                    return input;

                if (!string.IsNullOrEmpty(input))
                    return input;

                Console.WriteLine(inputName + " cannot be empty.");
                Console.Write(inputName + ": ");
            }
        }

        static List<string> GetStringParts(string inputString)
        {
            var retVal = new List<string>();
            string currentPart = string.Empty;
            int lexerState = 0;

            for (int i = 0; i < inputString.Length; i++)
            {
                switch (lexerState)
                {
                    case 0:
                        if (inputString[i] == ' ')
                        {
                            var res = currentPart.Trim();

                            if (res != string.Empty)
                                retVal.Add(currentPart.Trim());

                            currentPart = string.Empty;
                        }
                        else if (inputString[i] == '"')
                            lexerState = 1;
                        else
                            currentPart += inputString[i];
                        break;

                    case 1:
                        if (inputString[i] == '"')
                            lexerState = 0;
                        else
                            currentPart += inputString[i];
                        break;
                }


            }

            if (currentPart != string.Empty)
                retVal.Add(currentPart);

            return retVal;
        }


        static List<KeyValuePair<string, string>> CreateParamValuePairs(List<string> paramList)
        {
            var paramValuePairs = new List<KeyValuePair<string, string>>();
            for (int i = 0; i < paramList.Count; i++)
            {
                var parameter = paramList[i];
                if(isParam(parameter))
                {
                    if(i < paramList.Count -1)
                    {
                        if(isParam(paramList[i + 1]))
                        {
                            paramValuePairs.Add(new KeyValuePair<string, string>(parameter, string.Empty));
                        }
                        else
                        {
                            paramValuePairs.Add(new KeyValuePair<string, string>(parameter, paramList[i + 1]));
                            ++i;
                        }
                    }
                }
            }

            return paramValuePairs;
        }

        static bool isParam(string parameter)
        {
            return parameter[0] == '-';
        }


    }
}
