//
// User selects multiple files, Sees a progress bar for each file.
// In background worker pool, each file is uploaded in many small chunks.
// A server process will handle piecing the files back together 
// This implementation was inspired by:
// http://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal
//
// Author: Todd A. Fisher <todd.fisher@gmail.com>
//
FileSelector = Class.create({
  initialize: function(form, uploadUrl) {
    this.form = form;
    this.uploadUrl = uploadUrl;
    this.files = [];
    this.filter = ['image/gif', 'image/png', 'image/jpg', 'image/jpeg'];
    this.form.down("input[type='file']").observe("click", this.selectFiles.bindAsEventListener(this));
    //this.form.down("input[type='submit']").observe("click", this.sendFiles.bindAsEventListener(this));
    var ul = new Element('ul', { 'class': 'selected-files' })
    this.form.down("input[type='file']").up().insert(ul, 'bottom');
    this.fileList = ul;
    this.uploads = [];

    var frame = '' +
      '<div id="progress-frame">' +
      '<div class="progress-frame" style="display:none">' +
      '<div class="progress" style="margin-bottom:10px; margin-right:10px; float:left; width: 402px; border: 1px solid #CEE1EF">' +
      '<div class="bar" style="width: 1px; background-color: #CEE1EF; border: 1px solid white">' +
      '<div class="tp"></div>' +
      '<div style="text-align:left;width:400px;" class="rtp">0%</div>' +
      '</div>' +
      '</div>' +
      '<input type="button" class="upload-pause-resume" value="Pause"/>' +
      '<div class="clear"></div>' +
      '</div>' +
      '</div>';
    this.form.up().insert(frame, 'bottom');

    // create  worker pool to distribute each request too
    this.workerPool = google.gears.factory.create('beta.workerpool');
    this.workerPool.onmessage = this.messageCallback.bind(this);
    this.workerId = this.workerPool.createWorkerFromUrl("/javascripts/worker.js");
  },

  // User clicked select files
  //  - opens the multiple select file picker using the currently selected filters
  selectFiles: function(e) {
    var desktop = google.gears.factory.create('beta.desktop');
    desktop.openFiles(this.selectedFiles.bind(this), { filter: this.filter });
    Event.stop(e);
  },

  selectedFiles: function(files) {
    this.files = [];
    var progressFrame = $("progress-frame").innerHTML;

    for( var i = 0, len = files.length; i < len; ++i ) {
      var file = files[i];

      var li = $(document.createElement("li"));
      li.innerHTML = progressFrame;
      li.down(".rtp").innerHTML = file.name + " (waiting)";
      li.down(".progress-frame").style.display = "";

      // attach listener for pause button
      var pauseResumeButton = li.down(".upload-pause-resume");
      pauseResumeButton.observe("click", this.pauseResume.bindAsEventListener(this, pauseResumeButton,i));

      this.fileList.appendChild(li);
      this.files.push( {li:li, file: files[i]} ); // track the file

      this.workerPool.sendMessage({type:"upload:new", file: file, id: i, url: this.uploadUrl}, this.workerId);
    }
  }, 

  sendFiles: function(e) {
    for( var i = 0, len = this.files.length; i < len; ++i ) {
      var file = this.files[i].file;
      this.workerPool.sendMessage({type:"upload:new", file: file, id: i, url: this.uploadUrl}, this.workerId);
    }
    Event.stop(e);
  },

  // receive messages from workers
  //  - progress: refresh the UI with new progress
  //  - error: report errors sent from workers
  messageCallback: function(a, b, message ) {
    switch(message.body.type) {
    case 'progress':
      this.uploadProgress(message);
      break;
    case 'error':
      this.uploadError(message,true);
      break;
    case 'complete':
      this.uploadComplete(message);
      break;
    default:
      this.uploadError(message,false);
      break;
    }
  },

  uploadError: function(message, expected) {
    console.error(message.body);
    console.error(message.body.status);
  },

  // display progress events
  //   - worker.js sends these messages to notify us of the current upload status
  uploadProgress: function(message) {
    var id = message.body.id;
    var progress = message.body.progress;
    //console.log("(" + message.body.id + ")uploading: " + message.body.status + " percent complete: " + progress );
    var fileData = this.files[id];
    var li = fileData.li;
    var max = parseInt(li.down(".progress").style.width) - 2;
    var bar = li.down(".bar");
    var status = li.down(".rtp");
    var percent = Math.round(progress*100);
    bar.style.width = (progress * max) + "px";

    status.innerHTML = fileData.file.name + " (" + percent + "%)";
  },

  uploadComplete: function(message) {
    var id = message.body.id;
    var fileData = this.files[id];
    var li = fileData.li;
    var bar = li.down(".bar");
    var status = li.down(".rtp");
    var max = parseInt(li.down(".progress").style.width) - 2;
    bar.style.width = max + "px";
    var button = li.down('.upload-pause-resume');
    button.disabled = true;

    status.innerHTML = fileData.file.name + " (done)";
  },

  // user clicked the pause or resume button
  pauseResume: function(e,button,id)
  {
    //console.log("pause:" + button + ", " + id);
    if( button.value == "Pause" ) { // send pause
      button.value = "Resume";
      this.workerPool.sendMessage({type:"upload:pause", id: id}, this.workerId);
    } else { // send resume
      button.value = "Pause";
      this.workerPool.sendMessage({type:"upload:resume", id: id}, this.workerId);
    }
  }
});
Object.extend(FileSelector, {
  //
  // create the file selector form
  // once the DOM is ready create the selector object
  // and call the createdCB if it's defined
  //
  create: function(createdCB) {
    // now wait for things to be ready
    document.observe("dom:loaded", function() {
      var selector = new FileSelector($("upload-form"));
      if( createdCB && Object.isFunction(createdCB) ) {
        createdCB(selector);
      }
    });
  }
} );
