/*
 * @(#)jquery.xlt.printerPicker-1.0.js		1.00 11/08/09
 *
 * Copyright (c) 2011 SG Büromedien GmbH
 * Märkischer Ring 120, 58097 Hagen, Deutschland
 * All rights reserved.
 * 
 * @author		Marcus Holtgräwe
 * @version		1.1 12 Jan 2012
 */

(function($) {
	$.fn.printerPicker = function(dataSource, options) {
		$.fn.printerPicker.defaults = {
			captionVendors 	: "Wählen Sie bitte Ihren Druckerhersteller aus",
			captionModels 	: "Wählen Sie bitte Ihr Druckermodell aus",
			labelTopVendors	: "Top Hersteller",
			labelVendors	: "Hersteller",
			url				: "$1/$2/"
		};
		
		options = $.extend({}, $.fn.printerPicker.defaults, options || {});
		
		vendors$ = createSelectBox(options.captionVendors);
		models$ = createSelectBox(options.captionModels);		
		
		$(vendors$, this).change(function() {
			var vendor = $(this).val();
			callFunction(options.vendorSelect, this, vendor);
			loadModels(vendor);
		});
		
		$(models$, this).change(function() {
			var vendor = vendors$.val();
			var model = $(this).val();

			callFunction(options.modelSelect, this, model);
			
			if (options.url) {
				var url = options.url.replace("$1", vendor).replace("$2", model);
				window.location.href = url;
			}
		});
				
		vendors$.appendTo($(".vendors-container", this));
		models$.appendTo($(".models-container", this));
		
		loadVendors();
		
		return this;
		
		// -------------------------------------
		
		function createSelectBox(caption) {
			var selectBox$ = $("<select/>", { disabled : true});
			$("<option/>", { 
				text : caption, 
				value : "" 
			}).appendTo(selectBox$);
			return selectBox$;
		}
		
		function loadVendors() {
			loadData(vendors$, null, function() {
				addGroup(vendors$, options.labelTopVendors, this.topVendors);
				addGroup(vendors$, options.labelVendors, this.vendors);
				callFunction(options.vendorsLoad, vendors$);
				callFunction(options.vendorSelect, vendors$, null);
								
				if (options.defaultVendor != "undefined") {
					var vendorExists = vendors$
							.find("option[value=" + options.defaultVendor + "]")
							.length > 0;
					if (vendorExists) {
						vendors$.val(options.defaultVendor).trigger("change");
					}
				}
				
				return true;
			});
		}

		function loadModels(vendor) {
			loadData(models$, { vendor : vendor }, function() {
				var success = addGroup(models$, null, this.models);

				// HACK: There seems to be a bug in Opera 11.60:
				// if a large number of <option> elements is inserted into
				// a <select> element via JS, there needs to be a delay after
				// the insertion, or else some entries from the bottom
				// overwrite the top entries in the display
				if ($.browser.opera && $((this.models).length > 1000)) {
					sleep(500);
				}
				
				callFunction(options.modelsLoad, vendors$);
				callFunction(options.modelSelect, vendors$, null);
				return success;
			});
		}
		
		function loadData(selectBox$, params, successFunc) {
			params = params || {};
			
			selectBox$.attr("disabled", true)
					  .find(":not(:first)")
					  .remove();
			
			$.getJSON(dataSource, params,
				function(result) {
					if (result && successFunc.call(result)) {
						selectBox$.attr("disabled", false);
					}
				}
			);			
		}
		
		function addGroup(selectBox$, label, items) {
			if (!items) {
				return false;
			}
			
			$("<optgroup label='&nbsp;'></optgroup>").appendTo(selectBox$);
			
			if (label) {
				var group$ = $("<optgroup/>", { label: label } );
				addItems(group$, items);
				group$.appendTo(selectBox$);
			} else {
				addItems(selectBox$, items);
			}
			
			return true;
		}
		
		function addItems(selectBox$, items) {
			$.each(items, function() {
				$("<option/>", {
					value : this.link.replace(/\//g, ""),
					text : this.name
				}).appendTo(selectBox$);
			});
		}
		
		function callFunction(func, context) {
			if (typeof func == 'function') {
				var params = [];
				for (var i = 2; i < arguments.length; i++) {
					params.push(arguments[i]);
				}
				func.apply(context, params);
			}
		}
	};
	
	function sleep(milliseconds) {
		var start = new Date().getTime();
		for (var i = 0; i < 1e7; i++) {
		    if ((new Date().getTime() - start) > milliseconds) {
		    	break;
		    }
		}
	}	
})(jQuery);
