﻿(function () {
	App.MapFetcher = function (url, type) {
		this.url = url;
		this.locked = false;
		this.lastFetch = 0;
		this.currentFetchId = 0;
		this.previousRequest = false;
		this.type = type;
		this.activated = false;
		this.dataCache = {};
	}
	App.MapFetcher.prototype = {
		setMap: function (map) {
			this.map = map;
			this.map.bind("fetch", [this, "fetch"]);
			this.map.bind("fetchLocked", [this, "fetchLocked"]);
			this.map.bind("type", [this, "setFetchType"]);
		},
		setFetchType: function (e, data) {
			if (data == this.type) {
				this.activated = true;
			} else {
				this.activated = false;
				if (this.previousRequest) {
					this.previousRequest.abort();
					this.previousRequest = false;
					this.locked = false;
				}

			}
		},
		fetch: function (e, data) {
			this._fetch(e, data, false);
		},
		fetchLocked: function (e, data) {
			this._fetch(e, data, true);
		},
		_fetch: function (e, data, locked) {
			if (!this.activated)
				return;
			if (locked && this.locked)
				return;
			if (this.previousRequest) {
				this.previousRequest.abort();
			}
			this.locked = true;
			this.lastFetch = new Date().getTime();
			if (typeof (data) == 'undefined')
				data = {};

			data.fetchId = ++this.currentFetchId;
			this.map.trigger('loading');
			var dString = "";
			var cacheKey = "";
			for (var i in data) {
				dString += i + "=" + data[i] + "&";
				if (i != "fetchId")
					cacheKey += i + "=" + data[i] + "&";
			}
			dString = dString.substr(0, dString.length - 1);
			if (typeof (this.dataCache[cacheKey]) != "undefined") {
				var clb = this;
				var clb_data = this.dataCache[cacheKey];
				/* Run cached data callback with delay to allow thread to switch to other loader first */
				setTimeout(function () {
					clb.callback(clb_data, "success");
				}, 50);
				return;
			}
			this.previousRequest = $.ajax({
				url: this.url,
				context: this,
				data: dString,
				dataType: "json",
				xhr: function () {
					if ($.browser.msie && $.browser.version.substr(0, 1) <= 7)
						return new ActiveXObject("Microsoft.XMLHTTP");
					else
						return new XMLHttpRequest();
				},
				success: function (retData, textstatus) {
					if (retData != null && retData.success == true && retData.fetchId == this.currentFetchId) {
						if (textstatus == "success")
							this.dataCache[cacheKey] = retData.data;
						this.callback(retData.data, textstatus);
					}
				}
			});

		},
		callback: function (data, textstatus) {
			this.locked = false;
			this.previousRequest = false;
			this.map.trigger('loaded');
			if (textstatus == "success") {
				this.map.trigger("dataReady", [data]);
			}
		}

	}

	App.ProductMap = function (map) {
		var handler = this;
		//		this.fetcher.setCallback(this.fetchCallback);
		//		this.mapWrapper = $("<div />").addClass('wrapper').appendTo(masterWrapper);
		this.mapWrapper = $(map);
		this.fetchCount = 0;
		this.firstFetch = true;
		//this.fetcher.setMap(this.mapWrapper);
		this.fetchData = {};
		this.fetchType = "product";
		this.mapWrapper.bind('dataReady', [handler, 'fetchCallback']);
		this.mapWrapper.bind("loading", [handler, 'loading']);
		this.mapWrapper.bind("loaded", [handler, 'loaded']);
		this.mapWrapper.bind("reload", [handler, 'reload']);
		this.mapWrapper.bind("setMapData", [handler, 'setData']);
		this.mapWrapper.bind("type", [handler, 'setFetchType']);
		//		this.mapWrapper.bind("flush", [handler, 'doDirectionFlush']);
		this.initialize();
	}
	App.ProductMap.Options = {
		zoom: 6
	}

	App.ProductMap.prototype = {
		setFetchType: function (e, data) {
			this.fetchType = data;
			/*if (data == "trip")
			this.plotDirections = true;*/
		},

		fetchCallback: function (e, data, textstatus) {
			$("#loadingsplash").hide();
			var append = true;
			this.fetchCount--;
			if (this.fetchCount <= 0) {
				$("#mapticker").hide();
				this.mapWrapper.removeClass('loading');
				this.fetchCount = 0;
			}
			if (this.firstFetch) {
				append = false;
				this.firstFetch = false;
			}
			if (!append) {
				this.mapWrapper.trigger("flush");
				this.prevBounds = new google.maps.LatLngBounds();
			}

			if (this.fetchType == "product") {
				this.plotData(data, append);
			}
		},

		plotData: function (data, append) {
			var bounds = new google.maps.LatLngBounds();

			if (append) {
				bounds = this.prevBounds;
			}
			var spots = [];
			for (var i = 0; i < data.length; i++) {
				if (data[i].Latitude != 0 && data[i].Longitude != 0) {
					var marker = new App.ProductMarker(data[i], this.mapWrapper, this.map);
					var latlng = marker.getPosition();
					bounds.extend(latlng);
					spots.push(latlng);
				}
			}
			this.prevBounds = bounds;
			if (!bounds.isEmpty()) {
				this.map.fitBounds(bounds);
			}

			/*			if (this.plotDirections) {
			var request = {
			travelMode: google.maps.DirectionsTravelMode.DRIVING
			};
			waypoints = [];
			var maxWpts = Math.min((spots.length - 1), 9);
			for (var i = 1; i < maxWpts; i++) {
			waypoints.push({ location: spots[i], stopover: true });
			}
			request.origin = spots[0];
			request.destination = spots[spots.length - 1];
			request.waypoints = waypoints;
			var dirDisplay = this.directionsDisplay;
			try {
			this.directionsService.route(request, function (response, status) {
			if (status == google.maps.DirectionsStatus.OK) {
			dirDisplay.setDirections(response);
			}
			});
			} catch (er) { console.log(er); }
			}*/
		},

		loading: function () {
			if (this.fetchCount == 0)
				this.firstFetch = true;
			$("#mapticker").show();
			$("#loadingsplash p").hide();
			$("#loadingsplash p." + this.fetchType).show();
			$("#loadingsplash").show();

			this.mapWrapper.addClass('loading');
			this.fetchCount++;
		},

		loaded: function () {
		},

		reload: function (withLock) {
			if (typeof (withLock) == "undefined")
				withLock = false;
			this.fetchCount = 0;
			this.firstFetch = true;
			if (withLock)
				this.mapWrapper.trigger("fetchLocked", [this.fetchData]);
			else
				this.mapWrapper.trigger("fetch", [this.fetchData]);
			//this.fetcher.fetch(this.fetchData);
		},

		setData: function (e, data) {
			for (var i in data) {
				this.fetchData[i] = data[i];
			}
		},

		//		doDirectionFlush: function () {
		//			try {
		//							this.directionsDisplay.setDirections();
		//			} catch (er) { console.log(er); }
		//		},

		initialize: function () {
			var defaultPos = new google.maps.LatLng(App.MapDefaultPosition.Lat, App.MapDefaultPosition.Lng);
			var myOptions = {
				zoom: 8,
				disableDefaultUI: true,
				center: defaultPos,
				mapTypeId: google.maps.MapTypeId.ROADMAP,
				mapTypeControl: false,
				mapTypeControlOptions: { style: google.maps.MapTypeControlStyle.DROPDOWN_MENU },
				navigationControl: true,
				navigationControlOptions: { style: google.maps.NavigationControlStyle.SMALL }
			};
			this.map = new google.maps.Map(this.mapWrapper[0], myOptions);
			//			this.directionsService = new google.maps.DirectionsService();
			//			this.directionsDisplay = new google.maps.DirectionsRenderer();
			//			this.directionsDisplay.setMap(this.map);
			//			this.plotDirections = false;
		}
	}


	App.ProductMarker = function (json, wrapper, map) {
		this.data = json;
		this.map = map;
		this.wrapper = wrapper;
		this.flushobject = [this, 'flush'];
		this.wrapper.bind('flush.' + json.Id, this.flushobject);
		this.init();
	}
	App.ProductMarker.prototype = {
		init: function () {
			this.marker = new App.CustomMarker(this.data, this.getPosition(), this.map);
		},

		flush: function () {
			this.marker.remove();
			this.wrapper.unbind('.' + this.data.Id);
		},
		getPosition: function () {
			if (typeof (this.position) == 'undefined') {
				this.position = new google.maps.LatLng(this.data.Latitude, this.data.Longitude);
			}
			return this.position;
		}
	}


	App.CustomMarker = function (dataSet, latlng, map) {
		this.latlng_ = latlng;
		this.productData = dataSet;
		this.cssClass = dataSet.Type;
		this.isSelected = typeof (dataSet.Selected) ? dataSet.Selected : false;
		this.hoverTimer = 0;
		// Once the LatLng and text are set, add the overlay to the map.  This will
		// trigger a call to panes_changed which should in turn call draw.
		this.setMap(map);
	}

	App.CustomMarker.prototype = new google.maps.OverlayView();

	App.CustomMarker.prototype.draw = function () {
		var me = this;

		// Check if the div has been created.
		var div = this.div_;
		if (!div) {
			// Create a overlay text DIV
			var jDiv = $("<div id='pinProduct" + this.productData.Id + "'/>")
				.addClass('pin')
				.addClass(this.cssClass)
				.attr('title', this.productData.Name);

			$("<div class='icon' />").appendTo(jDiv);

			if (this.isSelected) {
				jDiv.addClass('selected');
				$("<div class='selicon' />").appendTo(jDiv);
			}

			div = this.div_ = jDiv[0];
			// Then add the overlay to the DOM
			var panes = this.getPanes();
			panes.overlayImage.appendChild(div);

			this.listProduct = false;
			$(div).bind("mouseenter", [this, "pinHoverIn"]);
			$(div).bind("mouseleave", [this, "pinHoverOut"]);
			$(div).bind("click", [this, "pinClick"]);
		}

		// Position the overlay 
		var point = this.getProjection().fromLatLngToDivPixel(this.latlng_);
		if (point) {
			div.style.left = (point.x - 20) + 'px';
			div.style.top = (point.y - 38) + 'px';
		}
	};

	App.CustomMarker.prototype.remove = function () {
		// Check if the overlay was on the map and needs to be removed.
		if (this.div_) {
			$(this.div_).remove();
		}
	};

	App.CustomMarker.prototype.getPosition = function () {
		return this.latlng_;
	};

	App.CustomMarker.prototype.pinHoverIn = function () {
		if (this.listProduct === false)
			this.listProduct = $("#iproduct" + this.productData.Id);

		$(this.div_).addClass('highlight');
		$(this.listProduct).addClass('hover');
		var self = this;
		this.hoverTimer = setTimeout(function () {
			self.scrollToProduct();
		}, 300);

	};
	App.CustomMarker.prototype.pinHoverOut = function () {
		clearTimeout(this.hoverTimer);
		$(this.listProduct).removeClass('hover');
		$(this.div_).removeClass('highlight');
	};
	App.CustomMarker.prototype.pinClick = function () {
		$.ProductModal(this.productData.Link);
	};
	App.CustomMarker.prototype.scrollToProduct = function () {
		$(this.listProduct).parent().scrollTo(this.listProduct, 400, { axis: "y", duration: 600 });
	}
})();