using System;
using System.Collections;
using Microsoft.DirectX.DirectInput;
using Icarus.Input.ButtonEvents;
using Icarus.Input.MovementEvents;

namespace Icarus.Input {

	/// <summary>
	/// Sorts and adds button and movement events to event queues.
	/// </summary>
	public class QueueEventSorter 	{

        #region Instance Variables
        /// <summary>
        /// List of current keyboard keys that are being held down.
        /// </summary>
        private ArrayList currentKeyboardDownList = new ArrayList();
        /// <summary>
        /// List of current mouse buttons that are being held down.
        /// </summary>
        private ArrayList currentMouseDownList = new ArrayList();
        /// <summary>
        /// List of current joystick buttons that are being held down.
        /// </summary>
        private ArrayList currentJoystickDownList = new ArrayList();
        #endregion

        #region Key and Button Event Adding
        /// <summary>
        /// Takes in a list of new events and determines the current states of each 
        /// and adds them to the current queue.
        /// </summary>
        /// <param name="queue">Current keyboard queue to add new events to.</param>
        /// <param name="events">List of new events to sort and add.</param>
        /// <returns>The updated current keyboard event queue.</returns>
        public ArrayList AddKeyboardEvents(ArrayList queue, Key[] events) {
            ArrayList newDownList = new ArrayList();

            foreach(Key k in events) {
                newDownList.Add(k.ToString());
                if (currentKeyboardDownList.Contains(k.ToString())) {
                    queue.Add(new KeyboardButtonPressEvent(k.ToString(), false, true, false));
                } else {
                    currentKeyboardDownList.Add(k.ToString());
                    queue.Add(new KeyboardButtonPressEvent(k.ToString(), true, false, false));
                }
            }

            foreach (string key in currentKeyboardDownList) {
                if (!newDownList.Contains(key)) {                    
                    queue.Add(new KeyboardButtonPressEvent(key, false, false, true));
                }
            }
            currentKeyboardDownList = newDownList;

            return queue;
        }

        /// <summary>
        /// Takes in a list of new events and determines the current states of each 
        /// and adds them to the current queue.
        /// </summary>
        /// <param name="queue">Current mouse queue to add new events to.</param>
        /// <param name="events">List of new events to sort and add.</param>
        /// <returns>The updated current mouse event queue.</returns>
        public ArrayList AddMouseEvents(ArrayList queue, byte[] events) {
            ArrayList newDownList = new ArrayList();

            for (int i = 0; i < events.Length; i++) {
                string name = "Button:" + i;
                if (events[i] != 0) {                    
                    newDownList.Add(name);
                    if (currentMouseDownList.Contains(name)) {
                        queue.Add(new MouseButtonPressEvent(name, false, true, false));
                    } else {
                        currentMouseDownList.Add(name);
                        queue.Add(new MouseButtonPressEvent(name, true, false, false));
                    }
                }
            }

            foreach (string buttonName in currentMouseDownList) {
                if (!newDownList.Contains(buttonName)) {                    
                    queue.Add(new MouseButtonPressEvent(buttonName, false, false, true));
                }
            }
            currentMouseDownList = newDownList;

            return queue;
        }

        /// <summary>
        /// Takes in a list of new events and determines the current states of each 
        /// and adds them to the current queue.
        /// </summary>
        /// <param name="queue">Current joystick queue to add new events to.</param>
        /// <param name="events">List of new events to sort and add.</param>
        /// <returns>The updated current joystick event queue.</returns>
        public ArrayList AddJoystickEvents(ArrayList queue, byte[] events) {
            ArrayList newDownList = new ArrayList();

            for (int i = 0; i < events.Length; i++) {
                string name = "Button:" + i;
                if (events[i] != 0) {                    
                    newDownList.Add(name);
                    if (currentJoystickDownList.Contains(name)) {
                        queue.Add(new JoystickButtonPressEvent(name, false, true, false));
                    } else {
                        currentJoystickDownList.Add(name);
                        queue.Add(new JoystickButtonPressEvent(name, true, false, false));
                    }
                }
            }

            foreach (string buttonName in currentJoystickDownList) {
                if (!newDownList.Contains(buttonName)) {                    
                    queue.Add(new JoystickButtonPressEvent(buttonName, false, false, true));
                }
            }
            currentJoystickDownList = newDownList;

            return queue;
        }
        #endregion

        #region Movement Event Adding
        /// <summary>
        /// Takes in assorted movement readings from the mouse to create a new event
        /// and add it to the current queue.
        /// </summary>
        /// <param name="queue">Current mouse queue to add new event to.</param>
        /// <param name="dx">Change in x-coordinate.</param>
        /// <param name="dy">Change in y-coordinate.</param>
        /// <param name="dz">Change in z-coordinate.</param>
        /// <returns>The updated current mouse event queue.</returns>
        public ArrayList AddMouseMovementEvent(ArrayList queue, int dx, int dy, int dz) {
            if (dx != 0 || dy != 0 || dz != 0) {
                queue.Add(new MouseMovementEvent(dx, dy, dz));
            }
            return queue;
        }

        /// <summary>
        /// Takes in assorted movement readings from the joystick to create a new event
        /// and add it to the current queue.
        /// </summary>
        /// <param name="queue">Current joystick queue to add new event to.</param>
        /// <param name="dx">Change in x-coordinate.</param>
        /// <param name="dy">Change in y-coordinate.</param>
        /// <param name="dz">Change in z-coordinate.</param>
        /// <returns>The updated current joystick event queue.</returns>
        public ArrayList AddJoystickMovementEvent(ArrayList queue, int dx, int dy, int dz) {
            if (dx != 0 || dy != 0 || dz != 0) {
                queue.Add(new JoystickMovementEvent(dx, dy, dz));
            }
            return queue;
        }
        #endregion

	}
}
