
function DragFilesTool(options) {
  options = $.extend(true, {
    i18n: {
      copy: 'Copy',
      move: 'Move',
      remove: 'Delete',
      confirm_remove: 'Delete items ?'
    }
  }, options)
  
  var isMouseDown = false
  var selectedObject = {}
  var destDir = 0
  var div = null
  var menu = null
  var mouseCoordinates = {}
  var cursorOffset = 5
  var mouseDownCoordinates = {}
  var dragFlag = false


  function fixEvent(e) {
    // Calculate pageX/Y if missing and clientX/Y available
    // note: IE seems to be the only one that needs this because
    //       jQuery will add it for others. Don't know why not
    //       for IE.
    if (e.pageX == null && e.clientX != null) {
      var e = document.documentElement, b = document.body;
      e.pageX = e.clientX + (e && e.scrollLeft || b.scrollLeft || 0);
      e.pageY = e.clientY + (e && e.scrollTop || b.scrollTop || 0);
    }

    return e;
  }

  function stopEvent(e) {
    if (e.stopPropagation) e.stopPropagation()
    else e.cancelBubble = true
    if (e.preventDefault) e.preventDefault()
    else e.returnValue = false
  }

  function callback(data) {
    if (data.success) {
      AccountFacade.reloadCurrentDir()
      AccountFacade.reloadFolderTree()
    } else  if(data.errorMessage!=null) alert(data.errorMessage)
  }

  function doCopy() {
    if (selectedObject.type == 'folder') {
      AccountFacade.copy(null, selectedObject.id, destDir, callback)
    } else {
      AccountFacade.copy(selectedObject.id, null, destDir, callback)
    }
    hideMenu()
    isMouseDown = false
    dragFlag = false

    DragFilesTool.log('[copy click]')
    return false
  }

  function doMove() {
    if (selectedObject.type == 'folder') {
      AccountFacade.move(null, selectedObject.id, destDir, callback)
    } else {
      AccountFacade.move(selectedObject.id, null, destDir, callback)
    }
    hideMenu()
    isMouseDown = false
    dragFlag = false

    DragFilesTool.log('[move click]')
    return false
  }

  function doRemove() {
    if (!confirm(options.i18n.confirm_remove)) return

    if (selectedObject.type == 'folder') {
      AccountFacade.remove(null, selectedObject.id, callback)
    } else {
      AccountFacade.remove(selectedObject.id, null, callback)
    }
    hideMenu()
    isMouseDown = false
    dragFlag = false

    return false
  }

  function distance(coords1, coords2) {
    return Math.sqrt(Math.pow(coords1.x - coords2.x, 2) + Math.pow(coords1.y - coords2.y, 2))
  }

  $(document.body).mousedown(function(e) {
    DragFilesTool.log('[document.body mousedown]')

    Utils.fixEventCoords(e)
    mouseDownCoordinates = {
      x: e.pageX,
      y: e.pageY
    }

    if ($(e.target).hasClass('dragDropCopy')) {
      DragFilesTool.log('[target == copy]')
      doCopy()
      return true
    }
    
    if ($(e.target).hasClass('dragDropMove')) {
      DragFilesTool.log('[target == move]')
      doMove()
      return true
    }

    if ($(e.target).hasClass('dragDropRemove')) {
      DragFilesTool.log('[target == remove]')
      doRemove()
      return true
    }

    isMouseDown = false
    hideDragDiv()
    hideMenu()

    //stopEvent(e)
    return true
  })

  $(document.body).mouseup(function() {
    isMouseDown = false
    setDefaultCursor()
    hideDragDiv()
    hideMenu()
    dragFlag = false

    DragFilesTool.log('[document.body mouseup]')
    DragFilesTool.dir(selectedObject)
  })

  $(window).mouseup(function() {
    isMouseDown = false
    setDefaultCursor()
    hideDragDiv()
    hideMenu()
    dragFlag = false

    DragFilesTool.log('[window mouseup]')
    DragFilesTool.dir(selectedObject)
  })

  var copy = $('<a>').attr('href', '#')
                     .css({zIndex: '2000'})
                     .addClass('dragDropCopy')
                     .html('<img alt="Copy" class="icon16 fcopy" src="/images/spacer.gif"> ' + options.i18n.copy)

  var move = $('<a>').attr('href', '#')
                     .css({zIndex: '2000'})
                     .addClass('dragDropMove')
                     .html('<img alt="Move" class="icon16 fmove" src="/images/spacer.gif"> ' + options.i18n.move)

  var remove = $('<a>').attr('href', '#')
                       .css({zIndex: '2000'})
                       .addClass('dragDropRemove')
                       .html('<img alt="Move" class="icon16 fmove" src="/images/spacer.gif"> ' + options.i18n.remove)

  function extractData(element) {
    var id = element.attr('id')
    var match = /ml_(\w+)_(\d+)/i.exec(id)
    if (!match) return false

    return {
      name: $(this).html(),
      type: match[1],
      id: match[2]
    }
  }

  function setDragCursor() {
    //$(document.body).css('cursor', 'url("http://www.test4shared.com:8080/images/icons/closedhand.cur.ico")')
    //$(document.body).css('cursor', 'crosshair')
    $(document.body).css('cursor', 'url("/images/icons/closedhand.cur.ico")')
    //$('a').css('cursor', 'crosshair')
  }

  function setDefaultCursor() {
    $(document.body).css('cursor', 'auto')
    //$('a').css('cursor', 'auto');
  }

  function showDragDiv(filename) {
    if (div) return

    div = $('<div>').css({
      fontSize: '12px',
      position: 'absolute',
      left: (mouseCoordinates.x + cursorOffset) + 'px',
      top: (mouseCoordinates.y + cursorOffset) + 'px',
      backgroundColor: 'white',
      border: '1px solid gray',
      padding: '5px',
      width: '200px',
      display: 'none',
      zIndex: '2000'
    })
    .html(filename)
    $(document.body).append(div)
    $(window).css('cursor', 'move')
  }

  function hideDragDiv() {
    if (!div) return
    div.remove()
    div = null
  }

  function showMenu(buttons) {
    if (menu) return

    menu = $('<div>').css({
      position: 'absolute',
      left: mouseCoordinates.x + 'px',
      top: mouseCoordinates.y + 'px',
      backgroundColor: 'white',
      zIndex: '2000'
    })
    .addClass('dragDropMenu')
    .addClass('cmenudiv')
    .mouseup(function() {
      $('#filespace').mouseup()
    })

    var ul = $('<ul>')
             .addClass('cmenu')
    if (buttons.remove) {
      var li = $('<li>')
      li.append(remove)
      ul.append(li)
    } else {
      if (buttons.copy) {
        var li = $('<li style="display: inline;">')
        li.append(copy)
        ul.append(li)
      }

      if (buttons.move) {
        var li = $('<li>')
        li.append(move)
        ul.append(li)
      }
    }

    menu.append(ul)

    $(document.body).append(menu)
    menu.show()

    mouseDownCoordinates = null
    dragFlag = false
  }

  function hideMenu() {
    if (!menu) return
    menu.remove()
    menu = null

    mouseDownCoordinates = null
    dragFlag = false
  }

  $(document).mousemove(function(e) {
    Utils.fixEventCoords(e)

    mouseCoordinates = {
      x: e.pageX,
      y: e.pageY
    }

    if (!mouseDownCoordinates) return
    if (!dragFlag && distance(mouseCoordinates, mouseDownCoordinates) > 35) {
      dragFlag = true
    }
    if (!dragFlag) return

    if (!isMouseDown) return
    if (!div) return
    if (!div.is(':visible')) div.show()

    var left = (mouseCoordinates.x + cursorOffset)
    var top = (mouseCoordinates.y + cursorOffset)

    if (left + div.width() > $(window).width()) {
      left += -div.width() - 2 * cursorOffset
    }
    if (top + div.height() > $(window).height()) {
      top += -div.height() - 2 * cursorOffset
    }

    div.css({
      left: left + 'px',
      top: top + 'px'
    })

    stopEvent(e)
    return false
  })

  function initDOMEvents() {
    DragFilesTool.log('[initDOMEvents]')
    
    $('a', '.filelistname').mousedown(function(e) {
      DragFilesTool.log('[a mousedown] e.which = ' + e.which)
      if (e.which != 1) return true

      Utils.fixEventCoords(e)
      mouseDownCoordinates = {
        x: e.pageX,
        y: e.pageY
      }

      hideMenu()
      isMouseDown = true
      selectedObject = extractData($(this))

      setDragCursor()
      showDragDiv($(this).html())

      DragFilesTool.log('[a mousedown]')
      DragFilesTool.dir(selectedObject)

      stopEvent(e)
      return false
    })

    $('.thumbcell').mousedown(function(e) {
      DragFilesTool.log('[a .thumbcell mousedown] e.which = ' + e.which)
      if (e.which != 1) return true

      Utils.fixEventCoords(e)
      mouseDownCoordinates = {
        x: e.pageX,
        y: e.pageY
      }

      hideMenu()
      isMouseDown = true
      selectedObject = extractData($(this))

      setDragCursor()
      showDragDiv($(this).html())

      DragFilesTool.log('[a mousedown]')
      DragFilesTool.dir(selectedObject)

      stopEvent(e)
      return false
    })

    $('a', '.filelistname').mousemove(function(e) {
      //DragFilesTool.log('[a .filelistname mousemove]')
      if (!isMouseDown) return true

      stopEvent(e)
      return false
    })

    $('img', '.thumbcell').mousemove(function(e) {
      if (!isMouseDown) return true

      stopEvent(e)
      return false
    })

    $('#filespace').mouseup(function(e) {
      DragFilesTool.log('[#filespace mouseup]')

      if (e.which != 1) return true
      if (!isMouseDown) return true
      if (!div || !div.is(':visible')) {
        stopEvent(e)
        return false
      }

      destDir = currentDirId
      setDefaultCursor()
      hideDragDiv()
      showMenu({copy: true})
      dragFlag = false

      DragFilesTool.log('[#filespace mouseup]')
      DragFilesTool.dir(selectedObject)

      stopEvent(e)
      return false
    })

    $('a', '.filelistname').mouseup(function(e) {
      DragFilesTool.log('[a .filelistname mouseup]')

      if (e.which != 1) return true
      if (!isMouseDown) return true
      if (!div || !div.is(':visible')) {
        stopEvent(e)
        isMouseDown = false
        setDefaultCursor()
        return false
      }

      var d = extractData($(this))
      destDir = d.id

      setDefaultCursor()
      hideDragDiv()

      showMenu({copy: true, move: destDir != currentDirId, remove: AccountFacade.isRecycleBin(destDir)})

      dragFlag = false

      DragFilesTool.dir(selectedObject)

      stopEvent(e)
      return false
    })

    $('img', '.thumbcell').mouseup(function(e) {
      DragFilesTool.log('[img .thumbcell mouseup]')

      if (e.which != 1) return true
      if (!isMouseDown) return true
      if (!div || !div.is(':visible')) {
        stopEvent(e)
        isMouseDown = false
        setDefaultCursor()
        return false
      }

      var d = extractData($(this))
      destDir = d.id

      setDefaultCursor()
      hideDragDiv()

      showMenu({copy: true, move: destDir != currentDirId, remove: AccountFacade.isRecycleBin(destDir)})

      dragFlag = false

      DragFilesTool.dir(selectedObject)

      stopEvent(e)
      return false
    })

    // Для дерева
    $('a', '#foldertree').mousedown(function(e) {
      if ($(this).attr('data-root')) return true

      DragFilesTool.log('[a #foldertree mousedown]')

      if (e.which != 1) {
        DragFilesTool.log('e.which != 1')
        return true
      }

      Utils.fixEventCoords(e)
      mouseDownCoordinates = {
        x: e.pageX,
        y: e.pageY
      }

      hideMenu()
      isMouseDown = true

      var regexp = /changeDirLeft\((\d+)\)/;
      var match = regexp.exec($(this).attr('href'));
      if (!match || !match[1] || AccountFacade.isSpecialDir(match[1])) {
        return true
      }
      
      selectedObject = {
        name: $(this).html(),
        type: 'folder',
        id: match[1]
      }

      setDragCursor()
      showDragDiv($(this).html())

      DragFilesTool.dir(selectedObject)

      stopEvent(e)
      return false
    })

    $('a', '#foldertree').mouseover(function(e) {
      if (!isMouseDown) return true
      //$(this).addClass('dnd_folder_over')
      $(this).addClass('tree_item_highlight')
    })

    $('a', '#foldertree').mouseout(function(e) {
      //$(this).removeClass('dnd_folder_over')
      $(this).removeClass('tree_item_highlight')
    })

    $('a', '#foldertree').mouseup(function(e) {
      DragFilesTool.log('[a #foldertree folder mouseup]')

      if (e.which != 1) return true
      if (!div || !div.is(':visible')) {
        stopEvent(e)
        isMouseDown = false
        setDefaultCursor()
        return false
      }

      setDefaultCursor()
      hideDragDiv()
      dragFlag = false

      var regexp = /changeDirLeft\((\d+)\)/;
      var match = regexp.exec($(this).attr('href'));
      if (!match || !match[1] || match[1] == options.recycleBinId) return

      destDir = match[1]
      showMenu({copy: true, move: destDir != currentDirId, remove: AccountFacade.isRecycleBin(destDir)})

      stopEvent(e)
      return false
    })
  }

  initDOMEvents()

  Events.addListener('folder.reload', function() {
    initDOMEvents()
  })

  return this
}

DragFilesTool.debug = false

DragFilesTool.log = function(text) {
  if (!DragFilesTool.debug) return;

  try {
    console.log(text)
  } catch(e) { }
}

DragFilesTool.dir = function(object) {
  if (!DragFilesTool.debug) return

  try {
    console.dir(object)
  } catch(e) { }
}
