﻿(function () {
	App.MapFetcher = function (url, type) {
		this.fetchType = "get";
		this.fetchAllPages = false;
		this.init(url, type);
	}
	App.MapFetcher.prototype = {
		init: 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 = {};
			this.fetchedPages = {};
		},
		setMap: function (map) {
			this.map = map;
			this.map.bind("fetch", [this, "fetch"]);
			this.map.bind("fetchLocked", [this, "fetchLocked"]);
			this.map.bind("type", [this, "setFetchType"]);
			this.map.bind("abort", [this, "_abortPrevious"]);
			this.map.bind("setInTrip", [this, "setInTrip"]);
		},
		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;
				}

			}
		},
		_abortPrevious: function () {
			if (this.previousRequest) {
				this.previousRequest.abort();
				this.previousRequest = false;
				this.locked = false;
				this.lastFetch = 0;
			}
		},
		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.previousRequest = false;
				this.locked = false;
				this.lastFetch = 0;
			}
			this.locked = true;
			this.lastFetch = new Date().getTime();
			if (typeof (data) == 'undefined')
				data = {};

			data.fetchId = ++this.currentFetchId;
			var dString = "";
			var cacheKey = this.url;
			var page = 0;
			if (this.fetchAllPages) {
				if (typeof (data["page"]) != "undefined") {
					page = data["page"];
					if (page == 1) {
						this.map.trigger('loading');
					}
				} else {
					page = data["page"] = 1;
					this.map.trigger('loading');
				}
			} else {
				this.map.trigger('loading');
			}
			this.lastData = data;
			for (var i in data) {
				dString += i + "=" + data[i] + "&";
				if (i != "fetchId" && (!this.fetchAllPages || i != "page"))
					cacheKey += i + "=" + data[i] + "&";
			}
			dString = dString.substr(0, dString.length - 1);

			this._doFetch(this.url, dString, cacheKey, page);
		},

		_doFetch: function (url, dataString, cacheKey, page) {
			this.lastCacheKey = cacheKey;
			if (typeof (this.fetchedPages[cacheKey]) == "undefined")
				this.fetchedPages[cacheKey] = {};
			if (typeof (this.fetchedPages[cacheKey][page]) == "undefined")
				this.fetchedPages[cacheKey][page] = false;

			if (typeof (this.dataCache[cacheKey]) != "undefined" && this.fetchedPages[cacheKey][page] == true) {
				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: url,
				context: this,
				data: dataString,
				dataType: "json",
				type: this.fetchType,
				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") {
							if (!this.fetchAllPages) {
								this.dataCache[cacheKey] = retData;
							} else {
								if (retData.TotalPages > retData.Page) {
									var clb = this.map;
									var clb_data = this.lastData;
									clb_data["page"] = retData.Page + 1;
									/* Run cached data callback with delay to allow thread to switch to other loader first */
									setTimeout(function () {
										clb.trigger("fetch", [clb_data]);
									}, 100)
								}
								if (typeof (this.dataCache[cacheKey]) == "undefined") {
									this.fetchedPages[cacheKey][retData.Page] = true;
									this.dataCache[cacheKey] = retData;
								} else if (this.fetchedPages[cacheKey][retData.Page] == false) {
									this.fetchedPages[cacheKey][retData.Page] = true;
									retData = this.combineResults(cacheKey, retData);
								}
							}
						}
						this.callback(retData, textstatus);
					}
				}
			});
		},

		combineResults: function (cacheKey, retData) {
			this.dataCache[cacheKey].PageSize += retData.PageSize;
			this.dataCache[cacheKey].Total = retData.Total;
			this.dataCache[cacheKey].fetchId = retData.fetchId;
			var addCount = retData.data.length;
			for (var i = 0; i < addCount; i++) {
				this.dataCache[cacheKey].data.push(retData.data[i]);
			}
			return this.dataCache[cacheKey];
		},

		callback: function (data, textstatus) {
			this.locked = false;
			this.previousRequest = false;
			this.map.trigger('loaded');
			if (textstatus == "success") {
				this.map.trigger("dataReady", [data]);
			}
		},

		setInTrip: function (e, options) {
			if (typeof (this.dataCache[this.lastCacheKey]) == "undefined")
				return;
			var dataCount = this.dataCache[this.lastCacheKey].data.length;
			for (var i = 0; i < dataCount; i++) {
				if (this.dataCache[this.lastCacheKey].data[i].Id == options.Id) {
					this.dataCache[this.lastCacheKey].data[i].IsInTrip = options.State;
					return;
				}
			}
		}

	}

	App.ProductMap = function (map, options) {
		this.options = $.extend({}, App.ProductMap.Options, options);
		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("setMapDataFlush", [handler, 'setDataFlush']);
		this.mapWrapper.bind("type", [handler, 'setFetchType']);
		this.mapWrapper.bind("viewType", [handler, 'setViewType']);
		//		this.mapWrapper.bind("flush", [handler, 'doDirectionFlush']);
		this.mapCreated = false;
	}
	App.ProductMap.Options = {
		zoom: 6,
		maxBoundZoom: 15,
		zoomControl: true,
		scrollToProduct: true,
		hoverBubble: false,
		pinClickEvent: true
	}

	App.ProductMap.prototype = {
		setFetchType: function (e, data) {
			this.fetchType = data;
			/*if (data == "trip")
			this.plotDirections = true;*/
		},

		setViewType: function (e, data) {
			this.viewType = data;
			if (!this.mapCreated && data == "map")
				this.initialize();
		},

		fetchCallback: function (e, dataSet, textstatus) {
			if (this.viewType != "map")
				return;
			var data = dataSet.data;
			$("#loadingsplash").hide();
			var append = true;
			this.fetchCount--;
			if (this.fetchCount <= 0) {
				$("#mapticker").hide();
				this.mapWrapper.removeClass('loading');
				this.fetchCount = 0;
			}
			if (typeof (dataSet.Page) != "undefined" && dataSet.Page > 1) {
				append = true;
			} else 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, this.options.scrollToProduct, this.options.hoverBubble, this.options.pinClickEvent);
					var latlng = marker.getPosition();
					bounds.extend(latlng);
					spots.push(latlng);
				}
			}
			this.prevBounds = bounds;
			if (!bounds.isEmpty()) {
				this.map.fitBounds(bounds);
				var zoom = this.map.getZoom();
				if (zoom > this.options.maxBoundZoom)
					this.map.setZoom(this.options.maxBoundZoom);
			}

			/*			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);
		},

		setDataFlush: function(e, data) {
			this.fetchData = {};
			this.setData(e, data);
		},

		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: this.options.zoomControl,
				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;

			if ($("#zoomcontrol").length > 0) {
				$("#zoomout").click([this, "zoomOut"]);
				$("#zoomin").click([this, "zoomIn"]);
			}
		},

		zoomOut: function (e) {
			this.zoomChange(e, -1);
		},
		zoomIn: function (e) {
			this.zoomChange(e, 1);
		},
		zoomChange: function (e, change) {
			this.map.setZoom(this.map.getZoom() + change);
		}

	}


	App.ProductMarker = function (json, wrapper, map, scrollToProduct, showInfoBubble, clickEvent) {
		this.data = json;
		this.productId = json.Id;
		this.map = map;
		this.wrapper = wrapper;
		this.scrollToProduct = scrollToProduct;
		this.showInfoBubble = showInfoBubble;
		this.clickEvent = clickEvent;
		//		this.modalCloseCallback = modalCloseCallback;
		this.flushobject = [this, 'flush'];
		this.wrapper.bind('flush.' + json.Id, this.flushobject);
		this.init();
	}
	App.ProductMarker.prototype = {
		init: function () {
			if (typeof (App.CustomMarker) == "undefined")
				App.CreateCustomMarkerClass();

			var cnt = this;
			this.marker = new App.CustomMarker(this.data, this.getPosition(), this.map, this.scrollToProduct, this.showInfoBubble, function () { cnt.checkStatus(); }, this.clickEvent);
		},

		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;
		},

		checkStatus: function () {
			$.ajax({ url: "/Product/ProductInTrip/" + this.productId,
				context: this,
				dataType: "json",
				type: "get",
				success: this.statusFetched
			});
		},

		statusFetched: function (retData, textStatus) {
			this.marker.setSelected(retData.InTrip);
			this.wrapper.trigger("setInTrip", [{ Id: this.productId, State: retData.InTrip}]);
		}
	}

	App.CreateCustomMarkerClass = function () {
		App.CustomMarker = function (dataSet, latlng, map, scrollToProduct, showInfoBubble, modalCloseCallback, clickEvent) {
			this.latlng_ = latlng;
			this.productData = dataSet;
			this.cssClass = dataSet.Type;
			this.scrollToProduct = scrollToProduct;
			this.showInfoBubble = showInfoBubble;
			this.infoWindowRendered = false;
			this.isSelected = typeof (dataSet.IsInTrip) ? dataSet.IsInTrip : false;
			this.hoverTimer = 0;
			if (typeof (modalCloseCallback) == "undefined") {
				modalCloseCallback = function () { };
			}
			this.onModalClose = modalCloseCallback;
			this.pinClickEvent = clickEvent;

			// 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.map = map;
			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).hover([this, "pinHoverIn"], [this, "pinHoverOut"]);
				//				$(div).bind("mouseleave", [this, "pinHoverOut"]);
				if (this.pinClickEvent) {
					$(div).bind("click", [this, "pinClick"]).css("cursor", "pointer");
				}
			}

			// 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 () {
			clearTimeout(this.hoverOutTimer);
			$(this.div_).addClass('hover');

			if (this.scrollToProduct) {
				if (this.listProduct === false)
					this.listProduct = $("#iproduct" + this.productData.Id);

				$(this.listProduct).addClass('hover');
			}
			var mrkr = this;
			this.hoverTimer = setTimeout(function () {
				mrkr.delayedHover();
			}, 300);

		};
		App.CustomMarker.prototype.pinHoverOut = function () {
			clearTimeout(this.hoverTimer);
			$(this.listProduct).removeClass('hover');
			$(this.div_).removeClass('hover');

			if (this.showInfoBubble && this.infoWindowRendered) {
				var mrkr = this;
				this.hoverOutTimer = setTimeout(function () {
					mrkr.infoWindow.hide().detach();
				}, 50);
			}

		};
		App.CustomMarker.prototype.setSelected = function (state) {
			if (state) {
				if ($(".selicon", this.div_).length == 0)
					$("<div class='selicon' />").appendTo(this.div_);
				$(this.div_).addClass("selected");
			} else
				$(this.div_).removeClass("selected");
		}
		App.CustomMarker.prototype.pinClick = function () {
			$.ProductModal(this.productData.Link, this.onModalClose);
		};
		App.CustomMarker.prototype.delayedHover = function () {
			if (this.scrollToProduct) {
				$(this.listProduct).parent().scrollTo(this.listProduct, 400, { axis: "y", duration: 600 });
			}
			if (this.showInfoBubble) {
				if (!this.infoWindowRendered) {
					this.renderInfoBubble();
				}
				this.positionBubble();
				this.infoWindow.appendTo("body").show();
			}
		}

		App.CustomMarker.prototype.renderInfoBubble = function () {
			this.infoWindow = $("<div class='mapmarker_infowindow'/>");
			$("<p>" + this.productData.Name + "</p>").appendTo(this.infoWindow);
			$("<img />").attr("src", this.productData.ImageUrl.replace("%w%", 40).replace("%h%", 40).replace("%f%", 0).replace("%c%", 1)).appendTo(this.infoWindow);
			$("<p class='desc'>" + this.productData.Categories + "</p>").appendTo(this.infoWindow);
			//$("<p class='desc'>" + this.productData.Categories + "</p>").appendTo(this.infoWindow);
			$('<div class="bubblecorner"></div>').appendTo(this.infoWindow);

			var mrkr = this;
			$(this.infoWindow).hover(function (e) {
				clearTimeout(mrkr.hoverOutTimer);
			}, [this, "pinHoverOut"])
			this.infoWindowRendered = true;

		}
		App.CustomMarker.prototype.positionBubble = function () {
			var position = $(this.div_).offset();
			this.infoWindow.css({ left: (position.left + 35) + "px", top: (position.top - 50) + "px" });


		}
	}
})();

