/*
 * jQuery Wex Plugins
 *
 * @requires jQuery v1.3.+ or later
 * @requires jQuery UI 1.7.2 or later
 * @requires jstree 0.9.8. or later
 * @requires jquery.form 2.28 or later
 *
 * It is critically important when writing jQuery extension to maintain
 * namespacing rules. They are the following:
 *
 * 1. When adding custom utility functions in the '$' function, simply create them
 * as part of the provided '$.wex' object.
 *
 * 2. When adding wrapped set selector functions in the '$.fn' function, name the
 *    the functions with 'wex' prefix to avoid namespace collisions.
 *
 * @author Kyrill Alyoshin
 */

(function($) {
  /**
   * ==============================================================================================
   * ==================================== WEX Utility Functions ===================================
   * ==============================================================================================
   */

  //Creating WEX namespace
  $.wex = {};
  // helper for console logging
  $.wex.log = function() {
    window.console.log("[jquery.wex.plugins] " + Array.prototype.join.call(arguments, ''));
  };
  //Branding
  $.wex.brands = {
    pacpride: "pacpride",
    jiffylube: "jiffylubedistrib",
    sinclair: "sinclairdistrib",
    valvoline: "valvdistrib",
    wex: "wexdistrib",
    tesoro: "tesorodistrib",
    fina: "finadistrib"
  };
  //return brand information
  $.wex.getBrand = function() {
    var brand = $("meta[name=brand]").attr("content");
    if (!brand) {
      alert("Brand is not provided as a meta tag!");
    }
    return brand;
  };
  //utility function to determine if a pacpride brand.
  $.wex.isPacPride = function() {
    return $.wex.getBrand() === $.wex.brands.pacpride;
  };

  //utility function that checks for PCI compliance of passwords
  $.wex.isPciCompliant = function(password) {
    var length = password.length;
    if (length < 8 || length > 32) {
      return false;
    }

    var uppercaseSatisfied = false;
    var lowercaseSatisfied = false;
    var digitSatisfied = false;

    for (var i = 0; i < length; ++i) {
      var c = password.charAt(i);
      if (/^[A-Z]$/.test(c)) {
        uppercaseSatisfied = true;
        continue;
      }
      if (/^[a-z]$/.test(c)) {
        lowercaseSatisfied = true;
        continue;
      }
      if (/^[0-9]$/.test(c)) {
        digitSatisfied = true;
      }
    }

    return uppercaseSatisfied && lowercaseSatisfied && digitSatisfied;
  };

  //utility function that will sublcass a class
  // @author: Ben Babics
  $.wex.Extends = function(subClass, superClass) {
	var F = function() {};
		F.prototype = superClass.prototype;

	subClass.prototype = new F();
	subClass.prototype.constructor = subClass;
	
	subClass.superClass = superClass.prototype;
	if (superClass.prototype.constructor == Object.prototype.constructor) {
		superClass.prototype.constructor = superClass;
	}
  };
  
  //utility function that creates an OO Interface
  // @author: Ben Babics
  $.wex.Interface = function(methods) {
    if (!$.isArray(methods)) {
      throw new Error('Interface constructor expects an array of public methods as an argument');
    }
    
    for (i=0; i < methods.length; i++) {
      if (typeof methods[i] !== 'string') {
        throw new Error('Interface constructor expects method names to be passed in as a string.');
      }
    }
    
    return {
      ensureImplementation: function(obj) {
        for (i=0; i < methods.length; i++) {
          var method = methods[i];
            if (obj[method] == null) {
              throw new Error('Object does not implement all of the methods from this interface. Method: "' + method + '", was not found.');
            }
        }
      }
    }
  };


  /**
   * ==============================================================================================
   * ================================ WEX Wrapped Set Functions ===================================
   * ==============================================================================================
   */


  /**
   * This function prepends a given character
   * to the 'value' attribute of a DOM element, up to a certain length.
   * Designed to operate on a single dom node.
   *
   * @param prefix   string to prepend (required to contain only one character).
   * @param length (optional) the total max length of the value to reach. This is
   *                optional, as, if not defined, the function will attempt to use the value
   *                of maxlength attribute.
   */
  $.fn.wexPrepend = function(prefix, length) {
    var maxlength = length || this.attr("maxlength");

    //validate maxlength
    if (!maxlength || maxlength < 1) return this;
    //validate prefix
    if (typeof prefix !== "string" || prefix.length !== 1) return this;

    var value = this.val();
    //validate value
    if (!value || !$.trim(value)) return this; //user didn't provide any value to begin with

    value = $.trim(value);
    while (value.length < maxlength) {
      value = prefix + value;
    }
    return this.val(value);
  };

  /**
   * ==========================================================================
   * ===================== jQuery Plugins and Extensions ======================
   * ==========================================================================
   */

  /**
   * jQuery extension to open dialogs
   */
  var dlg = null; //our dialog
  $.fn.wexOpenDialog = function(options) {
    var fixed = {
      modal: true,
      resizable: false,
      bgiframe: true,
      show: "clip"
    };
    var defaults = {
      title: "Results",
      height: 500,
      width: 550
    };

    var settings = $.extend({}, defaults, options || {}, fixed);

    //assign a function to perform to perform an action on
    // the server when the dialog is closed
    if (settings.closeUrl) {
      settings.close = function() {
        $.post(settings.closeUrl);
      };
    }

    if (!dlg) {
      dlg = this.dialog(settings);
      this.addClass("copy");
    }
    else {
      //deal with events
      //since there may be multiple dialog definitions on a page and only one dialog -> 'dlg'
      //we need to reset mutable values every time.
      dlg.unbind("close", dlg.dialog("option", "close"));
      if (settings.close) {
        dlg.dialog("option", "close", settings.close);
      }
     // Resetting buttons if empty.
      try{
          if(!settings.buttons){
            dlg.dialog('option', 'buttons', {});
          }
      }catch(err){}
        
      dlg.dialog("option", "title", settings.title);
      dlg.dialog("option", "height", settings.height);
      dlg.dialog("option", "width", settings.width);

      dlg.dialog("open");
    }
    return this;
  };


  /**
   * jQuery extension to display tree structures
   *
   * options parameter must provide URL as 'url' property to be invoked
   * on the server to get the tree nodes
   */
  $.fn.wexDisplayTree = function(options) {
    var clicked = {}; //hash map for clicked URLs.

    var settings = {
      data : $.extend({
        type: "json",
        method: "POST"
      }, options.data || {}),

      ui: {
        theme_path: "web/css/jstree-ui/themes/",
        theme_name: "classic"
      },

      rules : {
        renameable: "none",
        deletable: "none",
        creatable: "none",
        draggable: "none",
        dragrules: "none"
      },

      callback: {
        onchange: function(node) {
          //make clickable only those links that actually have real URLs
          var href = $(node).children("a:first").filter("a[href*=.do]").attr("href");
          if (href && !clicked[href]) {
            clicked[href] = true; //prevents reloads on double-clicks

            if (options.onClickCallback) {
              dlg.dialog("destroy");
              dlg = null;
              options.onClickCallback();
            }
            document.location.href = href;
          }
        }
      }
    };

    this.tree(settings);
    return this;
  };

  /**
   * jQuery extension to submit a form and send the contents from the server to the dialog.
   *
   */
  $.fn.wexSendFormToDialog = function(options) {
    var dialogContent = options.dialogContent ? options.dialogContent : $("#dialogContent");
    var settings = $.extend({
      dataType: "json",
      error: function(xhr) {
        dialogContent.html(xhr.responseText);
      }
    }, options || {});

    return this.ajaxForm(settings);
  };

  /**
   * jQuery extension to send the results of clicking a link to the dialog
   *
   */
  $.fn.wexSendLinkToDialog = function(options) {
    var dialogContent = options.dialogContent ? options.dialogContent : $("#dialogContent");
    var settings = $.extend({
      dataType: "json",
      type: "POST",
      error: function(xhr) {
        dialogContent.html(xhr.responseText);
      }
    }, options || {});

    this.unbind("click");

    return this.click(function() {
      if (!settings.url) {
        settings.url = $(this).attr("href");
      }
      $.ajax(settings);
      return false;
    });
  };
})(jQuery);

/**
 * This function uses jQuery's Special Events API to create two events, "scrollstart" and "scrollstop"
 * author: Ben Babics
 */
(function() {
  var special = jQuery.event.special;
  var uid1 = 'D' + (+new Date());
  var uid2 = 'D' + (+new Date() + 1);

  special.scrollstart = {
    setup: function() {
      var timer, handler = function(evt) {
        var _self = this;
        var _args = arguments;

        if (timer) {
          clearTimeout(timer);
        } else {
          evt.type = 'scrollstart';
          jQuery.event.handle.apply(_self, _args);
        }

        timer = setTimeout(function() {
          timer = null;
        }, special.scrollstop.latency);

      };

      jQuery(this).bind('scroll', handler).data(uid1, handler);
    },
    teardown: function() {
      jQuery(this).unbind('scroll', jQuery(this).data(uid1));
    }
  };

  special.scrollstop = {
    latency: 300,
    setup: function() {
      var timer, handler = function(evt) {
        var _self = this;
        var _args = arguments;
        if (timer) {
          clearTimeout(timer);
        }

        timer = setTimeout(function() {
          timer = null;
          evt.type = 'scrollstop';
          jQuery.event.handle.apply(_self, _args);
        }, special.scrollstop.latency);
      };

      jQuery(this).bind('scroll', handler).data(uid2, handler);
    },
    teardown: function() {
      jQuery(this).unbind('scroll', jQuery(this).data(uid2));
    }
  };
})();
