-class window.Candru
+noop = ->
+
+# Borrowing the Emitter from dropzone
+# https://raw.githubusercontent.com/enyo/dropzone/master/src/dropzone.coffee
+class Emitter
+  addEventListener: @::on
+  on: (event, fn) ->
+    @_callbacks = @_callbacks || {}
+    # Create namespace for this event
+    @_callbacks[event] = [] unless @_callbacks[event]
+    @_callbacks[event].push fn
+    return @
+
+
+  emit: (event, args...) ->
+    @_callbacks = @_callbacks || {}
+    callbacks = @_callbacks[event]
+
+    if callbacks
+      callback.apply @, args for callback in callbacks
+
+    return @
+
+  removeListener: @::off
+  removeAllListeners: @::off
+  removeEventListener: @::off
+  off: (event, fn) ->
+    if !@_callbacks || arguments.length == 0
+      @_callbacks = {}
+      return @
+
+    # specific event
+    callbacks = @_callbacks[event]
+    return @ unless callbacks
+
+    # remove all handlers
+    if arguments.length == 1
+      delete @_callbacks[event]
+      return @
+
+    # remove specific handler
+    for callback, i in callbacks
+      if callback == fn
+        callbacks.splice i, 1
+        break
+
+    return @
+
+class window.Candru extends Emitter
   # Define a couple of useful helpers
   extend = (object, properties) ->
     for key, val of properties

    e.preventDefault()
    e.stopPropagation()

    removeClass(this.el, this.defaults.overClass)

    files = e.dataTransfer.files
    for file in files
      if not this.fileTypeCheck(file)
        console.log('Skipping file of type: ', file.type)
        continue

      if not this.fileSizeCheck(file)
        console.log('Skipping file of size: ', file.size)
        continue

      uploadItem = this.defaults.createUploadItem(file, this._index)
      this.el.appendChild(uploadItem)

      if this.defaults.queue
        this._fileQueue.push({
          file: file,
          index: this._index,
          state: 'unprocessed'
        })
      else
        this.defaults.uploadHandler(file, this._index)

      this._index++

    false

  uploadHandler: (file, index) =>
    throw new Error('Evaporate instance is null.') unless this.defaults.evaporate
    evap = this.defaults.evaporate

    evap.add({
      name: this.defaults.sanitizeFilename(file),
      file: file,
      complete: =>
        this.defaults.uploadComplete(file, index)
      progress: (progress) =>
        this.defaults.uploadProgress(progress, file, index)
      info: (message) =>
        this.defaults.uploadInfo(message, file, index)
      warn: (message) =>
        this.defaults.uploadWarn(message, file, index)
      error: (message) =>
        this.defaults.uploadError(message, file, index)
    })

  uploadComplete: (file, index) =>
    this._complete++

    uploadMeter = this.defaults.getMeterEl(index)
    uploadMeter.style.width = '100%' # Sometimes it goes so fast it doesn't get progress before it finishes
    addClass(uploadMeter, this.defaults.uploadSuccessClass)

    cancelEl = this.defaults.getCancelEl(index)
    addClass(cancelEl.querySelector('a'), 'hidden')

  uploadProgress: (progress, file, index) =>
    uploadMeter = this.defaults.getMeterEl(index)
    uploadMeter.style.width = "#{progress * 100.0}%"

  uploadCancel: (file, index) =>
    this._cancelled++

    throw new Error('Evaporate instance is null.') unless this.defaults.evaporate
    evap = this.defaults.evaporate

    uploadMeter = this.defaults.getMeterEl(index)
    addClass(uploadMeter, this.defaults.uploadCancelledClass)
    uploadMeter.style.width = '100%'

    cancelEl = this.defaults.getCancelEl(index)
    addClass(cancelEl.querySelector('a'), 'hidden')

    if this.defaults.queue
      for queuedFile in this._fileQueue
        if queuedFile.index is index
          queuedFile.state = 'cancelled'

    evap.cancel(index)

  uploadInfo: (message, file, index) =>
    if this.defaults.debug
      console.log('INFO: File:', file, 'Index:', index, 'Message:', message)

  uploadWarn: (message, file, index) =>
    if this.defaults.debug
      console.log('WARN: File:', file, 'Index:', index, 'Message:', message)

  uploadError: (message, file, index) =>
    if this.defaults.debug
      console.log('ERROR: File:', file, 'Index:', index, 'Message:', message)

    this._failed++

    uploadMeter = this.getMeterEl(index)
    addClass(uploadMeter, this.defaults.uploadFailedClass)

  processQueue: ->
    return false unless this.defaults.queue

    for queuedFile in this._fileQueue
      if queuedFile.state is 'unprocessed'
        this.defaults.uploadHandler(queuedFile.file, queuedFile.index)
        queuedFile.state = 'processed'
      else

  cancelAll: ->
    cancelTriggers = this.el.querySelectorAll(this.defaults.cancelSelector + ' a')

    # Fake the cancel click
    for trigger in cancelTriggers
      console.log(trigger, hasClass(trigger, 'hidden'))
      trigger.click() unless hasClass(trigger, 'hidden')

    # Clear up the queue
    if this.defaults.queue
      for queuedFile in this._fileQueue
        if queuedFile.state is 'unprocessed'
          queuedFile.state = 'cancelled'

  getFileCount: ->
    return this._index

  allFilesFinished: ->
    return this._index == (this._complete + this._failed + this._cancelled)


  getMeterEl: (index) =>
    uploadMeterSelector = ".candru [data-upload-id=\"#{index}\"] .meter"
    return @el.querySelector(uploadMeterSelector)

  getCancelEl: (index) =>
    uploadMeterSelector = ".candru [data-upload-id=\"#{index}\"] .cancel"
    return @el.querySelector(uploadMeterSelector)

  createUploadItem: (file, index) =>
    uploadItem = document.createElement('div')
