

Ext.ns("LSI.Widgets");
LSI.Widgets.PriceCompareGraphe = Ext.extend(Object, {

		axisWidth  : 30,
		axisHeight : 30,

		grapheMarginLeft   : 0,
		grapheMarginRight  : 0,
		grapheMarginTop    : 0,
		grapheMarginBottom : 0,

		openAdsInNewWindow : false,

		autoHideOnClick : false,

		previewId : null,

		linkRel : null,

		avgPrice : null,

		anims : {
			previewWin   : { duration: 0.2, easing : 'easeIn' },
			previewArrow : { duration: 0.2, easing : 'easeIn' }
		},

		previewTpl : new Ext.Template(
			'<div class="container">',
				'<div class="closeBtn" title="Fermer"></div>',
				'<div class="header">',
					'<span class="type">{type}</span>',
					'<span class="city">{city}</span>',
					'<span class="price">{f_price}</span>',
					'<span class="infos">{rooms} pièce(s), {surface} m&sup2;</span>',
				'</div>',

				'<div class="infos">',
					'<p class="interest interest-{interestCls}">Intérêt de l\'annonce :',
						' <span class="verdict">{interest}</span>',
						' <span class="priceSm">({priceSm} &euro; / m&sup2;)</span></p>',
					'<p class="explanation">{explanation}</p>',
					'<p class="notice"><strong>Note : </strong>certaines prestations',
						' supplémentaires peuvent justifier cet écart de prix, le texte de l\'annonce vous',
						' permettra de mieux appréhender ce bien dans son contexte.</p>',
				'</div>',

				'<div class="operations">',
					'{operations}',
				'</div>',

				'<div class="photo" style="background:url({photo}) no-repeat">',
				'</div>',
			'</div>'),

		constructor : function(config) {

			Ext.apply(this, config);

			this.el = Ext.get(this.el);
			this.el.update("");

		},

		init : function() {

			if (this.assertBrowser() === false)
				return;

			if (this.ads.length == 1) {
				this.el.update("Lesiteimmo n'a trouvé aucune autre annonce dans la même catégorie de prix.");
				return;
			}

			this.computeValues();
			this.createGrapheZone();
			this.createAxis();

			this.dotLabel = this.el.createChild({
					cls:"priceCompareGraphe-dotLabel",
					style:"visibilty: hidden;"
				});

			this.autoShowDot = null;

			Ext.each(this.ads, function(ad) {

					var dot, cls, pos;

					cls = ad.requested ? "big dot" : "dot";
					pos = this.convertXY( ad.surface, ad.price / ad.surface);

					dot = this.el.createChild({ cls : cls });
					dot.ad = ad;
					dot.setLeft(pos.x - dot.getWidth() / 2);
					dot.setBottom(pos.y - dot.getHeight() / 2);

					dot.hover(
						function(e) {dot.addClass("over"); this.showDotLabel(dot); this.showPreviewWin(dot);},
						function() {dot.removeClass("over");},
						this);

					dot.on('click', function(e) { this.showPreviewWin(dot); }, this);

					if (ad.requested) this.autoShowDot = dot;

				}, this);

			this.addAxisLabel("x", this.minSurface, this.minSurface + " m&sup2;");
			this.addAxisLabel("x", this.maxSurface, this.maxSurface + " m&sup2;");
			this.addAxisLabel("y", this.minPriceSm, this.minPriceSm + " &euro; / m&sup2;");
			this.addAxisLabel("y", this.maxPriceSm, this.maxPriceSm + " &euro; / m&sup2;");

			this.addAvgLine();

			this.axisY.createChild({
					cls : "axis-title axis-title-y",
					html : "Prix"});
			if (this.linkRel) {
				Ext.select('a[rel='+this.linkRel+']').on('click', function(e) {

						if (e.isFloating) e.stopEvent();

						if (this.autoShowDot)
							this.showPreviewWin.defer(200, this, [this.autoShowDot]);


					}, this);
			}

			if (this.autoShowDot)
				this.showPreviewWin.defer(1000, this, [this.autoShowDot, false]);

		},

		createGrapheZone : function() {

			this.grapheZoneEl = this.el.createChild({cls:'grapheZone'});
			this.grapheZoneEl.setLeft(this.axisWidth);
			this.grapheZoneEl.setBottom(this.axisHeight);
			this.grapheZoneEl.setWidth(this.grapheWidth);
			this.grapheZoneEl.setHeight(this.grapheHeight);

		},

		computeValues : function() {

			if (!this.width) this.width  = this.el.getWidth();
			else this.el.setWidth(this.width);

			if (!this.height) this.height = this.el.getHeight();
			else this.el.setHeight(this.height);

			this.margins = {
				x : this.grapheMarginLeft + this.grapheMarginRight,
				y : this.grapheMarginBottom + this.grapheMarginTop
			};

			this.grapheWidth  = this.width  - this.axisWidth;
			this.grapheHeight = this.height - this.axisHeight;

			// look for min/max priceSm, and min/max surface
			var minSurface  = 99999,
			    maxSurface  = 0,
			    diffSurface = 0,
			    minPriceSm  = 99999,
			    maxPriceSm  = 0,
					diffPriceSm = 0;

			Ext.each(this.ads, function(ad) {
					minSurface = Math.min(ad.surface, minSurface);
					maxSurface = Math.max(ad.surface, maxSurface);
					minPriceSm = Math.min(Math.round(ad.price / ad.surface), minPriceSm);
					maxPriceSm = Math.max(Math.round (ad.price / ad.surface), maxPriceSm);
				});

			minPriceSm -= 1;
			maxPriceSm += 1;
			diffSurface = maxSurface - minSurface;
			diffPriceSm = maxPriceSm - minPriceSm;

			this.minSurface  = minSurface;
			this.maxSurface  = maxSurface;
			this.minSurface  = minSurface;
			this.maxSurface  = maxSurface;
			this.diffSurface = diffSurface;
			this.minPriceSm  = minPriceSm;
			this.maxPriceSm  = maxPriceSm;
			this.minPriceSm  = minPriceSm;
			this.maxPriceSm  = maxPriceSm;
			this.diffPriceSm = diffPriceSm;

		},

		createAxis : function() {
			var axisX = this.el.createChild({cls   : "axis-x"});
			axisX.setLeft(0);
			axisX.setBottom(0);
			axisX.setWidth(this.width);
			axisX.setHeight(this.axisHeight);

			var axisY = this.el.createChild({cls   : "axis-y"});
			axisY.setLeft(0);
			axisY.setBottom(0);
			axisY.setWidth(this.axisWidth);
			axisY.setHeight(this.height);

			this.axisX = axisX;
			this.axisY = axisY;
		},

		addAxisLabel : function(axis, position, label, config) {

			var axisEl, labelEl, tickEl, pos, tickPos;

			config = Ext.applyIf(config || {}, {
					adjustX : 0,
					adjustY : 0,
					cls     : ""
				});

			if (axis != "x" && axis != "y")
				throw new Exception("Bad Axis (not x nor y)");

			axisEl = (axis == "x" ? this.axisX : this.axisY);

			labelEl = axisEl.createChild({
					cls : "axis-label axis-label-" + axis + " " + config.cls,
					html : label});
			tickEl = axisEl.createChild({
					cls : "axis-tick axis-tick-" + axis + " " + config.cls });

			pos = this.convertXY(position, position);

			if (axis == "x") {

				tickEl.setLeft(pos.x);
				tickPos = Math.round(0 - tickEl.getHeight() / 2) -1;
				tickEl.setTop(tickPos);

				labelEl.setHeight(this.axisHeight);
				labelEl.setTop(0 - tickPos + config.adjustY);
				labelEl.setLeft(pos.x - labelEl.getWidth() / 2 + config.adjustX);

			} else if (axis == "y") {

				tickEl.setBottom(pos.y);
				tickPos = Math.round(0 - tickEl.getWidth() / 2) -1;
				tickEl.setRight(tickPos);

				labelEl.setWidth(this.axisWidth);
				labelEl.setRight(0 - tickPos - config.adjustX);
				labelEl.setBottom(pos.y - labelEl.getHeight() / 2 + config.adjustY);
			}

		},

		addAvgLine : function() {

			var el, pos, config;

			config = {
				cls : 'avgPrice'
			};

			// avgPrice is not displayable
			if (this.avgPrice > this.maxPriceSm || this.avgPrice < this.minPriceSm)
				return;

			pos = this.convertXY(0, this.avgPrice);

			// avgPrice is displayable, but has to be adjusted on y
			// (to not overwrite labels)

			if (pos.y - this.axisHeight <= 25) {
				config.adjustY = 26 - (pos.y - this.axisHeight);
			} else if (this.height - pos.y <= 16) {
				config.adjustY = -16 + (this.height - pos.y);
			}


			el = this.el.createChild({cls:'avgLine'});
			el.setWidth(this.grapheWidth);
			el.setBottom(Math.round(pos.y - el.getHeight() / 2) + 1);
			el.setLeft(this.axisWidth);

			this.addAxisLabel("y", this.avgPrice,
				'Prix moyen<br/>' + this.avgPrice + '&euro; / m&sup2;',
				config);

			this.avgLineEl = el;


		},

		convertXY : function (x, y) {

			var ret = {
				x : this.axisWidth  + Math.round((x - this.minSurface) * (this.grapheWidth  - this.margins.x) / this.diffSurface) + this.grapheMarginLeft,
				y : this.axisHeight + Math.round((y - this.minPriceSm) * (this.grapheHeight - this.margins.y) / this.diffPriceSm) + this.grapheMarginBottom
			};

			return ret;
		},

		getPreviewWindow : function() {

			var win, el;

			if (!this.previewWindow) {

				if (this.previewId) el = Ext.get(this.previewId);

				if (el) {
					win = el.createChild({
							cls:"priceCompareGraphe-previewWindow",
							style:"visibilty: hidden;"
						});
				} else {
					win = this.el.createChild({
							cls:"priceCompareGraphe-previewWindow priceCompareGraphe-previewWindow-floating",
							style:"position: absolute; visibilty: hidden;"
						});
					win.isFloating = true;
					win.setXY(this.el.getXY());
				}

				win.selectArrow = this.el.createChild({
						cls:"priceCompareGraphe-previewWindow-selectArrow",
						style:"visibilty: hidden;"
					});

				win.on('click', this.hide, this, {delegate:'.closeBtn'});

				this.previewWindow = win;

			}

			return this.previewWindow;

		},

		computeAdTemplateValues : function(ad) {

			if (ad.computed === true) return;
			ad.computed = true;

			var priceSm, diff, compare, onClick;

			priceSm = ad.price / ad.surface;
			diff = (priceSm / this.avgPrice - 1) * 100;

			ad.percent = diff;
			
			if (diff >= 15) {
				ad.interest = "Médiocre";
				ad.interestCls = "low";
			} else if (diff <= -15) {
				ad.interest = "Très bon";
				ad.interestCls = "high";
			} else {
				ad.interest = "Bon";
				ad.interestCls = "medium";
			}

			ad.priceSm = Math.round(priceSm);

			ad.explanation = String.format('Le prix au m&sup2; de cette annonce ' +
					'est <span class="compare">{0}&nbsp;de&nbsp;{1}&nbsp;%</span> par ' +
					'rapport à celui du marché local ' +
					'(<span class="avg">{2}&nbsp;&euro;&nbsp;/&nbsp;m&sup2;</span>)',
				diff > 0 ? "supérieur" : "inférieur",
				Math.round(Math.abs(diff)),
				this.avgPrice);

			if (!ad.requested) {
				if (this.openAdsInNewWindow) {
					onclick = 'window.open(\'{0}\')';
				} else {
					onclick = 'location.href=\'{0}\'';
				}
				ad.operations = String.format('<button onclick="'+onclick+'">Voir cette annonce</button>',
					ad.url);
			}


		},

		showDotLabel : function(dot) {

			this.dotLabel.setXY([dot.getX(),
				dot.getY() - dot.getHeight()]);
			this.dotLabel.update( Math.round(dot.ad.price / dot.ad.surface) +
					" &euro; / m&sup2;");

		},

		showPreviewWin : function(dot, assertVisible) {

			var win, winPos, arrowPos;

			if (assertVisible !== false)
				assertVisible = true;

			win = this.getPreviewWindow();
			win.selectArrow.hide();

			this.computeAdTemplateValues(dot.ad);
			this.previewTpl.overwrite(win, dot.ad);

			winPos = [this.el.getX(), dot.getY()];
			winPos[0] += this.el.getWidth() + 25;
			winPos[1] -= win.getHeight() / 2;
			winPos[1] = Math.max(0, winPos[1]);

			arrowPos = dot.getXY();
			arrowPos[0] += dot.getWidth() + 2;
			arrowPos[1] += dot.getHeight() / 2 - win.selectArrow.getHeight() / 2;
			this.anims.previewArrow.x = arrowPos[0];
			this.anims.previewArrow.y = arrowPos[1];
			this.anims.previewArrow.width = winPos[0] - arrowPos[0];

			if (assertVisible) {
				this.anims.previewWin.scope = this;
				this.anims.previewWin.callback = this.assertWinVisible;
			}

			if (win.isFloating)
				win.setXY(winPos, this.anims.previewWin);

			win.selectArrow.shift(this.anims.previewArrow);

			win.selectArrow.show();

			if (win.isStyle('visibility', 'hidden')) {
				win.fadeIn({duration:0.5});
			}

			if (this.autoHideOnClick) {
				Ext.getDoc().un('click', this.autoHide, this);
				Ext.getDoc().on('click', this.autoHide, this);
			}


		},

		assertWinVisible : function() {

			var body, win, winY, winHeight, bodyY, bodyHeight;
			
			body = document.body;
			if (document.documentElement.clientWidth > 0)
				body = document.documentElement;

			win = this.getPreviewWindow();

			winY = win.getY();
			bodyY = body.scrollTop;
			bodyHeight = body.clientHeight;
			winHeight = win.getHeight();

			if (winY < bodyY ||
					winY > bodyY + bodyHeight ||
					winY + winHeight > bodyY + bodyHeight) {

				body.scrollTop = win.getY() - this.grapheHeight;

			}

		},

		autoHide : function(e) {

			var win = this.getPreviewWindow();

			if (!win.isVisible())    return;
			if (e.getTarget(".dot")) return;
			if (e.within(win)) return;

			this.hide();

		},

		hide : function() {

			var win = this.getPreviewWindow();

			win.hide(false);
			win.selectArrow.hide(false);

			if (this.autoHideOnClick)
				Ext.getDoc().un('click', this.autoHide, this);

		},

		assertBrowser : function() {
			// I'd love to uncomment this...
			// if (Ext.isIE6) {
			// 	this.el.update("Le graphique est incompatible avec Internet Explorer 6.");
			// 	return false;
			// }
			return true;

		}

	});

