/*!
 * jQuery.dropload v0.1
 *
 * Copyright 2010, Jökull Sólberg Auðunsson
 * FreeBSD License
 * Description:
 *   For each drop of one or more files the client asynchronously 
 *   sends the files to the server. The request is a multipart 
 *   formencoded binary stream, making it easy to process on the 
 *   server. Works in Chrome 7, maybe Safari.
 */

(function($){
  
  $.fn.dropload = function(options){
    var events = [ "onstart", "onprogress", "oncomplete", "onerror", 
      "onabort", "oncomplete", "onfileadded", 
      "ondrop", "onover", "onenter", "onleave" ];
    var config = { 
      // options
      url       : '',
      method    : 'POST',
      paramname : 'file',
                                                                 
      // events                                                  
      onstart     : function(event, files){ },                    // triggered right before the form is submitted
      onprogress  : function(event, completed, loaded, total){ }, // repeatedly triggered while the form is being submitted
      oncomplete  : function(event, responseText){ },             // triggered after the form has been fully submitted
      onerror     : function(event){ },                           // triggered if an error occurs during submission
      onabort     : function(event){ },                           // triggered if an abort() signal is received
      onenter     : function(event){ },
      onover      : function(event){ },
      ondrop      : function(event){ },
      onfileadded : function(i, file){  },
      ondrop      : function(event){  },
      onover      : function(event){  },
      onenter     : function(event){  },
      onleave     : function(event){  },
      ondocdrop   : function(event){  },
      ondocenter  : function(event){  },
      ondocleave  : function(event){  },
      ondocover   : function(event){  }
    };

    if (options) $.extend(config, options);
    
    $(document).
      bind('dragenter', function(event){
        event.stopPropagation();
        event.preventDefault();
        config.ondocenter(event);
      }).
      bind('dragover', function(event){
        event.stopPropagation();
        event.preventDefault();
        config.ondocover(event);
      }).
      bind('dragleave', function(event){
        event.stopPropagation();
        event.preventDefault();
        config.ondocleave(event);
      }).
      get(0).addEventListener('drop', function(event){
        event.stopPropagation();
        event.preventDefault();
        config.ondocdrop(event);
      }, false);
  
    var upload = function(that, files){

      // create request object and configure event handlers
      var xhr = new XMLHttpRequest();
  
      that.trigger("dropload.ondrop", [event, files]);
      xhr.onloadstart = function(event){ 
        that.trigger("dropload.onstart", [xhr]);
      }
      xhr.onload = function(event){ 
        that.triggerHandler("dropload.oncomplete", [xhr.responseText]); 
      }
      xhr.onerror = function(event){ 
        that.trigger("dropload.onerror");    
      }
      xhr.onabort = function(event){ 
        that.trigger("dropload.onabort");    
      }
      xhr.onreadystatechange = function(){
        if(this.readyState === 4){
          if(this.status === 200){
            that.trigger("dropload.onerror", [xhr.responseText]);
          }
        }
      }

      xhr.upload["onprogress"] = function(event){ 
        var completed = event.loaded / event.total;
        that.trigger("dropload.onprogress", [completed, event.loaded, event.total]); 
      }

      var formData = new FormData();
      $.each(files, function (i, file){
        formData.append(config.paramname, file);
        that.trigger("dropload.onfileadded", [i, file]);
      });
      xhr.open(config.method, config.url, true);
      xhr.setRequestHeader("Cache-Control", "no-cache");
      xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
      xhr.send(formData);
  
    }
    
    this.each(function(){

      var that = $(this);
      for (event in events){
        if (config[events[event]]) {
          that.bind("dropload." + events[event], config[events[event]]);
        }
      }
      
      this.addEventListener('dragenter', function(event){
        event.stopPropagation();
        event.preventDefault();
        that.trigger("dropload.onenter", [event]);
      }, false);
      this.addEventListener('dragleave', function(event){
        event.stopPropagation();
        event.preventDefault();
        that.trigger("dropload.onleave", [event]);
      }, false);
      this.addEventListener('dragover', function(event){
        event.stopPropagation();
        event.preventDefault();
        that.trigger("dropload.onover", [event]);
      }, false);
      this.addEventListener('drop', function(event){
        event.stopPropagation();
        event.preventDefault();
        that.trigger("dropload.ondrop", [event]);
        var files = event.dataTransfer.files;
        if(files.length) upload(that, files, files.length);
      }, false);

    });
  }
})(jQuery);
