using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using Icarus.Input.ButtonEvents;

namespace Icarus.Input {
    /// <summary>
    /// Summary description for InputTester.
    /// </summary>
    public class InputTester : System.Windows.Forms.Form {

        #region GUI Components
        private System.Windows.Forms.TextBox keyboardDisplay;
        private System.Windows.Forms.TextBox mouseDisplay;
        private System.Windows.Forms.TextBox joystickDisplay;
        private System.Windows.Forms.Label keyboardLabel;
        private System.Windows.Forms.Label mouseLabel;
        private System.Windows.Forms.Label joystickLabel;        
        private System.Windows.Forms.Button startButton;
        private System.Windows.Forms.Button stopButton;
        private System.Windows.Forms.TextBox keyTextBox;
        private System.Windows.Forms.ComboBox keyComboBox;
        private System.Windows.Forms.Button keyButton;
        private System.Windows.Forms.Button mouseButton;
        private System.Windows.Forms.ComboBox mouseComboBox;
        private System.Windows.Forms.TextBox mouseTextBox;
        private System.Windows.Forms.Button joystickButton;
        private System.Windows.Forms.ComboBox joystickComboBox;
        private System.Windows.Forms.TextBox joystickTextBox;
        private System.ComponentModel.Container components = null;
        #endregion

        #region Instance Variables
        /// <summary>
        /// The singleton input engine.
        /// </summary>
        private InputEngine engine = null;        
        /// <summary>
        /// Thread that constantly polls for input received.
        /// </summary>
        private Thread listenLoopThread = null;
        #endregion

        #region Execution
        /// <summary>
        /// Executes this tester form.
        /// </summary>
        public static void Main() {
            Console.WriteLine("You are now running the tester program for the InputEngine of the Icarus Game Engine");
            new InputTester().Show();      
        }

        /// <summary>
        /// Constructor for this Tester Form.
        /// </summary>
        public InputTester() {
            // Required for Windows Form Designer support
            InitializeComponent();
            fillComboBox(keyComboBox);
            fillComboBox(mouseComboBox);
            fillComboBox(joystickComboBox);
            engine = InputEngine.Instance;
            engine.Initialize(this);
        }

        /// <summary>
        /// Adds various test commands to be bound for testing.
        /// </summary>
        /// <param name="cBox">The comboBox to add these commands to.</param>
        private void fillComboBox(ComboBox cBox) {
            cBox.Items.Add("<DO NOTHING>");
            cBox.Items.Add("Red");
            cBox.Items.Add("Blue");
            cBox.Items.Add("Green");
            cBox.Items.Add("Yellow");
            cBox.Items.Add("Magenta");
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing ) {
            if( disposing ) {
                if(components != null) {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
            stopListening();
            Console.WriteLine("You have exited the tester program for the InputEngine of the Icarus Game Engine.");
            Console.WriteLine("Have A Nice Day!");    
        }
        #endregion

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent() {
            this.keyboardDisplay = new System.Windows.Forms.TextBox();
            this.mouseDisplay = new System.Windows.Forms.TextBox();
            this.joystickDisplay = new System.Windows.Forms.TextBox();
            this.keyboardLabel = new System.Windows.Forms.Label();
            this.mouseLabel = new System.Windows.Forms.Label();
            this.joystickLabel = new System.Windows.Forms.Label();
            this.startButton = new System.Windows.Forms.Button();
            this.stopButton = new System.Windows.Forms.Button();
            this.keyTextBox = new System.Windows.Forms.TextBox();
            this.keyComboBox = new System.Windows.Forms.ComboBox();
            this.keyButton = new System.Windows.Forms.Button();
            this.mouseButton = new System.Windows.Forms.Button();
            this.mouseComboBox = new System.Windows.Forms.ComboBox();
            this.mouseTextBox = new System.Windows.Forms.TextBox();
            this.joystickButton = new System.Windows.Forms.Button();
            this.joystickComboBox = new System.Windows.Forms.ComboBox();
            this.joystickTextBox = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // keyboardDisplay
            // 
            this.keyboardDisplay.Location = new System.Drawing.Point(32, 40);
            this.keyboardDisplay.Multiline = true;
            this.keyboardDisplay.Name = "keyboardDisplay";
            this.keyboardDisplay.ReadOnly = true;
            this.keyboardDisplay.Size = new System.Drawing.Size(272, 80);
            this.keyboardDisplay.TabIndex = 0;
            this.keyboardDisplay.Text = "";
            // 
            // mouseDisplay
            // 
            this.mouseDisplay.Location = new System.Drawing.Point(32, 168);
            this.mouseDisplay.Multiline = true;
            this.mouseDisplay.Name = "mouseDisplay";
            this.mouseDisplay.ReadOnly = true;
            this.mouseDisplay.Size = new System.Drawing.Size(272, 80);
            this.mouseDisplay.TabIndex = 1;
            this.mouseDisplay.Text = "";
            // 
            // joystickDisplay
            // 
            this.joystickDisplay.Location = new System.Drawing.Point(32, 296);
            this.joystickDisplay.Multiline = true;
            this.joystickDisplay.Name = "joystickDisplay";
            this.joystickDisplay.ReadOnly = true;
            this.joystickDisplay.Size = new System.Drawing.Size(272, 80);
            this.joystickDisplay.TabIndex = 2;
            this.joystickDisplay.Text = "";
            // 
            // keyboardLabel
            // 
            this.keyboardLabel.Location = new System.Drawing.Point(32, 16);
            this.keyboardLabel.Name = "keyboardLabel";
            this.keyboardLabel.Size = new System.Drawing.Size(88, 23);
            this.keyboardLabel.TabIndex = 3;
            this.keyboardLabel.Text = "Keyboard Input:";
            this.keyboardLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // mouseLabel
            // 
            this.mouseLabel.Location = new System.Drawing.Point(32, 144);
            this.mouseLabel.Name = "mouseLabel";
            this.mouseLabel.Size = new System.Drawing.Size(72, 23);
            this.mouseLabel.TabIndex = 4;
            this.mouseLabel.Text = "Mouse Input:";
            this.mouseLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // joystickLabel
            // 
            this.joystickLabel.Location = new System.Drawing.Point(32, 272);
            this.joystickLabel.Name = "joystickLabel";
            this.joystickLabel.Size = new System.Drawing.Size(80, 23);
            this.joystickLabel.TabIndex = 5;
            this.joystickLabel.Text = "Joystick Input:";
            this.joystickLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // startButton
            // 
            this.startButton.Location = new System.Drawing.Point(72, 400);
            this.startButton.Name = "startButton";
            this.startButton.Size = new System.Drawing.Size(88, 23);
            this.startButton.TabIndex = 6;
            this.startButton.Text = "Start Listening";
            this.startButton.Click += new System.EventHandler(this.startButton_Click);
            // 
            // stopButton
            // 
            this.stopButton.Location = new System.Drawing.Point(176, 400);
            this.stopButton.Name = "stopButton";
            this.stopButton.Size = new System.Drawing.Size(88, 23);
            this.stopButton.TabIndex = 7;
            this.stopButton.Text = "Stop Listening";
            this.stopButton.Click += new System.EventHandler(this.stopButton_Click);
            // 
            // keyTextBox
            // 
            this.keyTextBox.Location = new System.Drawing.Point(320, 40);
            this.keyTextBox.Name = "keyTextBox";
            this.keyTextBox.TabIndex = 8;
            this.keyTextBox.Text = "<Key Name>";
            // 
            // keyComboBox
            // 
            this.keyComboBox.Location = new System.Drawing.Point(320, 72);
            this.keyComboBox.Name = "keyComboBox";
            this.keyComboBox.Size = new System.Drawing.Size(104, 21);
            this.keyComboBox.TabIndex = 9;
            this.keyComboBox.Text = "<Action>";
            // 
            // keyButton
            // 
            this.keyButton.Location = new System.Drawing.Point(328, 104);
            this.keyButton.Name = "keyButton";
            this.keyButton.TabIndex = 10;
            this.keyButton.Text = "Bind Key";
            this.keyButton.Click += new System.EventHandler(this.keyButton_Click);
            // 
            // mouseButton
            // 
            this.mouseButton.Location = new System.Drawing.Point(328, 232);
            this.mouseButton.Name = "mouseButton";
            this.mouseButton.TabIndex = 13;
            this.mouseButton.Text = "Bind Button";
            this.mouseButton.Click += new System.EventHandler(this.mouseButton_Click);
            // 
            // mouseComboBox
            // 
            this.mouseComboBox.Location = new System.Drawing.Point(320, 200);
            this.mouseComboBox.Name = "mouseComboBox";
            this.mouseComboBox.Size = new System.Drawing.Size(104, 21);
            this.mouseComboBox.TabIndex = 12;
            this.mouseComboBox.Text = "<Action>";
            // 
            // mouseTextBox
            // 
            this.mouseTextBox.Location = new System.Drawing.Point(320, 168);
            this.mouseTextBox.Name = "mouseTextBox";
            this.mouseTextBox.TabIndex = 11;
            this.mouseTextBox.Text = "<Button Name>";
            // 
            // joystickButton
            // 
            this.joystickButton.Location = new System.Drawing.Point(328, 360);
            this.joystickButton.Name = "joystickButton";
            this.joystickButton.TabIndex = 16;
            this.joystickButton.Text = "Bind Button";
            this.joystickButton.Click += new System.EventHandler(this.joystickButton_Click);
            // 
            // joystickComboBox
            // 
            this.joystickComboBox.Location = new System.Drawing.Point(320, 328);
            this.joystickComboBox.Name = "joystickComboBox";
            this.joystickComboBox.Size = new System.Drawing.Size(104, 21);
            this.joystickComboBox.TabIndex = 15;
            this.joystickComboBox.Text = "<Action>";
            // 
            // joystickTextBox
            // 
            this.joystickTextBox.Location = new System.Drawing.Point(320, 296);
            this.joystickTextBox.Name = "joystickTextBox";
            this.joystickTextBox.TabIndex = 14;
            this.joystickTextBox.Text = "<Button Name>";
            // 
            // InputTester
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(440, 446);
            this.Controls.Add(this.joystickButton);
            this.Controls.Add(this.joystickComboBox);
            this.Controls.Add(this.joystickTextBox);
            this.Controls.Add(this.mouseButton);
            this.Controls.Add(this.mouseComboBox);
            this.Controls.Add(this.mouseTextBox);
            this.Controls.Add(this.keyButton);
            this.Controls.Add(this.keyComboBox);
            this.Controls.Add(this.keyTextBox);
            this.Controls.Add(this.stopButton);
            this.Controls.Add(this.startButton);
            this.Controls.Add(this.joystickLabel);
            this.Controls.Add(this.mouseLabel);
            this.Controls.Add(this.keyboardLabel);
            this.Controls.Add(this.joystickDisplay);
            this.Controls.Add(this.mouseDisplay);
            this.Controls.Add(this.keyboardDisplay);
            this.Name = "InputTester";
            this.Text = "InputTester";
            this.ResumeLayout(false);

        }
        #endregion

        #region Input Listening Thread Operations
        /// <summary>
        /// Method executed by the thread, that loops forever 
        /// polling the InputEngine for any input received.
        /// </summary>
        private void LoopAndListen() {
            string key = null;
            string action = null;

			engine.StartListening();
            while (true) {
                ArrayList keyboardQueue = engine.KeyboardEventQueue;
                foreach (object keyEvent in keyboardQueue) {
                    keyboardDisplay.AppendText(keyEvent.ToString() + " ");
                    if (keyEvent is KeyboardButtonPressEvent) {
                        key = ((KeyboardButtonPressEvent) keyEvent).Name;
                        action = engine.getKeyAction(key);
                        performAction(action, keyboardDisplay);
                    }
                }

                ArrayList mouseQueue = engine.MouseEventQueue;
                foreach (object mouseEvent in mouseQueue) {
                    mouseDisplay.AppendText(mouseEvent.ToString() + " ");                    
                    if (mouseEvent is MouseButtonPressEvent) {
                        key = ((MouseButtonPressEvent) mouseEvent).Name;
                        action = engine.getMouseButtonAction(key);
                        performAction(action, mouseDisplay);
                    }
                }

                ArrayList joystickQueue = engine.JoystickEventQueue;
                foreach (object joystickEvent in joystickQueue) {
                    joystickDisplay.AppendText(joystickEvent.ToString() + " ");
                    if (joystickEvent is JoystickButtonPressEvent) {
                        key = ((JoystickButtonPressEvent) joystickEvent).Name;
                        action = engine.getJoystickButtonAction(key);
                        performAction(action, joystickDisplay);
                    }
                }

                Thread.Sleep(1000);
				keyboardDisplay.Text = "";
				mouseDisplay.Text = "";
				joystickDisplay.Text = "";
            }
        }

        private void performAction(string action, TextBox display) {            
            if(action == "Red") {
                display.BackColor = Color.Red;
            } else if(action == "Blue") {
                display.BackColor = Color.Blue;
            } else if(action == "Green") {
                display.BackColor = Color.Lime;
            } else if(action == "Yellow") {
                display.BackColor = Color.Yellow;
            } else if(action == "Magenta") {
                display.BackColor = Color.Magenta;
            } else {
                display.BackColor = Color.White;
            }
        }

        private string getFirstKeyInput(string input) {
            input = input.Substring("Keyboard:".Length, input.Length - ("Keyboard:".Length));
            input = input.TrimStart(' ');
            if (input.IndexOf(" ") > 0) {
                input = input.Substring(0, input.IndexOf(" "));                
                return input;
            } else {
                return null;
            }
        }

        private string getFirstButtonInput(string input) {
            int start = input.IndexOf("Button:");
            if (start > 0) {
                start += "Button:".Length;
                input = input.Substring(start, input.Length - start);
                if (input.IndexOf("Button:") > 0) {
                    input = input.Substring(0, input.IndexOf("Button:"));
                }
                input = input.Trim();
                return input;
            } else {
                return null;
            }
        }

        /// <summary>
        /// Stop the thread from looping and polling the InputEngine.
        /// </summary>
        public void stopListening() {
            if (listenLoopThread != null) {
				engine.StopListening();
                listenLoopThread.Abort();
                listenLoopThread = null;
            }      
        }

        /// <summary>
        /// Starts the thread looping and polling the InputEngine.
        /// </summary>    
        public void startListening() {      
            if (listenLoopThread == null) {
                listenLoopThread = new Thread(new ThreadStart(LoopAndListen));
                listenLoopThread.Start();
            }
        }
        #endregion

        #region Button Click Methods
        private void startButton_Click(object sender, System.EventArgs e) {
            startListening();
        }

        private void stopButton_Click(object sender, System.EventArgs e) {
            stopListening();
        }
        
        private void keyButton_Click(object sender, System.EventArgs e) {
            string action = (string) keyComboBox.SelectedItem;
            if (action == "<DO NOTHING>") {
                action = null;
            }
            engine.bindKey(keyTextBox.Text, action);
        }

        private void mouseButton_Click(object sender, System.EventArgs e) {
            string action = (string) mouseComboBox.SelectedItem;
            if (action == "<DO NOTHING>") {
                action = null;
            }
            engine.bindMouseButton(mouseTextBox.Text, action);
        }

        private void joystickButton_Click(object sender, System.EventArgs e) {
            string action = (string) joystickComboBox.SelectedItem;
            if (action == "<DO NOTHING>") {
                action = null;
            }
            engine.bindJoystickButton(joystickTextBox.Text, action);
        }
        #endregion
    }
}
