# on why local storage is used in the enter events
# http://stackoverflow.com/questions/8762635/getting-the-filename-during-the-dragenter-event
DragNDrop = Ember.Namespace.create
  cancel: (e)->
    e.preventDefault()
    false
  nothing: ->

DragNDrop.Draggable = Ember.Mixin.create
  attributeBindings: 'draggable'
  draggable: 'true'
  dragStart: (ev)->
    @set 'isDragging', true
    @set 'globals.isDragging', true
    localStorage.setItem('draggingView', @get('elementId'))
    dataTransfer = ev.originalEvent.dataTransfer
    #dataTransfer.setData 'Text', @get('elementId')
    offset = $(ev.target).offset()
    dataTransfer.setData 'application/json', JSON.stringify
      id: @get('elementId')
      elementX: (ev.originalEvent.offsetX || ev.originalEvent.clientX) - offset.left
      elementY: (ev.originalEvent.offsetY || ev.originalEvent.clientY) - offset.top
      pageX: ev.originalEvent.pageX
      pageY: ev.originalEvent.pageY
  dragEnd: (e)->
    @set 'isDragging', false
    @set 'globals.isDragging', false
    localStorage.removeItem 'draggingView' if localStorage.getItem 'draggingView'
  touchStart: (ev)->
    ev.preventDefault()
    target = @$()
    touch = ev.originalEvent.changedTouches[0]
    @touchStartEvent =
      left: parseFloat(target.css('left'))
      top: parseFloat(target.css('top'))
      pageX: touch.pageX
      pageY: touch.pageY
    return unless target.prop 'draggable'

  touchMove: (ev)->
    ev.preventDefault()
    target = @$()
    return unless target.prop 'draggable'
    if ev.originalEvent.changedTouches.length is 1
      touch = ev.originalEvent.changedTouches[0]
      target.css
        left: "#{@touchStartEvent.left + touch.pageX - @touchStartEvent.pageX}px"
        top: "#{@touchStartEvent.top + touch.pageY - @touchStartEvent.pageY}px"
  touchEnd: (ev)->
    ev.preventDefault()
    touch = ev.originalEvent.changedTouches[0]
    if Math.abs(@touchStartEvent.pageX - touch.pageX) < 2 and Math.abs(@touchStartEvent.pageY - touch.pageY) < 2
      # The preventDefaults are preventing the click action to fire, therefore we trigger it ourselves
      # But do not trigger when a handle insed the element is clicked
      #NOTE: I think that $(ev.target).click() will work for all cases, makes the code simpler,
      # but no time to test that now. Tested mostly on section elements, since they are draggable, clickable
      # and have subclickable buttons
      unless $(ev.target).parents('.handles-inside-draggable') or $(ev.target).hasClass('handles-inside-draggable')
        @click() if @click
      else
        $(ev.target).click()

    @touchStartEvent = null
    this
DragNDrop.Droppable = Ember.Mixin.create
  dragEnter: (e)->
    if @dragEntered
      # e.preventDefault()
      viewId = localStorage.getItem 'draggingView'
      view = Ember.View.views[viewId]
      @dragEntered view
    # else
    #   DragNDrop.cancel(e)
  dragOver: DragNDrop.cancel # don't know why, but crucial for the current way of working with section tables
  # dragOver: (e)->(e.preventDefault(); false)
  touchEnd: (ev)->
    ev.preventDefault()
    view = ev.result
    return unless view._parentView
    target = view.$()
    return unless target.prop 'draggable'
    newX = parseFloat(target.css('left'))
    newY = parseFloat(target.css('top'))
    return unless newX? and newY?
    position =
      left: newX
      top: newY
    @dropped view, position if @dropped
    this
  dragLeave: ->
    if @dragLeft
      @dragLeft()
  drop: (ev)->
    # e.preventDefault()
    data = JSON.parse(ev.originalEvent.dataTransfer.getData('application/json'))
    #debugger
    viewRegistry = App.__container__.lookup("-view-registry:main") || Ember.View.views
    #view = Ember.View.views[data.id]
    return unless viewRegistry and view = viewRegistry[data.id]
    view.dragEnd(ev) if view.dragEnd # not triggered on its own on drop

    # Calculate the element's center drop position relative to container
    el = $(view.get('element'))
    offset = el.offset()
    parentOffset = el.offsetParent().offset()
    newX = offset.left - parentOffset.left + ev.originalEvent.pageX - data.pageX
    newY = offset.top - parentOffset.top + ev.originalEvent.pageY - data.pageY
    position =
      left: newX
      top: newY

    @dropped view, position if @dropped
    @dragLeft() if @dragLeft # not triggered by system itself in case of drop
    false

@DragNDrop = DragNDrop
