//
// NOTE: this code relies on prototype and scriptaclulous...
//

//
// make sure a file is selected before submission
//

function submitFormWithProgress(form, uuid, url) {
  if (/(.+)\.(zip|Zip|ZIP)$/.exec($('upload').value)) {
    UploadProgress.monitor(uuid, url) ;
    $(form).submit() ;
  } else {
    alert('Please choose a zip file to upload!') ;
  } 
}

//
// Prototype extensions
// 

PeriodicalExecuter.prototype.registerCallback = function() {
  this.intervalID = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
} ;

PeriodicalExecuter.prototype.stop = function() {
  clearInterval(this.intervalID);
} ;

//
// Upload Progress class (for use with apache mod_upload_progress)
//

var UploadProgress = {
  checking: false,
  uploading: false,
  processing: false,
  url: null, 
  
  monitor: function(uuid, url) {
    this.setAsStarting() ;
    this.url = url ;
    this.watcher = new PeriodicalExecuter(function() { UploadProgress.check(uuid) ; }, 3) ;
  },

  check: function(uuid) {
    switch (true) {
      case UploadProgress.uploading:
        if (!UploadProgress.checking) { 
          UploadProgress.checking = true ;
          new Ajax.Request('/progress?X-Progress-ID=' + uuid, {
            method: 'get',
            onComplete: function(transport) {
              // check status of upload 
              var upload = eval(transport.responseText) ; 
              if (upload.state) {
                if (upload.state == 'uploading') { 
                  if (upload.size == upload.received) {
                    UploadProgress.setAsProcessing() ; 
                  } else {
                    UploadProgress.update(upload.size, upload.received) ; 
                  } 
                }  
              }  
              UploadProgress.checking = false ;
            }
          });
        }  
        break ;
      case UploadProgress.processing:
        // continue checking until processing is complete
        break ;
      default:
        UploadProgress.setAsFinished() ;
    }
  },

  update: function(total, current) {
    if (!this.uploading) { return ; }
    var progress = current / total ;
    var maxWidth = $('ProgressBarShell').offsetWidth ;
    var newWidth = Math.floor(progress * maxWidth) ;
    $('ProgressBar').setAttribute('width', newWidth + 'px') ;
    $('ProgressBar').style.width = newWidth + 'px' ;
    $('ProgressBarText').innerHTML = progress.toPercentage() ;
    $('ProgressMessage').innerHTML = current.toHumanSize() + ' of ' + total.toHumanSize() + " uploaded" ;
  },
  
  setAsStarting: function() {
    this.uploading = true ;
    $('ProgressMessage').innerHTML = "Starting upload..." ;
    $('ProgressBar').style.width = '0%' ; 
    $('ProgressBar').className = 'Uploading' ;
    $('ProgressBarText').innerHTML  = '0%' ;
    Effect.Appear('ProgressBarShell') ;
  },
  
  setAsProcessing: function() {
    this.uploading = false ;
    this.processing = true ;
    $('ProgressBar').style.width = 'auto' ;
    $('ProgressBar').className   = 'Processing' ;
    $('ProgressBarText').innerHTML  = '100%' ;
    $('ProgressMessage').innerHTML = "Processing upload... please wait!" ;
  },

  setAsFinished: function() {
    this.uploading = false ;
    this.processing = false ;
    if (this.watcher) { this.watcher.stop() ; }
    if (this.url) { window.setTimeout("window.location.href = '" + this.url + "'", 3) ; }
    $('ProgressBar').style.width = 'auto' ;
    $('ProgressBar').className   = 'Finished' ;
    $('ProgressBarText').innerHTML  = '100%' ;
    $('ProgressMessage').innerHTML = "Finished!" ;
    Effect.Fade('ProgressBarShell', { duration: 2 }) ;
  }

} ;

//
// Number convenience methods
//

Number.prototype.bytes     = function() { return this; } ;
Number.prototype.kilobytes = function() { return this *  1024; } ;
Number.prototype.megabytes = function() { return this * (1024).kilobytes(); } ;
Number.prototype.gigabytes = function() { return this * (1024).megabytes(); } ;
Number.prototype.terabytes = function() { return this * (1024).gigabytes(); } ;
Number.prototype.petabytes = function() { return this * (1024).terabytes(); } ;
Number.prototype.exabytes =  function() { return this * (1024).petabytes(); } ;

['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte', 'petabyte', 'exabyte'].each( function(meth) {
  Number.prototype[meth] = Number.prototype[meth+'s'] ;
}) ;

Number.prototype.toPrecision = function() {
  var precision = arguments[0] || 2 ;
  var s         = Math.round(this * Math.pow(10, precision)).toString();
  var pos       = s.length - precision;
  var last      = s.substr(pos, precision);
  return s.substr(0, pos) + (last.match("^0{" + precision + "}$") ? '' : '.' + last);
} ;

Number.prototype.toPercentage = function() {
  return Math.floor(this * 100) + '%';
} ;

Number.prototype.toHumanSize = function() {
  if(this < (1).kilobyte())  return this + " Bytes";
  if(this < (1).megabyte())  return (this / (1).kilobyte()).toPrecision()  + ' KB';
  if(this < (1).gigabytes()) return (this / (1).megabyte()).toPrecision()  + ' MB';
  if(this < (1).terabytes()) return (this / (1).gigabytes()).toPrecision() + ' GB';
  if(this < (1).petabytes()) return (this / (1).terabytes()).toPrecision() + ' TB';
  if(this < (1).exabytes())  return (this / (1).petabytes()).toPrecision() + ' PB';
                             return (this / (1).exabytes()).toPrecision()  + ' EB';
} ;
