
jQuery.fn.variantConstructor = function() {
	var // Constructors' container
		context		= jQuery(this),
		// Set of dropdowns menus
		dropdowns	= jQuery('select.item', context),
		// Product information table
		variants	= jQuery('.combination', context),
		// Message box
		message		= jQuery('#price-from'),
		// Does we have enought information to build product
		enough		= true,
		// Pattern for variant group ID parsing
		pattern		= /variant-group-/,
		// Variant tree
		path		= {},
		// set of properties for next variant group
		nextSet = null,
		// groups order
		order = [];
	
	// Set the groups order
	for(var c = 0, len = dropdowns.length; c < len; c++) {
		var menu = $(dropdowns[c]);
		order.push(menu.attr('name').replace(pattern, ''));
	}
		
	// Initiallize constructor
	dropdowns.change(function(){
		var // Current dropdown menu
			self		= jQuery(this),
			// Place in list of menus
			index		= dropdowns.index(self),
			// Selected item in dropdown menu
			choice		= self.find('option:selected'),
			// 
			groupId		= order[index];
		// Nothing selected - do nothing
		if(choice.val() == 0) {
			resetDropdowns(self);
			return;
		}
		
		// Record path
		path[groupId] = choice.val();
		
		var // Next dropdown menu
			nextList	= jQuery(dropdowns[index + 1]),
			// Parse variant group ID
			nextGroupId	= (nextList.length != 0) ? nextList.attr('name').replace(pattern, '') : null,
			// Set of values for next list
			groupValues = [],
			//
			data = null;
			
		nextSet = getValues(choice.val());
		
		if(index < dropdowns.length - 1) {
			for(var id in nextSet) {
				var pair = { 'id': id, 'title' : combinations_titles[nextGroupId][id] };
				groupValues.push(pair);
			}
						
			data = { values : groupValues };
			
			// Update nex list of parameters
			nextList.removeAttr('disabled').process_tpl('#dropdown-tpl', data);
			
			if(groupValues.length == 1)
				nextList.change();
			else
				resetDropdowns(nextList);
		}
		
		showProduct();
	});
	
	$(dropdowns.get(0)).each(function(){
		var options = $('option', this);
		// If length of options in dropdown is 1 call change event
		if(options.length == 1) $(this).change();
	});
	
	/**
	 * Get list of related characteristics
	 */
	function getValues(deep) {
		var result = product_variants, seq = order, p = path;
		
		for(var i = 0, len = seq.length; i < len; i++){
			var step = seq[i], id = p[step];
			// update result
			result = result[id];
			
			if(id == deep) break;
		}
		
		return result;
	}
	
	/**
	 * Check is enough information for showing product variant
	 */
	function isEnough() {
		var results = [], isEnough = true;
		
		dropdowns.each(function(){
			var v = jQuery(this).find('option:selected').val();
			var flag = (v == 0 || v == undefined) ? false : true;
			results.push(flag);
		});

		for(var r in results) {
			if( ! results[r]) {
				isEnough = false;
				break;
			}
		}
		
		return isEnough;
	}
	
	/**
	 * Show product variant in acording to chosen characteristics
	 */
	function showProduct() {
		var ids = [], id = '';

		if(isEnough()) {
			dropdowns.each(function(){
				ids.push(jQuery(this).find('option:selected').val());
			});
		
			// Hide all visible variants
			variants.hide();
			message.hide(); 
		
			// Show compiled variant
			jQuery('#combination-' + ids.join('-')).show();	
		} else {
			// Hide all visible variants
			variants.hide();
			
			// Show message box
			message.show();
		}
	}
	
	/**
	 * Show product variant in acording to chosen characteristics
	 */
	function resetDropdowns(elem) {
		var index = dropdowns.index(elem);
		
		// Hide variants
		variants.hide();
			
		// Show message box
		message.show();
		
		dropdowns.each(function(){
			var self = jQuery(this);
			if(! (dropdowns.index(self) <= index)) {
				var data = { data: true };
				self.process_tpl('#empty-dropdown-tpl', data);
				self.attr('disabled', 'disabled');
			}
		});
	}
	
}

