/**
 * jQuery AJAXify lite
 * 
 * AJAX-'ifies' any <form> or <a> using the specified method of the form.
 * 
 * Also sends the value of the button clicked, and the x/y if using <input type="image"/>
 * 
 * @package jquery-ajaxify-lite
 * @author Dom Hastings
 */
(function($) {
  /**
   * jQuery.ajaxify
   * 
   * The main wrapper method for the Ajaxify object.
   * 
   * This adds the event handlers to the required elements.
   * 
   * It can accept an options object
   * 
   * @param options object
   * @return object (this)
   * @author Dom Hastings
   */
  $.fn.ajaxify = function(options) {
    /**
     * appendToURL
     * 
     * Appends the specified query string to the URL being requested
     * 
     * @param url string The URL being requested
     * @return string The URL with the query string appended if specified
     * @author Dom Hastings
     */
    var appendToURL = function(url, append) {
      // if the options specify a URL append
      if (append) {
        // if there's a # in the url, strip it off first
        if (url.indexOf('#') != -1) {
          url = url.substr(0, url.indexOf('#'));
        }

        // add it correctly (using & if ? already appears in the URL)
        url += (url.indexOf('?') == -1 ? '?' : '&') + (typeof append == 'string' ? append : $.param(append));
      }

      return url;
    }
    
    
    options = $.extend({
      'append': 'ajax=1',
      'buttons': 'button[type=submit], input[type=submit], input[type=image]',
      'replace': true,  // if set to true, will replace content in the update element, otherwise will just append
      'update': null,
      // jQuery AJAX options, see http://docs.jquery.com/Ajax/jQuery.ajax#toptions
      'async': true,
      'beforeSend': null,
      'complete': null,
      'contentType': null,
      'dataFilter': null,
      'dataType': 'html',
      'error': function(XHR, textStatus, errorThrown) {
        alert('Error processing data via AJAX:\n' + errorThrown + ' (' + textStatus + ')');
      },
      'success': function(data, textStatus) {
        if (this.replace) {
          jQuery(this.update).html(data);

        } else {
          jQuery(this.update).append(data);
        }
      },
      'type': null,
      'url': null
    }, options || {});
    
    $(this.selector).live('submit click', options, function(event) {
      // clone the options object, so you don't get the same details for each one
      var options = $.extend({}, event.data);
      
      if ($(this).attr('tagName').toLowerCase() == 'a' && event.type == 'click') {
        // prevent the normal 'default' action (eg. following the link)
        event.preventDefault();

        // set the url to the action attribute or the options url if specified on init
        options.url = options.url || appendToURL($(this).attr('href'), options.append);
        
        // update the element specified in options, or the parent element if not
        options.update = options.update || $(this).attr('target');
        
        // set the type to the method attribute or the options type
        options.type = options.type || 'GET';

        // set the content type
        options.contentType = options.contentType || 'application/x-www-form-urlencoded';

        // get the form data
        if (options.data && typeof options.data != 'string') {
          options.data = $.param(options.data);
          
        } else {
          options.data = false;
        }
        
        $.ajax(options);
        
      } else if ($(this).attr('tagName').toLowerCase() == 'form' && event.type == 'submit') {
        // prevent the normal 'default' action (eg. following the link)
        event.preventDefault();

        // set the url to the action attribute or the options url if specified on init
        options.url = options.url || appendToURL($(this).attr('action'), options.append);
        
        // update the element specified in options, or the parent element if not
        options.update = options.update || $(this).attr('target');
        
        // set the type to the method attribute or the options type
        options.type = options.type || $(this).attr('method').toUpperCase();
        
        // set the content type
        options.contentType = options.contentType || ($(this).attr('enctype') || 'application/x-www-form-urlencoded');
        
        // get the form data
        if (options.data) {
          if (typeof options.data == 'string') {
            options.data = $(this).serialize() + '&' + options.data;

          } else {
            options.data = $(this).serialize() + '&' + $.param(options.data);
          }

        } else {
          options.data = $(this).serialize();
        }
        
        $.ajax(options);
        
        // clean up the hidden inputs
        $('input.ajaxify__submitButton__').remove();
      }
    });
    
    // capture all the submit buttons
    var selectors = this.selector.split(/\s*,\s*/);
    var buttons = options.buttons.split(/\s*,\s*/);
    
    for (var i = 0; i < selectors.length; i++) {
      for (var j = 0; j < buttons.length; j++) {
        $(selectors[i] + ' ' + buttons[j]).live('mousedown keydown', function(event) {
          $(this).after('<input type="hidden" name="' + $(this).attr('name') + '" value="' + $(this).val() + '" class="ajaxify__submitButton__"/>');

          // if it's an imagae, also capture the x/y co-ordinates
          if ($(this).attr('type') == 'image') {
            $(this).after('<input type="hidden" name="' + $(this).attr('name') + '_y" value="' + (event.pageY - $(this).offset().top) + '" class="ajaxify__submitButton__"/>');
            $(this).after('<input type="hidden" name="' + $(this).attr('name') + '_x" value="' + (event.pageX - $(this).offset().left) + '" class="ajaxify__submitButton__"/>');
          }
        });
      }
    }

    // return the jQuery object for chaining
    return this;
  }
})(jQuery);

