   plugin = null
   AXIS_MAX = 32767
   DEAD_ZONE = AXIS_MAX * 0.2
+  TRIP_HIGH = AXIS_MAX * 0.75
+  TRIP_LOW = AXIS_MAX * 0.5
 
+  # Raw Joysticks data
+  previousJoysticks = []
   joysticks = []
+
+  controllers = []
 
   buttonMapping =
     "A": 1

    "HOME": 256
    "GUIDE": 256

    "ANY": 0xFFFFFF

  displayInstallPrompt = (text, url) ->

      text: text
    .appendTo("body")

  Controller = (i) ->
    currentState = ->
      joysticks[i]

    previousState = ->
      previousJoysticks[i]

    axisTrips = []

    self = Core().include(Bindable).extend
      actionDown: (buttons...) ->
        if state = currentState()
          buttons.inject false, (down, button) ->
            down || state.buttons & buttonMapping[button]
        else
          false

      # true if button was just pressed
      buttonPressed: (button) ->
        buttonId = buttonMapping[button]

        return (self.buttons() & buttonId) && !(previousState().buttons & buttonId)

      position: (stick=0) ->
        if state = currentState()
          Joysticks.position(state, stick)
        else
          Point(0, 0)

      axis: (n) ->
        self.axes()[n] || 0

      axes: ->
        if state = currentState()
          state.axes
        else
          []

      buttons: ->
        if state = currentState()
          state.buttons

      processEvents: ->
        [x, y] = [0, 1].map (n) ->
          if !axisTrips[n] && self.axis(n).abs() > TRIP_HIGH
            axisTrips[n] = true

            return self.axis(n).sign()

          if axisTrips[n] && self.axis(n).abs() < TRIP_LOW
            axisTrips[n] = false

          return 0

        self.trigger("tap", Point(x, y)) if !x || !y

      drawDebug: (canvas) ->
        lineHeight = 18
        canvas.fillColor("#FFF")

        for axis, i in self.axes()
          canvas.fillText(axis, 0, i * lineHeight)

        canvas.fillText(self.buttons(), 0, i * lineHeight)

  getController: (i) ->
    controllers[i] ||= Controller(i)

  init: ->
    unless plugin
