/** "Color Information" service interface
 *  @author danyastuff 
 *  @version 1.0
 *  @description required libraries: jquery.event.drag.js, jquery-ui.js, complex-search.js
 */

var //for colors array
	iRU = 0, iEN = 1, iSYN = 2, iHEX = 3, iCSS = 4, 
	iR = 5,	iG = 6, iB = 7, iRGB = 8,
	iH = 9, iS = 10, iV = 11, iHSV = 12,
	iC = 13, iM = 14, iY = 15, iK = 16, iCMYK = 17,
	iDESC= 18;	
var iLang = Language == 'en' ? iEN : iRU;
var iNames = [s('Name'), 'en', s('Synonim'), 'hex', 'CSS', 'R', 'G', 'B', 'RGB', 'H', 'S', 'V', 'HSV', 'C', 'M', 'Y', 'K', 'CMYK', s('Description')];
	
var ColorInterface = function() {
	var self = this;
// Parts	
	this.panton  = $('#panton');
	this.rainbow = $('#rainbow');
	this.circle	 = $('#circle');
	this.picker  = $('#hue-picker');
	this.colorArea = $('#color-area');
	this.miniColorArea = $('#mini-preview'); 
	this.colorInf  = $('#color-info');
	this.colorName = $('#color-info H2'); // > A
	//this.colorName = $('h1.title');
	this.colorInp  = $('#inp-color');
	this.exactLink = $('#exact-link');
	this.showPreview = $('#show-preview');
	this.colorDesc = $('#color-desc');
	this.colorPic = $('#color-pic');
	this.dataTable = $('#DataTable');
	this.alike = {
		tag: $('#alike-colors'),
		one: s('Similiar color'),
		many: s('Similiar colors') + ': '
	};
	this.embed = {
		inp:  $('#embed-input'),
		code: $('#embed-code'),
		name: $('#whoyougle-name'),
		color:$('#whoyougle-color'),
		link: $('#link-input'),
		href: $('#href-input'),
		visible: false
	};
	this.h;
	this.s;
	this.v;
	
	this.allInp = $('.color-view INPUT');
	this.inp = {
		r: $('#rgb-r'),	g: $('#rgb-g'), b: $('#rgb-b'),
		hex: $('#rgb-hex'),
		h: $('#hsv-h'), s: $('#hsv-s'),	v: $('#hsv-v'),
		c: $('#cmyk-c'), m: $('#cmyk-m'), y: $('#cmyk-y'), k: $('#cmyk-k')
	}
// Flags
	this.dragable = false;
	this.hashChange = true;
	this.linkNum = 0;
// Const
	this.RGB  = 'rgb';
	this.HSV  = 'hsv';
	this.HEX  = 'hex';
	this.CMYK = 'cmyk';
	this.ALL  = 'all';
	this.HASH = 'hash';
	
	this.mis  = 10; // color define range
	
	var foo = function() {}
	var allowHash = function() {self.hashChange = true; self.setHash()}
	var banHash	  = function() {self.hashChange = false}
// Circle over panton
	var circle = this.circle;
	// Chache:
		circle.width  = circle.width()  /2; // half of width cause of the center of circle
		circle.height = circle.height() /2; 
	var panton = this.panton;
		panton.width 	= panton.width();
		panton.height 	= panton.height();
		panton.offLeft 	= panton.offset().left;
		panton.offTop	= panton.offset().top;
	
	circle.drag(banHash, function(e) {
		var offX = e.offsetX - panton.offLeft + circle.width,
			offY = e.offsetY - panton.offTop  + circle.height;
		self.setS( offX / panton.width  * 100 );
		self.setV( 100 - offY / panton.height * 100 );
		self.setColor(self.ALL);
	},allowHash)

	circle.mouseover(function() {
		self.dragable = true;
	})
	circle.mouseout(function(e) {
		self.dragable = false;
	})

// Picker in rainbow
	var picker = this.picker;
		picker.width = picker.width() /2;
	var rainbow = this.rainbow;
		rainbow.width	= rainbow.width();
		rainbow.offLeft = rainbow.offset().left;
	picker.drag(banHash, function(e){
		var offX = e.offsetX - rainbow.offLeft + picker.width;
		self.setH( offX / rainbow.width * 360 );
		self.setColor(self.ALL);
	}, allowHash)

	picker.mouseover(function() {
		self.dragable = true;
	})
	picker.mouseout(function(e) {
		self.dragable = false;
	})

// Mouse down
	panton.mousedown(function(e) {
		if (! self.dragable) {
			var offX = e.pageX - panton.offLeft,
				offY = e.pageY - panton.offTop  
			self.setS( offX / panton.width  * 100 );
			self.setV( 100 - offY / panton.height * 100 );
			self.setColor(self.ALL);
		}
	})
	rainbow.mousedown(function(e) {
		if (! self.dragable) {
			var offX = e.pageX - rainbow.offLeft;
			self.setH( offX / rainbow.width * 360 );
			self.changeHue();
			self.setColor(self.ALL);
		}
	})
	
// Inputs change	
	var hsv = $('#hsv-h, #hsv-s, #hsv-v');
	hsv.blur(function(e) {
		self.setH(self.inp.h.attr('value')); 
		self.setS(self.inp.s.attr('value'));
		self.setV(self.inp.v.attr('value'));
		self.setColor(self.HSV);
	})
	
	var cmyk = $('#cmyk-c, #cmyk-m, #cmyk-y, #cmyk-k');
	cmyk.blur(function() {
		self.rgb = this.rgb = COLOR.cmyk2rgb({
			c:self.inp.c.attr('value'),
			m:self.inp.m.attr('value'),
			y:self.inp.y.attr('value'),
			k:self.inp.k.attr('value')
		}); 
		var hsv = COLOR.rgb2hsv({
			r:this.rgb.r, 
			g:this.rgb.g, 
			b:this.rgb.b
		});
		self.setH(hsv.h);
		self.setS(hsv.s);
		self.setV(hsv.v);
		self.setColor(self.CMYK);
	})
	
	var rgb = $('#rgb-r, #rgb-g, #rgb-b');
	rgb.blur(function() {
		self.rgb = this.rgb = {
			r: parseInt(self.inp.r.attr('value')),
			g: parseInt(self.inp.g.attr('value')),
			b: parseInt(self.inp.b.attr('value'))
		}
		var hsv = COLOR.rgb2hsv({
			r:this.rgb.r, 
			g:this.rgb.g, 
			b:this.rgb.b
		});
		self.setH(hsv.h);
		self.setS(hsv.s);
		self.setV(hsv.v);
		self.setColor(self.RGB);
	})
	
	var hex = $('#rgb-hex');
	hex.blur(function() {
		var rgb = self.rgb = COLOR.css2rgb(hex.attr('value'));
		var hsv = COLOR.rgb2hsv({r:rgb.r, g:rgb.g, b:rgb.b});
		self.setH(hsv.h);
		self.setS(hsv.s);
		self.setV(hsv.v);
		self.setColor(self.HEX);
	})
	
// Color input behaviour
	this.colorInp.setGhost   = function () {
		this.addClass('ghost').attr('value', s('Search colour by name or parameters')) 
	}
	this.colorInp.resetGhost = function () {
		if (this.hasClass('ghost'))
			this.removeClass('ghost').attr('value', '').focus() 
	}
	this.colorInp
		.bind('mousedown', function () {
			self.colorInp.resetGhost()
		})
		.bind('blur', function () {
			if ($(this).attr('value') == '')
				self.colorInp.setGhost()
		})
	this.colorInp.attr('value','').setGhost();
	
	var complex = new ComplexSearch({
		filter		: self.colorInp,	
		area		: colors,	
		banFields	: [iHEX, iDESC, iSYN, iR, iG, iB, iH, iS, iV, iC, iM, iY, iK],
		minChars	: 1,
		minDigits	: 2,
		maxToShow	: 99,
		maxHeight	: '400px',
		onMatch	: function (text, elem, index) {
			var span = $('<SPAN></SPAN>')
				span.attr('css', elem[iCSS])
			if (index == iLang || index == iSYN)
				span.html(text)
			else
			if (index == iEN || index == iRU)
				span.html( text + '<SMALL> — ' + elem[iLang] + '</SMALL>' )
			else
			if (index == iCSS)
				span.html( '#' + text + '<SMALL> — ' + elem[iLang] + '</SMALL>' )
			else
				span.html( '<i>'+iNames[index] + '</i> (' + text + ') <SMALL> — ' + elem[iLang] + '</SMALL>' )
			return span			
		},
		onResult : function (li) {
			var rgb = COLOR.css2rgb( li.find('SPAN').attr('css') ),
				hsv = COLOR.rgb2hsv({r:rgb.r, g:rgb.g, b:rgb.b});
			
			self.setH(hsv.h);
			self.setS(hsv.s);
			self.setV(hsv.v);
			self.setColor(self.HASH, true);
			self.setHash(rgb);
		}
	})
	
	var selectFn = function (e) {e.stopPropagation(); $(e.target).select()}
	this.embed.inp.click(selectFn);
	this.embed.link.click(selectFn);
	this.embed.href.click(selectFn);
	
	this.showPreview.click(function() {
		if (!self.embed.visible) 
			self.embed.code.slideDown('fast');
		else 
			self.embed.code.slideUp('fast');
		self.embed.visible = !self.embed.visible;
	})
	
	this.onExactClick = function(e) {
		var css = $(this).attr('href').replace(/^(.*)color\/(.*)\/?#?$/, '$2'); 
		self.checkHash(css);
		e.stopPropagation();
	}
	
// Dialog (22 nov 2009)
	var modal 		= $('#dialog');
		modal.link 	= $('#show-dialog');
		modal.title = $('#dialog h1');
		modal.body  = $('#color-sample');
	
	modal.dialog({
		autoOpen: false,
		height: 400,
		modal: true,
		open: function(event, ui) {
			$('.ui-dialog').css('overflow', 'visible')
			modal.title.text(
				self.colorName.text()
			)
			modal.body.css(
				'background-color', 
				self.colorArea.css('background-color')
			)
		},
		width: 600
	})
	modal.link.click(function () {
		modal.dialog('open')
	})
	
}

ColorInterface.prototype = {
	checkHash : function (hash) {
		if (!hash) return false;
		var hex  = parseInt(hash, 16), 
			rgb = COLOR.css2rgb(hex),
			hsv = COLOR.rgb2hsv({r:rgb.r, g:rgb.g, b:rgb.b});
		this.setH(hsv.h);
		this.setS(hsv.s);
		this.setV(hsv.v);
		this.rgb = rgb;
		this.setColor(this.HASH);
		this.setEmbed(hash);
		
		return true;
	},
	setHash : function(rgb) {
		if (this.hashChange) {
			if (!rgb) rgb = COLOR.hsv2rgb({h:this.h, s:this.s, v:this.v});
			css = COLOR.rgb2css(rgb);
			this.setEmbed(css);
		}
	},
	setSiteColor : function() {
		
	},
	/* Sets preview and refreshes embed code
	 * Issue: html for embed saved in string right here, not in html-page
	 */
	setEmbed : function (css) 
	{				
		var embedStr =  '<div style="margin:0; padding:0; padding:1em; width:15em; font-family:Arial; text-align:center; border:1px solid #DDD; background:#FFF">'+
		                '<p style="font-size:1em; margin:0; padding:0; margin-bottom:1em; color:#333">'+ this.colorName.text() +'</p>'+
		                '<div style="background:#'+ css +'; height:3em; margin:0; padding:0; margin-bottom:0.8em"> </div>'+
		                '<a href="http://' + BaseServer   + '" style="text-decoration:none; color:#444; letter-spacing:0.05em"><span style="font-family:Times"><font style="font-variant:small-caps; font-size:0.85em">Who</font><b style="font-size:1.2em; letter-spacing:-0.05em">Y<font style="position:relative; top:0.1em; left:-0.15em">o</font><i style="position:relative; top:-0.05em; left:-0.1em">u</i></b><font style="font-family:Georgia"><font color="#0066CC">g</font><font color="#009933">l</font><font color="#996600">e</font></font></span></a> — '+
		                '<a href="http://'+BaseServer+'/services/color" style="color:#0066CC; font-size:0.9em">'+
		                    s('colours')+
		                '</a></div>';
    
        this.embed.name.text(this.colorName.text());
    	this.embed.color.css( {background: '#'+css } );		
		this.embed.inp.attr('value', embedStr);
		
		var url = 'http://' + window.BaseServer + '/services/color/' + css;
		
		this.embed.link.val(url);
		this.embed.href.val('<a href="' + url + '">' + this.colorName.text() + '</a>');
		
		//Some day I will rewrite this servie, promise
		var $publish = $('a.facebook-publish'),
		    colorName = this.colorName.text();
		if ($publish.length)
		{
		    $publish.attr('onclick', '');
		    $publish.unbind('click');
		    $publish.bind('click', function () 
		    {
		        FACEBOOK.publish(
		            colorName,
		            $publish.attr('share-link').split('?')[0] + '/' + css,
		            $publish.attr('desc'),
		            'http://api.whoyougle.ru/images/block/'+ css +'_50x50.png'
		        );
		    })
		}
	},
	addExactLink : function(c) {
		if (this.linkNum < 9) { // too many links looks scary
			var frame = c[iV] > 90 && c[iS] < 11 ? 'frame' : '';
			this.exactLink.append($('<tr v="'+c[iV]+'"><td style="background:#'+c[iCSS]+'; border-color: #'+c[iCSS]+'" class="demo '+frame+'"></td><td style="padding-left: 0.4em"><a class="_'+c[iCSS]+'" href="/services/color/'+c[iCSS]+'" onclick="return false;">'+c[iLang]+'</a></td></tr>'))
			this.linkNum++;
		}
	},
	/* Sets case of sign "Near color(s)" 
	 * Issue: uses cache this.linkNum to not recalculate A-tags count
	 */
	refreshAlike : function() {
		var aLen = this.linkNum;
		this.alike.tag.text(aLen > 1 ? this.alike.many : (aLen == 1 ? this.alike.one : ''));
		this.linkNum = 0;
	},
	/* Searching for exact color and near colors. 
	 * Issue: when find exact we stop searching nears - strange but more quickly
	 */
	findColorName : function () { 
		var almost = {name:'', dif:99, css:''} //name, dif, css
		var c, best, 
			dif, preDif = 99;
		this.exactLink.html('');
		for (i=0, l=colors.length; i < l; i++) {
			c = colors[i];
			dif = this.vectorDist(
				{h: this.h, s:this.s, v:this.v},
				{h: c[iH], s: c[iS], v: c[iV]}
			);
			
			if ( dif < 10 && dif < preDif ) {	// exactly coincidence
				best = c;
				preDif = dif;
			} else
			if (dif < 20) {		// approximate
				this.addExactLink(c);
				if (almost.dif > dif) {
					almost.name = c.ru;
					almost.css = c.css;
				}
			}
		}
		this.refreshAlike();
		
		var colorInfo = ' — RGB ' + this.inp.r.val() + ', ' + this.inp.g.val() + ', ' + this.inp.b.val() + ', CMYK  ' + this.inp.c.val() + ', ' + this.inp.m.val() + ', ' + this.inp.y.val() + ', ' + this.inp.k.val() + ', HSV  ' + this.inp.h.val() + ', ' + this.inp.s.val() + ', ' + this.inp.v.val() + ', HEX #' + this.inp.hex.val();
		colorInfo += ' — WhoYOUgle';
		
		if (preDif < 99) {
			this.colorName.text(best[iLang]);
			document.title = best[iLang] + colorInfo;
			this.exactLink.find('A').click(this.onExactClick);
			return true;
		}
		
		if (almost.name) { 
			this.colorName.text(s('Close to', almost.name.toLowerCase())); 
			document.title = s('Close to', almost.name.toLowerCase()) + colorInfo;
		} else {
			this.colorName.text(s('Unknown'));// + colorInfo);
			document.title = s('Color info', colorInfo);
		}
		
		var links = this.exactLink.find('A');
			links.click(this.onExactClick);
		if (links.length > 1)
			this.exactLink.find('A._' + almost.css).css('font-weight', 'bold');

		return false;
	},
	/* Searching for color by HSV params
	 * Issue: exact result but slow works (using now)
	 */
	vectorDist : function (c1, c2) {
		return Math.sqrt(
			Math.pow(c1.h-c2.h,2) + Math.pow(c1.s-c2.s,2) + Math.pow(c1.v-c2.v,2)
		)
	},
	/* Searching for color by RGB params
	 * Issue: less exact result but quickly works
	 */
	getMaxDif : function (rgb1, rgb2) {
		return Math.max(
			Math.abs(rgb1.r - rgb2.r),
			Math.abs(rgb1.g - rgb2.g),
			Math.abs(rgb1.b - rgb2.b)
		);
	},
	/* Refresh all color fields and shows
	 * Issue: do not refresh color in @type filed - already defined
	 */
	setColor : function (type, fromColorInp) {		
		if (!this.rgb) 
			this.rgb = COLOR.hsv2rgb({h:this.h, s:this.s, v:this.v});
		
		var rgb  = this.rgb, 
			cmyk = COLOR.rgb2cmyk(rgb),
			css  = COLOR.rgb2css(rgb);
		this.changeHue();
		this.colorArea.css({ background: '#'+css });
		this.miniColorArea.css('background-color', '#'+css);
		
		if (type != this.HSV) { 
			this.inp.h.attr('value', this.h);
			this.inp.s.attr('value', this.s);
			this.inp.v.attr('value', this.v);
		} 
		if (type != this.RGB) {
			this.inp.r.attr('value', rgb.r);
			this.inp.g.attr('value', rgb.g);
			this.inp.b.attr('value', rgb.b);
		}
		if (type != this.HEX)
			this.inp.hex.attr('value', COLOR.rgb2css(rgb));
		if (type != this.CMYK) {
			this.inp.c.attr('value', cmyk.c);
			this.inp.m.attr('value', cmyk.m);
			this.inp.y.attr('value', cmyk.y);
			this.inp.k.attr('value', cmyk.k);
		}
		this.findColorName();
		if (type != this.HASH) this.setHash(rgb);
		this.rgb = null;
		if (!fromColorInp) this.colorInp.setGhost();
		
	},
	changeHue : function () {
		this.panton.children('#sv-grad').css({
			'background-color': '#' + COLOR.rgb2css(
				COLOR.hsv2rgb({h:this.h, s:100, v:100})
			)
		});
	},
	setH : function (h) {
		if (h < 0) h = 0; else if (h > 360) h = 360;
		var p = this.picker;
		var r = this.rainbow;
		var offX = r.width * h / 360 -p.width;
		var xOut = offX > r.width - p.width || offX < -p.width ? true : false;
		var x =	xOut ? p.css('left') : offX;
		
		this.picker.css( {left: x} );
		this.h = Math.round(h); 
	},
	setS : function (s) {
		s = s < 0 ? 0 : (s > 100 ? 100 : s);
		var p = this.panton;
		var c = this.circle;
		var offX = p.width * s / 100 - c.width;
		var xOut = offX > p.width - c.width || offX < -c.width  ? true : false; 
		var x =	xOut ? c.css('left') : offX;
		
		this.circle.css( {left: x} );
		this.s = Math.round(s); 
	},
	setV : function (v) { 
		v = v < 0 ? 0 : (v > 100 ? 100 : v);
		var p = this.panton;
		var c = this.circle;
		var offY = p.height * (100 - v) / 100 -c.height;
		var yOut = offY > p.height - c.height || offY < -c.height ? true : false;
		var y = yOut ? c.css('top') : offY;
		
		this.circle.css( {top: y} );
		this.v = Math.round(v); 
	},
	setHSV : function (h, s, v) {
		this.setH(h);
		this.setS(s);
		this.setV(v);
		this.circle.css({
			left: this.panton.width  * s / 100 - this.circle.width,
			top : this.panton.height * (100 - v) / 100 - this.circle.height
		})
		this.picker.css({
			left: this.rainbow.width * h / 360 - this.picker.width
		})
		this.setColor(this.HSV);
	}
}
