// -*- coding: utf-8 -*-
// vi:si:et:sw=2:sts=2:ts=2

// Workaround for Firefox 4.0 sending an empty string
// as filename for Blobs in FormData requests
// https://bugzilla.mozilla.org/show_bug.cgi?id=649150
function geckoFormData() {
  var self = this,
      that = {},
      boundary = '------XX' + Math.random(),
      dashdash = '--',
      crlf = '\r\n',
      builder = '', // Build RFC2388 string.
      wait = 0;

  builder += dashdash + boundary + crlf;

  that.append = function(name, data) {
    // Generate headers.
    builder += 'Content-Disposition: form-data; name="'+ name +'"';
    builder += crlf;
    builder += crlf;

    // Write data.
    builder += data;
    builder += crlf;

    // Write boundary.
    builder += dashdash + boundary + crlf;
  };
  that.appendFile = function(name, data, type, filename) {
    builder += 'Content-Disposition: form-data; name="'+ name +'"';
    builder += '; filename="' + filename + '"';
    builder += crlf;
    builder += 'Content-Type: ' + type;
    builder += crlf;
    builder += crlf;

    // Write binary data.
    builder += data;
    builder += crlf;

    // Write boundary.
    builder += dashdash + boundary + crlf;
  };
  that.appendBlob = function(name, blob, filename) {
    wait++;
    var reader = new FileReader();
    reader.onload = function(e) {
      that.appendFile(name, e.target.result, blob.type, filename);
      // Call onload after last Blob 
      wait--;
      if(!wait && self.onload) {
        self.onload();
      }
    };
    reader.readAsBinaryString(blob);
  };
  
  that.send = function(xhr) {
    self.onload = function() {
      // Mark end of the request.
      builder += dashdash + boundary + dashdash + crlf;

      // Send to server
      xhr.setRequestHeader("Content-type", "multipart/form-data; boundary=" + boundary);
      xhr.sendAsBinary(builder);
    };
    if(!wait) {
      self.onload();
    }
  };
  return that;
}

function FirefoggUploader(file, uploadUrl, uploadData, callback, progress_callback) {
  var self = this,
      that = {
        progress: 0
      },
      chunkSize = 1024*1024,
      chunkUrl,
      gecko = /gecko\//.test(navigator.userAgent.toLowerCase()),
      maxRetry = -1,
      progress,
      retries = 0;

  progress_callback = progress_callback || function(progress) {};
  callback = callback || function(result) {};

  function uploadChunk(chunkId) {
    var bytesAvailable = file.size,
        chunk,
        chunkOffset = chunkId * chunkSize;
    //Slice API was taken out and new version now require start/end and not start/length
    if(file.slice)
      chunk = file.slice(chunkOffset, chunkSize, file.type);
    else if(file.mozSlice)
      chunk = file.mozSlice(chunkOffset, chunkOffset+chunkSize, file.type);
    else if(file.webkitSlice)
      chunk = file.webkitSlice(chunkOffset, chunkOffset+chunkSize, file.type);

    that.progress = parseFloat(chunkOffset)/bytesAvailable;
    self.req = new XMLHttpRequest();
    self.req.addEventListener("load", function (evt) {
      var response;
      that.responseText = evt.target.responseText;
      try {
        response = JSON.parse(evt.target.responseText);
      } catch(e) {
        response = {};
      }
      if (response.done == 1) {
        //upload finished
        that.resultUrl = response.resultUrl;
        that.progress = 1;
        that.status = 'done';
        callback(that);
      }
      else if (response.result == 1) {
        //reset retry counter
        retries = 0;
        //start uploading next chunk
        uploadChunk(chunkId + 1);
      } else {
        //failed to upload, try again in 3 second
        retries++;
        if (maxRetry > 0 && retries > maxRetry) {
          that.status = 'uplaod failed';
          that.progress = -1;
          callback(that);
        } else {
          setTimeout(function() {
              uploadChunk(chunkId);
          }, 3000);
        }
      }
    }, false);
    self.req.addEventListener("error", function (evt) {
      //failed to upload, try again in 3 second
      retries++;
      if (maxRetry > 0 && retries > maxRetry) {
        that.status = 'uplaod failed';
        that.progress = -1;
        callback(that);
      } else {
        setTimeout(function() {
            uploadChunk(chunkId);
        }, 3000);
      }
    }, false);
    self.req.upload.addEventListener("progress", function (evt) {
      if (evt.lengthComputable) {
        that.progress = parseFloat(chunkOffset + evt.loaded) / bytesAvailable;
        progress_callback(that.progress);
      }
    }, false);
    self.req.addEventListener("abort", function (evt) {
      that.status = 'aborted';
      that.progress = -1;
      callback(that);
    }, false);

    var formData;
    if(gecko) {
      formData = new geckoFormData();
    } else {
      formData = new FormData();
    }
    formData.append('chunkId', chunkId);
    if (bytesAvailable <= chunkOffset + chunkSize) {
      formData.append('done', 1);
    }
    if(gecko) {
      formData.appendBlob('chunk', chunk, 'chunk.bin');
    } else {
      formData.append('chunk', chunk);
    }
    self.req.open("POST", chunkUrl, true);
    if(gecko) {
      formData.send(self.req);
    } else {
      self.req.send(formData);
    }
  }

  //request upload slot from server
  that.status = 'requesting chunk upload';
  self.req = new XMLHttpRequest();
  self.req.addEventListener("load", function (evt) {
    var response = {};
    that.responseText = evt.target.responseText;
    try {
      response = JSON.parse(evt.target.responseText);
    } catch(e) {
      response = {};
      that.status = "failed to parse response";
      that.progress = -1;
      callback(that);
    }
    if (response.maxRetry) {
      maxRetry = response.maxRetry;
    }
    chunkUrl = response.uploadUrl;
    if (chunkUrl) {
      that.status = 'uploading';
      that.progress = 0.0;
      //start upload
      uploadChunk(0);
    } else {
      that.status = 'upload failed, no upload url provided';
      that.progress = -1;
      callback(that);
    }
  }, false);
  self.req.addEventListener("error", function (evt) {
    that.status = 'uplaod failed';
    that.progress = -1;
    that.responseText = evt.target.responseText;
    callback(that);
  }, false);
  self.req.addEventListener("abort", function (evt) {
    that.status = 'aborted';
    that.progress = -1;
    callback(that);
  }, false);
  var formData = new FormData();
  for(var key in uploadData) {
    if (uploadData.hasOwnProperty(key)) {
      formData.append(key, uploadData[key]);
    }
  }
  self.req.open("POST", uploadUrl);
  self.req.send(formData);

  //public interface
  that.abort = function() {
    if (self.req) {
      self.req.abort();
      self.req = null;
    }
  };
  return that;
}

// Activate on page is possible
$(document).ready(function() {
  var Chrome = /chrome/.test(navigator.userAgent.toLowerCase()),
      GeckoVersion = navigator.userAgent.match(/rv\:(.+)\) Gecko/),
      WebKitVersion = navigator.userAgent.match(/AppleWebKit\/([\d\.]+)/);
  if (WebKitVersion) {
    WebKitVersion = WebKitVersion[1];
  }
  if (GeckoVersion) {
    GeckoVersion = GeckoVersion[1];
  }

  if (!(Chrome || WebKitVersion >= '534.28' ||
     (GeckoVersion >= '2.0'))) {
      alert("sorry, you need another browser to upload files to edgwareroad.org - try recent versions of firefox or chrome for best results.");
      window.location = "/";
//    $('#firefogg').hide();
//    $('#submit').hide();
/*
    $('#file').change(function(e) {
      if(this.files.length>0) {
        $('#file').hide();  
        $('#upload').show();  
      }
    });
    if($('#file')[0].files.length>0) {
      $('#file').hide();  
      $('#upload').show(); 
    } else {
      $('#upload').hide();
    }
*/
  /*
    $('#upload').click(function(e) {
      $('#upload').hide();
      e.stopPropagation();
      var file = $('#file')[0].files[0];
      var data = {
        'firefogg': 1,
        'name': file.name, // Send filename here since Blobs will have no name later
        'category': $('#files_category').val()
      };
      var ogg = FirefoggUploader(file, add_url, data, function(ogg) { //callback
        if(ogg.resultUrl) {
          document.location.href = ogg.resultUrl;
        } else {
          $('#progressstatus').html(ogg.status);
        }
      }, function(progress) { //progress callback
        //do something with status and progress, i.e. set progressbar width:
        $('#progress').css('width', parseInt(progress*100, 10) +'%');
        $('#progressstatus').html(parseInt(progress*100, 10) + '% - ' + ogg.status);
      });

      $('#submitFile').hide();

    });

    */
  }
});

