using UnityEngine;
namespace Passer {
    public enum GameControllers {
        Generic,
        Xbox,
        PS4,
        Steelseries,
        GameSmart,
        Oculus,
        OpenVR,
#if hDAYDREAM && UNITY_ANDROID
        Daydream
#endif
    }
    /// Controller input for all controllers
    /// Max 4 controllers are supports
    public static class Controllers {
        private static int maxControllers = 4;
        /// Array containing all controllers
        public static Controller[] controllers;
        /// Update the current values of the controller input
        public static void Update() {
            if (controllers != null) {
                for (int i = 0; i < controllers.Length; i++) {
                    if (controllers[i] != null)
                        controllers[i].Update();
                }
            }
        }
        /// Retrieves a controller and creates it when it is first accessed
        /// The index of the controller
        public static Controller GetController(int controllerID) {
            if (controllers == null)
                controllers = new Controller[maxControllers];
            if (controllers[controllerID] == null)
                controllers[controllerID] = new Controller();            
       
            return controllers[controllerID];
        }
        /// Reset the values of all buttons
        public static void Clear() {
            if (controllers != null) {
                for (int i = 0; i < controllers.Length; i++) {
                    if (controllers[i] != null)
                        controllers[i].Clear();
                }
            }
        }
        /// Called at the end of the frame to indicate that new controller values can be read
        public static void EndFrame() {
            if (controllers != null) {
                for (int i = 0; i < controllers.Length; i++)
                    if (controllers[i] != null)
                        controllers[i].EndFrame();
            }
        }
    }
    /// Controller input for a single controller
    public class Controller {
        /// Identification for the left or right side of the controller
        public enum Side {
            Left,
            Right
        }
        /// Button identification values
        public enum Button {
            ButtonOne = 0,
            ButtonTwo = 1,
            ButtonThree = 2,
            ButtonFour = 3,
            Bumper = 10,
            BumperTouch = 11,
            Trigger = 12,
            TriggerTouch = 13,
            StickButton = 14,
            StickTouch = 15,
            //Up = 20,
            //Down = 21,
            //Left = 22,
            //Right = 23,
            Option = 30,
            None = 9999
        }
        /// The left side of the controller
        public ControllerSide left;
        /// The right side of the controller
        public ControllerSide right;
        /// Update the current values of the controller input
        public void Update() {
            left.Update();
            right.Update();
        }
        /// Constructor for access to the controller input
        public Controller() {
            left = new ControllerSide();
            right = new ControllerSide();
        }
        private bool cleared;
        /// Reset the values of all buttons
        public void Clear() {
            if (cleared)
                return;
            cleared = true;
            left.Clear();
            right.Clear();
        }
        /// Called at the end of the frame to indicate that new controller values can be read
        public void EndFrame() {
            cleared = false;
        }
        /// Retrieve the pressed state of a button
        /// The identification of the side of the controller
        /// The identification of the requested button
        public bool GetButton(Side side, Button buttonID) {
            switch (side) {
                case Side.Left:
                    return left.GetButton(buttonID);
                case Side.Right:
                    return right.GetButton(buttonID);
                default:
                    return false;
            }
        }
    }
    /// Controller input for the left or right side of the controller (pair)
    public class ControllerSide {
        /// The vertical value of the thumbstick
        /// Values: -1..1
        public float stickHorizontal;
        /// The horizontal value of the thumbstick
        /// Values: -1..1
        public float stickVertical;
        /// The pressed state of the thumbstick
        public bool stickButton;
        /// The touched state of the thumbstick
        public bool stickTouch;
        /// The vertical value of the touchpad
        /// Values: -1..1
        public float touchpadVertical;
        /// The horizontal value of the touchpad
        /// Values: -1..1
        public float touchpadHorizontal;
        /// The pressed state of the touchpad
        public bool touchpadPress;
        /// The touched state of the touchpad
        public bool touchpadTouch;
        /// The pressed state of genertic buttons
        /// There can be up to 4 generic buttons.
        /// buttons[0] usually mathes the default fire button
        public bool[] buttons = new bool[4];
        /// The value of the first trigger
        /// Values: 0..1
        /// The first trigger is normally operated with the index finger
        public float trigger1;
        /// The value of the second trigger
        /// Values: 0..1
        /// The second trigger is normally operated with the middle finger
        public float trigger2;
        /// The pressed state of the option button
        /// The option button is usually a special button for accessing a specific menu
        public bool option;
        /// Event for handling Button down events
        public event OnButtonDown OnButtonDownEvent;
        /// Event for handling Button up events
        public event OnButtonUp OnButtonUpEvent;
        /// Function for processing button down events
        /// The idetification of the pressed button
        public delegate void OnButtonDown(Controller.Button buttonNr);
        /// Function for processing button up events
        /// The identification of the released button
        public delegate void OnButtonUp(Controller.Button buttonNr);
        private bool[] lastButtons = new bool[4];
        private bool lastBumper;
        private bool lastTrigger;
        private bool lastStickButton;
        private bool lastOption;
        /// Update the current values of the controller input
        public void Update() {
            for (int i = 0; i < 4; i++) {
                if (buttons[i] && !lastButtons[i]) {
                    if (OnButtonDownEvent != null)
                        OnButtonDownEvent((Controller.Button) i);
                } else if (!buttons[i] && lastButtons[i]) {
                    if (OnButtonUpEvent != null)
                        OnButtonUpEvent((Controller.Button) i);
                }
                lastButtons[i] = buttons[i];
            }
            if (trigger1 > 0.9F && !lastBumper) {
                if (OnButtonDownEvent != null)
                    OnButtonDownEvent(Controller.Button.Bumper);
                lastBumper = true;
            } else if (trigger1 < 0.1F && lastBumper) {
                if (OnButtonUpEvent != null)
                    OnButtonUpEvent(Controller.Button.Bumper);
                lastBumper = false;
            }
            if (trigger2 > 0.9F && !lastTrigger) {
                if (OnButtonDownEvent != null)
                    OnButtonDownEvent(Controller.Button.Trigger);
                lastTrigger = true;
            } else if (trigger2 < 0.1F && lastTrigger) {
                if (OnButtonUpEvent != null)
                    OnButtonUpEvent(Controller.Button.Trigger);
                lastTrigger = false;
            }
            if (stickButton && !lastStickButton) {
                if (OnButtonDownEvent != null)
                    OnButtonDownEvent(Controller.Button.StickButton);
            } else if (!stickButton && lastStickButton) {
                if (OnButtonUpEvent != null)
                    OnButtonUpEvent(Controller.Button.StickButton);
            }
            lastStickButton = stickButton;
            if (option && !lastOption) {
                if (OnButtonDownEvent != null)
                    OnButtonDownEvent(Controller.Button.Option);
            } else if (!option && lastOption) {
                if (OnButtonUpEvent != null)
                    OnButtonUpEvent(Controller.Button.Option);
            }
            lastOption = option;
        }
        /// Reset the values of all buttons
        public void Clear() {
            stickHorizontal = 0;
            stickVertical = 0;
            stickButton = false;
            stickTouch = false;
            touchpadHorizontal = 0;
            touchpadVertical = 0;
            touchpadPress = false;
            touchpadTouch = false;
            for (int i = 0; i < 4; i++)
                buttons[i] = false;
            trigger1 = 0;
            trigger2 = 0;
            option = false;
        }
        /// Retrieve the pressed state of a button
        /// The identification of the requested button
        public bool GetButton(Controller.Button buttonID) {
            switch (buttonID) {
                case Controller.Button.ButtonOne:
                    return buttons[0];
                case Controller.Button.ButtonTwo:
                    return buttons[1];
                case Controller.Button.ButtonThree:
                    return buttons[2];
                case Controller.Button.ButtonFour:
                    return buttons[3];
                case Controller.Button.Bumper:
                    return trigger1 > 0.9F;
                case Controller.Button.Trigger:
                    return trigger2 > 0.9F;
                case Controller.Button.StickButton:
                    return stickButton;
                case Controller.Button.StickTouch:
                    return stickTouch;
                case Controller.Button.Option:
                    return option;
                default:
                    return false;
            }
        }
    }
}