// =============================================
// namespace MapSites
// =============================================
var MapSites = 
{

	// =============================================
	// static utility methods: 
	// =============================================
	NIY : function(){alert('NIY');debugger;}
	,
	GetHttpText : function(url,onSuccess)
	{
		var oXmlHttp=GetXmlHttp();
		oXmlHttp.open("GET", url, true);
		
		oXmlHttp.onreadystatechange=function()
		{
			if (oXmlHttp.readyState!=4) return;
			if (oXmlHttp.responseText=='') return;

			// call the onSucess function with the responseText:
			onSuccess(oXmlHttp.responseText);

			// cleanup:
			delete oXmlHttp;
		}
			
		oXmlHttp.send(null);
	}
	,




	// =============================================
	// TypeIds:
	// =============================================
	TypeId :
	{
		None : 0,
		IsZmt : 1,
		IsZmt_Zomet : 1.1,
		IsZmt_Mehlaf : 1.2,
		Junction : 2,
		Address : 3,
		Address_City : 3.1,
		Address_Street : 3.2,
		Address_House : 3.3,
		Point : 4,
		NgItem : 5
	}
	,
	// =============================================
	// Static Initialization Functions
	// =============================================
	InitAsPoint : function(oSite)
	{
		oSite.SiteTypeId = MapSites.TypeId.Point;
		oSite.Serialize = function(){return MapSites.Serialization.Point.Serialize(this);}
	}	
	
	,
	
	InitAsAddress : function(oSite, cityCode,  cityName, street, houseNum)
	{
		// set type:
		oSite.SiteTypeId = MapSites.TypeId.Address;

		// set state:
		oSite.CityCode = cityCode;
		oSite.CityName = cityName;
		oSite.Street = street;
		oSite.HouseNum = houseNum;
		
		// normalize data:
		if (oSite.HouseNum == 0) oSite.HouseNum='';
		
		// set serialization strategy:
		oSite.Serialize = function(){return MapSites.Serialization.Address.Serialize(this);}
	}
	,
	InitAsJunction : function(oSite, cityCode, cityName, street1, street2)
	{
		// set type:
		oSite.SiteTypeId = MapSites.TypeId.Junction;

		// set state:
		oSite.CityCode = cityCode;
		oSite.CityName = cityName;
		oSite.Street1 = street1;
		oSite.Street2 = street2;

		// set serialization strategy:
		oSite.Serialize = function(){return MapSites.Serialization.Junction.Serialize(this);}
	}

	,
	InitAsIsZmt : function(oSite, isZmtName)
	{
		// set type:
		oSite.SiteTypeId = MapSites.TypeId.IsZmt;

		// set state:
		oSite.IsZmtName = isZmtName;

		// set serialization strategy:
		oSite.Serialize = function(){return MapSites.Serialization.IsZmt.Serialize(this);}
	}

	,
	InitAsNgItem : function(oSite, recordId, hebName)
	{
		// set type:
		oSite.SiteTypeId = MapSites.TypeId.NgItem;

		// set state:
		oSite.NgItemRecordId = recordId;
		oSite.NgItemHebName = hebName;

		// set serialization strategy:
		oSite.Serialize = function(){return MapSites.Serialization.NgItem.Serialize(this);}
	}

	,
	//=========================================
	// Static Creation Methods
	//=========================================
	Create : 
	{
		ByAuto : function(xRim, yRim, addressStr, addInfo, fOnAfterCreated)
		{
			// is it analyzable?
			if (isAnalyzable(addressStr))
			{
				// seems analyzable --> just analyze the address, ignoring everything else:
				MapSites.Create.ByAddressString(fOnAfterCreated, addressStr);
				return;
			}
			else if(isNgItem())
			{
				// seems like an ng item:
				var recordId, recordName;
				recordId = Number(addInfo.split('~')[1]);
				recordName = addressStr.substr(1,addressStr.length-2); // strip wrapping "[]"
				MapSites.Create.NgItem.ByIdAndName(fOnAfterCreated,recordId,recordName);
				return;
			}
			else if (HaveCoords()==false)
			{
				// no coords --> nothing:
				fOnAfterCreated(MapSites.GetNone());
				return;
			}
			else
			{
				// not an ng item and not analyzabe, but have coords -> regard it as a point:
				var oSite = new clsRoutePoint();
				oSite.SetPoint(addressStr,xRim,yRim,addInfo);
				fOnAfterCreated(oSite);
				return;
			}
			
			function HaveCoords()
			{
				if (String(xRim)=='') return false;
				if (String(xRim)=='0') return false;
				if (String(yRim)=='') return false;
				if (String(yRim)=='0') return false;
				return true;
			}
			
			function isAnalyzable(addressStr)
			{
				if (addressStr=='') return false;
				if (addressStr.charAt(0)=='[') return false;
				return true;
			}
			
			function  isNgItem()
			{
				if (addInfo==null) return false;
				if (addInfo=='') return false;
				if (addInfo.substr(0,3)=='poi') return true;
				return false;
			}
		}
		
		,
		NgItem :
		{
			ByIdAndName : function(fOnAfterCreated, recordId, recordName)
			{
				var url = '/maps/services/Geocode_NgItem_Json.asp?id=' + escape(recordId);
				MapSites.GetHttpText(url, function(responseText)
				{
					var coord = eval(responseText)
					var oSite = new clsRoutePoint();
					var addrStr = '[' + recordName + ']';
					var addInfo = 'poi~' + recordId + '~0';
					oSite.SetPoint(addrStr,coord.XRim,coord.YRim,addInfo, function(oSite){MapSites.InitAsNgItem(oSite,recordId,recordName);});
					
					fOnAfterCreated(oSite);
				});
			
			}
		}	
		,
		
		Address :
		{
			ByCityStreetHouse : function(fOnAfterCreated, cityCode, cityName, street, houseNum)
			{
				houseNum = (houseNum==null)?'':houseNum;
				var url = '/maps/services/Geocode_Address_Json.asp?Address=' + escape(cityCode + '_' + street + '_' + houseNum);
				MapSites.GetHttpText(url, function(responseText)
				{
					var coord = eval(responseText)
					var oSite = new clsRoutePoint();
					oSite.SetPoint((street==''?'':(street + ' ')) + (houseNum==''?'':(houseNum  + ' ')) + cityName,coord.XRim,coord.YRim,null, function(oSite){MapSites.InitAsAddress(oSite,cityCode, cityName, street, houseNum);});
					
					fOnAfterCreated(oSite);
				});
				
			}
		}
		
		,
		Junction :
		{
			ByCityStreetStreet : function(fOnAfterCreated, cityCode, cityName, street1, street2)
			{
				var url = '/maps/services/Geocode_Junction_Json.asp?Junction=' + escape(cityCode + '_' + street1 + '_' + street2);
				MapSites.GetHttpText(url, function(responseText)
				{
					var coord = eval(responseText)
					var oSite = new clsRoutePoint();
					oSite.SetPoint(street1 + ' פינת ' + street2 + ' ' + cityName,coord.XRim,coord.YRim,null, function(oSite){MapSites.InitAsJunction(oSite,cityCode, cityName, street1, street2);});
					
					fOnAfterCreated(oSite);
				});
			}
			
		}
		
		,
		IsZmt :
		{
			ByIdAndName : function(fOnAfterCreated, isZmtId, isZmtName)
			{
				var url = '/maps/services/Geocode_IsZmt_Json.asp?isZmtId=' + escape(isZmtId);
				MapSites.GetHttpText(url, function(responseText)
				{
					var coord = eval(responseText);
					var oSite = new clsRoutePoint();
					oSite.SetPoint(isZmtName,coord.XRim,coord.YRim,null, function(oSite){MapSites.InitAsIsZmt(oSite,isZmtName);});
					
					fOnAfterCreated(oSite);
				});
			
			
			}
			
			,
			
			ByName : function(fOnAfterCreated, isZmtName)
			{
				// lookup the id:
				var url = '/maps/services/Lookup_isZmt_Id_ByName.asp?isZmtName=' + escape(isZmtName);
				MapSites.GetHttpText(url,function(responseText)
				{
					var isZmtId = responseText;

					// create by id+name:
					MapSites.Create.IsZmt.ByIdAndName(fOnAfterCreated, isZmtId, isZmtName);
				});					
			}
		}
		

		,
		ByAddressStringUrl : function(fOnAfterCreated, url)
		{
			MapSites.GetHttpText(url,function(addressStr)
			{
				MapSites.Create.ByAddressString(fOnAfterCreated, addressStr);
			});
		}
		
		,
		ByAddressString : function(fOnAfterCreated, addressStr)
		{
			// empty address string --> no site:
			if (addressStr=='')
			{
				fOnAfterCreated(MapSites.GetNone());
				return;
			}
			
			// analyze the addressString:
			var url = '/gisservices/AddressAnalyzer/AnalyzeAddress4js.ashx?input=' + escape(addressStr);
			MapSites.GetHttpText(url,function(responseText)
			{
				// create a site by the analysis result:
				var oAnalyzed = eval(responseText);
				MapSites.Create.ByAnalyzed(fOnAfterCreated, oAnalyzed);
			});
		}
		
		,
		ByAnalyzed : function(fOnAfterCreated, oAnalyzed)
		{
			var fFactory = null;
			
			if(oAnalyzed.CityName != "")
			{
				fFactory = function(fOnAfterCreated){MapSites.Create.Address.ByCityStreetHouse(fOnAfterCreated,oAnalyzed.CityCode, oAnalyzed.CityName,'','');};
			}
			
			if(oAnalyzed.Street != "")
			{
				fFactory = function(fOnAfterCreated){MapSites.Create.Address.ByCityStreetHouse(fOnAfterCreated,oAnalyzed.CityCode, oAnalyzed.CityName,oAnalyzed.Street,'');};
			}

			if(oAnalyzed.Street2 != "")
			{
				fFactory = function(fOnAfterCreated){MapSites.Create.Junction.ByCityStreetStreet(fOnAfterCreated,oAnalyzed.CityCode, oAnalyzed.CityName,oAnalyzed.Street,oAnalyzed.Street2);};
			}
			
			if((oAnalyzed.HouseNum != null) && (oAnalyzed.HouseNum!=''))
			{
				fFactory = function(fOnAfterCreated){MapSites.Create.Address.ByCityStreetHouse(fOnAfterCreated,oAnalyzed.CityCode, oAnalyzed.CityName,oAnalyzed.Street,oAnalyzed.HouseNum);};
			}
					
			if(oAnalyzed.IsZmtName != "")
			{
				fFactory = function(fOnAfterCreated){MapSites.Create.IsZmt.ByName(fOnAfterCreated,oAnalyzed.IsZmtName, oAnalyzed.CityName,oAnalyzed.Street,oAnalyzed.Street2);};
			}
			
			// any identified factory?
			if (fFactory==null)
			{
				// no identified factory --> no site:
				fOnAfterCreated(MapSites.GetNone());
				return;
			}

			// create the site:			
			fFactory(fOnAfterCreated);
		}
	}
	
	,
	//===============================
	// static de/serialization methods:
	//===============================
	Serialization :
	{
		Nothing :
		{
			Serialize : function(oSite)
			{
				var data = new Array();
				data[0] = '';
				return data;
			}
			,
			Deserialize : function(data,fOnAfterDeserialized)
			{
				fOnAfterDeserialized(MapSites.GetNone());
			}

		}
		,
		NgItem :
		{
			//2refactor: de/serialize NgItem by Id. This means we need a Create.NgItem.ById()
			Serialize : function(oSite)
			{
				var data = new Array();
				data[0] = 3; // 3 = NgItem
				data[1] = oSite.NgItemRecordId;
				data[2] = oSite.NgItemHebName;

				return data;
			}			
			,
			
			Deserialize : function(data,fOnAfterDeserialized)
			{
				MapSites.Create.NgItem.ByIdAndName(fOnAfterDeserialized,data[1],data[2]);
			}			
		}
		,
		IsZmt :
		{
			//2refactor: de/serialize isZmt by id. this means we need a Create.IsZmt.ById()
			Serialize : function(oSite)
			{
				var data = new Array();
				data[0] = 2; // 2 = IsZmt
				data[1] = oSite.IsZmtName;

				return data;
			}			
			,
			
			Deserialize : function(data,fOnAfterDeserialized)
			{
				MapSites.Create.IsZmt.ByName(fOnAfterDeserialized,data[1]);
			}			
		}
		,
		Address :
		{
			//2refactor: de/serialize address without cityname. this means we need a Create.ByCode()
			Serialize : function(oSite)
			{
				var data = new Array();
				data[0] = 1; // 1 = address
				data[1] = oSite.CityCode;
				data[2] = oSite.CityName;
				data[3] = oSite.Street;
				data[4] = oSite.HouseNum;

				return data;
			}			
			,
			
			Deserialize : function(data,fOnAfterDeserialized)
			{
				MapSites.Create.Address.ByCityStreetHouse(fOnAfterDeserialized,data[1],data[2],data[3],data[4]);
			}			
		}
		
		,

		Junction :
		{
			//2refactor: de/serialize junction without cityname. this means we need a Create.ByCode()
			Serialize : function(oSite)
			{
				var data = new Array();
				data[0] = 4; // 4 = junction
				data[1] = oSite.CityCode;
				data[2] = oSite.CityName;
				data[3] = oSite.Street1;
				data[4] = oSite.Street2;

				return data;
			}			
			,
			
			Deserialize : function(data,fOnAfterDeserialized)
			{
				MapSites.Create.Junction.ByCityStreetStreet(fOnAfterDeserialized,data[1],data[2],data[3],data[4]);
			}			
		}
		
		,
		Point : 
		{
			Serialize : function(oSite)
			{
				var data = new Array();
				data[0] = 0; // 0 = point
				data[1] = oSite.GetPointAddress();
				data[2] = oSite.GetPointAdditionalInfo();
				data[3] = oSite.GetPointX();
				data[4] = oSite.GetPointY();
				return data;
			}			
			,
			
			Deserialize : function(data,fOnAfterDeserialized)
			{
				var oSite = new clsRoutePoint();
				oSite.SetPoint(data[1],data[3],data[4],data[2])
				fOnAfterDeserialized(oSite);
			}			
		}
	}
	,
	Deserialize : 
	{
		Collection : function(serialized, fDeserializeItem, fOnAfterDeserialized)
		{
			if (serialized=='') 
			{
				fOnAfterDeserialized(new Array());
				return;
			}
			
			var items = serialized.split(/\,/g);
			for(var i=0;i<items.length;i++)
			{
				items[i] = items[i].replace(/\&psik\;/g,',').replace(/\&amp\;/g,'&');
			}

			// start deserializing items:
			var done = 0;
			for(var i=0;i<items.length;i++)
			{
				// notice: we use the doIt(i) construct to maintain i's value upon async callback
				function doIt(i)
				{
					fDeserializeItem(items[i],function(deserialized)
					{
						items[i] = deserialized;
						done++;
					});
				}
				doIt(i);
			}
			
			// wait for it to finish
			waitUntilDone();
			
			function waitUntilDone()
			{
				if (done<items.length)
				{
					// wait some more...
					window.setTimeout(waitUntilDone,50);
					return;
				}
				
				// done:
				fOnAfterDeserialized(items);
			}
		}		


		,
		
		Site : function(data,fOnAfterDeserialized)
		{
			// pick a deserializer according to the first member
			var fDeserialize;
			switch(String(data[0]))
			{
				case '1':
					fDeserialize = MapSites.Serialization.Address.Deserialize;
					break;

				case '2':
					fDeserialize = MapSites.Serialization.IsZmt.Deserialize;
					break;

				case '3':
					fDeserialize = MapSites.Serialization.NgItem.Deserialize;
					break;


				case '4':
					fDeserialize = MapSites.Serialization.Junction.Deserialize;
					break;

				case '':
					fDeserialize = MapSites.Serialization.Nothing.Deserialize;
					break;

				default:
					fDeserialize = MapSites.Serialization.Point.Deserialize;
					break;
			}
			
			// deserialize:
			fDeserialize(data,fOnAfterDeserialized);			
		}
		,
		FromUrl : function(serialized, fOnAfterDeserialized)
		{
			// 2do: decode content 'x'
			var data = serialized.split('x');
			
			// and deserialize it:
			MapSites.Deserialize.Site(data,fOnAfterDeserialized);			
		}
		

		

	}
	

	,
	Serialize : 
	{
		// serialize a collection of items
		Collection : function(items,fSerializeItem)
		{
			if (items.length==0) return '';
			
			var serialized = new Array();
			for(var i=0;i<items.length;i++)
			{
				serialized.push(fSerializeItem(items[i]).replace(/\&/g,'&amp;').replace(/\,/g,'&psik;'));
			}
			
			return serialized.join(',');
		}
		,	
		
		
		// Serialize a site for URL	
		ForUrl : function(oSite)
		{
			// use 'x' as a url-friendly seperator
			// 2do: encode content-'x' into some other token...
			return oSite.Serialize().join('x');
		}

	}
	
	,
	// NullObject:
	_none: null,
	GetNone : function()
	{
		if (MapSites._none==null)
		{
			MapSites._none = new clsRoutePoint();
			MapSites._none.Init();
			MapSites._none.SetPoint('','','','',function(oSite)
			{
				oSite.SiteTypeId = MapSites.TypeId.None;
				oSite.Serialize = function(){return MapSites.Serialization.Nothing.Serialize();}
			});
		}
		
		return MapSites._none;
	}
	
}



