/* Inject alternative Ajax implementation using javascript injection
 *
 * (c) 2005 Fingertips (Manfred Stienstra <m.stienstra@fngtps.com>)
 *
 * Inject is freely distributable under the terms of an MIT-style license
 * under the same terms as Prototype. For details, see the Prototype
 * website: http://prototype.conio.net/
 *
 * Original idea by Julien Lamarre http://zingzoom.com/ajax/ajax_with_js.php
 *
 * Only use Inject if you want to do cross-domain calls, in all other cases
 * Ajax is a much more complete and robust solution for remote calls.
 */

var Inject = {};

/* Inject.Request works roughly the same as Ajax.Request, but there are a few
 * distinct differences. A request is _always_ asynchronous and the return is
 * _always_ evaluated. There is no way to do unevaluated calls.
 */
Inject.Request = Class.create();
Inject.Request.prototype = {
  /*
   * Options:
   *  cropForIE: Crop the URL is it's too large for IE (default: true)
   *  confirmCropMessage: The message to display before we crop. If this is
   *    not set, the javascript will crop without mercy!
   *  onCancelledCrop: This is called when the user clicks 'cancel' in the
   *    crop confirmation window.
   *  onCrop: This is called just after the crop was performed.
   */
  initialize: function(url, options) {
    this.setOptions(options);
    this.request(url);
  },
  
  setOptions: function(options) {
    this.options = {
      parameters: '',
      cropForIE: true,
		  onCrop: false
    }
    Object.extend(this.options, options || {});
  },
  
  request: function(url) {
    this.assureInjectContainer();

		requestURL = url + '?' + this.options.parameters;
		if (this.options.cropForIE)
  		requestURL = this.cropLargeURL(requestURL);


    var scriptElement = document.createElement('script');
    scriptElement.setAttribute('type', 'text/javascript');
    scriptElement.setAttribute('src', requestURL);
    $('_inject_container').appendChild(scriptElement);
  },
  
  assureInjectContainer: function() {
    if (!$('_inject_container')) {
      this.createInjectContainer();
    }
  },
  
  createInjectContainer: function() {
    var containerElement = document.createElement('div');
    containerElement.setAttribute('id', '_inject_container');
    containerElement.style.display = 'none';
    document.body.appendChild(containerElement);
  },
  
  cropLargeURL: function(url) {
    // Opera still puts MSIE in their user agent string
    if(/MSIE/.test(navigator.userAgent) && !(/Opera/.test(navigator.userAgent))) {
      // the variables part can't be larger than 2048
      var removeFromVariables = url.split('?')[1].length - 2048;
      // the total request URL can't be larger than 2083
      var removeFromURL = url.length - 2083;
      if (removeFromURL > removeFromVariables) {
        var removeCharacters = removeFromURL;
      } else {
        var removeCharacters = removeFromVariables;
      }
      // we can't just chop off a number of characters because the strings
      // are URL encoded
      var currentLength = 0
      if (removeCharacters > 0) {
        if (this.options.confirmCropMessage && (!confirm(this.options.confirmCropMessage))) {
					(this.options.onCropCancelled || Prototype.emptyFunction)(this);
          return '';
        }
        var urlParts = url.split('?')
        var pairs = urlParts[1].split('&')
        // we go backwards through all the key-value pairs and chop them off
        // we chop in values too 
        for (i=pairs.length-1; i>=0; i--) {
          if (removeCharacters < pairs[i].length) {
            var serializedPairs = '';
            if (i >= 1) 
              serializedPairs = pairs.slice(0, i).join('&') + '&';
            var pair = pairs[i].split('=');
            var newValue = pair[1].slice(0, -removeCharacters);
            
            // make sure the string doesn't end with half an encoded
            // character
            if (newValue.charAt(newValue.length-2) == '%')
              newValue = newValue.slice(0, -2);
            if (newValue.charAt(newValue.length-1) == '%')
              newValue = newValue.slice(0, -1);
            return urlParts[0] + '?' + serializedPairs + pair[0] + '=' + newValue;
          } else if (removeCharacters == 0) {
            return urlParts[0] + '?' + pairs.slice(0, i+1).join('&');
          } else {
            removeCharacters = removeCharacters - (pairs[i].length + 1);
          }
        }
      }
      (this.options.onCrop || Prototype.emptyFunction)(this); 
    }
    return url;
  }
}