var application = new function($) {

  this.core = {
    setGlobal: function(key, value) {
      priv.setProp('global', key, value);
    },
    getGlobal: function(key, def) {
      return priv.getProp('global', key, def);
    },
	isGlobalDefined: function(key) {
      return priv.isPropDefined('global', key);
    },
	
    setLang: function(key, value) {
      priv.setProp('lang', key, value);
    },
    getLang: function(key, def) {
      return priv.getProp('lang', key, def);
    },
	isLangDefined: function(key) {
      return priv.isPropDefined('lang', key);
    },
    getLangFormatted: function(key, replacements) {
	  return application.util.formatMessage(application.core.getLang(key, ''), replacements || []);
    },
	
	isLive: function() {
	  return application.core.getGlobal('environment').toLowerCase() == 'production';
	},
	
	apply: function(fn) {
	  fn.apply(application, Array.prototype.slice.call(arguments, 1));	
	},

	extend: function() {
	  if (arguments.length > 1) {
	    return $.extend.apply(null, arguments);
	  } else {
		var a = $.makeArray(arguments);
		a.unshift(application);
		return $.extend.apply(null, a);
	  }
	},
	
	ready: function(fn, scope) {
	  var args = Array.prototype.slice.call(arguments, 2);
	  
	  $(function() {
		fn.apply(scope || application, args); 
	  });		
	}
  };
  
  this.util = {	
	roundTo: function(base, precision) {
	  var m = Math.pow(10, precision);
	  var a = Math.round(parseFloat(base) * m) / m;
	  return a;
	},
	
	formatTo: function(base, precision) {
	  var a = application.util.roundTo(base, precision);
	  var s = a.toString();
	  var decimalIndex = s.indexOf('.');
	  
	  if (precision > 0 && decimalIndex < 0) {
		decimalIndex = s.length;
		s += '.';
	  }
	  while (decimalIndex + precision + 1 > s.length) {
		s += '0';
	  }
	  return s;
	},
	
	formatCurrency: function() {
	  var a = arguments;
	  return (a[2] || '$') + application.util.formatTo.apply(null, [a[0], a[1] || 2]);
	},
  
	truncate: function(string, length) {
	  return string.length > length ? string.substring(0, length).replace(/[\s\.,;\?]*\w+[\s\.,;\?]*$/, '') + '...' : string;
	},
	
	keysToLowerCase: function(o, deep) {
	  if (o.constructor == Array) {
		for (var i = 0, n = []; i < o.length; i++) {
		  n[i] = (deep === false || typeof o[i] != 'object') ? o[i] : application.util.keysToLowerCase(o[i], deep);
		}
	  } else if (o.constructor == Object) {
		var i, n = {};
		for (i in o) {
		  n[i.toLowerCase()] = (deep === false || typeof o[i] != 'object') ? o[i] : application.util.keysToLowerCase(o[i], deep);
		}
	  } else {
	    return o;
	  }
	  
	  return n;
	},
	
	appendQueryString: function(s, v) {
	  return (s += (s.indexOf('?') == -1 ? '?' : '&') + (typeof v == 'string' ? v : $.param(v))).replace(/(\?|&){1}$/, '');
	},
	
    formatMessage: function() {
	  var a = arguments, result = a[1].constructor == Array ? a[1] : a; 
	  return a[0].replace(/\{\d+\}/gim, function() { 
	    return result[arguments[0].replace(/[\{\}]/g, '')]; 
	  });
    },
	
	getById: function(id) {
	  return $(id.indexOf('#') == 0 ? id : '#' + id);
	},

	scopeCallback: function(callback, scope, args) {
	  return function() {
		return callback.apply(scope, args || []);
	  };
    },
	
	queryToArray: function(query) {
	  var q = application.util.keysToLowerCase(typeof query == 'object' ? query : eval('query=' + query), false);
	  var c = $.map(q.columns, function(n) { return n.toLowerCase(); }), d = q.data;
	  
	  return $.map(d, function(n) {
		for (var i = 0, o = {}; i < n.length; i++) {
		  o[c[i]] = n[i];
		}
		return o;					   
	  });
	},
	
	fileNameFromPath: function(path) {
	  return path.split('/').pop();
	},
	
	parseJson: function(data) {
	  if (/^\s*</.test(data)) {
		alert(data);
		return;
	  }
	  
	  if (typeof(JSON) !== 'undefined' && typeof(JSON.parse) === 'function') {
		return JSON.parse(data);
	  } else {
		return eval('(' + data + ')');
	  }
	}
  };  
  
  this.ui = {
    init: function() {},	
	
	icons: {
	  getIconClassPreifx: function() {
		return 'system-file-';
	  },
	  
	  getIconClass: function(filename) {
		return this.getIconClassPreifx() + this.getIcon(filename);
	  },
	  
	  getIconImagePreifx: function() {
		return 'icon-';
	  },
	  
	  getIconImage: function(filename) {
		return this.getIconImagePreifx() + this.getIcon(filename);
	  },
	  
	  getIcon: function(filename) {
		return (filename ? this.getFilenameIcon(filename) : this.getFolderIcon())
	  },
	  
	  getFolderIcon: function() {
		return 'folder';  
	  },
	  
	  getFilenameIcon: function(filename) {
		switch (/\./.test(filename) ? filename.split('.').pop().toLowerCase() : 'unknown') {
		  case 'htm':
		  case 'html':
		  case 'cfm':
		  case 'asp':
		  case 'aspx':
		  case 'php':
		  case 'jsp': {
			return 'webpage';
		  }
		  case 'jpg':
		  case 'jpeg': {
			return 'jpg';
		  }
		  case 'gif': {
			return 'gif';
		  }
		  case 'bmp':
		  case 'tif':
		  case 'tiff': {
			return 'bmp';
		  }		  
		  case 'pdf': {
			return 'pdf';
		  }
		  case 'swf': {
			return 'swf';
		  }		  
		  case 'txt':
		  case 'js':
		  case 'as':
		  case 'h':		  
		  case 'c':		  
		  case 'cs':		  
		  case 'cpp':		  		  
		  case 'sql':
		  case 'wddx':
		  case 'xml':
		  case 'xsl': {
			return 'text';
		  }
		  case 'ini':
		  case 'css': {
			return 'ini';
		  }
		  case 'doc':
		  case 'rtf': {
			return 'word';
		  }
		  case 'xls':
		  case 'csv':
		  case 'tab': {
			return 'excel';
		  }
		  case 'ppt': {
			return 'powerpoint';
		  }		  
		  case 'mdb': {
			return 'access';
		  }				  
		  case 'eml': {
			return 'outlook';
		  }				  
		  case 'pub': {
			return 'publisher';
		  }				  
		  case 'zip':
		  case 'rar': 
		  case 'tar': {
			return 'zip';
		  }
		  case 'psd': {
			return 'photoshop';
		  }		  
		  case 'ai':
		  case 'eps': {
			return 'illustrator';
		  }
		  case 'png': {
			return 'fireworks';
		  }				  
		  case 'id': {
			return 'indesign';
		  }				  
		  case 'dwt': {
			return 'dreamweaver';
		  }				  
		  case 'fla': {
			return 'flash';
		  }
		  case 'aep': {
			return 'aftereffects';
		  }		
		  case 'ppj':
		  case 'pproj': {
			return 'premier';
		  }		
		  case 'sb':
		  case 'sbp': {
			return 'soundbooth';
		  }				  
		  case 'exe': {
			return 'exe';
		  }
		  case 'avi':
		  case 'mpg':
		  case 'mpeg': {
			return 'mpg';
		  }
		  case 'wmv':
		  case 'wma': {
			return 'windowsmedia';
		  }
		  case 'mp3':
		  case 'wav': {
			return 'mp3';
		  }
		  case 'mov': {
			return 'quicktime';
		  }		  
		  default: {
			return 'unknown';
		  }
		}
	  }
	},
	
	clearText: function(selector) {
	  return $(selector).clearText({
		onFocus: function($el) { 
		  $el.addClass('focus'); 
		}, 
		onBlur: function($el) { 
		  $el.removeClass('focus'); 
		}
	  });			
	},
	
	linkFormSubmit: function(selector) {
	  return $(selector).bind('click', function(e) {
		  application.ui.util.triggerParentFormSubmit('', this);
		  
		  return false;
		}
	  );
	},
	
	clearSearch: function(selector) {
	  return $(selector).bind(
	    'click', 	
		function() {
		  if(this.form != undefined) {
			$(this.form).clearForm().trigger('submit');  
		  }
		}
	  );
	},
	
	autocompleteOff: function() {
	  if (application.core.isLive()) {
	    $('input[type=text]').attr('autocomplete', 'off');  
	  }
    },	
	
	actionmenu: {
	  associate: function(selector, options) {
		return $(selector).actionMenu($.extend({
		  actionSelector: 'div' 
		}, options));
	  }
	},		
	
	tableactions: {
	  associate: function(selector, options) {
		return $(selector).tableActions($.extend({
		  changeLocationSelector: 'div.action-menu a:has(i.view)'
		}, options));
	  }
	},		
	
	tinymce: {
	  associate: function(selector, options) {
		return $(selector || 'textarea.tinymce').tinymce($.extend({
		  script_url: application.core.getGlobal('generalResourcesPath') + 'javascript/jquery/plugins/tiny_mce/tiny_mce.js',

		  document_base_url: application.core.setGlobal('root'),
		  relative_urls: false,
		  width: '90%',
		  height: '500',
			
		  content_css: application.core.getGlobal('websiteResourcesPath') + 'css/editor.css',
	
		  external_link_list_url: application.core.getGlobal('editorLinkListPath'),
		  external_image_list_url: application.core.getGlobal('editorImageListPath'),
		  media_external_list_url: application.core.getGlobal('editorMediaListPath'),
		  template_external_list_url: application.core.getGlobal('editorTemplateListPath'),			
								
		  theme: 'advanced',
		  skin: 'o2k7',
		  skin_variant: 'silver',
		  plugins: 'safari,style,table,advimage,advlink,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,fullscreen,noneditable,xhtmlxtras',
	
		  theme_advanced_buttons1: 'newdocument,preview,|,undo,redo,|,bold,italic,|,justifyleft,justifycenter,justifyright,justifyfull,|,link,unlink,image,media,styleselect,formatselect',
		  theme_advanced_buttons2: 'cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,sub,sup,|,insertdate,inserttime,|,hr,removeformat,visualaid,|,styleprops,|,charmap,iespell',
		  theme_advanced_buttons3: 'tablecontrols,|,cite,abbr,acronym,del,ins,attribs,|,code,fullscreen,print,cleanup',
		  theme_advanced_toolbar_location: 'top',
		  theme_advanced_toolbar_align: 'left',
		  theme_advanced_statusbar_location: 'bottom',
		  theme_advanced_resizing: false
	    }, options));
	  },
	  
	  associateForFlash: function(selector, options) {
		return application.ui.tinymce.associate(selector || 'textarea.tinymce-flash', $.extend({
		  valid_elements: 'a[href|target=_blank],b/strong,br,font[color|face|size],img[src|id|width|height|align|hspace|vspace],i/em,li,p[align|class],h1,h2,h3,h4,h5,h6,span[class],textformat[blockindent|indent|leading|leftmargin|rightmargin|tabstops],u',
		  
		  height: '300',
		  
		  theme_advanced_buttons1: 'newdocument,preview,|,undo,redo,|,cut,copy,paste,pastetext,pasteword,|,search,replace,|,charmap,iespell,|,code,fullscreen,print,cleanup,|,bold,italic,bullist,|,link,unlink,image,formatselect',
		  theme_advanced_buttons2: '',
		  theme_advanced_buttons3: ''
		}, options));
	  }
	},
	
	swfupload: {
	  associate: function(selector, options) {
		return $(selector.ui).swfupload($.extend({
		  upload_url: '',
		  file_size_limit: '100 MB',
		  file_types: application.ui.swfupload.allowedFiletypes('*'),
		  file_types_description: '',
		  file_upload_limit: 0,
		  file_queue_limit: 0,
		  flash_url: application.core.getGlobal('generalResourcesPath') + 'javascript/swfupload/swfupload.swf',
		  button_image_url: '',
		  button_width: 80,
		  button_height: 22,
		  button_text: '',
		  button_text_style: ".styled {  }",
		  button_text_left_padding: 0,
		  button_text_top_padding: 0,
		  button_placeholder: null,
		  button_placeholder_id: null,
		  button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
		  button_cursor: SWFUpload.CURSOR.POINTER,	
		  debug: false,
		  post_params: {},
		  custom_settings: {}
		}, options)).bind('swfuploadPreLoad', function(event) {
		  // fire ui update			
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, {});
		}).bind('swfuploadLoadFailed', function(event) {
		  // it failed, hide wrap, show alternate
		  $(selector.wrap).hide();			
		  $(selector.alternate).show();	
		  // fire ui update			
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, {});			
		}).bind('swfuploadLoaded', function(event) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, {});			  
		}).bind('fileQueued', function(event, file) {
		  // fire ui update			
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file });				
		}).bind('fileQueueError', function(event, file, errorCode, message) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file, errorCode: errorCode, message: message });						  
		}).bind('fileDialogStart', function(event) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, {});			  
		}).bind('fileDialogComplete', function(event, numFilesSelected, numFilesQueued) {
		  // start the upload since it's queued
		  $(this).swfupload('startUpload');						
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { selected: numFilesSelected, queued: numFilesQueued });						  
		}).bind('uploadStart', function(event, file) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file });						  
		}).bind('uploadProgress', function(event, file, bytesLoaded, bytesTotal) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file, percent: Math.ceil((bytesLoaded / bytesTotal) * 100), bytesLoaded: bytesLoaded, bytesTotal: bytesTotal });
		}).bind('uploadSuccess', function(event, file, serverData) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file, data: serverData });
		}).bind('uploadComplete', function(event, file) { 
		  // fire ui update
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file, filesQueued: application.ui.swfupload.getInstance(this).getStats().files_queued });						
		}).bind('uploadError', function(event, file, errorCode, message) {
		  // fire ui update			  
		  application.ui.swfupload.dispatchEvent.call(this, event, selector, { file: file, errorCode: errorCode, message: message, filesQueued: application.ui.swfupload.getInstance(this).getStats().files_queued });						  
		});
	  },
	  
	  getInstance: function(selector) {
		 return $.swfupload.getInstance(selector); 
	  },
	  
	  getCustomSettings: function(selector) {
		 return application.ui.swfupload.getInstance(selector).customSettings; 
	  },
	  
	  getCustomSetting: function(selector, key) {
		 return application.ui.swfupload.getCustomSettings(selector)[key]; 
	  },
	  
	  setCustomSetting: function(selector, key, value) {
		 application.ui.swfupload.getCustomSettings(selector)[key] = value; 
	  },	  
	  
	  allowedFiletypes: function(list) {
		return $.map(($.isArray(list) ? list : list.split(',')), function(n) {
		  return '*.' + n;													   
		}).join(';');
	  },
	  
	  dispatchEvent: function(event, selector, args) {
		var defaultEvent = 'defaultEvent';
		var settings = application.ui.swfupload.getCustomSettings(this);
		
		if (settings[event.type] != undefined) {
		  settings[event.type].apply(this, arguments);
		} else if (settings[defaultEvent] != undefined) {
		  settings[defaultEvent].apply(this, arguments);
		}
	  }
	},
	
	grid: {
	  build: function (selector, type, params) {
	    switch (type) {
	      case 'remote': {
	        var options = {
			  url: '',
			  params: [],
			  dataType: 'json',
			  height: 300,
		  	  striped: true,
			  showTableToggleBtn: true,					
			  title: '',
			  pagestat: application.core.getLang('gridPageStats'),
			  procmsg: application.core.getLang('gridProcessingMessage'),
			  nomsg: application.core.getLang('gridNoItemsMessage'),					
			  errormsg: application.core.getLang('gridErrorMessage'),						
			  colModel : [],
			  sortname: 'id',
			  sortorder: 'ASC',
			  usepager: true,
			  useRp: true,
			  rp: 100,
			  rpOptions: [5, 10, 20, 30, 50, 100],
			  searchitems: [],									
			  onError: application.ui.util.dump,
			  onSuccess: function() {
				$('a', selector).popup();  
			  },			  
			  preProcess: function(data) { 
				return application.util.keysToLowerCase(data);
			  },
			  onSubmit: function() { 
				return true; 
			  }			  
		    };
		    break;
	      }
	      case 'simple': {
	        var options = {
			  width: 'auto',
			  height: 'auto',
			  striped: true,
			  showTableToggleBtn: true,					
			  title: ''			
		    };	
		    break;
	      }
	    }

	    $(function() { 
	      var $el = $(selector);
	      if ($el.length) {
		    $el.flexigrid($.extend(options, params));
	      }
	    });
      },
	  
	  buttons: function(a) {
		$(function() {
		  $.each(a, function(i, n) {
		    $(n.selector).bind(
			  'click.buttons',
			  function() {
				n.onpress(n.name, $(this).parents('table'));
				return false;
			  }
		    );
	      });
		});
	  }
	},
	
	datepicker: {
	  associate: function(selector, options) {
		return $(selector).removeClass($.datepicker.markerClassName).datepicker($.extend({}, application.ui.datepicker.getLang(), { 
		    duration: 'fast',
		    onSelect: function(d, i) { 
		      if ($.fn.validate) { 
			    $(i.input[0].form).validate().element(i.input); 
			  } 
		    } 
		  }, options)).bind('blur', function() {
		    var inst = $.datepicker._getInst(this);
		    var currentDate = $(this).datepicker('getDate');
		    var minDate = $.datepicker._get(inst, 'minDate');
		    var maxDate = $.datepicker._get(inst, 'maxDate');

		    if ((currentDate && minDate && minDate !== null) && currentDate < minDate) {
			  $(this).datepicker('setDate', minDate);
		    } else if ((currentDate && maxDate && maxDate !== null) && currentDate > maxDate) {
			  $(this).datepicker('setDate', maxDate);
		    }
		});
	  },
	  
	  getLang: function() {
		return {
			clearText: 'Clear', 
			clearStatus: 'Erase the current date',
			closeText: 'Close', 
			closeStatus: 'Close without change', 
			prevText: '&#x3c;Prev', 
			prevStatus: 'Show the previous month', 
			prevBigText: '&#x3c;&#x3c;',
			prevBigStatus: 'Show the previous year',
			nextText: 'Next&#x3e;', 
			nextStatus: 'Show the next month',
			nextBigText: '&#x3e;&#x3e;',
			nextBigStatus: 'Show the next year', 
			currentText: 'Today', 
			currentStatus: 'Show the current month', 
			monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
			monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 
			monthStatus: 'Show a different month',
			yearStatus: 'Show a different year',
			weekHeader: 'Wk',
			weekStatus: 'Week of the year', 
			dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
			dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 
			dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], 
			dayStatus: 'Set DD as first week day',
			dateStatus: 'Select DD, M d', 
			dateFormat: 'dd/mm/yy', 
			firstDay: 0, 
			initStatus: 'Select a date',
			isRTL: false
		};		  
	  }
	},
	
	tooltip: {
	  associate: function(selector, options) {
		return $(selector).tooltip($.extend({
		  track: true,
		  delay: 0,
		  showBody: ' - ',
		  showURL: false
		}, options));
	  },
	  
	  helpTip: function() {
		this.associate('span.help', { 
		  extraClass: 'help-tooltip', 
		  track: false, 
		  bodyHandler: function() { return $(this).html(); } 
		});  
	  }
	},	
	
	accordion: {
	  associate: function(selector, options) {
		var selectedClass = options && options.selectedClass ? options.selectedClass : 'selected', toggleClass = ['toggle', 'toggle-m'];
		  
		return $(selector).accordion(
		  $.extend({ autoheight: false, selectedClass: selectedClass,  header: 'div.toolbar' }, options)
		).bind('change.ui-accordion', function(e, ui) { 
		  ui.oldHeader.find('a.' + toggleClass[0]).removeClass(toggleClass[1]);
		  ui.newHeader.find('a.' + toggleClass[0]).addClass(toggleClass[1]);
		}).find('div.toolbar div').prepend('<a href="javascript:;" class="' + toggleClass[0] + '"></a>').end().find('.' + selectedClass + ' a.' + toggleClass[0]).addClass(toggleClass[1]);
	  },
	  
	  build: function(views, options) { 
		var wrap = $('<div class="accordion"' + ($.browser.msie && $.browser.version == 6 ? '' : ' style="position:relative;"') + '></div>');
		
		$.each(views, function(i, n) {
		  var title = $('<div class="toolbar"><div class="title">' + n.title + '</div></div>');
			
		  wrap.append(title);
		  wrap.append(n.content);
		});
		
		this.associate(wrap, options);
		
		return wrap;
	  }
	},
	
	autocomplete: {
	  associate: function(selector, url, params, options) {
		$(function() {
		  var el = $(selector);
		  var width = el.width() + parseInt(el.css('paddingLeft'), 10) + parseInt(el.css('paddingRight'), 10);

		  el.autocomplete(
		    url, 
			$.extend(
			  {
				max: 25,				  
				width: width,
				multiple: false,
				multipleSeparator: ",",
				scroll: true,
				scrollHeight: 250,
				dataType: 'json',
				extraParams: params || {},
				parse: function(data) {
				  var i = 0, p = [];

				  for (; i < data.length; i++) {

					p[p.length] = {
					  data: [data[i].key, data[i].value, data[i]],
					  value: data[i].key, 
					  result: data[i].key 
				    };  
				  }

				  return p;
				},
				formatItem: function(row, i, max) {
				  return row[0] + '<br />' + row[1];
				},
				formatResult: function(row, i, max) {
				  return row[0];
				}
			  },
			  options
		    )
		  ).result(function(event, data, formmated) {
			if ($.fn.validate) {
			  $(event.target.form).validate().element(event.target);
			}	
		  });
		})
	  }
	},
	
	ajax: {
	  get: function(scope, el, success, failure, url, params, dataType, timeout) {
		this.request('get', scope, el, success, failure, url, params, dataType, timeout);
	  },
	  
	  post: function(scope, el, success, failure, url, params, dataType, timeout) {
		this.request('post', scope, el, success, failure, url, params, dataType, timeout);
	  },	  
	  
	  request: function(type, scope, el, success, failure, url, params, dataType, timeout) {
	    var fn = this.ajaxSuccess;
		
		if (el) {
		  application.ui.util.message.addBeforeEl(el, application.ui.util.message.build('array', [{ severity: 'spinner', message: application.core.getLang('processingRequest') }]));
		}
		
		$.ajax({
		  type: type,
		  url: url,
		  data: params,
		  dataType: dataType || 'json',
		  success: function(json) 
		  { 
		    fn(scope, json, el, success, failure, timeout);
		  },
		  error: application.ui.util.dump
	    });		  
	  },
	  
	  ajaxSuccess: function(scope, json, el, success, failure, timeout) {
		setTimeout(function() {
		  var data = application.util.keysToLowerCase(json, true);
		  var messages = data && data.messages;

		  if (el) {
		    if (messages) {
			  application.ui.util.message.addBeforeEl(el, application.ui.util.message.build('query', data.messages));
			} else {
			  application.ui.util.message.addBeforeEl(el, application.ui.util.message.build('array', [{ severity: 'notice', message: application.core.getLang('requestComplete') }]));			
			}
		  }

		  if (success && (!messages || application.ui.util.message.success(data.messages))) {
			success.apply(scope, [data, el]);
		  } else if (failure) {
			failure.apply(scope, [data, el]);
		  }
		}, timeout || 1000);		  
	  },	  
	  
	  ajaxSubmit: function(scope, form, success, failure, error, dataType, timeout, iframe) {
		$(form).ajaxSubmit(this.getAjaxFormOptions.apply(this, arguments)); 
	  },
	   
	  ajaxForm: function(scope, form, success, failure, error, dataType, timeout, iframe) {
		$(form).ajaxForm(this.getAjaxFormOptions.apply(this, arguments));
	  },
	  
	  getAjaxFormOptions: function(scope, form, success, failure, error, dataType, timeout, iframe) {
		var fn = this.ajaxSuccess;
		var useIframe = iframe === true ? true : false;
		
		return {
		  dataType: dataType || 'json',
		  data: { token: application.core.getGlobal('userToken'), xhr: !useIframe },
		  beforeSubmit: function() {
			application.ui.util.message.addBeforeEl(form, application.ui.util.message.build('array', [{ severity: 'spinner', message: application.core.getLang('processingRequest') }]));
				
			form.find('label').remove();
		  },
		  error: error || application.ui.util.dump,			  
		  success: function(json) {
			fn(scope, json, form, success, failure, timeout);
		  },
		  iframe: useIframe
	    };		  
	  }
	},
	
	validate: {
	  setForms: function(forms) {
		this.forms = forms;
	  },
	  
	  getForms: function() {
		return this.forms;
	  },	  
	  
	  getForm: function(form) {
		return this.forms[form];
	  },
	  
	  run: function(form, options, selector) {
		var self = this;

		$(function() {
		  if (form && self.forms[form]) {
		    $(selector ? selector : form).validate($.extend(self.defaults, self.forms[form], options));
		  } else {
		    $.each( self.forms, function(i, n) { $(i).validate($.extend(self.defaults, n, options)); } );
		  }
	    });
	  },
	  
	  runAjaxForm: function(scope, id, form, success, failure, error, timeout) {
		this.run(id, {
		  submitHandler: function() {
		    application.ui.ajax.ajaxSubmit(scope, form, success, failure, error, timeout);
		  }
	    }, form);		  
	  },
	  
	  init: function(forms) {		  
		if (typeof forms == 'object') {
		  this.setForms(forms);
		}
	  },
	  
	  defaults: { 
	    ignoreTitle: true,
		errorClass: 'error-message',
		errorElement: 'label',
		errorPlacement: function(error, element) {
		  if (element.is(":radio,:checkbox")) {
			if (element.parent().parent().find('>label.simple').size()) {
			  element.parent().parent().find('>label.simple').after(error);
			} else {
			  element.parent().append(error);
			}
		  } else {
			element.next().size() ? element.nextAll().after(error) : element.after(error);
		  }
		},			
		success: function(label) {
		  label.html('&nbsp;').addClass('success-message');
	    }
	  },
	  forms: {}
	},
	
	select: {
	  multiReplace: function(el) {
		if (!el) { return; }
		ISSelectReplacement.replace_select(el.jquery != undefined ? el[0] : el);
	  }
	},
	
	window: {
	  make: function(content, settings) {
	    return new Boxy(
		  content, 
		  $.extend(
		    { 
		  	  closeText: '<span class="close-btn"></span>',
			  title: application.core.getGlobal('name')
		    },
		    settings
		  )
	    );
	  },
	  
	  alert: function(content, severity, callback, modal) {
		 this.dialouge(content, severity, [application.core.getLang('ok')], callback, modal); 
	  },
	  
	  confirm: function(content, severity, callback, modal) {
		 this.dialouge(content, severity, [application.core.getLang('yes'), application.core.getLang('no'), application.core.getLang('cancel')], callback, modal); 
	  },
	  
	  simpleConfirm: function(content, severity, callback, modal) {
		 this.dialouge(content, severity, [application.core.getLang('yes'), application.core.getLang('no')], function(c, a) { if ($.inArray(c, a) == 0) { callback.apply(null, arguments) } }, modal); 
	  },	  
	  
	  dialouge: function(content, severity, answers, callback, modal) {
		Boxy.ask(
		  !severity ? content : ('<span class="' + severity.toLowerCase() + '">' + content + '</span>'), 
		  answers, 
		  function(clicked) {
			if (callback) {
			  callback.apply(this, [clicked, answers]);
			}
		  }, 
		  { 
			modal: (modal === null || modal === undefined) ? false : modal, title: application.core.getGlobal('name'), offset: this.offset
		  }
		);
	  },
	  
	  offset: 20
	},
	
	util: {
	  fixBgCache: function() {
	    try {
	      document.execCommand('BackgroundImageCache', false, true);
	    } catch(e) {};
	  },
		
      triggerParentFormSubmit: function(name, element) { 
	    $(element).parents('form').trigger('submit'); 
	  },
	
	  toggleCheckBoxesInEl: function(method, element) {
	    $('input[type=checkbox]', element).not('[name=""]').attr('checked', method.toLowerCase().indexOf('uncheck') == -1 ? 'checked' : '');
	  },
	  
	  addCancelAfterSubmit: function($el) {
	    if (!$el.find('[name=cancelButton]').length) {
	      $el.find('[type=submit]').after(' <input type="button" name="cancelButton" class="close btn" value="' + application.core.getLang('cancel') + '" />');
	    }		  
	  },
	  
	  fieldFocus: function(form) {
		try { 
		  var field;
		  
		  if (form) {
		    field = form.find('input[type=text]:first');
		    field = field.length ? field : form.find('textarea:first');
		  } else {
			field = $('#load-focus');
		  }
		  
		  if (field.size()) {
		    field[0].focus(); 
		  }
		} catch (e) {};
	  },  
	  
	  disableSelection: function(el) {
		el.onselectstart = function() { return false; };
		el.unselectable = 'on';
		el.style.MozUserSelect = 'none';
		el.style.cursor = 'default';			
	  },	  
	  
	  hide: function(selector) {
		$(selector).hide();		  
	  },
	  
	  toggle: function(selector, slide, toggleClass) {
		$(selector).bind('click', function() {
		  var el = $(this), rel = el.attr('rel'), c = toggleClass != undefined ? toggleClass : 'toggle-m', a;
		  
		  switch (rel) {
			case 'tbody': {
			  a = el.parents('table');
			  
			  if (a.find('caption').length) {  
			    a = a.find('tbody, thead');
			  } else {
				a = a.find('tbody');
			  }
			  break;
			}
			default: {
			  a = application.util.getById(rel);
			}
		  }
		  
		  // yuk
		  if ($.browser.msie && $.browser.version == 8) {
			if ((!$.trim(a[0].style.display).length && a.is(':visible')) || ($.trim(a[0].style.display).length && !/none/i.test(a[0].style.display))) {
			  slide ? a.slideUp('fast') : a.hide();			  
			  el.removeClass(c);    
			} else {	 
			  slide ? a.slideDown('fast') : a.show();
			  el.addClass(c);  
			}
		  } else {
		    if ((slide ? a.slideToggle('fast') : a.toggle()).is(':hidden')) {
		  	  el.removeClass(c);    
		    } else {
		  	  el.addClass(c);  
		    }
		  }
		});		  
	  },
	  
	  confirmDelete: function(selector) {
		$(selector).filter('a, [type=submit]').bind('click', function(e) {
		  var loc, form, el = this;
		  
		  if ($.nodeName(el, 'a')) {
			loc = $(el).attr('href');
		  } else if ($.nodeName(el, 'input')) {
			form = $(el.form);
		  }

		  if (loc || form) {
		    application.ui.window.simpleConfirm(application.core.getLang('areYouSureYouWishToDelete'), 'warning', function() {
			  if (loc) {
			    window.location = loc;
			  } else if (form) {
				form.append('<input type="hidden" name="' + el.name + '" value="' + el.value + '" />').trigger('submit');
			  }
		    }, true);
			
			return false;
		  } else {
			return true;
		  }
		});
	  },
	  
	  dump: function(o, st, sa) {
		$.dump.call(this, o.responseText || o, st, sa);
	  }, 
	  
	  message: {
		build: function(type, data) {
		  var a, m, c = 'messages';
		  
		  switch (type.toLowerCase()) {
			case 'query': {
			  a = application.util.queryToArray(data);
			  break;	
			}
			default: {
			  a = data;	
			}
		  }
		  
		  if (a.length) { 
		    m = $('<ul class="' + c + '">');
			$.each(a, function() { $('<li class="' + this.severity + '">' + this.message + '</li>').appendTo(m); });
			
			return m;
		  }		
		},		
		
		addBeforeEl: function(el, messages) {
		  $(el).parent().find('.messages').remove().end().prepend(messages);
		},
		
		success: function(query) {
		  for (var i = 0, q = application.util.queryToArray(query); i < q.length; i++) { 
		    if (q[i].severity.toLowerCase() != 'success') { return false; } 
		  }
		  return true;
		}
	  },
	  
	  html: {
	    makeOption: function(value, display) {
		  return $('<option value="' + value + '">' + display + '</option>');
		},
		
		getGridTable: function(title, rows, buttons, titleType, form) {
		  var i, toolbar, body = '', ht = true, hc = true, tt = titleType || 'default', uf = (form === null || form === undefined) ? true : form, $el;

		  for (i = 0; i < rows.length; i++) {
			ht = rows[i].title && rows[i].title.length, hc = rows[i].content && rows[i].content.length;
		    body += '<tr' + (rows[i].className ? ' class="' + rows[i].className + '"' : '') + '>' + (ht ? '<th' + (!hc ? ' colspan="2"' : '') + '>' + rows[i].title + '</th>' : '') + (hc ? '<td' + (!ht ? ' colspan="2"' : '') + '>' + rows[i].content + '</td>' : '') + '</tr>';
		  }
		
		  $el = $((uf ? '<form action="javascript:;" method="post">' : '') + '<table class="repeat-grid">' + (buttons ? '<caption><div class="toolbar"><div class="title">' + (tt == 'default' ? application.core.getLang('toolbar') : title) + '</div>' + (buttons && buttons.length ? '<div class="menu"></div>' : '') + '</div></caption>' : '') + '<thead>' + (title && title.length && tt == 'default' ? '<tr><th colspan="2">' + title + '</th></tr>' : '') + '</thead><tbody>' + body + '</tbody></table>' + (uf ? '</form>' : ''));
		  
		  if (buttons) {
			toolbar = $el.find('div.menu');
			
			for (i = 0; i < buttons.length; i++) {
			  if (buttons[i].separator) {
				toolbar.append('<div class="separator"></div>');  
			  } else {
				$('<a href="javascript:;"><span><i' + (buttons[i].className ? ' class="' + buttons[i].className + '"' : '') + '>' + buttons[i].text + '</i></span></a>').
				bind(
				  'click',
				  buttons[i].onpress
				).appendTo(toolbar);  
			  }
			}			
		  }
		  
		  return $el;
	    }
	  },
	  
	  uniqueIds: function(selector, uuid) {
	    $(selector).each(
	      function() {
		    var rand = Math.random().toString().replace('.', '');
		    var el = $(this);
		  
		    try {
			  el.attr('id', (el.attr('id').length ? el.attr('id') : rand) + uuid);
		    } catch (e) {
		      var attr = this.getAttributeNode('id');
		
		      if (attr) {
		        this.getAttributeNode('id').nodeValue = (attr.nodeValue && attr.nodeValue.length ? attr.nodeValue : rand) + uuid;			
		      }			  
		    }
		  }
	    );
	  }
	}
  };

  this.init = function() {
	application.core.ready(function() {
	  this.ui.init();
    });
  };  
  
  var priv = {
    global: {},
    lang: {},
  
    setProp: function(s, k, v) {
	  priv[s][k] = v;
    },
	
	getProp: function(s, k, d) {
	  return (!priv.isPropDefined(s, k) && d != undefined) ? d : priv[s][k];
	},
	
	isPropDefined: function(s, k) {
	  return priv[s][k] != undefined;
	}
  };
}(jQuery);