
var HUE 	= 'h';
var SAT 	= 's';
var VAL 	= 'v';
var RED 	= 'r';
var GREEN 	= 'g';
var BLUE 	= 'b';

function ColorPicker (	myId, 
						myName,
						name,
						svBarId, 
						hueBarId, 
						baseSwatch, 
						swatch, 
						extraSwatch,
						hsvImg, 
						hueImg,
						hueRgb,
						hueRyb,
						isRyb,
						draggerInstance,
						firstInstance
						) 
{
	var me = this;

	var debug = 0;
	var colorDelay = 0;
	var sliderDelay = 0;
	var formDelay = 0;
	var setupDelay = 0;
	
	var rgb, hsv, bsHsv, dHsv;
	bsHsv = new HsvType(0,1,1);
	hsv = new HsvType(null,null,null);
	this.getHsv = function() {
		return hsv;
	}
	rgb = new RgbType(1,0,0);
	dHsv = new HsvType(0, 0, 0);
	this.getDeltaHsv = function() {
		return dHsv;
	}
		
	var fieldSequence = new Array(HUE, SAT, VAL, RED, GREEN, BLUE);
	var formPrefix = new Array();
	formPrefix[HUE]		= 'h';
	formPrefix[SAT]		= 's';
	formPrefix[VAL]		= 'v';
	formPrefix[RED]		= 'r';
	formPrefix[GREEN]	= 'g';
	formPrefix[BLUE]	= 'b';
	
	this.id = myId;
	this.name = name;
	
	baseSwatch = aa.get(baseSwatch);
	swatch = aa.get(swatch);
	extraSwatch = aa.get(extraSwatch);
	var hueImage = aa.get(hueImg);
	
	/** hook for color updates */
	this.onSetColor = null;
	/** flag to indicate repositioning needs  after window resizing */
	this.hasExtraSwatchMoved = false;
	
	var firstId = myId;
	this.isRYB = isRyb;
	if (typeof(firstInstance) == 'object') {
		firstId = firstInstance.id;
	} else {
		firstInstance = me;
	}
	this.firstInstance = firstInstance;

	/** tracks the field the user is currently editing. */
	this.isActive = null;
	/** specifies permission to change the field the user is currently editing once. */
	this.mayChange = null;
	this.isActiveField = function(myTag) {
		if (me.firstInstance.isActive == myTag) {
			if (me.firstInstance.mayChange == myTag) {
				me.firstInstance.mayChange = null;
				return false;
			}
			return true;
		}
		return false;
	}
	this.setActiveField = function(myTag) {
//		if(debug) logger.dump(myName+'.setActiveField ['+myTag.name+']');
		me.firstInstance.isActive = myTag;
	}
	this.setMayChange = function(myTag) {
//		if(debug) logger.dump(myName+'.setMayChange ['+myTag.name+']');
		me.firstInstance.mayChange = myTag;
	}

	
	this.scmRgb = document.standard[firstId + 'isRyb'][0];
	this.scmRyb = document.standard[firstId + 'isRyb'][1];
	this.form2scheme = function() {
		if(debug) logger.dump(myName+'.form2scheme');
		for (var i in me.firstInstance.pickers) {
			me.firstInstance.pickers[i].setRyb(me.scmRyb.checked);
		}
	}
	
	this.getRyb = function(){
		return me.firstInstance.isRYB;
	}
	this.setRyb = function(is){
		if(debug) logger.dump(myName+'.setRyb('+is+']');
		me.firstInstance.isRYB = is;
		if (is) {
			hueImage.src = hueRyb;
		} else {
			hueImage.src = hueRgb;
		}
		hsv = rgb.toHsv(is);
		me.slider2type(HUE);
	}

	this.pickers = new Array();
	this.addPicker = function(myPicker) {
		me.pickers[me.pickers.length] = myPicker;
	}
	this.getPicker = function(idx) {
		if (idx == 0) return null;
		return me.pickers[idx-1];
	}
	me.firstInstance.addPicker(me);

	// get common fields
	this.maximum = new Array();			// maximum fields
	this.maxVals = new Array();			// copy of maximum values 
										// (used to restore from garbage entries)
	this.copyMax = function(valueType) {
		me.firstInstance.maxVals[valueType] = me.maximum[valueType].value;
	}
	this.getMax = function(valueType) {
		return me.firstInstance.maxVals[valueType];
	}
	this.field = new Array();			// value fields
	this.masterField = new Array();	// master number drop downs
	this.delta = new Array();			// delta fields

	for (var i = 0; i < fieldSequence.length; i++) {
		var type = fieldSequence[i];
		var myType = myId + formPrefix[type];
		me.maximum[type] = document.standard[firstId + formPrefix[type] + 'x'];
		me.copyMax(type);
		me.field[type] = document.standard[myType];
		me.masterField[type] = document.standard[myType + 'm'];
		me.delta[type] = document.standard[myType + 'd'];
	}

	var hex;
	hex = document.standard[myId + 'hex'];

	this.d = null;	// dragger instance


	/**
	 *	initializes picker
	 */
	this.init = function() {
		var dims = me.getDims(hsvImg);
		if (typeof(draggerInstance) == 'object') {
			me.d = draggerInstance;
			me.d.setDragger(svBarId, dims['l'], dims['l'] + dims['w'], true, 
							dims['t'], dims['t'] + dims['h'], true, true); 
		} else {
			me.d = new Dragger(svBarId, dims['l'], dims['l'] + dims['w'], true, 
							dims['t'], dims['t'] + dims['h'], true, true); 
		}
	
		dims = me.getDims(hueImg);
		me.d.setDragger(hueBarId, dims['l'], dims['l'] + dims['w'], true, 
							dims['t'], dims['t'] + dims['h'], true, true); 
	
		if(debug) logger.dump('// **********************************************');
		if(extraSwatch != null) {
			me.d.setDragger(extraSwatch.id, 0, null, false, 0, null, false, false); 
			me.d.onAfterDrag(extraSwatch.id, myName+'.hasExtraSwatchMoved = true');
		
			dims = me.getDims(swatch.id);
			if(debug) logger.dump('dims[l]: ['+dims['l']+'] dims[t]: ['+dims['t']+']');
			aa.moveTo(aa.get(me.d.getIdWithWrapper(extraSwatch.id)), 
					dims['l'], dims['t']);
		}
		me.d.onDrag(svBarId, myName+'.onSVDrag()');
		me.d.onDrag(hueBarId, myName+'.onHueDrag()');
//		me.setRyb(isRyb);
		for (var i = 0; i < fieldSequence.length; i++) {
			var type = fieldSequence[i];
			if(debug) logger.dump('\n'+myName+'.init('+type+')');
			if(!me.isHsvType(type)) continue;
			me.form2delta(type);
			me.form2master(type);
			me.form2type(type);
		}

		colorDelay = 10;
		sliderDelay = 50;
		formDelay = 100;
		setupDelay = 250;
		aa.show(aa.get(myName+'_table'));
	}


	this.getDims = function(myId) {
		var tag = aa.get(myId);
		var ret = new Array();
		tl = aa.getComputedTopLeft(tag);
		ret['t'] = tl['top'];
		ret['l'] = tl['left'];
		ret['w'] = aa.getWidth(tag);
		ret['h'] = aa.getHeight(tag);
		logger.dumpHash('dims for ' + myId, ret);
		return ret;
	}



	// master and slave picker references
	var slaves = new Array();
	slaves[HUE] = new Array();
	slaves[SAT] = new Array();
	slaves[VAL] = new Array();

	var master = new Array();
	master[HUE] = null;
	master[SAT] = null;
	master[VAL] = null;

	/**
	 *	handles setting and validating of linked pickers
	 */
	this.form2master = function(valueType) {
		if(debug) logger.dump(myName+'.form2master('+valueType+')');
		var mcp = master[valueType];
		if (mcp != null) {
			if(debug) logger.dump('old master: ' + mcp.id);
			me.removeLink(mcp, me, valueType);
		}
		var myTag = me.masterField[valueType];
		var idx = myTag.selectedIndex;
		if(debug) logger.dump('master index: ' + idx);
		if (typeof(idx) == 'undefined') {
			idx = 0;
		}
		var ms = myTag.options[idx].value;
		mcp = firstInstance.getPicker(ms);
		if (mcp != null) {
			if(debug) logger.dump('new master: ' + mcp.id);
			if(!mcp.addSlave(me, valueType)) {
				myTag.selectedIndex = 0;
				mcp = null;
			} else {
				mcp.propagate(true, null, valueType);
			}
		}
		if(debug) logger.dump(myName+'.form2master setting master['
							+valueType+'] to ['+mcp+']');
		master[valueType] = mcp;
	}
	
	/**
	 *	Removes a link
	 */
	this.removeLink = function (myMaster, mySlave, valueType) {
		myMaster.removeSlave(mySlave, valueType);
		mySlave.removeMaster(valueType);
	}

	/**
	 *	Removes master picker of type
	 */
	this.removeMaster = function(valueType) {
		if(debug) logger.dump(myName+'.removeMaster('+valueType+')');
		master[valueType] = null;
		if(debug) logger.dumpHash('after '+myName+'.removeMaster master:', master);
	}

	/**
	 *	Removes slave picker from type
	 */
	this.removeSlave = function(mySlave, valueType) {
		if(debug) logger.dump(myName+'.removeSlave('+mySlave+', '+valueType+')');
		slaves[valueType][mySlave.id] = null;
		if(debug) logger.dumpHash('after '+myName+'.removeSlave slaves:', slaves);
	}

	/**
	 *	Adds slave picker to type
	 */
	this.addSlave = function(mySlave, valueType) {
		if(debug) logger.dump(myName+'.addSlave('+mySlave+', '+valueType+')');
		slaves[valueType][mySlave.id] = mySlave;
		var res = mySlave.isRecursive(me, valueType);
		if (res != false) {
			me.removeLink(me, mySlave, valueType);
			alert("Sorry but this link will make things go in a circle.\n"
					+ "It would go from " + mySlave.name + " to " + res + '.');
			return false;
		}
		return true;
	}

	/**
	 *	Checks for circles
	 */
	this.isRecursive = function(start, valueType) {
		if(debug) logger.dump(myName+'.isrecursive('+start+', '+valueType+')');
		if (me == start) {
			// duplicate
			if(debug) logger.dump('found existing ' + me.id);
			return me.name;
		} else {
			if (null == start) {
				start = me;
			}
		}
		var mySlaves = slaves[valueType];
		for(var i in mySlaves) {
			if (null == mySlaves[i] || typeof(mySlaves[i]) == 'undefined') {
				continue;
			}
			
			var res = mySlaves[i].isRecursive(start, valueType);
			if(res != false) {
				return res + ' to ' + me.name;
			}
		}
		return false;
	}



	/**
	 * Sets delta object from form field
	 */
	this.form2delta = function(valueType, isKey, evt) {
		if(debug) logger.dump(myName+'.form2delta('+valueType+', '+isKey+', '+evt+')');
		var d = me.delta[valueType];
		if (isKey) {
		    evt = aa.getEvent(evt);
			if (evt.keyCode == 9) {
				return false;
			}
			me.setActiveField(d);
			if (evt.keyCode == 13) {
				isKey = false;
				me.setMayChange(d);
			}
		}
		var m = me.masterField[valueType];
		var delta = parseInt(d.value, 10);
		if(debug) logger.dump(myName+'.form2delta delta = ['+delta+']');
		var isDirty = true;
		if (isNaN(delta)) {
			if (isKey) return false;
			d.value = 0;
			isDirty = dHsv.set(0, valueType);
		} else {
			var myMax = me.maximum[valueType].value;
			delta %= myMax;
			isDirty = dHsv.set(delta/myMax, valueType);
			if (d.value != delta) {
				if (isKey) return false;
				d.value = delta;
			}
		}
		if(debug) logger.dump(myName+'.form2delta dHsv = ['+dHsv+']');
		var mcp = master[valueType];
		if (mcp != null && isDirty) {
			mcp.propagate(true, null, valueType);
		}
		return false;
	}


	/**
	 * Reads hsv/rgb type and populates proper form field
	 */
	this.delta2form = function(valueType) {
		me.delta[valueType].value = Math.round(
						dHsv.get(valueType) * me.maximum[valueType].value );
	}


	/**
	 * Reads hsv/rgb type and populates proper form field
	 */
	this.type2form = function(valueType) {
		if (formDelay == 0) {
			me.type2formNow(valueType);
			return;
		}
		sh.queue(myName + '.type2formNow(\''+valueType+'\')', formDelay);
		return;
	}

	this.type2formNow = function(valueType) {
		if(debug) logger.dump(myName + '.type2formNow('+valueType+')');
		var newType = me.get(valueType);
		if (me.getRyb() && valueType == HUE) {
			// do conversion mine to standard
			newType = hsv.toStandardHue(newType);
		}
		var newVal = Math.round( newType * me.maximum[valueType].value );
		if (!me.isActiveField(me.field[valueType]) && 
			me.field[valueType].value != newVal) {
			me.field[valueType].value = newVal
		}
	}

	/**
	 * Sets new hue/sat/val/red/green/blue values and triggers updates
	 */
	this.set = function (val, valueType) {
		if(debug) logger.dump(myName + '.set('+val+', '+valueType+')');
		if(val == me.get(valueType)) {
			if(debug) logger.dump('value the same so skipped');
			return false;
		}
		if (me.isHsvType(valueType)) {
			hsv.set(val, valueType);
			if (valueType == HUE) {
				bsHsv.set(val, valueType);
			}
			rgb = hsv.toRgb(me.getRyb());
			me.type2form(RED);
			me.type2form(GREEN);
			me.type2form(BLUE);
		} else {
			rgb.set(val, valueType);
			hsv = rgb.toHsv(me.getRyb());
			bsHsv.set(hsv.get(HUE), HUE);
			me.type2form(HUE);
			me.type2form(SAT);
			me.type2form(VAL);
		}
		var newVal = rgb.getHex();
		if (!me.isActiveField(hex) && 
			hex.value != newVal) {
			hex.value = newVal
		}
		me.setColor();
		me.type2slider(valueType);
		me.type2form(valueType);
		return true;
	}


	/**
	 * Gets hue/sat/val/red/green/blue values
	 */
	this.get = function (valueType) {
		var ret;
		if (me.isHsvType(valueType)) {
			ret = hsv.get(valueType);
		} else {
			ret = rgb.get(valueType);
		}
//		if(debug) logger.dump(myName + '.get('+valueType+') = '+ret);
		return ret;
	}


	/**
	 *	returns true for hsv type false for rgb type
	 */
	this.isHsvType = function(valueType) {
		return (valueType == HUE || valueType == SAT || valueType == VAL);
	}

	/**
	 * Propagates setting
	 */
	this.propagate = function(setMaster, excludedChild, valueType) {
		if(debug) logger.dump(
			myName+'.propagate('+setMaster+', '+excludedChild+', '+valueType+')');
		if(debug) logger.dumpHash(myName+'.propagate masters are:', master);
		var mcp = master[valueType];
		if (setMaster && mcp != null) {
			if(debug) logger.dump(myName+'.propagate doing master '+mcp);
			if(mcp.set( hsv.getDelta(dHsv.get(valueType) * -1, 
						mcp.get(valueType), me.get(valueType)), valueType)) {
				mcp.propagate(true, me, valueType);
			} else {
				if(debug) logger.dump(myName+'.propagate cancelled no changes');
			}
		}
		if(debug) logger.dumpHash(myName+'.propagate slaves are:', slaves);
		var mySlaves = slaves[valueType];
		for (var i in mySlaves) {
			var scp = mySlaves[i];
			if (null == scp || typeof(scp) == 'undefined' || scp == excludedChild) {
				continue;
			}
			var slHsv = scp.getHsv();
			var slDHsv = scp.getDeltaHsv();
			if(debug) logger.dump(myName+'.propagate doing slave '+scp);
			if(scp.set(hsv.getDelta(slDHsv.get(valueType), 
						slHsv.get(valueType), me.get(valueType)), valueType)) {
				scp.propagate(false, me, valueType);
			} else {
				if(debug) logger.dump(myName+'.propagate cancelled no changes');
			}
		}
	}


	/**
	 * Sets new hue/sat/val slider from hsvType
	 */
	this.type2slider = function(valueType) {
		if (sliderDelay == 0) {
			me.type2sliderNow(valueType);
			return;
		}
		sh.queue(myName + '.type2sliderNow(\''+valueType+'\')', sliderDelay);
		return;
	}
	this.type2sliderNow = function(valueType) {
		var val = me.get(valueType);
		if(debug) logger.dump(myName+'.type2slider('+valueType+') value is ['+val+']');
		switch(valueType) {
			case HUE:
				me.d.setLeftPercentage(hueBarId, val);
				break;
			case SAT:
				me.d.setLeftPercentage(svBarId, 1 - val);
				break;
			case VAL:
				me.d.setTopPercentage(svBarId, 1 - val);
				break;
			case RED:
			case GREEN:
			case BLUE:
				me.type2slider(HUE);
				me.type2slider(SAT);
				me.type2slider(VAL);
				break;
			default:
				if(debug) logger.dump(myName+'type2slider failed. type: ['+valueType+'] not found');
				break;
		}
		isT2s = false;
	}

	/**
	 * Sets new hue from slider
	 */
	this.onHueDrag = function() {
		me.slider2type(HUE);
	}
	

	/**
	 * Sets new hue from slider
	 */
	this.onSVDrag = function() {
		me.slider2type(SAT);
		me.slider2type(VAL);
	}
	
	/**
	 * Sets new hue/sat/val from slider
	 */
	this.slider2type = function(valueType) {
		if(debug) logger.dump(myName+'.slider2type('+valueType+')');
		var isDirty = true;
		switch(valueType) {
			case HUE :
				isDirty = me.set(me.d.getLeftPercentage(hueBarId), valueType);
				break;
			case SAT :
				isDirty = me.set(1 - me.d.getLeftPercentage(svBarId), valueType);
				break;
			case VAL :
				isDirty = me.set(1 - me.d.getTopPercentage(svBarId), valueType);
				break;
			default:
				if(debug) logger.dump('invalid slider [' + valueType + ']');
				return;
				break;
		}
		if (isDirty) {
			me.propagate(true, null, valueType);
		}
	}


	/**
	 * Sets color swatches
	 */
	this.setColor = function() {
		if (colorDelay == 0) {
			me.setColorNow();
			return;
		}
		sh.queue(myName + '.setColorNow()', colorDelay);
		return;
	}
	this.setColorNow = function () {
		aa.bgColor(baseSwatch, bsHsv.toRgb(me.getRyb()).getHex());
		var hex = rgb.getHex();
		aa.bgColor(swatch, hex);
		if(extraSwatch != null) {
			aa.bgColor(extraSwatch, hex);
		}
		if (typeof(me.onSetColor) == 'function') {
			me.onSetColor(hex);
		}
		isCleaningColor = false;
	}


	this.nudge = function(valueType, inc) {
		if(debug) logger.dump(myName+'.nudge('+valueType+', '+inc+')');
		var val = me.get(valueType);
		if(debug) logger.dump(myName+'.nudge('+valueType+', val:['+val+'])');
		if(debug) logger.dump(myName+'.nudge('+valueType+', max:['+me.maximum[valueType].value+'])');
		val += inc/me.maximum[valueType].value;
		if (val < 0) {
			val = 1;
		}
		if (val > 1) {
			val = 0;
		}
		if (me.set(val, valueType)) {
			me.propagate(true, null, valueType);
		}
	}


	/**
	 * Sets new hue sat and value from button
	 */
	this.setMax = function(valueType, isKey, evt) {
		if(debug) logger.dump(myName+'.setMax('+valueType+', '+isKey+', '+evt+')');
		var maxField = me.maximum[valueType];
		if (isKey) {
		    evt = aa.getEvent(evt);
			if (evt.keyCode == 9) {
				return;
			}
			me.setActiveField(maxField);
			if (evt.keyCode == 13) {
				isKey = false;
				me.setMayChange(maxField);
			}
		}
		var num = parseInt(maxField.value,10);
		if(debug) logger.dump(myName+'.setMax('+valueType+') val = ['+maxField.value+'] num = ['+num+']');
		if (isNaN(num)) {
			if (isKey) return;
			// restore previous
			maxField.value = me.getMax(valueType);
		} else {
			if (num < 1) {
				num = 1;
			}
			if (maxField.value != num) {
				if (isKey) return;
				maxField.value = num;
			}
			me.copyMax(valueType);
		}
		for (var i in me.firstInstance.pickers) {
			me.firstInstance.pickers[i].type2form(valueType);
			if (me.isHsvType(valueType)) {
				me.firstInstance.pickers[i].delta2form(valueType);
			}
		}
	}


	/**
	 * Sets new hue sat and value from button
	 */
	this.setField = function(valueType, isKey, evt) {
		if(debug) logger.dump(myName+'.setField('+valueType+', '+isKey+', '+evt+')');
		var field = me.field[valueType];
		if (isKey) {
		    evt = aa.getEvent(evt);
			if(debug) logger.dump(myName+'.setField keycode('+evt.keyCode+')');
			if (evt.keyCode == 9) {
				return;
			}
			me.setActiveField(field);
			if (evt.keyCode == 13) {
				isKey = false;
				me.setMayChange(field);
			}
		}
		if(!me.form2type(valueType, isKey)) {
			return false;
		}
		if (me.isHsvType(valueType)) {
			me.propagate(true, null, valueType);
		} else {
			me.propagate(true, null, HUE);
			me.propagate(true, null, SAT);
			me.propagate(true, null, VAL);
		}
		return false;
	}


	/**
	 * Reads form field and populates proper hsv/rgb type 
	 */
	this.form2type = function(valueType, isKey) {
		var field = me.field[valueType];
		var val = field.value;
		var num = parseInt(val, 10);
		if (isNaN(num)) {
			if (isKey) return false;
			// restore value
			me.type2form(valueType);
			return false;
		} else {
			var myMax = me.maximum[valueType].value;
			if(num < 0) {
				num = 0;
			} else if (num > myMax) {
				num = myMax;
			}
			if (num != val && isKey) return false;
			num /= myMax;
			if (me.getRyb() && valueType == HUE) {
				// do conversion standard to mine
				num = hsv.toRybHue(num);
			}
			return me.set(num, valueType);
		}
	}


	/**
	 * Reads 24 bit web hex value from form and translates it to color.
	 */
	this.setHex = function(isKey, evt) {
		if(debug) logger.dump(myName+'.setHex('+isKey+', '+evt+')');
		if (isKey) {
		    evt = aa.getEvent(evt);
			if(debug) logger.dump(myName+'.setHex keycode('+evt.keyCode+')');
			if (evt.keyCode == 9) {
				return;
			}
			me.setActiveField(hex);
			if (evt.keyCode == 13) {
				isKey = false;
				me.setMayChange(hex);
			}
		}

		var val = hex.value;
		if(debug ||1) logger.dump(myName+'.setHex hex.val '+val);

		if (val.match(/^[\da-fA-F]{3}$/)) {
			// double them
			if (isKey) return;
			val = val.substr(0,1) + val.substr(0,1) 
				+ val.substr(1,1) + val.substr(1,1) 
				+ val.substr(2,1) + val.substr(2,1);
		} else if (val.match(/^[\da-fA-F]{1,5}$/)) {
			// add leading zeros
			if (isKey) return;
			val = '000000'.substr(0, 6-val.length) + val;
		} else if (!val.match(/^[\da-fA-F]{6}$/)) {
			// garbage good bye
			if (isKey) return;
			hex.value = rgb.getHex();
			return false;
		}
		if(debug) logger.dump(myName+'.setHex cleaned val ['+val+']');

		var r = parseInt( val.substr(0,2), 16);
		var g = parseInt( val.substr(2,2), 16);
		var b = parseInt( val.substr(4,2), 16);
		if(debug) logger.dump(myName+'.setHex r '+r+' g '+g+' b '+b+')');

		var trgb = new RgbType(r/ 255, g/ 255, b/ 255);
		var tmpHsv = trgb.toHsv(me.getRyb());
		me.set(tmpHsv.h, HUE);
		me.propagate(true, null, HUE);
		me.set(tmpHsv.s, SAT);
		me.propagate(true, null, SAT);
		me.set(tmpHsv.v, VAL);
		me.propagate(true, null, VAL);
		if(!isKey) { hex.value = val; }
		return false;
	}
	


	/**
	 *	Ths deals with window resizing
	 */
	this.setUpSliders = function() {
		if (setupDelay == 0) {
			me.setUpSlidersNow();
			return;
		}
		sh.queue(myName + '.setUpSlidersNow()', setupDelay);
		return;
	}
	this.setUpSlidersNow = function() {
		var list = me.firstInstance.pickers;
		for (var i in list) {
			list[i].setNewLimits();
		}
		this.to = null;
	}


	this.setNewLimits = function() {
		var dims = me.getDims(hsvImg);
		me.d.setLimits(svBarId, dims['l'], dims['l'] + dims['w'], true, 
							dims['t'], dims['t'] + dims['h'], true, true); 

		dims = me.getDims(hueImg);
		me.d.setLimits(hueBarId, dims['l'], dims['l'] + dims['w'], true, 
							dims['t'], dims['t'] + dims['h'], true, true); 
		me.type2slider(HUE);
		me.type2slider(SAT);
		me.type2slider(VAL);
		if (extraSwatch == null || me.hasExtraSwatchMoved) {
			return;
		}
		dims = me.getDims(swatch.id);
		aa.moveTo(aa.get(me.d.getIdWithWrapper(extraSwatch.id)), 
						dims['l'], dims['t']);
	}

	this.toString = function() {
		return myName;
	}
	
	me.init();
	
}
