var charset="";
/**********************************************************************
 *
 * $Id: startUp.js,v 1.8 2006/12/14 17:24:41 lbecchi Exp $
 *
 * purpose: start up code to bootstrap initialization of kaMap within
 *          the sample interface.  Examples of using many parts of
 *          the kaMap core api.
 *
 * purpose: This is the sample ka-Map interface.  Feel free to use it 
 *          as the basis for your own applications or just to find out
 *          how ka-Map works.
 *
 * author: Lorenzo Becchi and Andrea Cappugi (www.ominiverdi.org)
 *
 * ka-Explorer interface has been developer for Food and Agriculture 
 * Organization of the United Nations (FAO-UN)
 *
 *
 **********************************************************************
 *
 * Copyright (c) 2006 Food and Agriculture Organization of the United Nations (FAO-UN)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/******************************************************************************
 *
 * To customize startUp:
 *
 * 1) modify toolbar Layout
 *  act on screen.css file and modify the funcion myMapInitialized().
 *  If you change pan and identifyer images edit switchMode() function too.
 *
 *****************************************************************************/
var ICTMAP = null;
var ICTMAP_URL = "http:/"+"/map.kumamoto-net.ne.jp/ictmap/";
var ICTMAP_INIT = "/*init*/aszScales=new Array('600000','300000','100000','50000','25000','12500','10000','7500','5000','2500');defaultKihonLayer=new Array();defaultGeomLayer=new Array('4');var map = new _map({name:'gmap',title:'amakusaict',currentScale: 0,units:5,resolution:72,version:'',scales:aszScales});map.setDefaultExtents(129.942751522,32.0900215666,131.339655464,33.2329429742);map.setBackgroundColor('#9BAFCD');map.addLayer(new _layer( { name:'back',name2:'背景',visible:true,opacity:100,imageformat:'AGG_PNG24',queryable:false,tileSource:'auto',redrawInterval:-1,refreshInterval:-1,scales: new Array('1','1','1','1','1','1','1','1','1','1'),visibilityContorol:0}));map.addLayer(new _layer( { name:'base',name2:'地図標準アイコン',visible:false,opacity:100,imageformat:'AGG_PNG24',queryable:false,tileSource:'auto',redrawInterval:-1,refreshInterval:-1,scales: new Array('0','0','0','0','1','1','1','1','1','1'),visibilityContorol:1}));map.addLayer(new _layer( { name:'schoolarea',name2:'学校区域線',visible:false,opacity:100,imageformat:'AGG_PNG24',queryable:false,tileSource:'auto',redrawInterval:-1,refreshInterval:-1,scales: new Array('1','1','1','1','1','1','1','1','1','1'),visibilityContorol:1}));map.resolution = 72;this.addMap( map );this.tileWidth=256;this.tileHeight=256;this.server = '"+ICTMAP_URL+"';this.tileURL = 'tile.phtml';this.selectMap('gmap');this.hl='0';"
var ICTMAP_INIT_POINT = "130.71514754505813,32.8029555744417,12500";

//var oJsr = null;
/*
var myKaMap = myKaNavigator = myKaQuery = myScalebar = null;
var queryParams = null;
var mgpath = "";
*/

/**
 * parse the query string sent to this window into a global array of key = value pairs
 * this function should only be called once
 */
/*
function parseQueryString() {
    queryParams = {};
    var s=window.location.search;
    if (s!='') {
        s=s.substring( 1 );
        var p=s.split('&');
        for (var i=0;i<p.length;i++) {
            var q=p[i].split('=');
            queryParams[q[0]]=q[1];
        }
    }
}
*/
/**
 * get a query value by key.  If the query string hasn't been parsed yet, parse it first.
 * Return an empty string if not found
 */
/*
function getQueryParam(p) {
    if (!queryParams) {
        parseQueryString();
    }
    if (queryParams[p]) {
        return queryParams[p];
    } else {
        return '';
    }
}
*/
// setTimeout関数のオブジェクト指向対応
Function.prototype.applyTimeout = function (ms, self, args) {
  var f = this;
  return setTimeout(
    function () {
      f.apply(self, args);
    },
    ms);
};

Function.prototype.callTimeout = function (ms, self) {
  return this.applyTimeout(
      ms,
      self,
      Array.prototype.slice.call(arguments, 2));
};

Function.prototype.applyInterval = function (ms, self, args) {
  var f = this;
  return setInterval(
    function () {
      f.apply(self, args);
    },
    ms);
};

// メインクラス
function IctMap(objname){
	
	this.scalebarWidth = null;
	this.objName = objname;

	var initX;
	var initY;
	var initScale;
	if(arguments.length == 4){
		initX = arguments[1];
		initY = arguments[2];
		initScale = arguments[3];
	}
	var opt = null;
	if(arguments.length == 5){
		opt = arguments[4];
		alert(opt);
		for(a in opt){
			var str = "this." + a + "=" + opt[a];
			alert(str);
			eval(str);
		}
	}
	
	this.CONST_VIEWPORT_ID = 'ictmap';
	this.CONST_SUBMAP_ID = 'ictsubmap';

	//スケールバーの表示
	this.scalebarID = "scaleReference";
	this.dspScalebar = true;
	
	//拡大縮小など
	this.controlID = "toolbarContainer";
	this.dspContorol = false;
	
	//学校区名
	this.schoolnameID = "schoolname";
	this.dspSchoolname = false;
	
	//サブマップ
	this.submapID = this.CONST_SUBMAP_ID;
	this.dspSubmap = false;
	
	//スケールバーの表示・非表示
	this.DspScalebar = function(mode){
		var obj = getRawObject(this.scalebarID);
		if(mode){
			this.dspScalebar = true;
			obj.style.display = 'block';
		}else{
			this.dspScalebar = false;
			obj.style.display = 'none';
		}
	};
	
	//スケールバーの幅を変える
	this.ChgScalebarMaxWidth = function(width){
		var obj = getRawObject(this.scalebarID);
		obj.style.width = width+"px";
		if(this.scalebar.minWidth > width){
			this.scalebar.minWidth=width-10;
		}
		this.scalebar.maxWidth=width;
		this.scalebar.update();
	};
	
	//コントローラーの表示・非表示
	this.DspContorol = function(mode){
		var obj = getRawObject(this.controlID);
		if(mode){
			this.dspContorol = true;
			obj.style.display = 'block';
		}else{
			this.dspContorol = false;
			obj.style.display = 'none';
		}
	};
	
	//学校名の表示・非表示
	this.DspSchoolname = function(mode){
		var obj = getRawObject(this.schoolnameID);
		if(mode){
			this.dspContorol = true;
			obj.style.display = 'block';
		}else{
			this.dspContorol = false;
			obj.style.display = 'none';
		}
	};
	
	//サブマップの表示・非表示
	this.DspSubmap = function(mode){
		var obj = getRawObject(this.submapID);
		if(mode){
			this.dspSubmap = true;
			obj.style.display = 'block';
		}else{
			this.dspSubmap = false;
			obj.style.display = 'none';
		}
	};
	
	//this.ICTMAP = this.myKaNavigator = this.myKaQuery = this.myScalebar = null;
	this.queryParams = null;
	this.mgpath = "";
	
	//SetCenter(x,y[,scale])
	//指定した経度・経度を中心にして、指定された
	//スケールで地図を表示する
	//引数：経度、緯度、スケール
	this.SetCenter = function(x,y){
		var str = arguments[2];
		if(str != null && str != ""){
			var scale = convertNum(str);
			if(this.CheckScale(scale)){
				ICTMAP.zoomTo(x,y,scale);
			}
		}else{
			ICTMAP.zoomTo(x,y);
		}
	};

	//指定されたスケールに拡大・縮小する
	//引数：スケール
	this.SetZoom = function(scale){
		if(this.CheckScale(scale)){
			ICTMAP.zoomToScale(scale);
		}
	};
	
	//妥当なスケールかどうかチェックする
	this.CheckScale = function(scale){
		var arrScales = ICTMAP.aMaps[ICTMAP.currentMap].getScales();
		var arrLen = arrScales.length;
		var matchFlg = false;
		for(i=0;i<arrLen;i++){
			if(scale == arrScales[i]){
				matchFlg = true;
				break;
			}
		}
		return matchFlg;
	};
	
	//中心の経度・緯度を返す
	//戻り値：Array(X,Y)
	this.GetCenter = function(){
			var extents = ICTMAP.getGeoExtents();
			var cx = (extents[2] + extents[0])/2;
			var cy = (extents[3] + extents[1])/2;
			return Array(cx,cy);
	};
	
	//範囲取得
	this.GetExtents = function(){
		return ICTMAP.getGeoExtents();
	};
	
	//スケール取得
	this.GetScale = function(){
		return ICTMAP.getCurrentScale();
	};
	
	//標準アイコンの表示・非表示
	this.DspLandmark = function(flg){
		if(flg){
			dispOverLayKihon(true);
			ICTMAP.dspLandmark = true;
		}else{
			dispOverLayKihon(false);
			ICTMAP.dspLandmark = false;
		}
	};
	
	//学校区を表示する
	this.dspSchoolArea = false;
	this.DspSchoolArea = function(flg){
		if(typeof(flg) == "boolean"){
			this.dspSchoolArea = flg;
			ICTMAP.setLayerVisibility('schoolarea', this.dspSchoolArea);
		}
	};
	
	//中心を表示する
	this.DspCenterPoint = function(flg){
		var centerPoint = getRawObject("ictmapCenter");
		if(flg){
			centerPoint.style.display="block";
			centerPoint.style.left = Math.round(ICTMAP.viewportWidth/2-8)+"px";
			centerPoint.style.top = Math.round(ICTMAP.viewportHeight/2-8)+"px";
		}else{
			centerPoint.style.display="none";
		}
	}
	
	//吹き出しを表示する
	this.DspFukidashi = function(x,y,opts){
		var icon = new ictMapIcon();
		icon.Icon.icon_src=this.server+"common/images/spacer.gif";
		icon.Icon.icon_w=1;
		icon.Icon.icon_h=1;
		var tmpPoint = this.AddPoint("tmp",x,y,icon,opts,"tmp");
		tmpPoint.div.firstChild.onclick();
	}
	
	//吹き出しを非表示にする
	this.HideFukidashi = function(){
		clearOverlaysymbolhtml();
	}
	
	//表示範囲が変わったときのイベント
	this.exetentChangeFunc = function(){
	};

	//地図の大きさを変更する
	this.Resize = function(width,height){
		var targetObj = getRawObject(this.objName);
		targetObj.style.width = width + "px";
		targetObj.style.height = height + "px";
		//VIEWPORTのサイズを設定
		var viewport = getRawObject(this.CONST_VIEWPORT_ID);
		viewport.style.width = width+"px";
		viewport.style.height = height+"px";
		/*viewport.style.top="0px";
		viewport.style.left="0px";*/
		ICTMAP.resize();
	}

	//アニメーション用プロパティ
	this.arrOnclick = [];
	this.arrOnclickAnimeIdx = 0;
	this.arrOnclickIndex = 0;
	this.animeFlg = null;
	this.animeActFlg = null;
	//アニメーションの開始
	this.animeTime = 3000;
	this.startOnclickAnime = function(){
		this.animeFlg = ICTMAP.IctMap.actAnime.applyInterval(this.animeTime,this,[]);
		this.animeActFlg = true;
	}
	this.stopOnclickAnime = function(){
		clearInterval(this.animeFlg);
		this.animeActFlg = false;
	}	
	this.actAnime = function(){
		if(this.arrOnclick.length > 0){
			this.arrOnclick[this.arrOnclickAnimeIdx]();
			this.arrOnclickAnimeIdx++;
			if(this.arrOnclickAnimeIdx == this.arrOnclick.length){
				this.arrOnclickAnimeIdx=0;
			}
		}
	}

	//初期処理
	if(initX != null && initY != null && initScale != null){
		this.init(objname,initX,initY,initScale);
	}else{
		this.init(objname);
	}
}

//*****************************
//	ポイントを一つ追加する
//  sakai
//*****************************
IctMap.prototype.AddPoint = function(pointid,lon,lat,icon,opts,pointName){
    var my_point = ICTMAP.myXmlOverlay.addNewPoint(ICTMAP.USERPOINT_PREFIX+pointid, lon, lat,opts,pointName);
	if(icon != null && typeof(icon) == "object"){
		my_point.addGraphic(icon.Icon);
	}else{
		var my_symbol = new kaXmlSymbol();
		my_symbol.size = 12;
		my_symbol.color = '#ff0000';
		my_point.addGraphic(my_symbol);
	}
	return my_point;
};

//*****************************
//	ポイントを削除する(ユーザポイント)
//  pointidがnullの場合ユーザポイントを全て削除する
//  sakai
//*****************************
IctMap.prototype.RemovePoint = function(pointid){
	if(pointid != null && pointid != ""){
    	ICTMAP.myXmlOverlay.removePoint(ICTMAP.USERPOINT_PREFIX+pointid);
	}else{
		ICTMAP.myXmlOverlay.removePoint("",ICTMAP.USERPOINT_PREFIX);
	}
};

//*****************************
//	アイコンオブジェクト
//  sakai
//*****************************
function ictMapIcon(){
	this.img_src = null;
	this.icon_w = 0;
	this.icon_h = 0;
	/*this.markerOption = new GMarkerOptions();
	this.markerOption.icon = new GIcon();
	this.markerOption.icon.image = this.img_src;
	this.markerOption.icon.size = null;*/
	this.Icon = new kaXmlIcon();
	this.Icon.img_src = this.img_src;
};

//*****************************
//	数値に変換する
//  sakai
//*****************************
function convertNum(str){
	try{
		var dst = parseInt(str,10);
		return dst;
	}catch(e){
		return null;
	}
};

//*****************************
//	イベントを追加する
//  sakai
//*****************************
function addEvent(target, type, func){
 if(target.attachEvent){
  target.attachEvent("on" + type, func);
 }else if(target.addEventListener){
  target.addEventListener(type, func, true);
 }else {
  target["on" + type] = func;
 }
};

/*
addEvent(window,"load",function(){
	var css = document.createElement("link");
	css.setAttribute("rel","stylesheet");
	css.setAttribute("type","text/css");
	css.setAttribute("href",ICTMAP.server+"ictmap.css");
	var head = document.getElementsByTagName("head");
	head[0].appendChild(css);
});
*/

//*****************************
//	初期処理
//  sakai
//*****************************
IctMap.prototype.init = function(objname) {

    initDHTMLAPI();
	//window.onresize=drawPage;

	//ベースHTMLを描画する
	var targetObj = getRawObject(objname);
	if(targetObj){
		targetObj.innerHTML = getBaseHtml();
	}else{
		alert("マップ表示用HTMLオブジェクトが不正です");
		return;
	}

	//VIEWPORTのサイズを設定
	var mapWidth = getObjectWidth(targetObj);
	var mapHeight = getObjectHeight(targetObj);
	var viewport = getRawObject(this.CONST_VIEWPORT_ID);
	viewport.style.width = mapWidth+"px";
	viewport.style.height = mapHeight+"px";

	ICTMAP = new kaMap(this.CONST_VIEWPORT_ID,"",ICTMAP_INIT);
	ICTMAP.IctMap = this;
	
	//var szMap = getQueryParam('map');
    //var szExtents = getQueryParam('extents');
    //var szCPS = getQueryParam('cps');
	var szMap = "";
    var szExtents = "";
    var szCPS = "";
	
	if(arguments.length > 2){
		szCPS = arguments[1]+","+arguments[2]+","+arguments[3];
	}

	// デモ用にデフォルトを熊本市中心で表示
	if(szCPS == ""){
		szCPS = ICTMAP_INIT_POINT;
	}

	var gbLegendOpacityControl = false;
	var gbLegendOrderControl = false;
	var gbLegendQueryControl = false;
	
    var legendOptions = {};
    legendOptions.visibility = typeof gbLegendVisibilityControl != 'undefined' ? gbLegendVisibilityControl : true;
    legendOptions.opacity = typeof gbLegendOpacityControl != 'undefined' ? gbLegendOpacityControl : true;
    legendOptions.order = typeof gbLegendOrderControl != 'undefined' ? gbLegendOrderControl : true;
    legendOptions.query = typeof gbLegendQueryControl != 'undefined' ? gbLegendQueryControl : true;

    //var myKaLegend = new kaLegend( ICTMAP, 'legend', false, legendOptions);
    var myKaKeymap = new kaKeymap( ICTMAP, this.CONST_SUBMAP_ID);
	ICTMAP.kaKeymap = myKaKeymap;
    myKaNavigator = new kaNavigator( ICTMAP );
    myKaNavigator.activate();
    myKaQuery = new kaQuery( ICTMAP, KAMAP_RECT_QUERY );
    myKaRubberZoom = new kaRubberZoom( ICTMAP );
    myKaTracker = new kaMouseTracker(ICTMAP);
    myKaTracker.activate();
    
    ICTMAP.registerForEvent( KAMAP_INITIALIZED, null, myInitialized );
    ICTMAP.registerForEvent( KAMAP_MAP_INITIALIZED, null, myMapInitialized );
    ICTMAP.registerForEvent( KAMAP_SCALE_CHANGED, null, myScaleChanged );
    ICTMAP.registerForEvent( KAMAP_EXTENTS_CHANGED, null, myExtentChanged );
    ICTMAP.registerForEvent( KAMAP_LAYERS_CHANGED, null, myLayersChanged );
    ICTMAP.registerForEvent( KAMAP_LAYER_STATUS_CHANGED, null, myLayersChanged );
    ICTMAP.registerForEvent( KAMAP_QUERY, null, myQuery );
    ICTMAP.registerForEvent( KAMAP_MAP_CLICKED, null, myMapClicked );
    ICTMAP.registerForEvent( KAMAP_MOUSE_TRACKER, null, myMouseMoved );

    myScalebar = new ScaleBar(1);
    myScalebar.divisions = 3;
    myScalebar.subdivisions = 2;
    myScalebar.minWidth = 100;
	myScalebar.maxWidth = 200;
	if(this.scalebarWidth != null){
		myScalebar.maxWidth = this.scalebarWidth;
		myScalebar.minWidth = this.scalebarWidth - 10;
		getRawObject(this.scalebarID).style.width=this.scalebarWidth+"px";
	}
    
    myScalebar.place('scalebar');
	this.scalebar = myScalebar;

	//toolTip = new kaToolTip( ICTMAP );
	
	ICTMAP.myXmlOverlay = new kaXmlOverlay( ICTMAP, 200);
	//drawPage();
	ICTMAP.initialize( szMap, szExtents, szCPS );
	
	myKaSearch = new kaSearch( ICTMAP );
	
	ICTMAP.myXmlOverlay.setBaseUrl();
	
	//スタイルシート読み込み
	if(ICTMAP.isIE6CSS&&!isFIREFOX){
		var css = document.createElement("link");
		css.setAttribute("rel","stylesheet");
		css.setAttribute("type","text/css");
		css.setAttribute("href",ICTMAP.server+"ictmap.css");
		var head = document.getElementsByTagName("head")[0].appendChild(css);
	}else{
		var defaultStyle = document.createElement('style');
		var styleText = '@import url(\"' + ICTMAP.server + 'ictmap.css\");';
		var styleTextElem = document.createTextNode(styleText);
		defaultStyle.appendChild(styleTextElem);	//ここでエラーが出るときはDOCTYPEを調整
		defaultStyle.type = 'text/css';
		document.getElementsByTagName('head')[0].appendChild(defaultStyle);
	}

	/*
	var tmp = "";
	for(i in defaultStyle){
		//console.log(i);
		tmp += "," + i
	}
	window.clipboardData.setData("text",tmp);
	*/
	
};

/**
 * event handler for KAMAP_INITIALIZED.
 *
 * at this point, ka-Map! knows what map files are available and we have
 * access to them.
 */
function myInitialized() {
    //myMapInitialized( null, ICTMAP.getCurrentMap().name );
	//dispOverLay();
	//updateLinkToView();
}

/**
 * event handler for KAMAP_MAP_INITIALIZED
 *
 * the scales are put into a select ... this will be used for zooming
 */
function myMapInitialized( eventID, mapName ) {
    //get list of maps and populate the maps select box
    var aMaps = ICTMAP.getMaps();

	//update the scales select
    var currentMap = ICTMAP.getCurrentMap();
    var scales = currentMap.getScales();
    var currentScale=ICTMAP.getCurrentScale();
	//oSelect = document.toolbar.scales;
	oSelect = getRawObject("toolbar_scales");
	if(oSelect){
		while( oSelect.options[0] ) oSelect.options[0] = null;
	    j=0;
	    //for(var i in scales)
		for(i=0;i<scales.length;i++)
	    {
	        oSelect.options[j++] = new Option("1:"+scales[i],scales[i],false,false);
	    }
	}

	//chgMode();

    //Activate query button
    switchMode('toolPan');
    
    //Activate service box
    switchService('toolMapinfo');
    
	/* handle request for layer visibility */
	/*
	var layers = getQueryParam('layers');
	if (layers != '') {
		var map = ICTMAP.getCurrentMap();
		//turn off all layers
		var allLayers = map.getAllLayers();
		for (var i=0; i<allLayers.length; i++) {
			allLayers[i].setVisibility(false);
		}
		aLayers = layers.split(',');
		for (var i=0;i<aLayers.length; i++) {
			//ICTMAP.setLayerVisibility (unescape(aLayers[i]), true);
			kaLegend_toggleLayerVisibility2(unescape(aLayers[i]),true);	//sakai
		}
	}
	*/
	
	//set current scale in the interface
	ICTMAP.triggerEvent( KAMAP_SCALE_CHANGED, ICTMAP.getCurrentScale() );

	// dispOverlayPoint sakai
	dispOverLay();
}

function dispOverLay(){
	//$('loadingmsg').style.display = "block";				// sakai ローディングメッセージを表示
	
	// メモリ解放の為50以上シンボルがたまった場合が一旦全削除
	if(ICTMAP.myXmlOverlay.ovrObjects.length > 50){
		ICTMAP.myXmlOverlay.removePoint("",ICTMAP.BASEPOINT_PREFIX);			// 標準ポイントを一旦削除
	};
	dispOverLayKihon(ICTMAP.dspLandmark);
	var extents=ICTMAP.getGeoExtents();
	dispSchoolName(extents);
}

function checkboxserialize2(elem,sep){
	var dst = "";
	if(elem){
		len = elem.length;
		if(len > 1){
			for(i=0;i<len;i++){
				if(elem[i].checked){
					dst += sep +elem[i].value;
				}
			}
			if(dst != ""){
				dst = dst.substr(1);
			}
		}else{
			if(elem.checked){
				dst = elem.value;
			}
		}
	}
	return dst;
}

function dispOverLayKihon(flg){

	// flgがfalseの場合 標準ポイント削除
	if(!flg){
		ICTMAP.myXmlOverlay.removePoint("",ICTMAP.BASEPOINT_PREFIX);
		return;
	};

	// スケールが1/25000以上だったら標準ポイントを表示する。
	// それ以外は削除
	var extents=ICTMAP.getGeoExtents();
	var pars = "";
	if(ICTMAP.getCurrentScale() <= 25000){
		var kpxmlurl = 'kihonpointsjson.phtml?minx='+extents[0]+'&miny='+extents[1]+'&maxx='+extents[2]+'&maxy='+extents[3]+pars;
		ICTMAP.myXmlOverlay.loadXml2(kpxmlurl);
	}else{
		ICTMAP.myXmlOverlay.removePoint("",ICTMAP.BASEPOINT_PREFIX);
	}
}

function setGeomLayer(arrLay,theForm){
	if(arrLay != null){
		if(arguments.length == 1){
			var theForm = document.frminfocategory;
		}
		if(theForm){
			var arrLaylen = arrLay.length;
			if(theForm.elements["hl[]"]){
				for(i=0;i<theForm.elements["hl[]"].length;i++){
					for(j=0;j<arrLaylen;j++){
						if(arrLay[j]+"" == theForm.elements["hl[]"][i].value+""){	//文字列で比較
							theForm.elements["hl[]"][i].checked = true;
							break;
						}
					}
				}
			}
		}
	}
}

/*
* 中心点が含まれる小学校区名を表示する
*/
function dispSchoolName(extents){
	var url = ICTMAP.server+'schoolnamejson.phtml?minx='+extents[0]+'&miny='+extents[1]+'&maxx='+extents[2]+'&maxy='+extents[3];
    var soJsr = new JSONscriptRequest(url+'&callback=dispSchoolNameExe');
    soJsr.buildScriptTag();
    soJsr.addScriptTag();
	
	/*var myAjax = new Ajax.Updater(
		'schoolname', 
		url, 
		{
			method: 'get', 
			parameters: pars,
		}
		);
	*/
}
function dispSchoolNameExe(data){
	//alert(typeof(soJsr));
	if(typeof(soJsr) != "undefined") soJsr.removeScriptTag();
	getRawObject("schoolname").innerHTML = data.center;
}


/**
 * handle the extents changing by updating a link in the interface that links
 * to the current view
 */
function myExtentChanged( eventID, extents ) {
	updateLinkToView();
	if(!ICTMAP.automove){
		dispOverLay();
		//ICTMAP.IctMap.stopOnclickAnime();
		clearInterval(ICTMAP.IctMap.animeFlg);
		ICTMAP.IctMap.arrOnclick = [];
		ICTMAP.IctMap.arrOnclickAnimeIdx = 0;
		ICTMAP.IctMap.arrOnclickIndex = 0;
	
		ICTMAP.IctMap.exetentChangeFunc();
	}
	ICTMAP.automove = false;
	getRawObject("namelist").style.display='none';
}

function myMouseMoved( eventID, position) {
	/* sakai
    var geopos = document.getElementById('geoPosition');
    if(geopos) geopos.innerHTML = 'x: ' + roundIt(position.x,2) + '<BR>y: ' + roundIt(position.y,2);
	*/
}

function myLayersChanged(eventID, map) {
	updateLinkToView();
}

function updateLinkToView()  {
	var port = (window.location.port)? window.location.port : 80;
	var url = window.location.protocol+'/'+'/'+window.location.host +':'+ port +''+window.location.pathname+'?';
	var extents = ICTMAP.getGeoExtents();
	var cx = (extents[2] + extents[0])/2;
	var cy = (extents[3] + extents[1])/2;
	var cpsURL = 'cps='+cx+','+cy+','+ICTMAP.getCurrentScale();
	//var mapURL = 'map=' + ICTMAP.currentMap;
    var theMap = ICTMAP.getCurrentMap();
	var aLayers = theMap.getLayers();
	var layersURL = 'layers=';
	var sep = '';
	for (var i=0;i<aLayers.length;i++) {
		layersURL += sep + aLayers[i].name;
		sep = ',';
	}
	
	var link = getRawObject('linkToView');
	if(link) link.href = url + cpsURL + '&' + layersURL + hl;
	
	var linkContent = getRawObject('linkContent');
	if(linkContent) linkContent.value = myUrlEncode('This is a link:\n-------\n'+ url + mapURL + '&' + cpsURL + '&' + layersURL +'\n-------\n\nRemember to copy the entire link string.');


	//this should stay in an independant function
	/* sakai
	var geoExtent = getRawObject('geoExtent');
	
	if(geoExtent) {
		geoExtent.innerHTML = 'minx: ' + roundIt(extents[0],2) +'<br>' +
							'miny: ' + roundIt(extents[1],2) +'<br>' +
							'maxx: ' + roundIt(extents[2],2) +'<br>' +
							'maxy: ' + roundIt(extents[3],2) +'<br>';
	}
	*/
}

function sendLinkToView(email,body) {
	
	var mySubject = myUrlEncode('Authomatic ka-Map mail');
	var myBody = myUrlEncode(body);
		
	location.replace( 'mailto:' + email + '?subject=' + mySubject + '&body=' + body);
}



/**
 * called when kaMap tells us the scale has changed
 */
function myScaleChanged( eventID, scale ) {

	getRawObject("pointinfo").style.visibility='hidden';	// sakai

	//var oSelect = document.toolbar.scales;
	var oSelect = getRawObject("toolbar_scales");
	if(oSelect){
	    for (var i=0; i<oSelect.options.length; i++)
	    {
	        if (oSelect.options[i].value == scale)
	        {
	            oSelect.options[i].selected = true;
	            if(i==0)zoomout_disable();
	            else zoomout_enable();
	            if (i==oSelect.options.length - 1) zoomin_disable();
	            else zoomin_enable();
	        }
	    }
    }
    myScalebar.update(scale);
   
    /*
    if (scale >= 1000000) {
        scale = scale / 1000000;
        scale = scale + " Million";
    }
    var outString = 'current scale 1:'+ scale;
    getRawObject('scale').innerHTML = outString;
    */
}




/**
 * called when the user changes scales.  This will cause the map to zoom to
 * the new scale and trigger a bunch of events, including:
 * KAMAP_SCALE_CHANGED
 * KAMAP_EXTENTS_CHANGED
 */
function mySetScale( scale ) {
    ICTMAP.zoomToScale( scale );
}

/**
 * called when the map selection changes due to the user selecting a new map.
 * By calling ICTMAP.selectMap, this triggers the KAMAP_MAP_INITIALIZED event
 * after the new map is initialized which, in turn, causes myMapInitialized
 * to be called
 */
function mySetMap( name ) {
    ICTMAP.selectMap( name );
}


function myQuery( eventID, queryType, coords ) {
    var szLayers = '';
    var layers = ICTMAP.getCurrentMap().getQueryableLayers();
    if(layers.length==0) {
     alert("No queryable layers at this scale and extent");
     return;
    }
    for (var i=0;i<layers.length;i++) {
        szLayers = szLayers + "," + layers[i].name;
    };


    var extent = ICTMAP.getGeoExtents();
    var scale = ICTMAP.getCurrentScale();
    var cMap = ICTMAP.getCurrentMap().name;
	var params='map='+cMap+'&q_type='+queryType+'&scale='+scale+'&groups='+szLayers+'&coords='+coords+'&extent='+extent[0]+'|'+extent[1]+'|'+extent[2]+'|'+extent[3];
		
	getRawObject('queryOut').innerHTML = '<h3>Processing query. <br> please wait...</h3><hr>';
		
	call('map_query_float.phtml?'+params,this, myQueryOutput);
	
//    alert( "Map: " + cMap + " | Scale: " + scale + " | Extent: " + extent + " | QUERY: " + queryType + " " + coords + " on layers " + szLayers );
}

function myQueryOutput (szText){
	getRawObject('queryOut').innerHTML=szText;
}


function myMapClicked( eventID, coords ) {
    //alert( 'myMapClicked('+coords+')');
	//ICTMAP.zoomTo(coords[0],coords[1]);
}

function myZoomIn() {
    ICTMAP.zoomIn();
}

function myZoomOut() {
    ICTMAP.zoomOut();
}

function myPrint(output_type) {
    var szLayers = '';
    var szOpacitys = '';
    
    var layers = ICTMAP.getCurrentMap().getLayers();
    for (var i=0;i<layers.length;i++) {
        szLayers = szLayers + "," + layers[i].name;
        szOpacitys = szOpacitys + "," + layers[i].opacity;
    };

    var extent = ICTMAP.getGeoExtents();
    var scale = ICTMAP.getCurrentScale();
    var cMap = ICTMAP.getCurrentMap().name;
    
    var img_width = '600';// pixel dimension. max_img_width set inside print_map.phtml
    
    //output_type
	var params='output_type='+output_type+'&map='+cMap+"&opacitys="+szOpacitys+'&scale='+scale+'&img_width='+img_width+'&groups='+szLayers+'&extent='+extent[0]+'|'+extent[1]+'|'+extent[2]+'|'+extent[3];
 	
 	//create and download the output file
 	location.href='tools/print/print_map.phtml?'+params;
 	
 	//or open it in a new window
    //WOOpenWin( 'Print', '../tools/print/print_map.phtml?'+params, 'resizable=yes,scrollbars=yes,width=600,height=400' );

}



/**
 * drawPage - calculate sizes of the various divs to make the app full screen.
 */
function drawPage() {
    ICTMAP.resize();
}

function showContent(url) {
	var content = getRawObject('content');
	var viewport = getRawObject('ICTMAP.IctMap.CONST_VIEWPORT_ID');
	content.style.top = parseInt(viewport.style.top) + 10 + "px";
	content.style.display = "block";
	call(url,this, setContent);
}

function setContent(szContent){
	var contentText = getRawObject('contentText');
	contentText.innerHTML = szContent;
}
function hideContent() {
	var content = getRawObject('content');
	var viewport = getRawObject('ICTMAP.IctMap.CONST_VIEWPORT_ID');
	content.style.display = "none";
	//content.style.top = parseInt(viewport.style.top) + parseInt(viewport.style.height) + "px";
}

/**
 * getFullExtent
 * ...
 */
function getFullExtent() {
    var exStr = ICTMAP.getCurrentMap().defaultExtents.toString();
    var ex = ICTMAP.getCurrentMap().defaultExtents;
    ICTMAP.zoomToExtents(ex[0],ex[1],ex[2],ex[3]);
}

/**
 * switchMode
 * ...
 */
function switchMode(id) {
    if (id=='toolQuery') {
        myKaQuery.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_2.png)';
        getRawObject('toolPan').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_pan_1.png)';
        getRawObject('toolZoomRubber').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
    } else if (id=='toolPan') {
        myKaNavigator.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';//sakai
        getRawObject('toolPan').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_pan_2.png)';
        getRawObject('toolZoomRubber').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
    } else if (id=='toolZoomRubber') {
        myKaRubberZoom.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';
        getRawObject('toolPan').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_pan_1.png)';
        getRawObject('toolZoomRubber').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_rubberzoom_2.png)';
    } else {
        myKaNavigator.activate();
    }
}


/**
 * switchMode
 * ...
 * sakai modify
 */
function switchService(id) {
	var service = getRawObject('service');
    if (id=='toolQuery') {
        myKaQuery.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_2.png)';
        //getRawObject('toolLegend').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_legend_1.png)';
        //getRawObject('toolMapinfo').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_mapinfo_1.png)';
        //getRawObject('toolPrint').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_print_1.png)';
        //getRawObject('toolZoomRubber').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
		//getRawObject('toolLink').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_link_1.png)';
		//getRawObject('toolSearch').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_search_1.png)';
 		//getRawObject('mapInfo').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('mapLegend').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('print').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('identifier').style.top = '0';
		//getRawObject('curtain').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('link').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('search').style.top =  parseInt(getObjectHeight(service)) + "px";
    } else if (id=='toolLegend') {
        myKaNavigator.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';
        //getRawObject('toolMapinfo').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_mapinfo_1.png)';
        //getRawObject('toolLegend').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_legend_2.png)';
        //getRawObject('toolPrint').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_print_1.png)';
        //getRawObject('toolPan').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_pan_2.png)';
        //getRawObject('toolZoomRubber').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
		//getRawObject('toolLink').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_link_1.png)';
		//getRawObject('toolSearch').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_search_1.png)';
		//getRawObject('mapLegend').style.top = '0';
		//getRawObject('mapInfo').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('print').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('identifier').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('curtain').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('link').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('search').style.top =  parseInt(getObjectHeight(service)) + "px";
    } else if (id=='toolPrint') {
        myKaNavigator.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';
        //getRawObject('toolLegend').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_legend_1.png)';
        //getRawObject('toolMapinfo').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_mapinfo_1.png)';
        //getRawObject('toolPrint').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_print_2.png)'; 
        //getRawObject('toolPan').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_pan_2.png)';
        //getRawObject('toolZoomRubber').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
		//getRawObject('toolLink').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_link_1.png)';
		//getRawObject('toolSearch').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_search_1.png)';
        //getRawObject('mapLegend').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('mapInfo').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('print').style.top = '0';
		//getRawObject('identifier').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('curtain').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('link').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('search').style.top =  parseInt(getObjectHeight(service)) + "px";
    } else if (id=='toolLink') {
        myKaNavigator.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';
        //getRawObject('toolLegend').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_legend_1.png)';
        //getRawObject('toolMapinfo').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_mapinfo_1.png)';
        //getRawObject('toolPrint').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_print_1.png)'; 
        //getRawObject('toolPan').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_pan_2.png)';
        //getRawObject('toolZoomRubber').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
		//getRawObject('toolLink').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_link_2.png)';
		//getRawObject('toolSearch').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_search_1.png)';
		//getRawObject('mapInfo').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('mapLegend').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('print').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('identifier').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('curtain').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('link').style.top =   "0px";
		//getRawObject('search').style.top =  parseInt(getObjectHeight(service)) + "px";
	} else if (id=='toolSearch') {
		myKaNavigator.activate();
		//getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';
        //getRawObject('toolLegend').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_legend_1.png)';
        //getRawObject('toolMapinfo').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_mapinfo_1.png)';
        //getRawObject('toolPrint').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_print_1.png)'; 
        //getRawObject('toolPan').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_pan_2.png)';
        //getRawObject('toolZoomRubber').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
		//getRawObject('toolLink').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_link_1.png)';
		//getRawObject('toolSearch').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_search_2.png)';
		//getRawObject('mapLegend').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('mapInfo').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('print').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('identifier').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('curtain').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('link').style.top =   parseInt(getObjectHeight(service)) + "px";
		//getRawObject('search').style.top =  "0px";
    } else if (id=='toolMapinfo') {
        myKaNavigator.activate();
        //getRawObject('toolQuery').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_query_1.png)';
        //getRawObject('toolLegend').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_legend_1.png)';
        //getRawObject('toolMapinfo').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_mapinfo_2.png)';
        //getRawObject('toolPrint').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_print_1.png)'; 
        //getRawObject('toolPan').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_pan_2.png)';
        //getRawObject('toolZoomRubber').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_rubberzoom_1.png)';
		//getRawObject('toolLink').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_link_1.png)';
		//getRawObject('toolSearch').style.backgroundImage = 'url(common/images2/icon_set_explorer/tool_search_1.png)';
		//getRawObject('mapLegend').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('mapInfo').style.top = "0px";
		//getRawObject('print').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('identifier').style.top = parseInt(getObjectHeight(service)) + "px";
		//getRawObject('curtain').style.top =  parseInt(getObjectHeight(service)) + "px";
		//getRawObject('link').style.top =   parseInt(getObjectHeight(service)) + "px";
		//getRawObject('search').style.top =  parseInt(getObjectHeight(service)) + "px";
    } else {
        myKaNavigator.activate();
    }
}


/**
 * called scale level is at maximum value.  This will cause the zoom out
 * buttons been disabled
 */
function zoomout_disable(){

	getRawObject('toolZoomOut').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_zoomout_3.png)';
	//getRawObject('toolZoomFull').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_zoomfull_3.png)';
}

/**
 * called scale level is not at minimum value.  This will cause the zoom out
 * buttons been enabled
 */
function zoomout_enable(){

	getRawObject('toolZoomOut').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_zoomout_1.png)';
	//getRawObject('toolZoomFull').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_zoomfull_1.png)';
}

/**
 * called scale level is at minimum value.  This will cause the zoom in
 * buttons been disabled
 */
function zoomin_disable(){

	getRawObject('toolZoomIn').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_zoomin_3.png)';
	getRawObject('toolZoomRubber').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_rubberzoom_3.png)';

}
/**
 * called scale level is not at minimum value.  This will cause the zoom in
 * buttons been enabled
 */
function zoomin_enable(){

	getRawObject('toolZoomIn').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_zoomin_1.png)';
	getRawObject('toolZoomRubber').style.backgroundImage = 'url('+ICTMAP_URL+'common/images2/icon_set_explorer/tool_rubberzoom_1.png)';

}


/*
 *  applyPNGFilter(o)
 *
 *  Applies the PNG Filter Hack for IE browsers when showing 24bit PNG's
 *
 *  var o = object (this png element in the page)
 *
 * The filter is applied using a nifty feature of IE that allows javascript to
 * be executed as part of a CSS style rule - this ensures that the hack only
 * gets applied on IE browsers :)
 */
function applyPNGFilter(o) {
    var t="common/images2/a_pixel.gif";
    if( o.src != t ) {
        var s=o.src;
        o.src = t;
        o.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')";
    }
}

//functions to open popup

function WOFocusWin( nn ) {
	eval( "if( this."+name+") this."+name+".moveTo(50,50); this."+name+".focus();" );
}

function WOOpenWin( name, url, ctrl ) {
    eval( "this."+name+"=window.open('"+url+"','"+name+"','"+ctrl+"');" );

    /*IE needs a delay to move forward the popup*/
    // window.setTimeout( "WOFocusWin(nome);", 300 );
}

function WinOpener() {
    this.openWin=WOOpenWin;
	this.focusWin=WOFocusWin;
}


//URL SYNTAX ENCODING
function myUrlEncode(string) {
  encodedHtml = escape(string);
  encodedHtml = encodedHtml.replace("/","%2F");
  encodedHtml = encodedHtml.replace(/\?/g,"%3F");
  encodedHtml = encodedHtml.replace(/=/g,"%3D");
  encodedHtml = encodedHtml.replace(/&/g,"%26");
  encodedHtml = encodedHtml.replace(/@/g,"%40");
  return encodedHtml;
};
  
function myUrlDecode(sz){
	return unescape(sz).replace(/\+/g," ");
};

//MATH FUNCTIONs
function roundIt(number,decimals){
	var base10 = 10;
	for(var i=0;i<decimals-1;i++)
		base10 = base10 *10;
	 
	return Math.round(number * base10)/base10;
}


// 地図描画に必要なベースのHTMLを書き出す
// amakusa
function getBaseHtml(){
	var baseHtml = "<div id=\"ictmap\"><div id=\"scaleReference\" style=\"display:block;\"><div id=\"scaleBackground\" class=\"transparentBackground\"></div><div id=\"scalebar\"></div></div><div id=\"kihonlabel\"></div><div id=\"pointinfo\"><div class=\"arrow\"></div><div id=\"infobox\"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"hukidashi\"><tr><td width=\"5\" class=\"lt\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td><td class=\"ct\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td><td class=\"rt\" width=\"5\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td></tr><tr><td width=\"5\" class=\"lm\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td><td class=\"cm\"><div id=\"infoboxmemo\"></div></td><td width=\"5\" class=\"rm\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td></tr><tr><td width=\"5\" class=\"lb\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td><td class=\"cb\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td><td width=\"5\" class=\"rb\"><img src=\""+ICTMAP_URL+"common/images/spacer.gif\"></td></tr></table></div></div><div id=\"schoolname\" style=\"display:none\"></div><div id=\"toolbarContainer\" style=\"display:none;\"><img id=\"toolPan\" onclick=\"switchMode(this.id)\" title=\"ドラック＆ドロップで移動\" alt=\"ドラック＆ドロップで移動\" src=\""+ICTMAP_URL+"common/images2/a_pixel.gif\"><img id=\"toolZoomRubber\" onclick=\"switchMode(this.id)\" title=\"範囲指定拡大\" alt=\"範囲指定拡大\" src=\""+ICTMAP_URL+"common/images2/a_pixel.gif\" ><img id=\"toolZoomIn\" onclick=\"myZoomIn()\" title=\"拡大\" alt=\"拡大\" src=\""+ICTMAP_URL+"common/images2/a_pixel.gif\" onMouseDown=\"this.id='toolZoomInDown';\"  onMouseUp=\"this.id='toolZoomIn';\"><img id=\"toolZoomOut\" onclick=\"myZoomOut()\" title=\"縮小\" alt=\"縮小\" src=\""+ICTMAP_URL+"common/images2/a_pixel.gif\" onMouseDown=\"this.id='toolZoomOutDown';\"  onMouseUp=\"this.id='toolZoomOut';\"><select id=\"toolbar_scales\" name=\"scales\" onchange=\"mySetScale(this.options[this.selectedIndex].value)\"></select></div><div id=\"loadingmsg\" style=\"display:none\"><img src=\""+ICTMAP_URL+"common/images/loading.gif\" alt=\"読み込み中\"><br>読み込み中</div><div id=\"namelist\"></div><div id=\"ictsubmap\" style=\"display:none\"></div><div id=\"ictmapCredit\"></div><div id=\"ictmapCenter\"><img src=\""+ ICTMAP_URL + "common/images/icons/point1.gif\" /></div></div>";
	return baseHtml;
}


/************************************************************************************/
/*
    IctMap 機能追加クラス
    2010.02.19 M.KAKIMOTO
*/
/************************************************************************************/



/****************************************************************/
/*
    (method)IctMap.AddPolyline
    マップ上に多角線を引きます。
    
    id          : ポイントID (多角線の開始位置のポイント)
    coordinates : "経度 緯度,経度 緯度" の形式の文字列
    options     : オプション
                  {
                     color   : "線の色",
                     stroke  : "ラインの太さ(pixel)",
                     opacity : "透明度(1.0で不透明、0.0で完全透明)"
                  }
    
    (戻り値)
    開始点のkaXmlPointクラス
*/
/****************************************************************/
IctMap.prototype.AddPolyline = function(id, coordinates, options)
{
    return this.__AddMultiPointObject(id, coordinates, options, kaXmlLinestring);
};



/****************************************************************/
/*
    (method)IctMap.AddPolygon
    マップ上に多角形を作成します。
    
    id          : ポイントID (多角線の開始位置のポイント)
    coordinates : "経度 緯度,経度 緯度" の形式の文字列
    options     : オプション
                  {
                     color   : "線の色",
                     stroke  : "ラインの太さ(pixel)",
                     opacity : "透明度(1.0で不透明、0.0で完全透明)"
                  }
    
    (戻り値)
    開始点のkaXmlPointクラス
*/
/****************************************************************/
IctMap.prototype.AddPolygon = function(id, coordinates, options)
{
    return this.__AddMultiPointObject(id, coordinates, options, kaXmlPolygon);
};


/****************************************************************/
/*
    (method)IctMap.__AddMultiPointObject
    PolylineまたはPolygon生成の共通処理です。
    
    id          : ポイントID (多角線の開始位置のポイント)
    coordinates : "経度 緯度,経度 緯度" の形式の文字列
    options     : オプション
                  {
                     color   : "線の色",
                     stroke  : "ラインの太さ(pixel)",
                     opacity : "透明度(1.0で不透明、0.0で完全透明)"
                  }
    _class      : 生成するクラス(kaXmlLinestringまたはkaXmlPolygonを想定)
    
    (戻り値)
    開始点のkaXmlPointクラス
*/
/****************************************************************/
IctMap.prototype.__AddMultiPointObject = function(id, coordinates, options, _class)
{
    var op = {color:"", stroke:"", opacity:""};
    if(options)
    {
        for(var o in op)
        {
            op[o] = (options[o]) ? options[o] : "";
        }
    }
    op.color   = (op.color.length   == 0) ? "black" : op.color;
    op.stroke  = (op.stroke.length  == 0) ? "1"     : op.stroke;
    op.opacity = (op.opacity.length == 0) ? "1"     : op.opacity;
    
    var coords = coordinates.split(",");
    var pos = coords[0].split(/\s/);
    var x = parseFloat(pos[0]);
    var y = parseFloat(pos[1]);
    
    var point = ICTMAP.myXmlOverlay.addNewPoint(ICTMAP.USERPOINT_PREFIX+id, x, y);
    var polyline = new _class(point);
    polyline.readCoordinates(point, coordinates);
    for(var o in op)
    {
        polyline[o] = op[o];
    }
    point.addGraphic(polyline);
    
    return point;
}


/****************************************************************/
/*
    (method)IctMap.RemovePolyline
    マップ上の多角線を削除します。
    
    id : ポイントID (多角線の開始位置のポイント)
    
    (戻り値)
    void
*/
/****************************************************************/
IctMap.prototype.RemovePolyline = function(id)
{
    var reg;
    if(id != null && id != ""){
        var pointid = ICTMAP.USERPOINT_PREFIX+id;
        reg = new RegExp("^"+pointid+"$");
    }else{
        reg = new RegExp("^" + ICTMAP.USERPOINT_PREFIX);
    }
    for(var i=0; i<ICTMAP.myXmlOverlay.ovrObjects.length; i++)
    {
        if(ICTMAP.myXmlOverlay.ovrObjects[i] == null) continue;
        if(reg.test(ICTMAP.myXmlOverlay.ovrObjects[i].pid))
        {
            ICTMAP.myXmlOverlay.ovrObjects[i].clear();
        }
    }
    this.RemovePoint(id);
};


/****************************************************************/
/*
    (method)IctMap.RemovePolyline
    マップ上の多角形を削除します。
    
    id : ポイントID (多角線の開始位置のポイント)
    
    (戻り値)
    void
*/
/****************************************************************/
IctMap.prototype.RemovePolygon = IctMap.prototype.RemovePolyline;



/***********************************************************************************/
/*
    (namespace)IctMap.Tools
    IctMap上に、線やポリゴンを書き込む為のツールを提供する名前空間です。
    
    (使用例)
    var ictMap = new IctMap("map");
    var polylineTool = new ictMap.Tools.Polyline();
*/
/***********************************************************************************/
IctMap.prototype.Tools = {};




/***********************************************************************************/
/*
    (static method)IctMap.Tools.ToGeometory
    マウスイベントから緯度経度を取得します。
    
    e : FireFoxのイベント
    
*/
/***********************************************************************************/
IctMap.prototype.Tools.ToGeometory = function(e)
{
    //マウスの位置情報を緯度・経度に変換
    e = (e)?e:((event)?event:null);
    
    var x = e.pageX || (e.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
                (document.documentElement.scrollTop || document.body.scrollTop));
    
    var apixes = ICTMAP.currentTool.adjustPixPosition(x,y);
    var geo = ICTMAP.pixToGeo(apixes[0],apixes[1]);
    
    return {x:geo[0], y:geo[1]};
};

/***********************************************************************************/
/*
    (static method)IctMap.Tools.ToCanvasOffset
    マウスイベントからcanvas上の座標を取得します。
    
    kaXmlObject : canvasで描画しているkaXmlOverlayオブジェクト
    geom        : 緯度・経度{x:x, y:y}
    
*/
/***********************************************************************************/
IctMap.prototype.Tools.ToCanvasOffset = function(kaXmlObject, geom)
{
	if(kaXmlObject == null) return null;
    var scf = ICTMAP.myXmlOverlay.kaMap.getCurrentScale() / kaXmlObject.maxScale;
    var p = 
    {
        x:Math.round((geom.x-kaXmlObject.cxmin)/kaXmlObject.mcs/scf),
        y:Math.round((kaXmlObject.cymax-geom.y)/kaXmlObject.mcs/scf)
    };
    return p;
};


/***********************************************************************************/
/*
    (class)IctMap.Tools.ExclusiveEvents
    マウスのイベント処理を排他的に処理する為のクラスです。
*/
/***********************************************************************************/
IctMap.prototype.Tools.ExclusiveEvents = function(){
    this.Initialize.apply(this, arguments);
};

IctMap.prototype.Tools.ExclusiveEvents.prototype = 
{
    /************************************************************/
    /*
        イベントをハンドリングするHTML要素です。
    */
    /************************************************************/
    HandlerElement : [],
    
    
    
    /************************************************************/
    /*
        本来のイベントハンドラを一時退避しておきます。
    */
    /************************************************************/
    EscapeHandlers : [],
    
    
    
    /************************************************************/
    /*
        コンストラクタ
    */
    /************************************************************/
    Initialize : function()
    {
        this.HandlerElement = ICTMAP.theInsideLayer;
        this.EscapeHandlers = {}
    },
    
    
    /************************************************************/
    /*
        イベントが排他的にロックされているかを確認します。
        type : イベントの種類("click", "mousedown", "mousemove"など)
        
        (戻り値)
        true : ロック中、false:ロックされていない
    */
    /************************************************************/
    IsEventLocked : function(type)
    {
        return (typeof this.EscapeHandlers["on" + type] != "undefined");
    },


    /************************************************************/
    /*
        他のイベントハンドラをロックして、登録したイベントハンドラのみが
        実行されるようにします。
        
        type    : イベントの種類("click", "mousedown", "mousemove"など)
        handler : イベントハンドラ関数
    */
    /************************************************************/
    LockEventHandler : function(type, handler)
    {
        if(this.IsEventLocked(type))
        {
            throw "このイベントは排他的にロックされています。";
        }
        
        this.EscapeHandlers["on" + type] = this.HandlerElement["on" + type];
        this.HandlerElement["on" + type] = handler;
    },
    
    
    /************************************************************/
    /*
        排他的にロックされているイベントを解放し、ロック前の状態に
        戻します。
        type : イベントの種類("click", "mousedown", "mousemove"など)
    */
    /************************************************************/
    ReleseEventHandler : function(type)
    {
        if(this.IsEventLocked(type))
        {
            this.HandlerElement["on" + type] = this.EscapeHandlers["on" + type];
            delete this.EscapeHandlers["on" + type];
        }
    }
}





/***********************************************************************************/
/*
    (class)IctMap.Tools.Polyline
    IctMap上に、多角線を入力する為のUIツールです。
*/
/***********************************************************************************/
IctMap.prototype.Tools.Polyline = function()
{
    this.Initialize.apply(this, arguments);
}

IctMap.prototype.Tools.Polyline.prototype = 
{
    /************************************************************/
    /*
        (property) TOOL_PREFIX
        id要素のプレフィックスです。
    */
    /************************************************************/
    TOOL_PREFIX : "",
    
    
    
    /************************************************************/
    /*
        (property) TOOL_LINE_PREFIX
        id要素のプレフィックス(線描画時)です。
    */
    /************************************************************/
    TOOL_LINE_PREFIX : "",
    
    
    /************************************************************/
    /*
        (property) PointCollection
        多角線の各ポイントを配列で管理します。
    */
    /************************************************************/
    PointCollection : [],
    
    
    
    /************************************************************/
    /*
        (property) PixelCollection
        多角線の各ポイントのマップ内での座標をピクセル単位の
        配列で管理します。
    */
    /************************************************************/
    PixelCollection : [],
    
    
    
    /************************************************************/
    /*
        (property) ExclusiveEvents
        イベントを排他的に処理する為のIctMap.Tools.ExclusiveEvents
        クラスのインスタンスです。
    */
    /************************************************************/
    ExclusiveEvents : null,
    
    
    
    /************************************************************/
    /*
        (property) IsClosed
        多角線の編集が確定したかどうか
    */
    /************************************************************/
    IsClosed : false,
    
    
    /************************************************************/
    /*
        (property) IsClickLocked
        OnClickイベントが別のハンドラからロックされているかを
        取得・設定します。
        これがtrueの時、ラインのポイントをセットする動作が
        一時的に無効になります。
    */
    /************************************************************/
    IsClickLocked : false,
    
    
    
    /************************************************************/
    /*
        (property) IsPopupMenuOpened
        ポイント追加・削除のポップアップメニューが表示されているか
        どうかを判定します。
    */
    /************************************************************/
    IsPopupMenuOpened : false,
    
    
    
    /************************************************************/
    /*
        (property) DraggingPointIndex
        ドラッグ中のラインのポイント配列番号です。
        ドラッグ中のポイントが無い場合は、-1がセットされます。
    */
    /************************************************************/
    DraggingPointIndex : -1,
    
    
    
    /************************************************************/
    /*
        (property) BodyOnMouseUp
        document.bodyのonmouseupイベントのエスケープ
    */
    /************************************************************/
    BodyOnMouseUp : null,
    
    
    
    /************************************************************/
    /*
        (property) PointStyle
        ポイントを表すアイコンのスタイルシートを定義します。
        ※Google ChromeやSafariなどのWebKit系ブラウザでは、
          画像をドラッグするとブラウザの機能でjavascriptのイベントを
          横取りしてしまうのでdivタグを使っています。
          
    */
    /************************************************************/
    PointStyle : {},
    
    
    
    /************************************************************/
    /*
        (property) LineStyle
        ラインのスタイルを定義します。
        (*)IctMap.AddPolyline メソッドで利用できるスタイル
        {
           color   : "線の色",
           stroke  : "ラインの太さ(pixel)",
           opacity : "透明度(1で不透明、0で完全透明)"
        }
    */
    /************************************************************/
    LineStyle : {},
    
    
    
    /************************************************************/
    /*
        IsActive
        ツールの状態が有効(Active)か無効(Deactive)かを確認します。
    */
    /************************************************************/
    IsActive : null,
    
    
    
    /************************************************************/
    /*
        IsVisible
        IsActiveがfalseの時、ラインを表示しているかどうかを確認します。
    */
    /************************************************************/
    IsVisible : null,
    
    
    
    /************************************************************/
    /*
        IsLineOnly
        IsActiveがfalseの時、ラインのみ表示するかどうかを確認します。
    */
    /************************************************************/
    IsLineOnly : null,
    
    
    /************************************************************/
    /*
        (property) IsMouseOverPosition
        マウスがポリゴン上に乗った事を示します。
    */
    /************************************************************/
    IsMouseOverPosition : false,
    
    
    /************************************************************/
    /*
        RefleshClearMode
        trueの場合、再描画以前に描画されたオブジェクトも
        まとめて削除します。
        falseの場合、Removeしません。
        既定値はtrueです。
    */
    /************************************************************/
    RefleshClearMode : true,
    
    
    /************************************************************/
    /*
        Canvas
        Polylineのベースとなるcanvasです。
    */
    /************************************************************/
    Canvas : null,
    
    
    /************************************************************/
    /*
        StartPoint
        描画中のオブジェクトの始点の参照です。
    */
    /************************************************************/
    StartPoint : null,
    
    
    /************************************************************/
    /*
        Name
        オブジェクトの名称です。
    */
    /************************************************************/
    Name : "",
    
    
    /************************************************************/
    /*
        Box
        バウンディングボックス。
        描画されたオブジェクトを内包可能な最小の四角形の
        4点の座標を保存します。
    */
    /************************************************************/
    Box : {minX:0, minY:0, maxX:0, maxY:0},
    
    
    
    /************************************************************/
    /*
        コンストラクタ
    */
    /************************************************************/
    Initialize : function()
    {
        //初期設定
        this.TOOL_PREFIX        = "_polyline_";
        this.TOOL_LINE_PREFIX   = "line_polyline";
        this.PointCollection    = [];
        this.ExclusiveEvents    = new ICTMAP.IctMap.Tools.ExclusiveEvents();
        this.IsClickLocked      = false;
        this.DraggingPointIndex = -1;
        this.IsActive           = true;
        this.IsLineOnly         = false;
        
        //ポイントスタイルのデフォルト値
        this.PointStyle = 
        {
            backgroundColor : "#fff",
            border          : "1px solid #000",
            width           : "10px",
            height          : "10px",
            position        : "absolute",
            cursor          : "pointer",
            fontSize        : "1px"
        };
        
        
        //ラインスタイルのデフォルト値
        this.LineStyle = 
        {
            color   : "blue",
            stroke  : "4",
            opacity : "0.5"
        }
        
        
        var self = this;
        //OnMapClickの呼び出し関数を定義
        this._OnMapClickTrigger = function()
        {
            self.OnMapClick.apply(self, arguments);
            self._OnMapClick.apply(self, arguments);
        }
        
        
        //Onclickでポイントが追加されるようにイベント追加
        this._OnMapClick = function(eventid, point)
        {
            if(!self.IsClickLocked && !self.IsClosed)
            {
                self.AddPoint.apply(self, [point[0], point[1]]);
            }
            self.IsClickLocked = false;
        };
        
        ICTMAP.registerForEvent(KAMAP_MAP_CLICKED, this, this._OnMapClickTrigger);
        
        
        //Canvasに描画されたオブジェクトのマウスイベント
        ICTMAP.registerForEvent(KAMAP_MOUSE_TRACKER, this, this._OnMouseEventsTrigger);
        
        //マップの解像度変更で再描画するようする
        ICTMAP.registerForEvent(KAMAP_SCALE_CHANGED, this, this.Reflesh);
    },
    
    
    
    /************************************************************/
    /*
        (method) AddPoint
        多角線の間接点を追加します。
        
        x : 経度
        y : 緯度
    */
    /************************************************************/
    AddPoint : function(x, y)
    {
        x = parseFloat(x);
        y = parseFloat(y);
        
        var p = {x:x, y:y};
        this.PointCollection.push(p);
        
        this._createBox(p);
        this.Reflesh();
    },
    
    
    
    /************************************************************/
    /*
        (method) RemovePoint
        多角線の間接点を削除します。
        
        index : 削除したい点の配列番号
    */
    /************************************************************/
    RemovePoint : function(index)
    {
        var p = this.PointCollection[index];
        p = {x:p.x, y:p.y};
        
        this.PointCollection.splice(index, 1);
        
        if(p.x == this.Box.maxX || p.y == this.Box.maxY || p.x == this.Box.minX || p.y == this.Box.minY)
        {
            this.Box.maxX = 0;
            this.Box.maxY = 0;
            this.Box.minX = 0;
            this.Box.minY = 0;
            
            for(var i=0; i<this.PointCollection.length; i++)
            {
                p = this.PointCollection[i];
                this._createBox(p);
            }
        }
        
        this.Reflesh();
    },
    
    
    
    /************************************************************/
    /*
        (method) InsertAfterPoint
        多角線の間接点と間接点の間にポイントを追加します。
        
        index : 追加したい場所の配列番号
    */
    /************************************************************/
    InsertAfterPoint : function(index)
    {
        var p1 = this.PointCollection[index];
        var p2 = this.PointCollection[index+1]
        
        var x = p1.x + parseFloat((p2.x - p1.x) / 2);
        var y = p1.y + parseFloat((p2.y - p1.y) / 2);
        
        this.PointCollection.splice(index+1, 0, {x:x, y:y});
        this.Reflesh();
    },
    
    
    
    /************************************************************/
    /*
        (method) ClearPoint
        全ての点を削除し、ラインをクリアします。
    */
    /************************************************************/
    ClearPoint : function()
    {
        this.PointCollection= [];
        this.IsClosed = false;
        this.Reflesh();
    },
    
    
    
    /************************************************************/
    /*
        (method) ReadCoordinates
        文字列で渡されたポイント情報でラインを表示します。
        
        coordinates : "経度 緯度,経度 緯度"の形式の文字列
    */
    /************************************************************/
    ReadCoordinates : function(coordinates)
    {
        this.Box = {maxX:0, maxY:0, minX:0,maxY:0};
        this.PointCollection = [];
        var coords = coordinates.split(",");
        for(var i=0; i<coords.length; i++)
        {
            var p = coords[i].split(/\s/g);
            p = {x:parseFloat(p[0]), y:parseFloat(p[1])};
            this.PointCollection.push(p);
            this._createBox(p);
        }
        this.IsClosed = true;
        this.Reflesh();
        this.IsClosed = true;
        this.IsClickLocked = false;
    },
    
    
    
    /************************************************************/
    /*
        (method) RefleshClear
        マップ上に配置したオブジェクトをクリアします。
    */
    /************************************************************/
    RefleshClear : function()
    {
        if(this.RefleshClearMode)
        {
            ICTMAP.IctMap.RemovePoint();
            ICTMAP.IctMap.RemovePolyline();
        }
        else
        {
            ICTMAP.myXmlOverlay.removePoint("", ICTMAP.USERPOINT_PREFIX+this.TOOL_PREFIX);
            ICTMAP.IctMap.RemovePolyline(this.TOOL_LINE_PREFIX);
        }
    },
    
    
    
    /************************************************************/
    /*
        (method) Reflesh
        ラインとポイントを再描画します。
    */
    /************************************************************/
    Reflesh : function()
    {
        //一旦削除
        this.RefleshClear();
        
        //ライン表示開始前のイベント
        if(typeof this.OnBeforeDrawLine == "function")
        {
            this.OnBeforeDrawLine();
        }
        
        //表示処理を行わない
        if(!this.IsActive && !this.IsVisible)
        {
            if(typeof this.OnAfterDrawLine == "function")
            {
                this.OnAfterDrawLine();
            }
            return;
        }
        
        //ラインの描画
        var coordinates = [];
        for(var i=0; i<this.PointCollection.length; i++)
        {
            coordinates.push(this.PointCollection[i].x+" " + this.PointCollection[i].y);
        }
        
        if(coordinates.length > 0)
        {
            var o = this.GetDrawObject();
            var m = this.GetDrawMethod();
            var p = m.apply
            (
                o, 
                [this.TOOL_LINE_PREFIX, coordinates.join(","), this.LineStyle]
            );
            var canvases = p.div.getElementsByTagName("canvas");
            if(canvases.length > 0)
            {
                this.Canvas = canvases[0];
            }
            this.StartPoint = p;
            var drawObj = p.graphics[0];
            var scf = ICTMAP.myXmlOverlay.kaMap.getCurrentScale() / drawObj.maxScale;
            this.PixelCollection = [];
            for(var i=0; i<drawObj.xn.length; i++)
            {
                this.PixelCollection.push
                (
                    {x:Math.round(drawObj.xn[i]/scf), y:Math.round(drawObj.yn[i]/scf)}
                );
            }
        }
        
        //ツールが無効で、ラインのみ表示するモードの時は、ポイントを描画しない
        if(!this.IsActive && this.IsVisible && this.IsLineOnly)
        {
            if(typeof this.OnAfterDrawLine == "function")
            {
                this.OnAfterDrawLine();
            }
            this.AfterReflesh();
            return;
        }
        
        
        //ポイントの描画
        for(var i=0; i<this.PointCollection.length; i++)
        {
            var point = this.CreatePointElement(i);
        }
        
        if(typeof this.OnAfterDrawLine == "function")
        {
            this.OnAfterDrawLine();
        }
        
        this.AfterReflesh();
    },
    
    /************************************************************/
    /*
        (protected method) _AfterReflesh
        描画後の処理です。
    */
    /************************************************************/
    AfterReflesh : function()
    {
        if(this.Canvas == null) return;
        var self = this;
        
        this.Canvas.onclick = function(e)
        {
             var p = ICTMAP.IctMap.Tools.ToGeometory(e);
             var pp = ICTMAP.IctMap.Tools.ToCanvasOffset(self.StartPoint.graphics[0], p);
             
             if(self.IsMouseOver(pp))
             {
                 self.OnClick.apply(self, arguments);
             }
        };
    },
    
    
    
    /************************************************************/
    /*
        (method) CreatePointElement
        多角線の間接点となるポイントクラスを生成します。
        
        index : PointCollectionの配列番号
    */
    /************************************************************/
    CreatePointElement : function(index)
    {
        var id = ICTMAP.USERPOINT_PREFIX+this.TOOL_PREFIX;
        
        //ポイント削除のメニューリンク
        var removeLink = 
                "<a href=\"#\" "
                + "onclick=\"__ictmap_tools_activetool_removepoint(" +index+");"
                + "return false;\">"
                + "このポイントを削除する</a><br>";
        
        //ポイント追加のメニューリンク
        var insertLink = 
                "<a href=\"#\" "
                + "onclick=\"__ictmap_tools_activetool_insertpoint(" +index+");"
                + "return false;\">"
                + "間にポイントを追加する</a><br>";
        
        
        //ポイントの作成
        var x = this.PointCollection[index].x;
        var y = this.PointCollection[index].y;
        
        var point = 
            ICTMAP.myXmlOverlay.addNewPoint(id+"p"+index, x, y);
        
        //ポイントアイコンの作成(divタグ)
        var div = this.CreatePointIconElement();
        point.div.appendChild(div);
        
        //アイコンの位置がポイントの中心に行くように位置を調整
        var top = point.div.style.top.replace("px","");
        var left = point.div.style.left.replace("px","");
        
        var width = div.style.width.replace("px","");
        var height = div.style.height.replace("px","");
        
        top = parseInt(top)-parseInt(parseInt(height)/2);
        left = parseInt(left)-parseInt(parseInt(width)/2);
        
        point.div.style.top = top + "px";
        point.div.style.left = left + "px";
        
        
        //イベントハンドラの登録
        var self = this;
        
        //ツールが有効じゃない場合は、イベントを登録しない。
        if(!this.IsActive)
        {
           div.style.cursor="";
           return point;
        }
        
        //ポイントのクリック(ドラッグ開始)
        div.onmousedown = function()
        {
            if(self.DraggingPointIndex > -1) return;
            self.DraggingPointIndex = index;
            self.OnDragPointStart.apply(self, arguments);
            self._OnDragPointStart.apply(self, arguments);
        };
        
        //ポイント削除メニューのクリック(グローバルスコープに関数追加)
        window["__ictmap_tools_activetool_removepoint"] = function()
        {
            self.IsClickLocked = true;
            self.RemovePoint.apply(self, arguments);
            clearOverlaysymbolhtml();
            if(typeof self.OnAfterRemovePoint == "function")
            {
                self.OnAfterRemovePoint.apply(self, arguments);
            }
        }
        
        //ポイント追加メニューのクリック
        window["__ictmap_tools_activetool_insertpoint"] = function()
        {
            self.IsClickLocked = true;
            self.InsertAfterPoint.apply(self, arguments);
            clearOverlaysymbolhtml();
            if(typeof self.OnAfterInsertPoint == "function")
            {
                self.OnAfterInsertPoint.apply(self,arguments);
            }
        }
        
        var menuString = removeLink;
        if(index < this.PointCollection.length-1)
        {
            menuString += insertLink;
        }
        
        //ポイントをクリックしたときのポップアップ表示
        point.div.onclick = function()
        {
             self.OnClickPoint(self, arguments);
             self.IsPopupMenuOpened = true;
             clickIconEvent(point, menuString);
             
             //clearOverlaysymbolhtmlを呼び出したときポイントが
            //追加されないようにオーバーライド
            var clearOverlaysymbolhtml_ = clearOverlaysymbolhtml;
            clearOverlaysymbolhtml = function()
            {
                self.IsClickLocked = true;
                self.IsPopupMenuOpened = false;
                clearOverlaysymbolhtml_();
                clearOverlaysymbolhtml = clearOverlaysymbolhtml_;
            };
        };
        
       return point;
    },
    
    
    
    /************************************************************/
    /*
        (method) CreatePointIconElement
        ドラッグ用のポイントアイコンを生成します。
    */
    /************************************************************/
    CreatePointIconElement : function()
    {
        var div = document.createElement("div");
        for(var p in this.PointStyle)
        {
            div.style[p] = this.PointStyle[p];
        }
        return div;
    },
    
    
    /************************************************************/
    /*
        (public virtual method) GetDrawMethod
        本クラスはTools.Polygonクラスに継承されます。
        その為、描画メソッドをクラスによって選択できるようにしました。
        このメソッドは、Tools.Polygonクラスでoverrideされます。
    */
    /************************************************************/
    GetDrawMethod : function()
    {
        return ICTMAP.IctMap.AddPolyline;
    },
    
    /************************************************************/
    /*
        (public virtual method) GetDrawObject
        本クラスはTools.Polygonクラスに継承されます。
        その為、描画オブジェクトをクラスによって選択できるようにしました。
        このメソッドは、Tools.Polygonクラスでoverrideされます。
    */
    /************************************************************/
    GetDrawObject : function()
    {
        return ICTMAP.IctMap;
    },
    
    
    /************************************************************/
    /*
        (property) LockDblClickEvent
        OnDblClickイベントを排他的にロック
    */
    /************************************************************/
    LockDblClickEvent : function()
    {
        var self = this;
        this.ExclusiveEvents.LockEventHandler
        (
            "dblclick",
            function(e)
            {
                var p = ICTMAP.IctMap.Tools.ToGeometory(e);
                
                self.OnDblClick.apply(self, arguments);
                self._OnDblClick.apply(self, arguments);
            }
        );
    },
    
    /************************************************************/
    /*
        (method) OnDblClick
        ダブルクリックしたときに発生するイベントのイベントハンドラです。
    */
    /************************************************************/
    OnDblClick : function()
    {
    },
    
    /************************************************************/
    /*
        (private method) _OnDblClick
        ダブルクリックしたときに発生するイベントのイベントハンドラです。
        (*)ユーザーに公開していない処理部分です。
    */
    /************************************************************/
    _OnDblClick : function(e)
    {
        if(this.IsClosed) return;
        
        var geo = ICTMAP.IctMap.Tools.ToGeometory(e);
        this.PointCollection.push(geo);
        this._createBox(geo);
        if(this.PointCollection.length > 0)
        {
            this.IsClosed = true;
            this.IsClickLocked = true;
            this.Reflesh();
        }
    },
    
    
    /************************************************************/
    /*
        (method) OnMapClick
        MAPをクリックしたときに発生するイベントハンドラです。
    */
    /************************************************************/
    OnMapClick : function()
    {
    },
    
    /************************************************************/
    /*
        (private method) _OnMapClick
        MAPをクリックしたときに発生するイベントハンドラです。
        (*)ユーザーに公開していない処理部分です。
    */
    /************************************************************/
    _OnMapClick : function()
    {
    },
    
    
    /************************************************************/
    /*
        (private method) _OnMapClickTrigger
        イベントハンドラとして登録される処理実体です。
        _OnMapClickを、thisをこのクラスとして実行します。
    */
    /************************************************************/
    _OnMapClickTrigger : function()
    {
    },

    
    
    /************************************************************/
    /*
        (private method) _OnMouseEventsTrigger
        マウスイベントのブラウザ依存を吸収します。
    */
    /************************************************************/
    _OnMouseEventsTrigger : function(eventid, p)
    {
         if(this.StartPoint == null)
         {
             return;
         }
         var gp = {x:(p.x) ? p.x : p[0], y:(p.y) ? p.y :p[1]};
         gp = {x:parseFloat(gp.x), y:parseFloat(gp.y)};
         
         if(gp.x > this.Box.maxX || gp.y > this.Box.maxY || gp.x < this.Box.minX || gp.y < this.Box.minY)
         {
            if(this.IsMouseOverPosition)
            {
                this.OnMouseOut.apply(this, arguments);
                this.IsMouseOverPosition = false;
            }
             return;
         }
         
         var pp = ICTMAP.IctMap.Tools.ToCanvasOffset(this.StartPoint.graphics[0], gp);
         
         if(this.IsMouseOver(pp))
         {
             if(!this.IsMouseOverPosition)
             {
                 this.OnMouseOver.apply(this, arguments);
                 this.IsMouseOverPosition = true;
             }
         }
         else
         {
             if(this.IsMouseOverPosition)
             {
                 this.OnMouseOut.apply(this, arguments);
                 this.IsMouseOverPosition = false;
             }
         }
    },
    
    
    /************************************************************/
    /*
        (method) OnDragPointStart
        ポイントのドラッグ開始のイベントハンドラです。
    */
    /************************************************************/
    OnDragPointStart : function()
    {
    },
    
    /************************************************************/
    /*
        (method) OnDragPoint
        ポイントのドラッグ中のイベントハンドラです。
        (*)ユーザーに公開していない処理部分です。
    */
    /************************************************************/
    OnDragPoint : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnDragPointEnd
        ポイントのドラッグ終了のイベントハンドラです。
    */
    /************************************************************/
    OnDragPointEnd : function()
    {
    },
    
    /************************************************************/
    /*
        (private method) _OnDragPointStart
        ポイントのドラッグ開始のイベントハンドラです。
        (*)ユーザーに公開していない処理部分です。
    */
    /************************************************************/
    _OnDragPointStart : function()
    {
        var self = this;
        
        //地図フィールドのonmousedownと、onmouseupを無効化
        this.ExclusiveEvents.LockEventHandler("mousedown", null);
        this.ExclusiveEvents.LockEventHandler("mouseup", null);
        
        //移動させる前の座標情報を保存
        var startCoordinates = this.GetCoordinates();
        
        //onmousemoveを排他的に上書き
        this.ExclusiveEvents.LockEventHandler
        (
            "mousemove", 
            function()
            {
                self._OnDragPoint.apply(self, arguments);
                self.OnDragPoint.apply(self, arguments);
            }
        );
        
        //ドラッグ終了はどこからでもハンドリング出来るように
        //document.bodyにセット
        this.BodyOnMouseUp = document.body.onmouseup;
        document.body.onmouseup = function()
        {
            //少しでも座標の変更があればドラッグとみなす
            if(startCoordinates != self.GetCoordinates())
            {
                self.OnDragPointEnd.apply(self, arguments);
            }
            self._OnDragPointEnd.apply(self, arguments);
        };
    },
    
    /************************************************************/
    /*
        (private method) _OnDragPoint
        ポイントのドラッグ中のイベントハンドラです。
        (*)ユーザーに公開していない処理部分です。
    */
    /************************************************************/
    _OnDragPoint : function(e)
    {
        //マウスの位置情報を緯度・経度に変換
        var geo = ICTMAP.IctMap.Tools.ToGeometory(e);
        
        //位置情報をドラッグ中のポイントに再セット
        this.PointCollection[this.DraggingPointIndex] = geo;
        
        this.Box = {maxX:0, maxY:0, minX:0,maxY:0};
        for(var i=0; i<this.PointCollection.length; i++)
        {
            this._createBox(this.PointCollection[i]);
        }
        this.Reflesh();
    },
    
    
    /************************************************************/
    /*
        (private method) _OnDragPointEnd
        ポイントのドラッグ終了のイベントハンドラです。
        (*)ユーザーに公開していない処理部分です。
    */
    /************************************************************/
    _OnDragPointEnd : function()
    {
        this.DraggingPointIndex = -1;
        
        //排他的にロックしていたイベントハンドラを解放
        this.ExclusiveEvents.ReleseEventHandler("mousedown");
        this.ExclusiveEvents.ReleseEventHandler("mouseup");
        this.ExclusiveEvents.ReleseEventHandler("mousemove");
        
        //document.bodyのイベントハンドラを元に戻す
        document.body.onmouseup = this.BodyOnMouseUp;
    },
    
    
    
    /************************************************************/
    /*
        (method) OnClickPoint
        ポイントをクリックした時のイベントハンドラです。
    */
    /************************************************************/
    OnClickPoint : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnBeforeDrawLine
        ラインを描画する直前に呼び出されるイベントです。
    */
    /************************************************************/
    OnBeforeDrawLine : function()
    {
    },
    
    
    
    /************************************************************/
    /*
        (method) OnAfterDrawLine
        ラインを描画した直後に呼び出されるイベントです。
        (*) IsActivateがfalse、IsVisible=falseでも呼び出されます。
    */
    /************************************************************/
    OnAfterDrawLine : function()
    {
    },
    
    
    
    /************************************************************/
    /*
        (method) OnAfterRemovePoint
        ポイント追加後に呼び出されるイベントです。
    */
    /************************************************************/
    OnAfterInsertPoint : function()
    {
    },
    
    
    
    /************************************************************/
    /*
        (method) OnAfterRemovePoint
        ポイント削除後に呼び出されるイベントです。
    */
    /************************************************************/
    OnAfterRemovePoint : function()
    {
    },
    
    
    
    /************************************************************/
    /*
        (method) OnMouseOver
        マウスポインタがラインの上にある時、発生するイベントです。
    */
    /************************************************************/
    OnMouseOver : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnMouseOut
        マウスポインタがラインから外れたときに発生するイベントです。
    */
    /************************************************************/
    OnMouseOut : function()
    {
    },
    
    /************************************************************/
    /*
        (method) OnActive
        Activateメソッドが呼び出された時発生するイベントです。
    */
    /************************************************************/
    OnActive : function()
    {
    },
    
    /************************************************************/
    /*
        (method) OnDeactive
        Deactivateメソッドが呼び出された時発生するイベントです。
    */
    /************************************************************/
    OnDeactive : function()
    {
    },
    
    /************************************************************/
    /*
        (method) DisplayBaloon
        吹き出しを生成します。
        
        x, y         : 吹き出しの表示位置(緯度・経度)
        html         : 表示するHTML
        url          : 表示するURL(html引数と同時に指定した場合、htmlが優先されます。)
        iframeSrc    : iframeのsrc属性
        iframeWidth  : iframeの幅
        iframeHeight : iframeの高さ
    */
    /************************************************************/
    DisplayBaloon : function(x, y, html, url, iframeSrc, iframeWidth, iframeHeight)
    {
        ICTMAP.myXmlOverlay.removePoint("___baloon___");
        var p = ICTMAP.myXmlOverlay.addNewPoint("___baloon___", x, y);
        
        this.IsPopupMenuOpened = true;
        clickIconEvent(p, html, url, iframeSrc, iframeWidth, iframeHeight);
    },
    
    
    
    /************************************************************/
    /*
        (method) Activate
        無効になっているツールをアクティブにします。
        (*)基本的には、イベントハンドラを有効にし、ポイントを
           再描画するだけ
    */
    /************************************************************/
    Activate : function()
    {
        if(this.IsActive)
        {
            return;
        }
        this.IsClickLocked = false;
        this.IsVisible = true;
        this.IsActive = true;
        this.IsLineOnly = false;
        
        ICTMAP.registerForEvent(KAMAP_MAP_CLICKED, this, this._OnMapClickTrigger);
        
        ICTMAP.deregisterForEvent(KAMAP_SCALE_CHANGED, this, this.Reflesh);
        ICTMAP.registerForEvent(KAMAP_SCALE_CHANGED, this, this.Reflesh);
        
        this.Reflesh();
        
        this.OnActive.apply(this, []);
    },
    
    
    
    /************************************************************/
    /*
        (method) Deactivate
        このツールのイベント処理を無効にします。
        
        isVisible  : ラインの表示を残すかどうか(true/false)
        isLineOnly : ラインのみ表示するか、ポイント間の"□"を表示するか(true/false)
                   : ※省略可 デフォルト true
    */
    /************************************************************/
    Deactivate : function(isVisible, isLineOnly)
    {
        this.IsActive = false;
        this.IsVisible = isVisible;
        this.IsClickLocked = true;
        
        if(typeof isLineOnly == "undefined" || isLineOnly == null)
        {
            isLineOnly = true;
        }
        this.IsLineOnly = isLineOnly;
        
        if(!isVisible)
        {
            this.RefleshClear();
            ICTMAP.deregisterForEvent(KAMAP_SCALE_CHANGED, this, this.Reflesh);
        }
        
        if(isVisible)
        {
            this.Reflesh();
        }
        clearOverlaysymbolhtml();
        ICTMAP.deregisterForEvent(KAMAP_MAP_CLICKED, this, this._OnMapClickTrigger);
        
        this.OnDeactive.apply(this, []);
    },
    
    /************************************************************/
    /*
        (method) GetCoordinates
        頂点情報を文字列で取得します。
    */
    /************************************************************/
    GetCoordinates : function()
    {
        var coordinates = [];
        for(var i=0; i<this.PointCollection.length; i++)
        {
            coordinates.push(this.PointCollection[i].x + " " + this.PointCollection[i].y);
        }
        return coordinates.join(",");
    },
    
    
    
    /************************************************************/
    /*
        (method) IsMouseOver
        任意の点がライン上に乗っているかどうかを判定します。
        
        p : 任意の{x:x, y:y}
    */
    /************************************************************/
    IsMouseOver : function(p)
    {
       //判定の誤差許容範囲
       var width = 15;
       for(var i=1; i<this.PixelCollection.length; i++)
       {
           var s = this.PixelCollection[i-1];
           var e = this.PixelCollection[i];
           var d = this._getDistance(s,e,p);
           
           if(d <= width) return true;
       }
       return false;
    },
    
    
    /************************************************************/
    /*
        (override method) toStringメソッドのオーバーライド
    */
    /************************************************************/
    toString : function()
    {
        return this.ClassName;
    },
    
    /************************************************************/
    /*
        (property) ClassName
        クラス名を文字列で取得します。
        IE7でtoStringメソッドが上手く動作しなかったので
        独自のプロパティとしました。
    */
    /************************************************************/
    ClassName : "IctMap.Tools.Polyline",
    
    
    /************************************************************/
    /*
        (private method) _getDistance
        2点が結ぶラインと、任意の点の距離を計算します。
        s : 始点の{x:x, y:y}
        e : 終点の{x:x, y:y}
        p : 任意の{x:x, y:y}
    */
    /************************************************************/
    _getDistance : function(s,e,p)
    {
        if(p == null) return;
        
        //pが|se|の線分に対して垂線を引ける位置にあるか？
        if(this._isPerpendicular(s, e, p))
        {
            //pから|se|に垂線を引き交点との距離が距離
            var d = this._getDistancePerpendicular(s, e, p);
            d = (d < 0) ? d*-1 : d;
            return d;
        }
        //pが|se|の線分に対して垂線を引ける位置じゃない場合
        else
        {
            //sとp、eとpの距離を測り短い方が距離
            var sp = {x:p.x-s.x, y:p.y-s.y};
            var ep = {x:p.x-e.x, y:p.y-e.y};
            
            var dsp = Math.sqrt(sp.x*sp.x + sp.y*sp.y);
            var dep = Math.sqrt(ep.x*ep.x + ep.y*ep.y);
            
            return (dsp < dep) ? dsp : dep;
        }
    },
    
    
    /************************************************************/
    /*
        (private method) _isPerpendicular
        2点が結ぶラインに対して、任意の点が垂線を引ける位置にあるかを
        判定します。
        s : 始点の{x:x, y:y}
        e : 終点の{x:x, y:y}
        p : 任意の{x:x, y:y}
    */
    /************************************************************/
    _isPerpendicular : function(s, e, p)
    {
        //s-->eのベクトル
        var se = {x:e.x-s.x, y:e.y-s.y};
        
        //s-->eに垂直で交わり、sを通る座標
        var sp = {x:se.y*-1 + s.x, y:se.x + s.y};
        
        //s-->eに垂直で交わり、eを通る座標
        var ep = {x:se.y*-1 + e.x, y:se.x + e.y};
        
        // sp、epに対してpの位置を判定
        var sd = this._getDistancePerpendicular(sp, s, p);
        var ed = this._getDistancePerpendicular(ep, e, p);
        
        return (sd <= 0 && ed >= 0);
    },
    


    /************************************************************/
    /*
        (private method) _getDistancePerpendicular
        2点が結ぶラインに対して、任意の点が垂線を引ける位置にある時、
        任意の位置からラインまでの距離を測ります。
        (s-->eのラインに対して、pから垂線を引き、その交点とpとの距離を測ります。)
        
        s : 始点の{x:x, y:y}
        e : 終点の{x:x, y:y}
        p : 任意の{x:x, y:y}
        
        (戻り値)
        ライン|se|に対するpからの距離。
        正の値 ==> ライン|se|のベクトルに対して左
        負の値 ==> ライン|se|のベクトルに対して右
    */
    /************************************************************/
    _getDistancePerpendicular : function(s, e, p)
    {
        //s-->p のベクトル
        var sp = {x:p.x-s.x, y:p.y-s.y};
        //s-->e のベクトル
        var se = {x:e.x-s.x, y:e.y-s.y};
        
        //seの長さ
        var d = Math.sqrt(se.x * se.x + se.y * se.y);
        if(d == 0)
        {
            //seの長さ0は点なので、sとpとの距離を求める
            return Math.sqrt( sp.x * sp.x + sp.y * sp.y );
        }
        
        /*  s-->pのベクトル|sp| * sin(@) ==> 距離d
         *  外積の公式 sp * se = |sp| |se| sin(@) から
         *  d= |sp| sin(@) = (sp*se) / |se| と考える
         */
        return (sp.x*se.y - sp.y*se.x) / d;
    },
    
    
    /************************************************************/
    /*
        (private method) _createBox
        バウンディングボックスを作成します。
    */
    /************************************************************/
    _createBox : function(p)
    {
        this.Box.maxX = (this.Box.maxX < p.x) ? p.x : this.Box.maxX;
        this.Box.maxY = (this.Box.maxY < p.y) ? p.y : this.Box.maxY;
        this.Box.minX = (this.Box.minX ==0 || this.Box.minX > p.x) ? p.x : this.Box.minX;
        this.Box.minY = (this.Box.minY ==0 || this.Box.minY > p.y) ? p.y : this.Box.minY;
    }
};






/***********************************************************************************/
/*
    (class)IctMap.Tools.Polygon    extends IctMap.Tools.Polyline
    IctMap上に、多角形を入力する為のUIツールです。
*/
/***********************************************************************************/
IctMap.prototype.Tools.Polygon = function()
{
    this.Initialize.apply(this, arguments);
}

//extends IctMap.Tools.Polyline
for(var p in IctMap.prototype.Tools.Polyline.prototype)
{
    IctMap.prototype.Tools.Polygon.prototype[p] = IctMap.prototype.Tools.Polyline.prototype[p];
}
IctMap.prototype.Tools.Polygon.prototype["parent"] = IctMap.prototype.Tools.Polyline.prototype;


var __ictmap_tools_polygon_prototype = 
{
    /************************************************************/
    /*
        (property) IsMouseOverPosition
        マウスがポリゴン上に乗った事を示します。
    */
    /************************************************************/
    IsMouseOverPosition : false,


    /************************************************************/
    /*
        (property) IsCanvasMouseOutOccured
        canvasに対するマウスアウトイベントの発生を保持します。
        (*)IE用
    */
    /************************************************************/
    IsCanvasMouseOutOccured : false,


    /************************************************************/
    /*
        (property) Initialize
        コンストラクタ
    */
    /************************************************************/
    Initialize : function()
    {
        this.parent.Initialize.apply(this, arguments);
        this.TOOL_PREFIX = "_polygon_"
        this.TOOL_LINE_PREFIX = "line_polygon";
        
        this.LockDblClickEvent();
        
        var onmapclick = this.OnMapClick;
        var self = this;
        this.OnMapClick = function()
        {
            if(!self.IsClosed)
            {
                onmapclick.apply(self, arguments);
            }
        };
        
        ICTMAP.registerForEvent(KAMAP_MAP_CLICKED, this, this._OnMouseEventsTrigger);
    },



    /************************************************************/
    /*
        (method) OnClick
        マウスがポリゴン上をクリックした時、発生するイベント
    */
    /************************************************************/
    OnClick : function()
    {
    },
    
    
    /************************************************************/
    /*
        (override method) RemovePoint
        ポイント配列からポイントを削除します。
    */
    /************************************************************/
    RemovePoint : function(index)
    {
        this.PointCollection.splice(index, 1);
        if(this.PointCollection.length < 3)
        {
            this.IsClosed = false;
        }
        this.Reflesh();
    },
    
    /************************************************************/
    /*
        (override method) AfterReflesh
        ポリゴンを描画後の処理です。
    */
    /************************************************************/
    AfterReflesh : function()
    {
        if(this.Canvas == null) return;
        var self = this;
    },
    
    
    /************************************************************/
    /*
        (private orveride method) _OnMouseEventsTrigger
        マウスイベントのブラウザ依存を吸収します。
    */
    /************************************************************/
    _OnMouseEventsTrigger : function(eventid, p)
    {
        if(!this.IsClosed) return;
        
        var gp = {x:(p.x) ? p.x : p[0], y:(p.y) ? p.y :p[1]};
        gp = {x:parseFloat(gp.x), y:parseFloat(gp.y)};
        
        if(gp.x > this.Box.maxX || gp.y > this.Box.maxY || gp.x < this.Box.minX || gp.y < this.Box.minY)
        {
            if(this.IsMouseOverPosition)
            {
                this.OnMouseOut.apply(this, arguments);
                this.IsMouseOverPosition = false;
            }
            return;
        }
        
        var pp = ICTMAP.IctMap.Tools.ToCanvasOffset(this.StartPoint.graphics[0], gp);
        
        switch(eventid)
        {
            case KAMAP_MOUSE_TRACKER :
                if(this.IsMouseOver(gp))
                {
                    if(this.IsMouseOverPosition) return;
                    this.OnMouseOver.apply(this, arguments);
                    this.IsMouseOverPosition = true;
                }
                else
                {
                    if(!this.IsMouseOverPosition) return;
                    if(!this.parent.IsMouseOver.apply(this, [pp]))
                    {
                        this.OnMouseOut.apply(this, arguments);
                        this.IsMouseOverPosition = false;
                    }
                }
                return;
            
            case KAMAP_MAP_CLICKED :
                if(this.IsMouseOver(gp))
                {
                    this.OnClick.apply(this, arguments);
                }
                return;
            
            default : return;
        }
    },
    
    /************************************************************/
    /*
        (override method) GetDrawMethod
        本クラスのデータを画面に描画するメソッドを取得します。
    */
    /************************************************************/
    GetDrawMethod : function()
    {
        return (this.IsClosed) ? ICTMAP.IctMap.AddPolygon : ICTMAP.IctMap.AddPolyline;
    },


    /************************************************************/
    /*
        (override method) GetDrawObject
        本クラスのデータを画面に描画するオブジェクトを取得します。
    */
    /************************************************************/
    GetDrawObject : function()
    {
        return ICTMAP.IctMap;
    },


    /************************************************************/
    /*
        (override method) IsMouseOver
        マウスが多角形の内点を指しているかを判定します。
    */
    /************************************************************/
    IsMouseOver : function(point)
    {
        var geo = point;
        var coordinates = [];
        for(var i=0; i<this.PointCollection.length; i++)
        {
            coordinates[i] = this.PointCollection[i];
        }
        if(coordinates.length > 0)
        {
            var st = coordinates[0];
            var ed = coordinates[coordinates.length-1];
            
            if(st.x != ed.x || st.y != ed.y)
            {
                coordinates.push(coordinates[0]);
            }
        }
        
        geo.x = parseFloat(geo.x);
        geo.y = parseFloat(geo.y);
        
        var clossLineCount = 0;
        var geo0 = coordinates[0];
        var isClossX0 = (geo.x <= geo0.x);
        var isClossY0 = (geo.y <= geo0.y);
        
        for(var i=1; i<coordinates.length;i++)
        {
            var geo1 = coordinates[i%coordinates.length];
            var isClossX1 = geo.x <= geo1.x;
            var isClossY1 = geo.y <= geo1.y;
            
            if(isClossY0 != isClossY1)
            {
                if(isClossX0 == isClossX1)
                {
                    if(isClossX0) clossLineCount += (isClossY0) ? -1 : 1;
                }
                else
                {
                    var clossX = 
                        geo0.x + (geo1.x - geo0.x) * 
                        (geo.y - geo0.y) / (geo1.y - geo0.y);
                    if(geo.x <= clossX) clossLineCount += (isClossY0) ? -1 : 1;
                }
            }
            geo0 = geo1;
            isClossX0 = isClossX1;
            isClossY0 = isClossY1;
        }
        return (0!=clossLineCount);
    },


    /************************************************************/
    /*
        (override method) Deactivate
        このツールのイベント処理を無効にします。
        
        isVisible  : ラインの表示を残すかどうか(true/false)
        isLineOnly : ラインのみ表示するか、ポイント間の"□"を表示するか(true/false)
                   : ※省略可 デフォルト true
    */
    /************************************************************/
    Deactivate : function()
    {
        this.parent.Deactivate.apply(this, arguments);
        this.ExclusiveEvents.ReleseEventHandler("dblclick");
    },
    
    
    
    /************************************************************/
    /*
        (override method) Activate
        無効になっているツールをアクティブにします。
        (*)基本的には、イベントハンドラを有効にし、ポイントを
           再描画するだけ
    */
    /************************************************************/
    Activate : function()
    {
        this.parent.Activate.apply(this, arguments);
        try
        {
            this.LockDblClickEvent();
        }
        catch(e)
        {
        }
    },
    
    /************************************************************/
    /*
        (override method) toStringメソッドのオーバーライド
    */
    /************************************************************/
    toString : function()
    {
        return this.ClassName;
    },
    
    /************************************************************/
    /*
        (property) ClassName
        クラス名を文字列で取得します。
        IE7でtoStringメソッドが上手く動作しなかったので
        独自のプロパティとしました。
    */
    /************************************************************/
    ClassName : "IctMap.Tools.Polygon"
};

//override && add properties
for(var p in __ictmap_tools_polygon_prototype)
{
    IctMap.prototype.Tools.Polygon.prototype[p] = __ictmap_tools_polygon_prototype[p];
}



/***********************************************************************************/
/*
    (class) IctMap.Tools.ToolBox
    複数のPolyline、PolygonとPointを管理する複合的ツールボックスクラスです。
*/
/***********************************************************************************/
IctMap.prototype.Tools.ToolBox = function()
{
    this.Initialize.apply(this, arguments);
};

IctMap.prototype.Tools.ToolBox.prototype = 
{
    /************************************************************/
    /*
        (property) ToolCollection
        Polylineまたは、Polygonのインスタンスを格納する配列
    */
    /************************************************************/
    ToolCollection  : [],
    
    
    /************************************************************/
    /*
        (property) PointCollection
        Pointのインスタンスを格納する配列
    */
    /************************************************************/
    PointCollection : [],
    
    
    /************************************************************/
    /*
        (property) NumberBaloonCollection
        オブジェクト番号吹き出し表示中のオブジェクト配列
    */
    /************************************************************/
    NumberBaloonCollection : [],
    
    
    /************************************************************/
    /*
        (property) PointCollection
        Pointのインスタンスを格納する配列
    */
    /************************************************************/
    PointDefaultIcon : null,
    
    
    /************************************************************/
    /*
        (property) PointExclusiveEvents
        Pointへのイベントをハンドリングする為の排他的イベントクラス
        です。
    */
    /************************************************************/
    PointExclusiveEvents : null,
    
    
    /************************************************************/
    /*
        (property) ToolConstructor
        PolylineやPolygonなどのクラスのコンストラクタを保持する
        連想配列です。
    */
    /************************************************************/
    ToolConstructor : {},
    
    
    
    /************************************************************/
    /*
        (property) ToolIndex
        PolylineやPolygonツールを生成する際に付される連番です。
    */
    /************************************************************/
    ToolIndex       : 0,
    
    
    /************************************************************/
    /*
        (property) ActiveTool
        現在有効になっているツールの参照です。
        本クラスのもとでは、1つのツールしか有効になりません。
        Pointモードを利用している間は、nullが格納されます。
    */
    /************************************************************/
    ActiveTool      : null,
    
    
    /************************************************************/
    /*
        (property) BaloonOpenObject
        バルーン(吹き出し)をオープンしているオブジェクトです。
    */
    /************************************************************/
    BaloonOpenObject : null,
    
    
    /************************************************************/
    /*
        ポイントオブジェクトのプレフィックス
    */
    /************************************************************/
    POINT_PREFIX : "__toolbox_p__",
    
    
    /************************************************************/
    /*
        編集モードのON/OFFフラグ
    */
    /************************************************************/
    IsEditable : true,
    
    
    /************************************************************/
    /*
        コンストラクタ
    */
    /************************************************************/
    Initialize : function()
    {
        this.ToolCollection = [];
        this.PointCollection = [];
        this.ToolConstructor = 
        {
            "IctMap.Tools.Polyline" : ICTMAP.IctMap.Tools.Polyline,
            "IctMap.Tools.Polygon"  : ICTMAP.IctMap.Tools.Polygon
        };
        
        this.PointExclusiveEvents = new ICTMAP.IctMap.Tools.ExclusiveEvents();
        
        var self = this;
        //ポイントドラッグ用のマウスイベント
        ICTMAP.registerForEvent(KAMAP_MOUSE_TRACKER, this, this._OnPointClickEventTrigger);
        
        this.IsEditable = true;
    },
    
    
    /************************************************************/
    /*
        (method) AddPoint
        マップ上に点を作成します。
    */
    /************************************************************/
    AddPoint : function(x, y, icon, pointName)
    {
        var id = this.PointCollection.length;
        var p = ICTMAP.IctMap.AddPoint
            (this.POINT_PREFIX + id, x, y, icon);
        
        p.pointName = pointName;
        
        this.PointCollection.push(p);
        
        return p;
    },
    
    
    /************************************************************/
    /*
        (method) RemovePoint
        マップの点を削除します。
    */
    /************************************************************/
    RemovePoint : function(p)
    {
        for(var i=0; i<this.PointCollection.length; i++)
        {
            if(this.PointCollection[i] == p)
            {
                p.removeFromMap();
                this.PointCollection.splice(i, 1);
            }
        }
    },
    
    /************************************************************/
    /*
        (method) AddTool
        ツールを追加します。
        
        t : 生成するクラスインスタンス名(ToolConstructorの要素名)
        
        (戻り値)
        ツールのインスタンスの参照
    */
    /************************************************************/
    AddTool : function(t, name)
    {
        var _class = this.ToolConstructor[t];
        
        if(_class == null) return;
        
        var tool = new _class();
        
        tool.RefleshClearMode = false;
        tool.TOOL_PREFIX += this.ToolIndex;
        tool.TOOL_LINE_PREFIX += this.ToolIndex;
        tool.Name = name;
        
        this.ToolCollection.push(tool);
        
        if(!tool.ExclusiveEvents.IsEventLocked("dblclick"))
        {
            tool.LockDblClickEvent();
        }
        
        this.SetToolEventHandler(tool);
        this.ToolIndex++;
        
        tool.IsClickLocked = false;
        tool.Deactivate(true);
        
        return tool;
    },
    
    
    
    /************************************************************/
    /*
        (method) RemoveTool
        ツールを削除します。
        
        tool : 削除したいツールのインスタンス
    */
    /************************************************************/
    RemoveTool : function(tool)
    {
        for(var i=0; i<this.ToolCollection.length; i++)
        {
            if(tool == this.ToolCollection[i])
            {
                if(this.ActiveTool == tool)
                {
                    this.ActiveTool = null;
                }
                tool.ClearPoint();
                tool.Deactivate();
                
                delete tool;
                this.ToolCollection.splice(i, 1);
                break;
            }
        }
    },
    
    
    /************************************************************/
    /*
        (method) ChangeActiveTool
        現在有効なツールを切り替えます。
        IsEditableがfalseの場合、何も処理しません。
    */
    /************************************************************/
    ChangeActiveTool : function(tool)
    {
        if(!this.IsEditable) return;
        for(var i=0; i<this.ToolCollection.length; i++)
        {
            if(this.ToolCollection[i] != tool)
            {
                if(this.ToolCollection[i].IsActive) 
                {
                    this.ToolCollection[i].Deactivate(true);
                }
            }
        }
        if(!tool.IsActive) tool.Activate();
        tool.IsClickLocked = false;
        this.ActiveTool = tool;
        ICTMAP.deregisterForEvent(KAMAP_MAP_CLICKED, this, this._OnMapClick);
    },
    
    
    /************************************************************/
    /*
        (method) ChangeToPointTool
        点を生成するツールに切り替えます。
        IsEditableがfalseの場合、何も処理しません。
    */
    /************************************************************/
    ChangeToPointTool : function()
    {
        if(!this.IsEditable) return;
        for(var i=0; i<this.ToolCollection.length; i++)
        {
            this.ToolCollection[i].Deactivate(true);
        }
        
        var self = this;
        this._OnMapClick = function(eventid, p)
        {
            var pp = {x:(p.x)?p.x:p[0], y:(p.y)?p.y:p[1]};
            var addp = self.AddPoint.apply(self, [pp.x, pp.y, self.PointDefaultIcon]);
            self.OnPointAdded.apply(self, [addp, eventid, p]);
            ICTMAP.deregisterForEvent(KAMAP_MAP_CLICKED, self, self._OnMapClick);
        };
        
        ICTMAP.registerForEvent(KAMAP_MAP_CLICKED, this, this._OnMapClick);
    },
    
    
    /************************************************************/
    /*
        (method) SetPopupMenuOpened
        ポップアップメニューが表示中であることを全てのオブジェクトに
        通達します。
    */
    /************************************************************/
    SetPopupMenuOpened : function(bool)
    {
        for(var i=0; i<this.ToolCollection.length; i++)
        {
            this.ToolCollection[i].IsPopupMenuOpened = bool;
        }
    },
    
    
    
    /************************************************************/
    /*
        (method) DisplayBaloon
        バルーン(吹き出し)を表示します。
        このメソッドで生成したバルーンは、クローズした際、
        OnCloseBaloonイベントを発生させます。
        
        o   : kaXmlPointまたはPolylineまたはPolygonのインスタンス
        p   : PolylineまたはPolygonの時の吹き出しを表示したい位置
        opt : オプション
    */
    /************************************************************/
    DisplayBaloon : function(o, p, opt)
    {
        opt = (opt) ? opt : {};
        var html   = (opt.infoWindowHtml)      ? opt.infoWindowHtml      : "";
        var url    = (opt.infoWindowUrl)       ? opt.infoWindowUrl       : "";
        var src    = (opt.infoIframeWindowSrc) ? opt.infoIframeWindowSrc : "";
        var width  = (opt.infoIframeWidth)     ? opt.infoIframeWidth     : "";
        var height = (opt.infoIframeHeight)    ? opt.infoIframeHeight    : "";
        
        if(this.IsPoint(o))
        {
            clickIconEvent(o, html, url, src, width, height);
        }
        else
        {
            o.DisplayBaloon(p.x, p.y, html, url, src, width, height);
        }
        this.SetPopupMenuOpened(true);
        this.BaloonOpenObject = o;
        var self = this;
        var f = clearOverlaysymbolhtml;
        clearOverlaysymbolhtml = function()
        {
            f();
            clearOverlaysymbolhtml = f;
            self.SetPopupMenuOpened(false);
            self.OnCloseBaloon.apply(self, [o]);
            self.BaloonOpenObject = null;
        }
    },
    
    /************************************************************/
    /*
        (method) SetToolEventHandler
        ツールにイベントハンドラを登録します。
        本クラスのイベントハンドラを呼び出す処理が追加されます。
    */
    /************************************************************/
    SetToolEventHandler : function(tool)
    {
        var self = this;
        var getArgs = function()
        {
            var args = [tool];
            for(var i=0; i<arguments.length; i++)
            {
                args.push(arguments[i]);
            }
            return args;
        };
        
        tool.OnMouseOver = function()
        {
            self.OnToolMouseOver.apply(self, getArgs.apply(this, arguments)); 
            self._OnToolMouseOver.apply(self, getArgs.apply(this, arguments)); 
        };
        
        tool.OnMouseOut = function()
        {
            self.OnToolMouseOut.apply(self, getArgs.apply(this, arguments)); 
            self._OnToolMouseOut.apply(self, getArgs.apply(this, arguments)); 
        };
        
        tool.OnClick = function()
        {
            self.OnToolClick.apply(self, getArgs.apply(this, arguments)); 
            self._OnToolClick.apply(self, getArgs.apply(this, arguments)); 
        };
        
        tool.OnDblClick = function()
        {
            self.OnToolDblClick.apply(self, getArgs.apply(this, arguments));
        };
        
        tool.OnDragPointStart = function()
        {
            self.OnPointDragStart.apply(self, getArgs.apply(this, arguments));
        };
        
        tool.OnDragPoint = function()
        {
            self.OnPointDrag.apply(self, getArgs.apply(this, arguments));
        };
        
        tool.OnDragPointEnd = function()
        {
            self.OnPointDragEnd.apply(self, getArgs.apply(this, arguments));
        };
        
        tool.OnAfterInsertPoint = function()
        {
            self.OnAfterInsertPoint.apply(self, getArgs.apply(this, arguments));
        };
        
        tool.OnAfterRemovePoint = function()
        {
            self.OnAfterRemovePoint.apply(self, getArgs.apply(this, arguments));
        };
        
        tool.OnActive = function()
        {
            self.OnToolActive.apply(self, getArgs.apply(this, arguments));
        };
        tool.OnDeactive = function()
        {
            self.OnToolDeactive.apply(self, getArgs.apply(this, arguments));
        };
    },
    
    
    /************************************************************/
    /*
        (method) SetPointEventHandler
        点にイベントハンドラを登録します。
    */
    /************************************************************/
    SetPointEventHandler : function(point, geo)
    {
        var self = this;
        
        var mousemove = function(_point, eventid, p)
        {
            p = {x:(p.x)?p.x:p[0], y:(p.y)?p.y:p[1]};
            self.OnPointDrag.apply(self, [_point, eventid, p]);
            var pixes = ICTMAP.geoToPix(p.x, p.y);
            
            _point.setPosition(p.x, p.y);
            
            _point.div.style.top = (pixes[1] - ICTMAP.yOrigin) + "px";
            _point.div.style.left = (pixes[0] - ICTMAP.xOrigin) + "px";
        };
        
        if(!this.IsEditable) mousemove = function(){};
        
        var getPosition = function(e)
        {
            e = (e)?e:(event)?event:null;
            var x = e.pageX || (e.clientX +
                  (document.documentElement.scrollLeft || document.body.scrollLeft));
            var y = e.pageY || (e.clientY +
                        (document.documentElement.scrollTop || document.body.scrollTop));
            return {x:x, y:y};
        };
        
        var startp;
        if(!this.PointExclusiveEvents.IsEventLocked("mousedown"))
        {
            this.PointExclusiveEvents.LockEventHandler
            (
                "mousedown",
                function(e)
                {
                    startp = getPosition(e);
                    self.OnPointDragStart.apply(self, [point, -1, geo]);
                    
                    self.PointExclusiveEvents.LockEventHandler(
                        "mousemove", 
                        function(e)
                        {
                            var g = ICTMAP.IctMap.Tools.ToGeometory(e);
                            mousemove.apply(self, [point, -1, g]);
                            return false;
                        }
                    );
                    
                    var bodymouseup = document.body.onmouseup;
                    document.body.onmouseup = function(e)
                    {
                        self.PointExclusiveEvents.ReleseEventHandler("mousemove");
                        var g = ICTMAP.IctMap.Tools.ToGeometory(e);
                        
                        var pos = getPosition(e);
                        if(Math.abs(startp.x - pos.x) > 2 && 
                            Math.abs(startp.y - pos.y) > 2)
                        {
                            self.OnPointDragEnd.apply(self, [point, -1, g]);
                        }
                        else
                        {
                            self.OnPointClick.apply(self, [point, KAMAP_MAP_CLICKED, g]);
                        }
                        document.body.onmouseup = bodymouseup;
                        return false;
                    }
                    self.PointExclusiveEvents.ReleseEventHandler("mousedown");
                    return false;
                }
            );
        }
    },
    
    
    /************************************************************/
    /*
        (method) _OnPointClickEventTrigger
        レイヤの重なりにより、点へのクリックイベント(ドラッグイベント)が
        発生しない問題に対応します。
    */
    /************************************************************/
    _OnPointClickEventTrigger : function(eventid, p)
    {
        if(this.BaloonOpenObject != null) return;
        
        p = {x:(p.x)?p.x:p[0], y:(p.y)?p.y:p[1]};
        var pixes = ICTMAP.geoToPix(p.x, p.y);
        var x = pixes[0];
        var y = pixes[1];
        var top = (y - ICTMAP.yOrigin);
        var left = (x - ICTMAP.xOrigin);
        var handlerSetten = false;
        for(var i=this.PointCollection.length-1; i>-1; i--)
        {
            var point = this.PointCollection[i];
            var obj = point.div;
            var pointx = parseInt(point.div.style.left);
            var pointy = parseInt(point.div.style.top);
            
            var iconw = (point.graphics[0].icon_w) ? parseInt(point.graphics[0].icon_w) : 0;
            var iconh = (point.graphics[0].icon_h) ? parseInt(point.graphics[0].icon_h) : 0;
            
            var isover = 
            (
                left >= pointx-(iconw/2) && left <= pointx+(iconw/2)
                && top >= pointy-(iconh/2) && top <= pointy+(iconh/2)
            );
            if(isover)
            {
                this._OnPointMouseOver.apply(this, [point, eventid, p]);
                point["isover"] = true;
                
                if(!handlerSetten)
                {
                    this.SetPointEventHandler(point, p);
                    handlerSetten = true;
                }
            }
            else
            {
                if(point["isover"])
                {
                    this._OnPointMouseOut.apply(this, [point, eventid, p]);
                    point["isover"] = false;
                }
            }
        }
        if(!handlerSetten)
        {
            this.PointExclusiveEvents.ReleseEventHandler("mousedown");
            this.PointExclusiveEvents.ReleseEventHandler("mousemove");
        }
    },
    
    
    /************************************************************/
    /*
        (method) OnToolMouseOver
        ツールからマウスカーソルが触れた時に発生するイベントです。
        
        tool      : イベントを発生させたツールのインスタンスです。
        eventid   : 発生したイベントID
        p         : ポイントの緯度・経度
    */
    /************************************************************/
    OnToolMouseOver : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnToolMouseOut
        ツールからマウスカーソルが離れた時に発生するイベントです。
        
        tool      : イベントを発生させたツールのインスタンスです。
        eventid   : 発生したイベントID
        p         : ポイントの緯度・経度
    */
    /************************************************************/
    OnToolMouseOut : function(tool)
    {
    },
    
    
    
    /************************************************************/
    /*
         (method) OnToolClick
        ツールをクリックした時に発生するイベントです。
        
        tool      : イベントを発生させたツールのインスタンスです。
        eventid   : 発生したイベントID
        p         : ポイントの緯度・経度
   */
   /************************************************************/
    OnToolClick : function()
    {
    },
    
    
    /************************************************************/
    /*
         (method) OnToolDblClick
        ツールをダブルクリックした時に発生するイベントです。
        
        tool      : イベントを発生させたツールのインスタンスです。
        eventid   : 発生したイベントID
        p         : ポイントの緯度・経度
   */
   /************************************************************/
    OnToolDblClick : function()
    {
    },
    
    
    /************************************************************/
    /*
         (method) OnPointAdded
         ポイントが追加されたときに発生します。
         
         p : 追加されたkaXmlPointオブジェクト
   */
   /************************************************************/
    OnPointAdded : function(p)
    {
    },
    
    
    /************************************************************/
    /*
         (method) OnPointClick
        点をクリックした時に発生するイベントです。
        
         p : クリックされたkaXmlPointオブジェクト
   */
   /************************************************************/
    OnPointClick : function(p)
    {
    },
    
    
    /************************************************************/
    /*
         (method) OnPointDragStart
         点や多角線・多角形の関節をドラッグしたとき発生するイベントです。
         
         tool : kaXmlPointオブジェクト無いし、Polyline または Polygonオブジェクト
   */
   /************************************************************/
    OnPointDragStart : function(tool)
    {
    },
    
    
    
    /************************************************************/
    /*
         (method) OnPointDrag
         点や多角線・多角形の関節をドラッグ中に発生するイベントです。
         
         tool : kaXmlPointオブジェクト無いし、Polyline または Polygonオブジェクト
   */
   /************************************************************/
    OnPointDrag : function(tool)
    {
    },
    
    
    
    /************************************************************/
    /*
         (method) OnPointDragEnd
         点や多角線・多角形の関節のドラッグが終了したときに、
         発生するイベントです。
         
         tool : kaXmlPointオブジェクト無いし、Polyline または Polygonオブジェクト
   */
   /************************************************************/
    OnPointDragEnd : function(tool)
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnPointMouseOver
        ポイントにマウスが乗った時の処理です。
    */
    /************************************************************/
    OnPointMouseOver : function(p)
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnPointMouseOver
        ポイントからマウスが離れた時の処理です。
    */
    /************************************************************/
    OnPointMouseOut : function(p)
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnCloseBaloon
        バルーン(吹き出し)が閉じられた時発生するイベントです。
    */
    /************************************************************/
    OnCloseBaloon : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnAfterInsertPoint
        多角線・多角形にポイントを追加したときに発生するイベントです。
    */
    /************************************************************/
    OnAfterInsertPoint : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) OnAfterRemovePoint
        多角線・多角形からポイントを削除したときに発生するイベントです。
    */
    /************************************************************/
    OnAfterRemovePoint : function()
    {
    },
    
    /************************************************************/
    /*
        (method) OnToolActive
        ツールのActivateメソッドが呼び出された時実行されます。
    */
    /************************************************************/
    OnToolActive : function()
    {
    },
    
    /************************************************************/
    /*
        (method) OnToolDeactive
        ツールのDeactivateメソッドが呼び出された時実行されます。
    */
    /************************************************************/
    OnToolDeactive : function()
    {
    },
    
    /************************************************************/
    /*
        (method) _OnPointMouseOver
        ポイントにマウスが乗った時の処理です。
    */
    /************************************************************/
    _OnPointMouseOver : function(p, eventid, g)
    {
        if(this.BaloonOpenObject == null) this._AddNameList(p, g);
    },
    
    
    /************************************************************/
    /*
        (method) _OnPointMouseOver
        ポイントからマウスが離れた時の処理です。
    */
    /************************************************************/
    _OnPointMouseOut : function(p, eventid, g)
    {
        this._RemoveNameList(p, g);
    },
    
    
    /************************************************************/
    /*
        (method) _OnToolMouseOver
        ツールからマウスカーソルが離れた時に発生するイベントです。
        本クラスは既定の動作として、ツールを有効(Activate)にします。
    */
    /************************************************************/
    _OnToolMouseOver : function(tool, eventid, p)
    {
        if(this.BaloonOpenObject ==null) this._AddNameList(tool, p);
        if(!this.IsEditable) return;
        if(this.ActiveTool!=null)
        {
            if
            (
                this.ActiveTool.DraggingPointIndex == -1  
                && this.ActiveTool.IsClosed
                && !this.ActiveTool.IsMouseOverPosition
                && !this.ActiveTool.IsPopupMenuOpened
            )
            {
                this.ChangeActiveTool(tool);
            }
        }
        else
        {
            if(this.BaloonOpenObject == null)
            {
               this.ChangeActiveTool(tool);
            }
        }
    },
    

    /************************************************************/
    /*
        (method) _OnToolMouseOut
        ツールからマウスカーソルが離れたときに発生するイベントです。
        本クラスは既定の動作として、ツールを無効(Deactivate)にします。
    */
    /************************************************************/
    _OnToolMouseOut : function(tool)
    {
        this._RemoveNameList(tool);
        if(!this.IsEditable) return;
        if(this.ActiveTool!=null && tool.IsActive)
        {
            if
            (
                this.ActiveTool.DraggingPointIndex == -1
                && this.ActiveTool.IsClosed
                && !this.ActiveTool.IsPopupMenuOpened
            )
            {
                tool.Deactivate(true);
            }
        }
    },
    

    /************************************************************/
    /*
        (method) _OnToolClick
        ツールをクリックした時に発生するイベントです。
        本クラスは既定の動作としてツールを有効(Activate)にします。
    */
    /************************************************************/
    _OnToolClick : function(tool)
    {
        if(!this.IsEditable) return;
        if
        (
            this.ActiveTool != null
            && !tool.IsActive 
            && this.ActiveTool.IsClosed
            && this.BaloonOpenObject == null
        )
        {
            this.ChangeActiveTool(tool);
        }
        else
        {
            if(this.ActiveTool == null)
            {
                this.ChangeActiveTool(tool);
            }
        }
    },
    
    /************************************************************/
    /*
        (method) _OnMapClick
        ポイントモードの時、マップをクリックしたとき実行させる
        ロジックの入れ子です。
    */
    /************************************************************/
    _OnMapClick : function()
    {
    },
    
    
    /************************************************************/
    /*
        (method) IsPoint
        オブジェクトがkaXmlPointオブジェクトかどうかを判定します。
    */
    /************************************************************/
    IsPoint : function(o)
    {
        return o.constructor.toString().match(/^function\skaXmlPoint\(/g) != null;
    },
    
    
    /************************************************************/
    /*
        (method) DisplayNumberBaloon
        オブジェクト番号を表示します。
    */
    /************************************************************/
    DisplayNumberBaloon : function(object, number)
    {
        var pp = (this.IsPoint(object)) ? object : 
                (object.StartPoint) ? object.StartPoint :null;
                
        if(pp == null) return;
        
        var p = ICTMAP.myXmlOverlay.addNewPoint(pp.sid + "___num_baloon___", pp.geox, pp.geoy);
        
        if(p.div)
        {
            var rdiv = document.getElementById(p.div.id + "___baloon___");
            if(rdiv)
            {
                rdiv.parentNode.removeChild(rdiv);
            }
            var div = document.createElement("div");
            div.setAttribute("id", p.div.id + "___baloon___");
            div.style.width = "30px";
            div.style.height = "40px";
            div.style.top = "-38px";
            div.style.left = "-5px";
            div.style.position="absolute";
            
            var self = this;
            div.onclick = function(e)
            {
                if(!self.IsPoint(object))
                {
                    var g = ICTMAP.IctMap.Tools.ToGeometory(e);
                    self.OnToolClick.apply(self, [object, KAMAP_MAP_CLICKED, g]);
                }
                else
                {
                    self.OnPointClick.apply(self, [object]);
                }
            };
            div.style.cursor = "pointer";
            
            
            var img = document.createElement("img");
            img.src =  ICTMAP_URL + "common/images2/number_label.gif";
            img.width = 30;
            img.height = 40;
            
            div.appendChild(img);
            
            div.innerHTML += "<br/>"
            
            /*
            div.style.backgroundImage="url('" + ICTMAP_URL + "common/images2/number_label.gif')";
            div.style.backgroundRepeat = "no-repeat";
            div.style.paddingTop = "3px";
            div.style.paddingLeft = "3px";
            div.style.zIndex = "999";
            */
            
            var cdiv = document.createElement("div");
            cdiv.style.position = "absolute";
            cdiv.style.top = "4px";
            cdiv.style.left = "2px";
            cdiv.style.width = "22px";
            cdiv.style.textAlign = "center";
            cdiv.innerHTML = number;
            div.appendChild(cdiv);
            
            p.div.appendChild(div);
            
            this.NumberBaloonCollection.push(pp.sid + "___num_baloon___");
        }
    },
    
    
    /************************************************************/
    /*
        (method) CloseNumberBaloon
        オブジェクト番号の表示を閉じます。
    */
    /************************************************************/
    CloseNumberBaloon : function(object)
    {
        if(typeof object == "undefined" || arguments.length == 0)
        {
            for(var i=0; i<this.NumberBaloonCollection.length; i++)
            {
                ICTMAP.myXmlOverlay.removePoint("", this.NumberBaloonCollection[i]);
            }
            this.NumberBaloonCollection = [];
        }
        else
        {
            var pp = (this.IsPoint(object)) ? object : 
                    (object.StartPoint) ? object.StartPoint :null;
                    
            if(pp == null) return;
            ICTMAP.myXmlOverlay.removePoint("", pp.sid + "___num_baloon___");
            
            for(var i=0; i<this.NumberBaloonCollection[i].length; i++)
            {
                if(pp.sid + "___num_baloon___" == this.NumberBaloonCollection[i])
                {
                    this.NumberBaloonCollection.splice(i, 1);
                    break;
                }
            }
        }
    },
    
    
    /************************************************************/
    /*
        (private method) _AddNameList
        名前リストを作成しレイヤーを表示します。
    */
    /************************************************************/
    _AddNameList : function(o, geom)
    {
        var p = (this.IsPoint(o)) ? o : o.StartPoint;
        var name = (this.IsPoint(o)) ? o.pointName : o.Name;
        
        var suffix = "__title_link";
        var nameList = getRawObject("namelist");
        
        var self = this;
        
        
        if(!this.IsPoint(o))
        {
            var left = parseInt(nameList.style.left.replace("px"));
            var top  = parseInt(nameList.style.top.replace("px"));
            
            left = (isNaN(left)) ? 0 : left;
            top  = (isNaN(top))  ? 0 : top;
            
            left += ICTMAP.xOrigin;
            top  += ICTMAP.yOrigin;
            
            var geo = ICTMAP.pixToGeo(left, top);
            var offsetPoint = ICTMAP.IctMap.Tools.ToCanvasOffset(o, geo);
            
            var overpoint = (o.ClassName == "IctMap.Tools.Polyline") ? offsetPoint : geo;
            if(!o.IsMouseOver(overpoint))
            {
                var pixes = ICTMAP.geoToPix(geom.x, geom.y);
                left = (pixes[0] - ICTMAP.xOrigin);
                top  = (pixes[1] - ICTMAP.yOrigin);
                
                nameList.style.left = left + "px";
                nameList.style.top = top + "px";
                
                this._RemoveNameObjects();
                
                o.StartPoint.div.canvas.appendChild(nameList);
            }
        }
        else
        {
            var s_left = parseInt(nameList.style.left.replace("px"));
            var s_top  = parseInt(nameList.style.top.replace("px"));
            var d_left = parseInt(o.div.offsetLeft);
            var d_top  = parseInt(o.div.offsetTop);
            
            s_left = (isNaN(s_left)) ? 0 : s_left;
            s_top  = (isNaN(s_top))  ? 0 : s_top;
            
            if(Math.abs(s_left - d_left) > 2 && Math.abs(s_top - d_top) > 2)
            {
                nameList.style.left = o.div.offsetLeft + "px";
                nameList.style.top  = o.div.offsetTop  + "px";
                
                this._RemoveNameObjects();
            }
            o.div.canvas.appendChild(nameList);
        }
        
        
        if(nameList.style.display == "none")
        {
            nameList.innerHTML = "";
            nameList.style.display = "block";
        }
        var a = $(p.sid + suffix);
        if(typeof a == "undefined" || a == null)
        {
            a = document.createElement("a");
            a.setAttribute("id", p.sid + suffix);
            a.href = "#";
            
            var callback = (this.IsPoint(o)) ? this.OnPointClick : this.OnToolClick;
            var g = {x:p.geox, y:p.geoy};
            
            a.onclick = function()
            {
                clearOverlaysymbolhtml();
                callback.apply(self, [o, KAMAP_MAP_CLICKED, g]);
                return false;
            };
            
            if(name)
            {
                a.innerHTML = name;
                nameList.appendChild(a);
            }
        }
    },
    
    
    /************************************************************/
    /*
        (private method) _RemoveNameList
        名前リストからの削除予約を行います。
        削除は、レイヤー位置が変更になったときに実行されます。
    */
    /************************************************************/
    _RemoveNameList : function(o)
    {
        var p = (this.IsPoint(o)) ? o : o.StartPoint;
        var suffix = "__title_link";
        var a = $(p.sid + suffix);
        this._RemoveNameObjectsList.push(a);
    },
    
    
    
    /************************************************************/
    /*
        (private method) _RemoveNameObjects
        名前リストから削除予約された名前を削除します。
    */
    /************************************************************/
    _RemoveNameObjects : function()
    {
        var nameList = getRawObject("namelist");
        for(var i=0; i<this._RemoveNameObjectsList.length; i++)
        {
            try
            {
                nameList.removeChild(this._RemoveNameObjectsList[i]);
            }
            catch(e)
            {
            }
        }
        this._RemoveNameObjectsList = [];
    },
    
    
    /************************************************************/
    /*
        (private method) _RemoveNameObjectsList
        名前リストから削除するオブジェクトの配列です。
    */
    /************************************************************/
    _RemoveNameObjectsList : []
};


if(typeof $ == "undefined") $ = function(id){ return document.getElementById(id)};
/*
    Added on 2011.06.20 | Clicking on an hyperlink -> display Small Window
*/
function markerClickPoint(pt1,pt2){
    if(typeof google != "undefined"){
		if(google.maps){
	        ICTMAP.points.each(function(pt){
	          if(pt.pointid==ICTMAP.USERPOINT_PREFIX+pt1+"-"+pt2){
	            google.maps.event.trigger(pt,'click');
	          }
	          $break;
	        });
	     }
	     else
		 {
	        var tgtDiv='xmlovr_user_'+pt1+'-'+pt2+'_div';
	        $(tgtDiv).firstChild.onclick();
	     }
	 }else{
	        var tgtDiv='xmlovr_user_'+pt1+'-'+pt2+'_div';
	        $(tgtDiv).firstChild.onclick();
	 }
 } 
 var charset="";
/* ***********************************************************
Example 4-3 (DHTMLapi.js)
"Dynamic HTML:The Definitive Reference"
2nd Edition
by Danny Goodman
Published by O'Reilly & Associates  ISBN 1-56592-494-0
http://www.oreilly.com
Copyright 2002 Danny Goodman.  All Rights Reserved.
************************************************************ */
// DHTMLapi.js custom API for cross-platform
// object positioning by Danny Goodman (http://www.dannyg.com).
// Release 2.0. Supports NN4, IE, and W3C DOMs.

// Global variables
var isCSS, isW3C, isIE4, isNN4, isIE6CSS, isFIREFOX;
// initialize upon load to let all browsers establish content objects
function initDHTMLAPI() {
    if (document.images) {
        isCSS = (document.body && document.body.style) ? true : false;
        isW3C = (isCSS && document.getElementById) ? true : false;
        isIE4 = (isCSS && document.all) ? true : false;
        isNN4 = (document.layers) ? true : false;
        isIE6CSS = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
		isFIREFOX = (navigator.userAgent.match(/Firefox/)) ? true : false;
    }
}
// set event handler to initialize API
//window.onload = initDHTMLAPI;

// Seek nested NN4 layer from string name
function seekLayer(doc, name) {
    var theObj;
    for (var i = 0; i < doc.layers.length; i++) {
        if (doc.layers[i].name == name) {
            theObj = doc.layers[i];
            break;
        }
        // dive into nested layers if necessary
        if (doc.layers[i].document.layers.length > 0) {
            theObj = seekLayer(document.layers[i].document, name);
        }
    }
    return theObj;
}

// Convert object name string or object reference
// into a valid element object reference
function getRawObject(obj) {
    var theObj;
    if (typeof obj == "string") {
        if (isW3C) {
            theObj = document.getElementById(obj);
        } else if (isIE4) {
            theObj = document.all(obj);
        } else if (isNN4) {
            theObj = seekLayer(document, obj);
        }
    } else {
        // pass through object reference
        theObj = obj;
    }
    return theObj;
}

// Convert object name string or object reference
// into a valid style (or NN4 layer) reference
function getObject(obj) {
    var theObj = getRawObject(obj);
    if (theObj && isCSS) {
        theObj = theObj.style;
    }
    return theObj;
}

// Position an object at a specific pixel coordinate
function shiftTo(obj, x, y) {
    var theObj = getObject(obj);
    if (theObj) {
        if (isCSS) {
            // equalize incorrect numeric value type
            var units = (typeof theObj.left == "string") ? "px" : 0;
            theObj.left = x + units;
            theObj.top = y + units;
        } else if (isNN4) {
            theObj.moveTo(x,y)
        }
    }
}

// Move an object by x and/or y pixels
function shiftBy(obj, deltaX, deltaY) {
    var theObj = getObject(obj);
    if (theObj) {
        if (isCSS) {
            // equalize incorrect numeric value type
            var units = (typeof theObj.left == "string") ? "px" : 0;
            theObj.left = getObjectLeft(obj) + deltaX + units;
            theObj.top = getObjectTop(obj) + deltaY + units;
        } else if (isNN4) {
            theObj.moveBy(deltaX, deltaY);
        }
    }
}

// Set the z-order of an object
function setZIndex(obj, zOrder) {
    var theObj = getObject(obj);
    if (theObj) {
        theObj.zIndex = zOrder;
    }
}

// Set the background color of an object
function setBGColor(obj, color) {
    var theObj = getObject(obj);
    if (theObj) {
        if (isNN4) {
            theObj.bgColor = color;
        } else if (isCSS) {
            theObj.backgroundColor = color;
        }
    }
}

// Set the visibility of an object to visible
function show(obj) {
    var theObj = getObject(obj);
    if (theObj) {
        theObj.visibility = "visible";
    }
}

// Set the visibility of an object to hidden
function hide(obj) {
    var theObj = getObject(obj);
    if (theObj) {
        theObj.visibility = "hidden";
    }
}

// Retrieve the x coordinate of a positionable object
function getObjectLeft(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (document.defaultView) {
        var style = document.defaultView;
        var cssDecl = style.getComputedStyle(elem, "");
        result = cssDecl.getPropertyValue("left");
    } else if (elem.currentStyle) {
        result = elem.currentStyle.left;
    } else if (elem.style) {
        result = elem.style.left;
    } else if (isNN4) {
        result = elem.left;
    }
    return parseInt(result);
}

// Retrieve the y coordinate of a positionable object
function getObjectTop(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (document.defaultView) {
        var style = document.defaultView;
        var cssDecl = style.getComputedStyle(elem, "");
        result = cssDecl.getPropertyValue("top");
    } else if (elem.currentStyle) {
        result = elem.currentStyle.top;
    } else if (elem.style) {
        result = elem.style.top;
    } else if (isNN4) {
        result = elem.top;
    }
    return parseInt(result);
}

// Retrieve the rendered width of an element
function getObjectWidth(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (elem.offsetWidth) {
        result = elem.offsetWidth;
    } else if (elem.clip && elem.clip.width) {
        result = elem.clip.width;
    } else if (elem.style && elem.style.pixelWidth) {
        result = elem.style.pixelWidth;
    }
    return parseInt(result);
}

// Retrieve the rendered height of an element
function getObjectHeight(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (elem.offsetHeight) {
        result = elem.offsetHeight;
    } else if (elem.clip && elem.clip.height) {
        result = elem.clip.height;
    } else if (elem.style && elem.style.pixelHeight) {
        result = elem.style.pixelHeight;
    }
    return parseInt(result);
}


// Return the available content width space in browser window
function getInsideWindowWidth() {
    if (window.innerWidth) {
        return window.innerWidth;
    } else if (isIE6CSS) {
        // measure the html element's clientWidth
        return document.body.parentElement.clientWidth;
    } else if (document.body && document.body.clientWidth) {
        return document.body.clientWidth;
    }
    return 0;
}
// Return the available content height space in browser window
function getInsideWindowHeight() {
    if (window.innerHeight) {
        return window.innerHeight;
    } else if (isIE6CSS) {
        // measure the html element's clientHeight
        return document.body.parentElement.clientHeight;
    } else if (document.body && document.body.clientHeight) {
        return document.body.clientHeight;
    }
    return 0;
}

var charset="";
/**********************************************************************
 *
 * $Id: xhr.js,v 1.8 2006/02/07 03:19:55 pspencer Exp $
 *
 * purpose: a simple cross-browser XmlHttpRequest interface that adds
 *          support for multiple, concurrent requests
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 * TODO:
 *   - reponse only contains responseText, should contain response so
 *     access to reponseXML is possible if we ever want to implement
 *     xml stuff (i.e. real AJAX)
 * 
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/* to make an asynchronous call to the server, execute the call() function
 * with the URL to the script to be executed.  The second and third
 * parameters to call() define object and method to call when the server
 * returns its response ... if the second parameter is null, third is
 * just a function.  If second is an object, then the third is a method
 * of that instance.
 *
 * There is an optional fourth parameter to issue the request as a POST
 * to the server.  This is important in some browsers due to limited 
 * URL length.
 * 
 * The callback function is called when the request completes.  There is
 * currently no callback for errors so they just silently fail if the
 * server side script dies.  The callback function is passed a single
 * parameter, the text output of the server side script.  In ka-Map, this
 * text is typically some javascript to eval().
 */
var aXmlHttp = new Array();
var aXmlResponse = new Array();
function xmlResult()
{
    for(var i=0;i<aXmlHttp.length;i++)
    {
        if(aXmlHttp[i] && aXmlHttp[i][0] && aXmlHttp[i][0].readyState==4&&aXmlHttp[i][0].responseText)
        {
            //must null out record before calling function in case
            //function invokes another xmlHttpRequest.
            var f = aXmlHttp[i][2];
            var o = aXmlHttp[i][1];
            var s = aXmlHttp[i][0].responseText;
            aXmlHttp[i][0] = null;
            aXmlHttp[i][1] = null;
            aXmlHttp[i] = null;
            f.apply(o,new Array(s));
        }
    }
}

// u -> url
// o -> object (can be null) to invoke function on
// f -> callback function
// p -> optional argument to specify POST
function call(u,o,f)
{
    var method = "GET";
    var dat;
    if (arguments.length==4){
      method = "POST";
      tmp = u.split(/\?/);
      u = tmp[0];
      dat = tmp[1];

    }
    var idx = aXmlHttp.length;
    for(var i=0; i<idx;i++)
    if (aXmlHttp[i] == null)
    {
        idx = i;
        break;
    }
    aXmlHttp[idx]=new Array(2);
    aXmlHttp[idx][0] = getXMLHTTP();

    aXmlHttp[idx][1] = o;
    aXmlHttp[idx][2] = f;
    if(aXmlHttp[idx])
    {
        aXmlHttp[idx][0].open(method,u,true);
        if(method == "POST"){
          aXmlHttp[idx][0].setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

          aXmlHttp[idx][0].send(dat);
        }
        aXmlHttp[idx][0].onreadystatechange=xmlResult;
        
       if(method =="GET"){ aXmlHttp[idx][0].send(null);}
    }
}

function getXMLHTTP()
{
    var A=null;
    if(!A && typeof XMLHttpRequest != "undefined")
    {
        A=new XMLHttpRequest();
    }
    if (!A)
    {
        try
        {
            A=new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch(e)
        {
            try
            {
                A=new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(oc)
            {
                A=null
            }
        }
    }    
    return A;
}var charset="";
/**********************************************************************
 *
 * $Id: kaLegend.js,v 1.37 2006/10/25 01:48:05 pspencer Exp $
 *
 * purpose: a structured legend that supports grouped layers, visibility, 
 *          expand/collapse, and queryability
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 * The original kaLegend code was written by DM Solutions Group.  Lorenzo
 * Becchi and Andrea Cappugi contributed a bunch of code too!
 *
 * TODO:
 * 
 *   - drag and drop layer re-ordering would be nice, see script.alicio.us
 *
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************
 *
 * To use kaLegend:
 * 
 * 1) add a script tag to your page:
 * 
 * <script type="text/javascript" src="kaLegend.js"></script>
 *
 * 2) add a <div> element to your page to contain the legend.  The div must
 *    have a unique id:
 *
 * <div id="legend"></div>
 * 
 * 3) create a new instance of kaLegend and pass it the id of the div:
 * 
 * myKaLegend = new kaLegend( 'legend' );
 *
 * and that's it :)
 * 
 *****************************************************************************/

/******************************************************************************
 * kaLegend
 * 
 * internal class to handle the legend.
 * 
 * oKaMap - the ka-Map object to attach to.
 * szID - string, the id of a div that will contain the legend
 * bStatic - boolean, true to use static legends, false to use dynamic legends
 *
 *****************************************************************************/
function kaLegend(oKaMap, szID, bStatic, options) {
    this.kaMap = oKaMap;
    this.domObj = this.kaMap.getRawObject(szID);
    this.type = (bStatic)?'static':'dynamic';
    this.expanders = [];
    this.queryCBs = [];

    this.urlBase = this.kaMap.server;
    this.urlBase += (this.urlBase!=''&&this.urlBase.substring(-1)!='/')?'':'/';

    this.showQueryCBs = true;    

    if (this.type == 'static') {
        this.domImg = document.createElement( 'img' );
        this.domImg.src = this.kaMap.aPixel.src;
        this.domObj.appendChild( this.domImg );
    } else {
        this.domObj.innerHTML = '&nbsp;';
    }
    this.showVisibilityControl = true;
    this.showQueryControl = true;
    this.showOpacityControl = true;
    this.showOrderControl = true;
    
    if (typeof options != 'undefined') {
        this.showVisibilityControl = typeof options.visibility != 'undefined' ? options.visibility : true;
        this.showQueryControl = typeof options.query != 'undefined' ? options.query : true;
        this.showOpacityControl = typeof options.opacity != 'undefined' ? options.opacity : true;
        this.showOrderControl = typeof options.order != 'undefined' ? options.order : true;
    }

    this.kaMap.registerForEvent( KAMAP_SCALE_CHANGED, this, this.update );
    this.kaMap.registerForEvent( KAMAP_MAP_INITIALIZED, this, this.update );
    this.kaMap.registerForEvent( KAMAP_LAYERS_CHANGED, this, this.draw );
    this.kaMap.registerForEvent( KAMAP_LAYER_STATUS_CHANGED, this, this.update );
};

kaLegend.prototype.update = function(eventID)
{
    var url = '';
    if (this.type == 'static') {
        var newImg = document.createElement('img');
        newImg.src = 'legend.phtml?map=' + this.kaMap.currentMap + '&scale='+this.kaMap.getCurrentScale();
        this.domObj.replaceChild(newImg, this.domImg);
        this.domImg = newImg;
    } else {
        if (eventID == KAMAP_MAP_INITIALIZED) {
            while(this.domObj.childNodes.length > 0) {
                this.domObj.removeChild(this.domObj.childNodes[0]);
            } this.draw();
                
        } else if (eventID == KAMAP_SCALE_CHANGED) {
            var oMap = this.kaMap.getCurrentMap();
            var aLayers = oMap.getAllLayers();
            var s = this.kaMap.getCurrentScale();
            for (var i in aLayers) {
                var oLayer = aLayers[i];
                var oImg = this.kaMap.getRawObject( 'legendImg_' + oLayer.name);
                
                if (oImg) {
                    //added by Lorenzo
                    var oParent = oImg.parentNode; 
                    var tId = oImg.id;
                    var tVisibility = oImg.visibility;
                    oParent.removeChild(oImg);
                    oImg = document.createElement('img');
                    oImg.id = tId;
                    oImg.title = tId;
                    oImg.visibility = tVisibility;
                    oImg.src = 'legend.phtml?map=' + 
                               this.kaMap.currentMap + '&scale=' + s + '&g=' + 
                               oLayer.name;
                    oParent.appendChild(oImg);
					/*
                    expander = getRawObject('expander_'+oLayer.name);
                    expander.expandable = oImg;
                    expander.expanded = true;
                    kaLegend_expander.apply( expander );
					*/
                }
                //added by cappu
                this.setOnOffLayer(oLayer);
            }
        } else if (eventID == KAMAP_LAYER_STATUS_CHANGED) {
			var layer = arguments[1];
			for (var i=0; i<this.queryCBs.length; i++) {
				if (this.queryCBs[i].oLayer == layer) {
					this.queryCBs[i].checked = layer.visible;
				}
			}
		}
    }
};

/**
 * legend.draw( szContents )
 *
 * render the contents of a legend template into a div
 */
kaLegend.prototype.draw = function() {
/*modificato da kappu non trova url corretto se non lo metto anche qui*/
    this.urlBase = this.kaMap.server;
    this.urlBase += (this.urlBase!=''&&this.urlBase.substring(-1)!='/')?'':'/';

    var oMap = this.kaMap.getCurrentMap();

    this.expanders = [];
    this.queryCBs = [];

    //if (this.domObj.childNodes.length == 0) {
    //    this.domObj.appendChild(this.createHeaderHTML());
    //}

    var aLayers = oMap.getAllLayers();
    for (var i=(aLayers.length-1);i>=0;i--) {
        if (aLayers[i].kaLegendObj == null) {
				this.createLayerHTML( aLayers[i] );
        } else {
            try{this.domObj.removeChild( aLayers[i].kaLegendObj );}
            catch(e){};
        }
    }

    for (var i=(aLayers.length-1);i>=0;i--) {
        this.domObj.appendChild( aLayers[i].kaLegendObj );
    }

    if (this.kaMap.isIE4) {
        for(var i=0; i<this.queryCBs.length; i++) {
            this.queryCBs[i].checked = this.queryCBs[i].oLayer.visible;
        }
    }
    return;
};

kaLegend.prototype.createHeaderHTML = function() {
    var d, t, tb, tr, td, img;

    d = document.createElement( 'div' );
    d.className = 'kaLegendTitle';
	
	t = document.createElement( 'table' );

    t.setAttribute('width','226px');
    t.setAttribute('cellPadding', "0");
    t.setAttribute('cellSpacing', "0");
    t.setAttribute('border', "0");

    tb = document.createElement( "tbody" );

    tr = document.createElement( 'tr' );

    td = document.createElement( 'td' );
    td.style.width='26px';
    img = document.createElement( 'img' );
    img.src = 'common/images2/expand.png';
    img.alt = 'expand all';
    img.title = 'expand all';
    img.kaLegend = this;
    img.onclick = kaLegend_expandAll;
    td.appendChild( img );
    
    img = document.createElement( 'img' );
    img.src = 'common/images2/collapse.png';
    img.alt = 'collapse all';
    img.title = 'collapse all';
    img.kaLegend = this;
    img.onclick = kaLegend_collapseAll;
    td.appendChild( img );
    
    tr.appendChild( td );

    td = document.createElement( 'td' );
    td.appendChild(document.createTextNode( 'Layers' ));

    tr.appendChild( td );
    tb.appendChild(tr);
    t.appendChild(tb);
    d.appendChild(t);
    return d;
};

kaLegend.prototype.createLayerHTML = function( oLayer ) {
    var d, t, tb, tr, td, expander, cb, img, name;

    d = document.createElement( 'div' );
    d.id = 'group_' + oLayer.name;
    d.className = "kaLegendLayer";
    d.oLayer=oLayer;
	
	//if(oLayer.visibilityContorol == 0){	// sakai
		d.style.visibility = "hidden";
	//}
	
    name = oLayer.name;
    if (name == '__base__') {
        name = 'Base';
    }

    t = document.createElement('table');
    t.setAttribute('width','190');
    t.setAttribute('cellPadding', "0");
    t.setAttribute('cellSpacing', "0");
    t.setAttribute('border', "0");

    tb = document.createElement( 'tbody' );
    tr = document.createElement('tr');
	
	/*
    td = document.createElement('td');
    td.setAttribute( "width", "9");
    expander = document.createElement( 'img' );
    expander.src = 'common/images2/collapse.png';
    expander.layerName = oLayer.name;
    expander.id = 'expander_'+oLayer.name;
    expander.onclick = kaLegend_expander;
    expander.expanded = true;
    this.expanders.push( expander );
    td.appendChild( expander );
    tr.appendChild(td);
	*/
    
    // layer visibility checkboxes
    // TODO: convert to images
    if (this.showVisibilityControl) {
        td = document.createElement('td');
        td.width = '22';
        if (oLayer.name != '__base__') {
            cb = document.createElement( 'input' );
            cb.type = 'checkbox';
            cb.name = 'layerVisCB';
            cb.value = oLayer.name;
            cb.checked = oLayer.visible;
            cb.kaLegend = this;
            cb.oLayer = oLayer;
            cb.onclick = kaLegend_toggleLayerVisibility;
            this.queryCBs.push(cb);
            td.appendChild( cb );
        }
        else {
            td.innerHTML = '&nbsp;';
        }
        tr.appendChild(td);
    }
	
	var oMap = this.kaMap.getCurrentMap();
    var aLayers = oMap.getAllLayers();
	
	//Choose if you want base element to be movable (comment on line or the other)
	//not movable
    //if (oLayer.name != '__base__')
	// movable	 
    if (aLayers.length > 1) {
        //OPACITY IMAGES
        if (this.showOpacityControl) {
            td = document.createElement('td');
            td.width = '19';
            img = document.createElement( 'img' );
            img.src = 'common/images2/sun_white.png';
            img.width = '7';
            img.alt = "Decrease layer opacity";
            img.title = "Decrease layer opacity";
            img.style.cursor ='crosshair';
            img.kaLegend = this;
            img.oLayer = oLayer;
            img.onclick = kaLegend_opacityDown;
            td.appendChild( img );
            img = document.createElement( 'img' );
            img.src = 'common/images2/sun_grey.png';
            img.width = '7';
            img.style.marginLeft = '2px';
            img.alt = "Increase layer opacity";
            img.title = "Increase layer opacity";
            img.style.cursor ='crosshair';
            img.kaLegend = this;
            img.oLayer = oLayer;
            img.onclick = kaLegend_opacityUp;
            td.appendChild( img );
            tr.appendChild(td);
        }
        if (this.showOrderControl) {
            //SHIFT LAYERS UP DOWN
            td = document.createElement('td');
            td.width = '10';
            td.style.padding = '1px';
            img = document.createElement( 'img' );
            img.src = 'common/images2/arrow_up.png';
            img.width = '10';
            img.height = '8';
            img.style.marginBottom = '2px';
            img.alt = "Shift Layer Up";
            img.title = "Shift Layer Up";
            img.style.cursor ='crosshair';
            img.kaLegend = this;
            img.oLayer = oLayer;
            img.myDiv = d;
            img.onclick = kaLegend_moveLayerUp;
            td.appendChild( img );
        
            img = document.createElement( 'img' );
            img.src = 'common/images2/arrow_down.png';
            img.width = '10';
            img.height = '8';
            img.alt = "Shift Layer Down";
            img.title = "Shift Layer Down";
            img.style.cursor ='crosshair';
            img.kaLegend = this;
            img.oLayer = oLayer;
            img.myDiv = d;
            img.onclick = kaLegend_moveLayerDown;
            td.appendChild( img );
        
            tr.appendChild(td);
        }
    }

    if (this.showQueryControl) {
        //layer queryable images
        td = document.createElement('td');
        td.width = '14';
    
        img = document.createElement( 'img' );
        img.width = '14';
        img.height = '14';
        if (oLayer.queryable) {
            if (oLayer.isQueryable()) {
                img.src = 'common/images2/icon_query_on.png';
            } else {
                img.src = 'common/images2/icon_query_off.png';
            }
            img.onmouseover = kaLegend_queryOnMouseOver;
            img.onmouseout = kaLegend_queryOnMouseOut;
            img.onclick = kaLegend_queryOnClick;
            img.oLayer = oLayer;
        } else {
            img.src = 'common/images2/icon_query_x.png';
        }
        
        td = document.createElement( 'td' );
        td.appendChild(img);
        td.width = '16';
        tr.appendChild(td);
    }
    td = document.createElement( 'td' );
    td.innerHTML = oLayer.name2;
    tr.appendChild(td);
	
    tb.appendChild(tr);
    
    t.appendChild( tb );
    d.appendChild(t);
    
    //img = document.createElement( 'img' );
    //img.id = 'legendImg_' + oLayer.name;
    //img.src = this.urlBase +  'legend.phtml?map='+this.kaMap.currentMap+'&scale='+this.kaMap.getCurrentScale()+'&g='+oLayer.name;
	/*modificato da kappu, nel cvs dimentica di aggiungere immagine */ 
	//d.appendChild(img);
    //expander.expandable = img;	sakai
    oLayer.kaLegendObj = d;
    //kaLegend_expander.apply( expander );	sakai
	//adedd by cappu
	this.setOnOffLayer(oLayer,oLayer.isVisible);  //prototype.jsを入れたらエラーになるのでコメントアウト
};

function kaLegend_toggleLayerQueryable() {
    this.kaLegend.kaMap.setLayerQueryable( this.value, this.checked );
};

function kaLegend_queryOnMouseOver() {
    if (this.oLayer.queryable) {
        this.src = 'common/images2/icon_query_over.png';
    }
};

function kaLegend_queryOnMouseOut() {
    if (this.oLayer.queryable) {
        if (this.oLayer.isQueryable()) {
            this.src = 'common/images2/icon_query_on.png';
        } else {
            this.src = 'common/images2/icon_query_off.png';
        }
    }
};

function kaLegend_queryOnClick() {
    if (this.oLayer.queryable) {
        if (this.oLayer.isQueryable()) {
            this.oLayer.setQueryable( false );
            this.src = 'common/images2/icon_query_off.png';
        } else {
            this.oLayer.setQueryable( true );
            this.src = 'common/images2/icon_query_on.png';
        }
    }
};

function kaLegend_toggleLayerVisibility() {
    this.kaLegend.kaMap.setLayerVisibility( this.value, this.checked );
}

function kaLegend_expander() {
    this.expanded = !this.expanded;
    
    this.src = (this.expanded)?'common/images2/collapse.png':'common/images2/expand.png';
    this.expandable.style.display = (this.expanded)?'block':'none';
};

function kaLegend_expandAll() {
    var kaLeg = this.kaLegend;
    for (var i=0; i<kaLeg.expanders.length; i++) {
        kaLeg.expanders[i].expanded = false;
        kaLegend_expander.apply( kaLeg.expanders[i] );
    }
};

function kaLegend_collapseAll() {
    var kaLeg = this.kaLegend;
    if (kaLeg.expanders) {
        for (var i=0; i<kaLeg.expanders.length; i++) {
            kaLeg.expanders[i].expanded = true;
            kaLegend_expander.apply( kaLeg.expanders[i] );
        }
    }
};


function kaLegend_opacityDown() {
    var opc;
    opc=this.oLayer.opacity-10;
    this.kaLegend.kaMap.setLayerOpacity(this.oLayer.name, opc );  
};

function kaLegend_opacityUp() {    
    var opc;
    opc=this.oLayer.opacity+10;
    this.kaLegend.kaMap.setLayerOpacity(this.oLayer.name, opc );
};

/*added by cappu used to hide layer not visible at current scala*/
kaLegend.prototype.setOnOffLayer = function(l) {
    /*if (l.isVisible()) {	  //prototype.jsを入れたらエラーになるのでコメントアウト
        if (l.kaLegendObj) {
            l.kaLegendObj.style.display='block';        
        } 
    } else {
        if(l.kaLegendObj) {
            l.kaLegendObj.style.display='none';
        }
    }*/
};

/**
* kaLegend_moveLayerDown 
* About a specific Group of layer, it moves the corresponding Legend div and 
*  the Viewport div to the next one
* @private 
* @author Lorenzo Becchi
*/

function kaLegend_moveLayerDown() {
    var myLayer= this.oLayer;
    var leg=this.myDiv.parentNode;
    var myDiv = this.myDiv;
    var lowerDiv = findLowerDiv(myDiv);
    
    if(lowerDiv && lowerDiv.className=='kaLegendLayer') {
        //search correspondant checbox to prevent IE uncheck on move bug
        var aCheckbox = document.getElementsByTagName('input');
        var checkboxStatusUp=null;
        var checkboxStatusDown=null;
        var checkboxUp=null;
        var checkboxDown=null;
        for(var i=0;i<aCheckbox.length;i++) {
            var inputTag = aCheckbox[i];
            if(inputTag.value == myDiv.id.replace(/\bgroup_/, '')) {
                checkboxUp = inputTag;
                checkboxStatusUp = checkboxUp.checked;
            }
            if(inputTag.value == lowerDiv.id.replace(/\bgroup_/, '')) {
                checkboxDown =inputTag;
                checkboxStatusDown = inputTag.checked;
            }
        }
        
        // move legend group div  (need to do it two allow hidden layers syncing)
        var proxyMy = myDiv.cloneNode(true);
        var proxyLower = lowerDiv.cloneNode(true);
        myDiv.parentNode.insertBefore( proxyMy , myDiv );
        myDiv.parentNode.insertBefore( proxyLower , lowerDiv );
        myDiv.parentNode.replaceChild( lowerDiv , proxyMy );
        myDiv.parentNode.replaceChild( myDiv , proxyLower );
        
        //confirm checbox status to prevent IE uncheck on move bug
        if(checkboxUp)checkboxUp.checked = checkboxStatusUp;
        if(checkboxDown)checkboxDown.checked = checkboxStatusDown;
	
		//added by cappu,set zindex order of div layer in vieport
		for  (i=0,n=leg.childNodes.length;i< leg.childNodes.length;i++) {
			var child= leg.childNodes[i];
			if(child && child.className=='kaLegendLayer') {
				child.oLayer.zIndex=(n);
				n--;
			}
		}
		
		//call function to redrow
		this.kaLegend.kaMap.setMapLayers();
    } else {
        alert('this layer can\'t go farther down');
    } 
};

/**
 * kaLegend_moveLayerUp
 * About a specific Group of layer, it moves the corresponding Legend div and 
 * the  Viewport div to the previous one
 * @private 
 * @author Lorenzo Becchi
 */
function kaLegend_moveLayerUp() {
    var myLayer= this.oLayer;
    var leg=this.myDiv.parentNode;
    var myDiv = this.myDiv;
    var upperDiv = findUpperDiv(myDiv);
    
     if(upperDiv && upperDiv.className=='kaLegendLayer') {
        //search correspondant checbox to prevent IE uncheck on move bug
        var aCheckbox = document.getElementsByTagName('input');
        var checkboxStatusUp=null;
        var checkboxStatusDown=null;
        var checkboxUp=null;
        var checkboxDown=null;
        for(var i=0;i<aCheckbox.length;i++) {
            var inputTag = aCheckbox[i];
            if(inputTag.value == upperDiv.id.replace(/\bgroup_/, '')) {
                checkboxUp = inputTag;
                checkboxStatusUp = checkboxUp.checked;
            }
            if(inputTag.value == myDiv.id.replace(/\bgroup_/, '')) {
                checkboxDown =inputTag;
                checkboxStatusDown = inputTag.checked;
            }
        }
        
        // switch legend groups div (need to do it two allow hidden layers syncing)
        var proxyMy = myDiv.cloneNode(true);
        var proxyUpper = upperDiv.cloneNode(true);      
        myDiv.parentNode.insertBefore( proxyMy , myDiv );
        myDiv.parentNode.insertBefore( proxyUpper , upperDiv );
        myDiv.parentNode.replaceChild( upperDiv , proxyMy );
        myDiv.parentNode.replaceChild( myDiv , proxyUpper );
        
        //confirm checbox status to prevent IE uncheck on move bug
        if(checkboxUp)checkboxUp.checked = checkboxStatusUp;
        if(checkboxDown)checkboxDown.checked = checkboxStatusDown;
		
		//added by cappu,set zindex order of div layer in vieport
		for  (i=0,n=leg.childNodes.length;i< leg.childNodes.length;i++) {
		    var child= leg.childNodes[i];
		    if(child && child.className=='kaLegendLayer') {
				child.oLayer.zIndex=(n);
				n--;
			}
		}
		//call function to redrow
		this.kaLegend.kaMap.setMapLayers();
    } else {
        alert('this layer can\'t go farther up');
    }
};

/**
* findLowerDiv
* find recursively nextSibling in legend list
* @private 
* @author Lorenzo Becchi
*/
function findLowerDiv(div) {
	lDiv = div.nextSibling;
	if(lDiv && lDiv.className=='kaLegendLayer' && lDiv.style.display=='none') {
		findLowerDiv(lDiv);
	}
	return lDiv;
};
/**
* findUpperDiv
* find recursively previousSibling in legend list
* @private 
* @author Lorenzo Becchi
*/
function findUpperDiv(div){
	uDiv = div.previousSibling;
	if(uDiv && uDiv.className=='kaLegendLayer' && uDiv.style.display=='none'){
		findUpperDiv(uDiv);
	}
	return uDiv;
}var charset="";
/**********************************************************************
 *
 * $Id: kaMap.js,v 1.99 2006/11/13 18:34:16 pspencer Exp $
 *
 * purpose: core engine for implementing a tiled, continuous pan mapping
 *          engine.
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 * The original kaMap code was written by DM Solutions Group.
 * bug fixes contributed by Lorenzo Becchi and Andrea Cappugi
 * max_extents support by Tim Schaub
 *
 * TODO:
 *
 *   - convert to prototype
 *   - code refactoring for simplification/speed
 *   - code refactoring
 *
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/**
 * kaMap! events
 */
var gnLastEventId = 0;
var KAMAP_ERROR = gnLastEventId ++;
var KAMAP_WARNING = gnLastEventId ++;
var KAMAP_NOTICE = gnLastEventId++;
var KAMAP_INITIALIZED = gnLastEventId ++;
var KAMAP_MAP_INITIALIZED = gnLastEventId ++;
var KAMAP_EXTENTS_CHANGED = gnLastEventId ++;
var KAMAP_SCALE_CHANGED = gnLastEventId ++;
var KAMAP_LAYERS_CHANGED = gnLastEventId ++;
var KAMAP_LAYER_STATUS_CHANGED = gnLastEventId ++;
var KAMAP_CONTEXT_MENU = gnLastEventId ++;
var KAMAP_METAEXTENTS_CHANGED = gnLastEventId++;
var KAMAP_MAP_CLICKED = gnLastEventId++;

/******************************************************************************
 * kaMap main class
 *
 * construct a new kaMap instance.  Pass the id of the div to put the kaMap in
 *
 * this class is the main API for any application.  Only use the functions
 * provided by this API to ensure everything functions correctly
 *
 * szID - string, the id of a div to put the kaMap! into
 *
 *****************************************************************************/


function kaMap( szID ,initFile,initSettings) {
    this.isCSS = false;
    this.isW3C = false;
    this.isIE4 = false;
    this.isNN4 = false;
    this.isIE6CSS = false;

    if (document.images) {
        this.isCSS = (document.body && document.body.style) ? true : false;
        this.isW3C = (this.isCSS && document.getElementById) ? true : false;
        this.isIE4 = (this.isCSS && document.all) ? true : false;
        this.isNN4 = (document.layers) ? true : false;
        this.isIE6CSS = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
    }

    this.domObj = this.getRawObject( szID );
    this.domObj.style.overflow = 'hidden';

    this.hideLayersOnMove = false;
    //if true layer not checked are loaded if false aren't loaded
    this.loadUnchecked=false;
    /**
     * initialization states
     * 0 - not initialized
     * 1 - initializing
     * 2 - initialized
     */
    this.initializationState = 0;

    //track mouse down events
    this.bMouseDown = false;

    //track last recorded mouse position
    this.lastx = 0;
    this.lasty = 0;

    //keep a reference to the inside layer since we use it a lot
    this.theInsideLayer = null;

    //viewport width and height are used in many calculations
    this.viewportWidth = this.getObjectWidth(this.domObj);
    this.viewportHeight = this.getObjectHeight(this.domObj);

    //track amount the inside layer has moved to help in wrapping images
    this.xOffset = 0;
    this.yOffset = 0;

    //track current origin offset value
    this.xOrigin = 0;
    this.yOrigin = 0;

    //the name of the current map
    this.currentMap = '';

    //the current width and height in tiles
    this.nWide = 0;
    this.nHigh = 0;

    //current top and left are tracked when the map moves
    //to start the map at some offset, these would be set to
    //the appropriate pixel value.
    this.nCurrentTop = 0; //null;
    this.nCurrentLeft = 0; //null;

    //keep a live reference to aPixel to help with caching problems - hish
    this.aPixel = new Image(1,1);
    this.aPixel.src = ICTMAP_URL + 'common/images2/a_pixel.gif';

    //error stack for tracking images that have failed to load
    this.imgErrors = new Array();

    //an array of available maps
    this.aMaps = new Array();

    //tile size and buffer size determine how many tiles to create
    this.tileWidth = null;
    this.tileHeight = null;
    this.nBuffer = 1;

    this.baseURL = '';

    //size of a pixel, geographically - assumed to be square
    this.cellSize = null;

    //image id counter - helps with reloading failed images
    this.gImageID = 0;

    //event manager
    this.eventManager = new _eventManager();

    //slider stuff
    this.as=slideid=null;
    this.accelerationFactor=1;
    this.pixelsPerStep = 30;
    this.timePerStep = 25;

    //this is a convenience to allow redirecting the client code to a server
    //other than the one that this file was loaded from.  This may not
    //work depending on security settings, except for loading tiles since
    //those come directly from a php script instead of an XmlHttpRequest.
    //
    //by default, if this is empty, it loads from the same site as the
    //page loaded from.  If set, it should be a full http:// reference to the
    //directory in which init.phtml, tile.phtml and the other scripts are located.
    this.server = '';

    //similarly, this is the global initialization script called once per page
    //load ... the result of this script tell the client what other scripts
    //are used for the other functions
    if(initFile != null){
		this.init = initFile;
	}else{
		this.init = "init.phtml";
	}
	
	//初期設定内容
	//API化するにあたってクロスドメイン対応
	this.initSettings = initSettings;

    //these are the values that need to be initialized by the init script
    this.tileURL = null;

    this.aObjects = [];
    this.aCanvases = [];
    this.layersHidden = false;

    this.aTools = [];
    this.aInfoTools = [];
	
	//サブマップ
	this.kaKeymap = null;

	// 自動で移動フラグ sakai
	this.automove = false;
	
	// 基本アイコン表示フラグ デフォルト非表示
	this.dspLandmark = false;

	//アイコンクリックオブジェクト
	this.iconClick = new Array();
	this.iconMouseOver = new Array();
	this.iconMouseOut = new Array();
	
	//標準ポイントプリフィックス
	this.BASEPOINT_PREFIX = "kp";

	//ユーザポイントプリフィックス
	this.USERPOINT_PREFIX = "user_";
	
    /* register the known events */
    for (var i=0; i<gnLastEventId; i++) {
        this.registerEventID( i );
    }
    this.createLayers();
};

kaMap.prototype.seekLayer = function(doc, name) {
    var theObj;
    for (var i = 0; i < doc.layers.length; i++) {
        if (doc.layers[i].name == name) {
            theObj = doc.layers[i];
            break;
        }
        // dive into nested layers if necessary
        if (doc.layers[i].document.layers.length > 0) {
            theObj = this.seekLayer(document.layers[i].document, name);
        }
    }
    return theObj;
};

// Convert object name string or object reference
// into a valid element object reference
kaMap.prototype.getRawObject = function(obj) {
    var theObj;
    if (typeof obj == "string") {
        if (this.isW3C) {
            theObj = document.getElementById(obj);
        } else if (this.isIE4) {
            theObj = document.all(obj);
        } else if (this.isNN4) {
            theObj = seekLayer(document, obj);
        }
    } else {
        // pass through object reference
        theObj = obj;
    }
    return theObj;
};

// Convert object name string or object reference
// into a valid style (or NN4 layer) reference
kaMap.prototype.getObject = function(obj) {
    var theObj = this.getRawObject(obj);
    if (theObj && this.isCSS) {
        theObj = theObj.style;
    }
    return theObj;
};

// Retrieve the rendered width of an element
kaMap.prototype.getObjectWidth = function(obj)  {
    var elem = this.getRawObject(obj);
    var result = 0;
    if (elem.offsetWidth) {
        result = elem.offsetWidth;
    } else if (elem.clip && elem.clip.width) {
        result = elem.clip.width;
    } else if (elem.style && elem.style.pixelWidth) {
        result = elem.style.pixelWidth;
    }
    return parseInt(result);
};

// Retrieve the rendered height of an element
kaMap.prototype.getObjectHeight = function(obj)  {
    var elem = this.getRawObject(obj);
    var result = 0;
    if (elem.offsetHeight) {
        result = elem.offsetHeight;
    } else if (elem.clip && elem.clip.height) {
        result = elem.clip.height;
    } else if (elem.style && elem.style.pixelHeight) {
        result = elem.style.pixelHeight;
    }
    return parseInt(result);
};

/**
 * kaMap.zoomTo( lon, lat [, scale] )
 *
 * zoom to some geographic point (in current projection) and optionally scale
 *
 * lon - the x coordinate to zoom to
 * lat - the y coordinate to zoom to
 * scale - optional. The scale to use
 */
kaMap.prototype.zoomTo = function( cgX, cgY ) {
	getRawObject("pointinfo").style.visibility='hidden';	// sakai
    var oMap = this.getCurrentMap();
    var inchesPerUnit = new Array(1, 12, 63360.0, 39.3701, 39370.1, 4374754);
    var newScale;
    var bScaleChanged = false;
    if (arguments.length == 3) {
        newScale = arguments[2];
        bScaleChanged = (newScale != this.getCurrentScale())
    } else {
        newScale = this.getCurrentScale();
    }
	var bZoomTo = true;
	if (!bScaleChanged) {
		var extents = this.getGeoExtents();
      	if (cgX >= extents[0] && cgX <= extents[2] &&
          	cgY >= extents[1] && cgY <= extents[3]) {
        	var cx = (extents[0]+extents[2])/2;
	        var cy = (extents[1]+extents[3])/2;
	        var dx = (cx - cgX)/this.cellSize;
	        var dy = (cgY - cy)/this.cellSize;
	        this.slideBy(dx,dy);
			bZoomTo = false;
      	}
	}
	if (bZoomTo) {
	    this.cellSize = newScale/(oMap.resolution * inchesPerUnit[oMap.units]);
	    var nFactor = oMap.zoomToScale( newScale );
	    this.setMapLayers();
	    var cpX = cgX / this.cellSize;
	    var cpY = cgY / this.cellSize;

	    var vpLeft = Math.round(cpX - this.viewportWidth/2);
	    var vpTop = Math.round(cpY + this.viewportHeight/2);


	    //figure out which tile the center point lies on
	    var cTileX = Math.floor(cpX/this.tileWidth)*this.tileWidth;
	    var cTileY = Math.floor(cpY/this.tileHeight)*this.tileHeight;


	    //figure out how many tiles left and up we need to move to lay out from
	    //the top left and have the top/left image off screen (or partially)
	    var nTilesLeft = Math.ceil(this.viewportWidth/(2*this.tileWidth))*this.tileWidth;
	    var nTilesUp = Math.ceil(this.viewportHeight/(2*this.tileHeight))*this.tileHeight;

	    this.nCurrentLeft = cTileX - nTilesLeft;
	    this.nCurrentTop = -1*(cTileY + nTilesUp);

	    this.xOrigin = this.nCurrentLeft;
	    this.yOrigin = this.nCurrentTop;

	    this.theInsideLayer.style.left = -1*(vpLeft - this.xOrigin) + "px";
	    this.theInsideLayer.style.top = (vpTop + this.yOrigin) + "px";
	    var layers = oMap.getLayers();
	    for( var k=0; k<layers.length; k++) {
	        var d = layers[k].domObj;
	        for(var j=0; j<this.nHigh; j++) {
	            for( var i=0; i<this.nWide; i++) {
	                var img = d.childNodes[(j*this.nWide)+i];
	                img.src = this.aPixel.src;
	                img.style.top = (this.nCurrentTop + j*this.tileHeight - this.yOrigin) + "px";
	                img.style.left = (this.nCurrentLeft + i*this.tileWidth - this.xOrigin) + "px";
	                layers[k].setTile(img);
	            }
	        }
	    }
	    this.checkWrap( );
	    this.updateObjects();
	}
    if (bScaleChanged) {
		this.triggerEvent( KAMAP_SCALE_CHANGED, this.getCurrentScale() );
	}
    this.triggerEvent( KAMAP_EXTENTS_CHANGED, this.getGeoExtents() );
};

/**
 * kaMap.zoomToExtents( minx, miny, maxx, maxy )
 *
 * best fit zoom to extents.  Center of extents will be in the center of the
 * view and the extents will be contained within the view at the closest scale
 * available above the scale these extents represent
 *
 * minx, miny, maxx, maxy - extents in units of current projection.
 */
kaMap.prototype.zoomToExtents = function(minx, miny, maxx, maxy) {
    /* calculate new scale from extents and viewport, then find closest
     * scale and calculate new extents from centerpoint and scale.  Then
     * move theInsideLayer and all the images to show that centerpoint at
     * the center of the view at the given scale
     */
    var inchesPerUnit = new Array(1, 12, 63360.0, 39.3701, 39370.1, 4374754);
    var oMap = this.getCurrentMap();

    //the geographic center - where we want to end up
    var cgX = (maxx+minx)/2;
    var cgY = (maxy+miny)/2;

    var tmpCellSizeX = (maxx - minx)/this.viewportWidth;
    var tmpCellSizeY = (maxy - miny)/this.viewportHeight;
    var tmpCellSize = Math.max( tmpCellSizeX, tmpCellSizeY );

    var tmpScale = tmpCellSize * oMap.resolution * inchesPerUnit[oMap.units];
    var newScale = oMap.aScales[0];
    for (var i=1; i<oMap.aScales.length; i++) {
        if (tmpScale >= oMap.aScales[i]) {
            break;
        }
        newScale = oMap.aScales[i];
    }
    //now newScale has our new scale size
    this.cellSize = newScale/(oMap.resolution * inchesPerUnit[oMap.units]);
    var nFactor = oMap.zoomToScale( newScale );
    this.setMapLayers();
    var cpX = cgX / this.cellSize;
    var cpY = cgY / this.cellSize;

    var vpLeft = Math.round(cpX - this.viewportWidth/2);
    var vpTop = Math.round(cpY + this.viewportHeight/2);


    //figure out which tile the center point lies on
    var cTileX = Math.floor(cpX/this.tileWidth)*this.tileWidth;
    var cTileY = Math.floor(cpY/this.tileHeight)*this.tileHeight;


    //figure out how many tiles left and up we need to move to lay out from
    //the top left and have the top/left image off screen (or partially)
    var nTilesLeft = Math.ceil(this.viewportWidth/(2*this.tileWidth))*this.tileWidth;
    var nTilesUp = Math.ceil(this.viewportHeight/(2*this.tileHeight))*this.tileHeight;

    this.nCurrentLeft = cTileX - nTilesLeft;
    this.nCurrentTop = -1*(cTileY + nTilesUp);

    this.xOrigin = this.nCurrentLeft;
    this.yOrigin = this.nCurrentTop;

    this.theInsideLayer.style.left = -1*(vpLeft - this.xOrigin) + "px";
    this.theInsideLayer.style.top = (vpTop + this.yOrigin) + "px";

    var layers = oMap.getLayers();
    for( var k=0; k<layers.length; k++) {
        var d = layers[k].domObj;
        for(var j=0; j<this.nHigh; j++) {
            for( var i=0; i<this.nWide; i++) {
                var img = d.childNodes[(j*this.nWide)+i];
                img.src = this.aPixel.src;
                img.style.top = (this.nCurrentTop + j*this.tileHeight - this.yOrigin) + "px";
                img.style.left = (this.nCurrentLeft + i*this.tileWidth - this.xOrigin) + "px";
                layers[k].setTile(img);
            }
        }
    }
    this.checkWrap( );
    this.updateObjects();
    this.triggerEvent( KAMAP_SCALE_CHANGED, this.getCurrentScale() );
    this.triggerEvent( KAMAP_EXTENTS_CHANGED, this.getGeoExtents() );
};

/**
 * kaMap.createDrawingCanvas( idx )
 *
 * create a layer on which objects can be drawn (such as point objects)
 *
 * idx - int, the z-index of the layer.  Should be < 100 but above the map
 * layers.
 */
kaMap.prototype.createDrawingCanvas = function( idx ) {
    var d = document.createElement( 'div' );
    d.style.position = 'absolute';
    d.style.left = '0px';
    d.style.top = '0px';
    d.style.width= '3000px';
    d.style.height = '3000px';
    d.style.zIndex = idx;
    this.theInsideLayer.appendChild( d );
    this.aCanvases.push( d );
    d.kaMap = this;
    return d;
};

kaMap.prototype.removeDrawingCanvas = function( canvas ) {

    for (var i=0; i<this.aCanvases.length;i++) {
        if (this.aCanvases[i] == canvas) {
            this.aCanvases.splice( i, 1 );
        }
    }
    this.theInsideLayer.removeChild(canvas);
    canvas.kaMap = null;
    return true;
};

/**
 * kaMap.addObjectGeo( canvas, lon, lat, obj )
 *
 * add an object to a drawing layer and position it at the given geographic
 * position.  This is defined as being in the projection of the map.
 *
 * TODO: possibly add ability to call a reprojection service (xhr request?) to
 * convert lon/lat into the current coordinate system if not lon/lat.
 *
 * canvas - object, the drawing canvas to add this object to
 * x - int, the x position in pixels
 * y - int, the y position in pixels
 * obj - object, the object to add (an img, div etc)
 *
 * returns true
 */
kaMap.prototype.addObjectGeo = function( canvas, lon, lat, obj ) {
    obj.lon = lon;
    obj.lat = lat;
    var aPix = this.geoToPix( lon, lat );
    return this.addObjectPix( canvas, aPix[0], aPix[1], obj );
};

/**
 * kaMap.addObjectPix( canvas, x, y, obj )
 *
 * add an object to the map canvas and position it at the given pixel position.
 * The position should not include the xOrigin/yOrigin offsets
 *
 * canvas - object, the canvas to add this object to
 * x - int, the x position in pixels
 * y - int, the y position in pixels
 * obj - object, the object to add (an img, div etc)
 *
 * returns true;
 */
kaMap.prototype.addObjectPix = function( canvas, x, y, obj ) {
    var xOffset = (obj.xOffset) ? obj.xOffset : 0;
    var yOffset = (obj.yOffset) ? obj.yOffset : 0;
    var top = (y - this.yOrigin + yOffset);
    var left = (x - this.xOrigin + xOffset);
    obj.style.position = 'absolute';
    obj.style.top = top + "px";
    obj.style.left = left + "px";
    obj.canvas = canvas;
    canvas.appendChild( obj );
    this.aObjects.push( obj );

    return true;
};

/**
 * kaMap.shiftObject( x, y, obj )
 *
 * move an object by a pixel amount
 *
 * x - int, the number of pixels in the x direction to move the object
 * y - int, the number of pixels in the y direction to move the object
 * obj - object, the object to move
 *
 * returns true
 */
kaMap.prototype.shiftObject = function( x, y, obj ) {
    var top = safeParseInt(obj.style.top);
    var left = safeParseInt(obj.style.left);

    obj.style.top = (top + y) + "px";
    obj.style.left = (left + x) + "px";

    return true;
};

/**
 * kaMap.removeObject( obj )
 *
 * removes an object previously added with one of the addObjectXxx calls
 *
 * obj - object, an object that has been previously added, or null to remove
 *       all objects
 *
 * returns true if the object was removed, false otherwise (i.e. if it was
 * never added).
 */
kaMap.prototype.removeObject = function( obj ) {
    if (obj == null) {
        for (var i=0; i<this.aObjects.length; i++) {
            obj = this.aObjects[i];
            if (obj.canvas) {
                obj.canvas.removeChild(obj);
            }
        }
        this.aObjects = [];
        return true;
    } else {
        for (var i=0; i<this.aObjects.length; i++) {
            if (this.aObjects[i] == obj) {
                obj = this.aObjects[i];
                if (obj.canvas) {
                    obj.canvas.removeChild( obj );
                    obj.canvas = null;
                }
                this.aObjects.splice(i,1);
                return true;
            }
        }
        return false;
    }
};

/**
 * kaMap.removeAllObjects( canvas )
 *
 * removes all objects on a particular canvas
 *
 * canvas - a canvas that was previously created with createDrawingCanvas
 */
kaMap.prototype.removeAllObjects = function(canvas) {
    for (var i=0; i<this.aObjects.length; i++) {
       obj = this.aObjects[i];
       if (obj.canvas && obj.canvas == canvas) {
          obj.canvas.removeChild( obj );
          obj.canvas = null;
          this.aObjects.splice(i--,1);
       }
    }
    return true;
};

/**
 * kaMap.centerObject( obj )
 *
 * slides the map to place the object at the center of the map
 *
 * obj - object, an object previously added to the map
 *
 * returns true
 */
kaMap.prototype.centerObject = function(obj) {
    var vpX = -safeParseInt(this.theInsideLayer.style.left) + this.viewportWidth/2;
    var vpY = -safeParseInt(this.theInsideLayer.style.top) + this.viewportHeight/2;

    var xOffset = (obj.xOffset)?obj.xOffset:0;
    var yOffset = (obj.yOffset)?obj.yOffset:0;

    var dx = safeParseInt(obj.style.left) - xOffset- vpX;
    var dy = safeParseInt(obj.style.top) - yOffset - vpY;

    this.slideBy(-dx, -dy);
    return true;
};

/**
 * kaMap.geoToPix( gX, gY )
 *
 * convert geographic coordinates into pixel coordinates.  Note this does not
 * adjust for the current origin offset that is used to adjust the actual
 * pixel location of the tiles and other images
 *
 * gX - float, the x coordinate in geographic units of the active projection
 * gY - float, the y coordinate in geographic units of the active projection
 *
 * returns an array of pixel coordinates with element 0 being the x and element
 * 1 being the y coordinate.
 */
kaMap.prototype.geoToPix = function( gX, gY ) {
    var pX = gX / this.cellSize;
    var pY = -1 * gY / this.cellSize;
    return [Math.floor(pX), Math.floor(pY)];
};

/**
 * kaMap.pixToGeo( pX, pY [, bAdjust] )
 *
 * convert pixel coordinates into geographic coordinates.  This can optionally
 * adjust for the pixel offset by passing true as the third argument
 *
 * pX - int, the x coordinate in pixel units
 * pY - int, the y coordinate in pixel units
 *
 * returns an array of geographic coordinates with element 0 being the x
 * and element 1 being the y coordinate.
 */
kaMap.prototype.pixToGeo = function( pX, pY ) {
    var bAdjust = (arguments.length == 3 && arguments[2]) ? true : false;

    if (bAdjust) {
        pX = pX + this.xOrigin;
        pY = pY + this.yOrigin;
    }
    var gX = -1 * pX * this.cellSize;
    var gY = pY * this.cellSize;
    return [gX, gY];
};

/**
 * kaMap.initialize( [szMap] )
 *
 * main initialization of kaMap.  This must be called after page load and
 * should only be called once (i.e. on page load).  It does not perform
 * intialization synchronously.  This means that the function will return
 * before initialization is complete.  To determine when initialization is
 * complete, the calling application must register for the KAMAP_INITIALIZED
 * event.
 *
 * szMap - string, optional, the name of a map to initialize by default.  If
 *         not set, use the default configuration map file.
 *
 * returns true
 */
kaMap.prototype.initialize = function() {
    if (this.initializationState == 2) {
        this.triggerEvent( KAMAP_ERROR, 'ERROR: ka-Map! is already initialized!' );
        return false;
    } else if (this.intializationState == 1) {
        this.triggerEvent( KAMAP_WARNING, 'WARNING: ka-Map! is currently initializing ... wait for the KAMAP_INITIALIZED event to be triggered.' );
        return false;
    }
    this.initializationState = 1;
	if(this.initSettings != null && this.initSettings != ""){
		if (arguments.length > 2 && arguments[2] != '') {
			this.initializeCallback(this.initSettings,arguments[2]);
	    }else{
			this.initializeCallback(this.initSettings);
		}
	}else{
	    /* call initialization script on the server */
	    var szURL = this.server+this.init;

	    var sep = (this.init.indexOf("?") == -1) ? "?" : "&";

	    if (arguments.length > 0 && arguments[0] != '') {
	        szURL = szURL + sep + "map="+ arguments[0];
	        sep = "&";
	    }
	    if (arguments.length > 1 && arguments[1] != '') {
	        szURL = szURL + sep + "extents="+ arguments[1];
	        sep = "&";
	    }
	    if (arguments.length > 2 && arguments[2] != '') {
	        szURL = szURL + sep + "centerPoint="+ arguments[2];
	        sep = "&";
	    }
	   call(szURL, this, this.initializeCallback);
	}
	
    return true;
};

/**
 * hidden function on callback from init.phtml
 */
kaMap.prototype.initializeCallback = function( szInit ) {
    // szInit contains /*init*/ if it worked, or some php error otherwise
    if (szInit.substr(0, 1) != "/") {
        this.triggerEvent( KAMAP_ERROR, 'ERROR: ka-Map! initialization '+
                          'failed on the server.  Message returned was:\n' +
                          szInit);
        return false;
    }
    eval(szInit);
	if(arguments.length > 1 && arguments[1] != null){
		var tmpArray = arguments[1].split(",");
		this.zoomTo(tmpArray[0], tmpArray[1], tmpArray[2]);
	}

    this.triggerEvent( KAMAP_INITIALIZED );

    this.initializationState = 2;
};

/**
 * kaMap.setBackgroundColor( color )
 *
 * call this to set a background color for the inside layer.  This color
 * shows through any transparent areas of the map.  This is primarily
 * intended to be used by the initializeMap callback function to set the
 * background to the background color in the map file.
 *
 * color: string, a valid HTML color string
 *
 * returns true;
 */
kaMap.prototype.setBackgroundColor = function( color ) {
    this.domObj.style.backgroundColor = color;
    return true;
};

/**
 * hidden method of kaMap to initialize all the various layers needed by
 * kaMap to draw and move the map image.
 */
kaMap.prototype.createLayers = function() {
    this.theInsideLayer = document.createElement('div');
    this.theInsideLayer.id = 'theInsideLayer';
    this.theInsideLayer.style.position = 'absolute';
    this.theInsideLayer.style.left = '0px';
    this.theInsideLayer.style.top = '0px';
    this.theInsideLayer.style.zIndex = '1';
    this.theInsideLayer.kaMap = this;
    if (this.currentTool) {
        this.theInsideLayer.style.cursor = this.currentTool.cursor;
    }
    this.domObj.appendChild(this.theInsideLayer);

    this.domObj.kaMap = this;
    this.theInsideLayer.onmousedown = kaMap_onmousedown;
    this.theInsideLayer.onmouseup = kaMap_onmouseup;
    this.theInsideLayer.onmousemove = kaMap_onmousemove;
    this.theInsideLayer.onmouseover = kaMap_onmouseover;
    this.domObj.onmouseout = kaMap_onmouseout;
    this.theInsideLayer.onkeypress = kaMap_onkeypress;
    this.theInsideLayer.ondblclick = kaMap_ondblclick;
    this.theInsideLayer.oncontextmenu = kaMap_oncontextmenu;
/*　マウスホイールでの拡大縮小をしないように *070615upd/
/*    this.theInsideLayer.onmousewheel = kaMap_onmousewheel;*/
    if (window.addEventListener &&
        navigator.product && navigator.product == "Gecko") {
/*        this.domObj.addEventListener( "DOMMouseScroll", kaMap_onmousewheel, false );*/
    }

    //this is to prevent problems in IE
    this.theInsideLayer.ondragstart = new Function([], 'var e=e?e:event;e.cancelBubble=true;e.returnValue=false;return false;');
};

/**
 * internal function
 * update the layer URLs based on their current positions
 */
kaMap.prototype.initializeLayers = function(nFactor) {
    var deltaMouseX = this.nCurrentLeft + safeParseInt(this.theInsideLayer.style.left) - this.xOrigin;
    var deltaMouseY = this.nCurrentTop + safeParseInt(this.theInsideLayer.style.top) - this.yOrigin;

    var vpTop = this.nCurrentTop - deltaMouseY;
    var vpLeft = this.nCurrentLeft - deltaMouseX;

    var vpCenterX = vpLeft + this.viewportWidth/2;
    var vpCenterY = vpTop + this.viewportHeight/2;

    var currentTileX = Math.floor(vpCenterX/this.tileWidth)*this.tileWidth;
    var currentTileY = Math.floor(vpCenterY/this.tileHeight)*this.tileHeight;

    var tileDeltaX = currentTileX - this.nCurrentLeft;
    var tileDeltaY = currentTileY - this.nCurrentTop;

    var newVpCenterX = vpCenterX * nFactor;
    var newVpCenterY = vpCenterY * nFactor;

    var newTileX = Math.floor(newVpCenterX/this.tileWidth) * this.tileWidth;
    var newTileY = Math.floor(newVpCenterY/this.tileHeight) * this.tileHeight;

    var newCurrentLeft = newTileX - tileDeltaX;
    var newCurrentTop = newTileY - tileDeltaY;

    this.nCurrentLeft = newCurrentLeft;
    this.nCurrentTop = newCurrentTop;

    var newTilLeft = -newVpCenterX + this.viewportWidth/2;
    var newTilTop = -newVpCenterY + this.viewportHeight/2;

    var xOldOrigin = this.xOrigin;
    var yOldOrigin = this.yOrigin;

    this.xOrigin = this.nCurrentLeft;
    this.yOrigin = this.nCurrentTop;

    this.theInsideLayer.style.left = (newTilLeft + this.xOrigin) + "px";
    this.theInsideLayer.style.top = (newTilTop + this.yOrigin) + "px";

    var layers = this.aMaps[this.currentMap].getLayers();
    for( var k=0; k<layers.length; k++) {
        var d = layers[k].domObj;
        for(var j=0; j<this.nHigh; j++) {
            for( var i=0; i<this.nWide; i++) {
                var img = d.childNodes[(j*this.nWide)+i];
                img.src = this.aPixel.src;
                img.style.top = (this.nCurrentTop + j*this.tileHeight - this.yOrigin) + "px";
                img.style.left = (this.nCurrentLeft + i*this.tileWidth - this.xOrigin) + "px";
                layers[k].setTile(img);
            }
        }
    }
    this.checkWrap();
    this.updateObjects();
};

/***************************************
 * internal function adedd by cappu
 * use to paint a layer calculating tile
 * position for current exten and scale
 * and calling the layer.seTile
 ***************************************/
kaMap.prototype.paintLayer = function(l) {
     var d = l.domObj;
	 if(d){		// sakai error
     for(var j=0; j<this.nHigh; j++) {
         for( var i=0; i<this.nWide; i++) {
             var img = d.childNodes[(j*this.nWide)+i];
			// img.src = this.aPixel.src;
             img.style.top = (this.nCurrentTop + j*this.tileHeight - this.yOrigin) + "px";
             img.style.left = (this.nCurrentLeft + i*this.tileWidth - this.xOrigin) + "px";
             l.setTile(img);
         }
     }
     this.checkWrap();
	 }
};

/* kaMap.updateObjects
 * call this after any major change to the state of kaMap including after
 * a zoomTo, zoomToExtents, etc.
 */
kaMap.prototype.updateObjects = function() {
    for (var i=0; i<this.aObjects.length;i++) {
        var obj = this.aObjects[i];
        var xOffset = (obj.xOffset) ? obj.xOffset : 0;
        var yOffset = (obj.yOffset) ? obj.yOffset : 0;
        var aPix = this.geoToPix( obj.lon, obj.lat );
        var top = (aPix[1] - this.yOrigin + yOffset);
        var left = (aPix[0] - this.xOrigin + xOffset);
        obj.style.top = top + "px";
        obj.style.left = left + "px";
    }
};

/**
 * kaMap.resize()
 *
 * called when the viewport layer changes size.  It is the responsibility
 * of the user of this API to track changes in viewport size and call this
 * function to update the map
 */
kaMap.prototype.resize = function( ) {
    if (this.initializationState != 2) {
        return false;
    }
	//alert("this.viewportWidth = " + this.viewportWidth);
	//alert("this.domObj = " + this.domObj);
	//alert("this.domObj.id = " + this.domObj.id);
	//alert("this.domObj.style.width=" + this.domObj.style.width);
	
    var newViewportWidth = this.getObjectWidth(this.domObj);
	
    var newViewportHeight = this.getObjectHeight(this.domObj);

	//alert("newViewportWidth = " + newViewportWidth);
	
    if (this.viewportWidth == null) {
        this.theInsideLayer.style.top = (-1*this.nCurrentTop + this.yOrigin) + "px";
        this.theInsideLayer.style.left = (-1*this.nCurrentLeft + this.xOrigin) + "px";
        this.theInsideLayer.style.top  = (safeParseInt(this.theInsideLayer.style.top) + (newViewportHeight - viewportHeight)/2)+"px";

        this.theInsideLayer.style.left = (safeParseInt(this.theInsideLayer.style.top) + (newViewportWidth - viewportWidth)/2)+"px";
        
        this.viewportWidth = newViewportWidth;
        this.viewportHeight = newViewportHeight;
    }
    var newWide = Math.ceil((newViewportWidth / this.tileWidth) + 2*this.nBuffer);
    var newHigh = Math.ceil((newViewportHeight / this.tileHeight) + 2*this.nBuffer);

    this.viewportWidth = newViewportWidth;
    this.viewportHeight = newViewportHeight;

    if (this.nHigh == 0 && this.nWide == 0) {
        this.nWide = newWide;
    }

    while (this.nHigh < newHigh) {

        this.appendRow();
    }
    while (this.nHigh > newHigh && newHigh > 3) {
        this.removeRow();
    }
    while (this.nWide < newWide) {
        this.appendColumn();
    }
    while (this.nWide > newWide && newWide > 3) {
        this.removeColumn();
    }
    //create image don't call layer.set tile so i need to do that!
    var map = this.getCurrentMap();
    var layers =map.getLayers();
    for(i=0;i<layers.length;i++) {
        layers[i].setTileLayer();
    }

    this.triggerEvent( KAMAP_EXTENTS_CHANGED, this.getGeoExtents() );
    this.triggerEvent( KAMAP_EXTENTS_CHANGED, this.getGeoExtents() );
};

/**
 * internal function to create images for map tiles
 *
 * top - integer, the top of this image in pixels
 * left - integer, the left of this image in pixels
 * obj - object, the layer in which this image will reside
 */
kaMap.prototype.createImage = function( top, left, obj ) {
    var img = document.createElement('img');
    img.src=this.aPixel.src;
    img.width=this.tileWidth;
    img.height=this.tileHeight;
    //first for firefox, rest for IE :(
    img.setAttribute('style', 'position:absolute; top:'+top+'px; left:'+left+'px;' );
    img.style.position = 'absolute';
    img.style.top = (top - this.yOrigin)+'px';
    img.style.left = (left - this.xOrigin)+'px';
    img.style.width = this.tileWidth + "px";
    img.style.height = this.tileHeight + "px";
    img.style.visibility = 'hidden';
    img.galleryimg = "no"; //turn off image toolbar in IE
    img.onerror = kaMap_imgOnError;
    img.onload = kaMap_imgOnLoad;
    img.errorCount = 0;
    img.id = "i" + this.gImageID;
    img.layer = obj;
    img.kaMap = this;
    this.gImageID = this.gImageID + 1;
    img.ie_hack = false;

    if (this.isIE4) {
    	if (obj.imageformat &&
    	       (obj.imageformat.toLowerCase() == "alpha")) {
		img.ie_hack = true;
	}
    }

    return img;
};

kaMap.prototype.resetTile = function( id, bForce ) {
    var img = this.DHTMLapi.getRawObject(id);
    if (img.layer) {
        img.layer.setTile(this, bForce);
    }
};

kaMap.prototype.reloadImage = function(id) {
};

kaMap.prototype.resetImage = function(id) {
};

/**
 * internal function to handle images that fail to load
 */
kaMap_imgOnError = function(e) {
    if (this.layer) {
        this.layer.setTile(this, true);
    }
};

/**
 * internal function to track images as they finish loading.
 */
kaMap_imgOnLoad = function(e) {
    if ((this.ie_hack) &&
    	(this.src != this.kaMap.aPixel.src)) {
    	var src = this.src;
        this.src = this.kaMap.aPixel.src;
        this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"')";
    }
    this.style.visibility = 'visible';
};

/**
 * internal function to append a row of images to each of the layers
 *
 * this function is used when the viewport is resized
 * modified by cappu can take a single layer as input
 */
kaMap.prototype.appendRow = function(layer) {
    if (this.nWide == 0) {
        return;
    }
    var layers = null;
    if(arguments.length==1) {
        layers = Array(layer);
    } else {
        layers = this.aMaps[this.currentMap].getLayers();
    }
    for( var i=0; i<layers.length; i++) {
        var obj = layers[i].domObj;
        for (var j=0; j<this.nWide; j++) {
            var top = this.nCurrentTop + (this.nHigh * this.tileHeight);
            var left = this.nCurrentLeft + (j * this.tileWidth);
            var img = this.createImage( top, left, layers[i] );
            //hack around IE problem with clipping layers when a filter is
            //active
            // mod 2011/03/16 T.Kozai Start ------------------------------
            // if (this.isIE4) {
            if (this.isIE4 && !this.isIE6CSS) {
            // mod 2011/03/16 T.Kozai End --------------------------------
                img.style.filter = "Alpha(opacity="+layers[i].opacity+")";
            }
            obj.appendChild( img );
        }
    }
    this.nHigh = this.nHigh + 1;
};

/**
 * internal function to append a column of images to each of the layers
 *
 * this function is used when the viewport is resized
 * modified by cappu can take a single layer as input
 */
kaMap.prototype.appendColumn = function(layer) {
    if (this.nHigh == 0) {
        return;
    }
    var layers = null;
    if(arguments.length==1) {
        layers = Array(layer);
    } else {
        layers = this.aMaps[this.currentMap].getLayers();
    }
    for( var i=0; i<layers.length; i++) {
        var obj = layers[i].domObj;
        for(var j=this.nHigh-1; j>=0; j--) {
            var top = this.nCurrentTop + (j * this.tileHeight);
            var left = this.nCurrentLeft + (this.nWide * this.tileWidth);
            var img = this.createImage( top, left, layers[i] );
            //hack around IE problem with clipping layers when a filter is
            //active
            if (this.isIE4) {
                img.style.filter = "Alpha(opacity="+layers[i].opacity+")";
            }
            if (j < this.nHigh-1) {
                obj.insertBefore(img, obj.childNodes[((j+1)*this.nWide)]);
            } else {
                obj.appendChild(img);
            }
         }
    }
    this.nWide = this.nWide + 1;
};

/**
 * internal function to remove a column of images to each of the layers
 *
 * this function is used when the viewport is resized
 * modified by cappu can take a single layer as input
 */
kaMap.prototype.removeColumn = function(layer) {
    if (this.nWide < 3) {
        return;
    }
    var layers = null;
    if(arguments.length==1) {
        layers = Array(layer);
    } else {
        layers = this.aMaps[this.currentMap].getLayers();
    }
    for( var i=0; i<layers.length; i++) {
        var d = layers[i].domObj;
        for(var j=this.nHigh - 1; j >= 0; j--) {
            var img = d.childNodes[((j+1)*this.nWide)-1];
            d.removeChild( img );
            //attempt to prevent memory leaks
            img.onload = null;
            img.onerror = null;
        }
    }
    this.nWide = this.nWide - 1;
};

/**
 * internal function to remove a row of images to each of the layers
 *
 * this function is used when the viewport is resized
 * modified by cappu can take a single layer as input
 */
kaMap.prototype.removeRow = function(layer) {
    if (this.nHigh < 3) {
        return;
    }

    var layers = null;
    if(arguments.length==1) {
        layers = Array(layer);
    } else {
        layers = this.aMaps[this.currentMap].getLayers();
    }

    for( var i=0; i<layers.length; i++) {
        var d = layers[i].domObj;
        for(var j=this.nWide - 1; j >= 0; j--) {
            var img = d.childNodes[((this.nHigh-1)*this.nWide)+j];
            d.removeChild( img );
            //attempt to prevent memory leaks
            img.onload = null;
            img.onerror = null;
        }
    }
    this.nHigh = this.nHigh - 1;
};

kaMap.prototype.hideLayers = function() {
    if (!this.hideLayersOnMove) {
        return;
    }

    if (this.layersHidden) {
        return;
    }
    var layers = this.aMaps[this.currentMap].getLayers();
    for( var i=0; i<layers.length; i++) {
        layers[i]._visible = layers[i].visible;
        if (layers[i].name != '__base__') {
            layers[i].setVisibility( false );
        }
    }
    for( var i = 0; i < this.aCanvases.length; i++) {
        this.aCanvases[i].style.visibility = 'hidden';
        this.aCanvases[i].style.display = 'none';
    }
    this.layersHidden = true;
};

kaMap.prototype.showLayers = function() {
    if (!this.hideLayersOnMove) {
        return;
    }

    if (!this.layersHidden) {
        return;
    }
    var layers = this.aMaps[this.currentMap].getLayers();
    for( var i=0; i<layers.length; i++) {
        layers[i].setVisibility( layers[i]._visible );
    }
    for( var i = 0; i < this.aCanvases.length; i++) {
        this.aCanvases[i].style.visibility = 'visible';
        this.aCanvases[i].style.display = 'block';
    }
    this.layersHidden = false;
};

/**
 * move the map by a certain amount
 */
kaMap.prototype.moveBy = function( x, y ) {
    var til = this.theInsideLayer;
    til.style.top = (safeParseInt(til.style.top)+y) + 'px';
    til.style.left = (safeParseInt(til.style.left)+x )+ 'px';
    this.checkWrap();
};

/**
 * slide the map by a certain amount
 */
kaMap.prototype.slideBy = function(x,y) {
    if (this.slideid!=null) {
        goQueueManager.dequeue( this.slideid );
    }

    this.as = [];

    var absX = Math.abs(x);
    var absY = Math.abs(y);

    var signX = x/absX;
    var signY = y/absY;

    var distance = absX>absY?absX:absY;
    var steps = Math.floor(distance/this.pixelsPerStep);

    var dx = dy = 0;
    if (steps > 0) {
        dx = (x)/(steps*this.pixelsPerStep);
        dy = (y)/(steps*this.pixelsPerStep);
    }

    var remainderX = x - dx*steps*this.pixelsPerStep;
    var remainderY = y - dy*steps*this.pixelsPerStep;

    var px=py=0;

    var curspeed=this.accelerationFactor;
    var i=0;
    while(i<steps) {
        if (i>0) {
          px+=this.as[i-1][0];
          py+=this.as[i-1][1];
        }

        var cx = px+Math.round(dx*this.pixelsPerStep);
        var cy = py+Math.round(dy*this.pixelsPerStep);
        this.as[i]=new Array(cx-px,cy-py);
        i++;
    }
    if (remainderX != 0 || remainderY != 0) {
        this.as[i] = [remainderX, remainderY];
    }
    this.hideLayers();
    this.slideid=goQueueManager.enqueue(this.timePerStep,this,this.slide,[0]);
};

/**
 * handle individual movement within a slide
 */
kaMap.prototype.slide = function(pos) {
    if (pos>=this.as.length) {
        this.as=slideid=null;
        this.showLayers();
        this.triggerEvent( KAMAP_EXTENTS_CHANGED, this.getGeoExtents() );
        return;
    }

    this.moveBy( this.as[pos][0], this.as[pos][1] );

    pos ++;
    this.slideid=goQueueManager.enqueue(this.timePerStep,this,this.slide,[ pos]);
};

/**
 * internal function to handle various events that are passed to the
 * current tool
 */
kaMap_onkeypress = function( e ) {
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onkeypress( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].onkeypress(e);
        }
    }
};

kaMap_onmousemove = function( e ) {
    e = (e)?e:((event)?event:null);
    if (e.button==2) {
        this.kaMap.triggerEvent( KAMAP_CONTEXT_MENU );
    }
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onmousemove( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].onmousemove(e);
        }
    }
};

kaMap_onmousedown = function( e ) {
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onmousedown( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].onmousedown(e);
        }
    }
};

kaMap_onmouseup = function( e ) {
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onmouseup( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].onmouseup(e);
        }
    }
};

kaMap_onmouseover = function( e ) {
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onmouseover( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].onmouseover(e);
        }
    }
};

kaMap_onmouseout = function( e ) {
     if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onmouseout( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].onmouseout(e);
        }
    }
};

kaMap_oncontextmenu = function( e ) {
    e = e?e:event;
    if (e.preventDefault) {
        e.preventDefault();
    }
    return false;
};

kaMap_ondblclick = function( e ) {
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.ondblclick( e );
    }
    if (this.kaMap.aInfoTools.length > 0) {
        for (var i=0; i<this.kaMap.aInfoTools.length; i++) {
            this.kaMap.aInfoTools[i].ondblclick(e);
        }
    }
};

kaMap_onmousewheel = function( e ) {
    if (this.kaMap.currentTool) {
        this.kaMap.currentTool.onmousewheel( e );
    }
};

kaMap.prototype.cancelEvent = function(e) {
    e = (e)?e:((event)?event:null);
    e.returnValue = false;
    if (e.preventDefault) {
        e.preventDefault();
    }
    return false;
};

kaMap.prototype.registerTool = function( toolObj ) {
    this.aTools.push( toolObj );
};

kaMap.prototype.activateTool = function( toolObj ) {
    if (toolObj.isInfoTool()) {
        this.aInfoTools.push(toolObj);
    } else {
        if (this.currentTool) {
            this.currentTool.deactivate();
        }
        this.currentTool = toolObj;
        if (this.theInsideLayer) {
            this.setCursor(this.currentTool.cursor);
        }
    }
};

kaMap.prototype.deactivateTool = function( toolObj ) {
    if (toolObj.isInfoTool()) {
        for (var i=0; i<this.aInfoTools.length; i++) {
            if (this.aInfoTools[i] == toolObj) {
                this.aInfoTools.splice(i,1);
                break;
            }
        }
    } else {
        if (this.currentTool == toolObj) {
            this.currentTool = null;
        }
        if (this.theInsideLayer) {
            this.theInsideLayer.style.cursor = 'auto';
        }
    }
};

/*
 * inspired by code in WindowManager.js
 * Copyright 2005 MetaCarta, Inc., released under the BSD License
 */
kaMap.prototype.setCursor = function(cursor) {
    if (cursor && cursor.length && typeof cursor == 'object') {
        for (var i = 0; i < cursor.length; i++) {
            this.theInsideLayer.style.cursor = cursor[i];
            if (this.theInsideLayer.style.cursor == cursor[i]) {
                break;
            }
        }
    } else if (typeof cursor == 'string') {
        this.theInsideLayer.style.cursor = cursor;
    } else {
        this.theInsideLayer.style.cursor = 'auto';
    }
};

/**
 * internal function to check if images need to be wrapped
 */
kaMap.prototype.checkWrap = function() {
    var bWrapped = false;
    // adjust theInsideLayer so it doesn't show more than maxExtents (if set)
    this.checkMaxExtents();

    this.xOffset = safeParseInt(this.theInsideLayer.style.left) + this.nCurrentLeft - this.xOrigin;
    this.yOffset = safeParseInt(this.theInsideLayer.style.top) + this.nCurrentTop - this.yOrigin;

	//TODO: the various wrap functions remove/append child nodes but its probably
	//not necessary since we are absolutely positioning the images.  This is
	//actually a leftover from when we were relatively positioning images (which
	//ended up being too slow).
    while (this.xOffset > 0) {
        this.wrapR2L();
        bWrapped = true;
    }
    while (this.xOffset < -(this.nBuffer*this.tileWidth)) {
        this.wrapL2R();
        bWrapped = true;
    }
    while (this.yOffset > -(this.nBuffer*this.tileHeight)) {
        this.wrapB2T();
        bWrapped = true;
    }
    while (this.yOffset < -(2*this.nBuffer*this.tileHeight)) {
        this.wrapT2B();
        bWrapped = true;
    }

    var layer = this.aMaps[this.currentMap].getLayers()[0];
    if (layer) {
        var img = layer.domObj.childNodes[0].style;
        this.nCurrentTop = safeParseInt(img.top) + this.yOrigin;
        this.nCurrentLeft = safeParseInt(img.left) + this.xOrigin;
    }

    if (bWrapped) {
        this.triggerEvent( KAMAP_METAEXTENTS_CHANGED, this.getMetaExtents() );
    }
};

/**
 * kaMap.checkMaxExtents()
 *
 * For maps with maxExtent set, this function adjusts the position of
 * theInsideLayer so it never shows more than the maximum extent specified
 * in the mapfile.  Called from kaMap.checkWrap() since that is called
 * with all movement of theInsideLayer
 *
 * Added by tschaub
 */
kaMap.prototype.checkMaxExtents = function() {
    var maxExtents = this.getCurrentMap().maxExtents;
    if (maxExtents.length == 4) {
		if ((maxExtents[0] >= maxExtents[2]) || (maxExtents[1] >= maxExtents[3])) {
			// fail silently
			return false;
		}
        var geoExtents = this.getGeoExtents();
        var hPixelAdjustment = 0;
        var vPixelAdjustment = 0;
        // check left and right
        if (geoExtents[0] < maxExtents[0]) {
            // extra on right
            hPixelAdjustment = Math.round((maxExtents[0] - geoExtents[0]) / this.cellSize);
        }
        if (geoExtents[2] > maxExtents[2]) {
            // extra on left
			if(hPixelAdjustment != 0)
			{
				// if both left and right are over, split the difference
	            hPixelAdjustment += Math.round((maxExtents[2] - geoExtents[2]) / this.cellSize);
				hPixelAdjustment /= 2;
			} else {
				hPixelAdjustment += Math.round((maxExtents[2] - geoExtents[2]) / this.cellSize);
			}
        }
		// check if horizontal adjustment is needed
		if(hPixelAdjustment != 0) {
            this.theInsideLayer.style.left = (safeParseInt(this.theInsideLayer.style.left) - hPixelAdjustment) + 'px';
        }
        // check top and bottom - both can not be corrected
        if(geoExtents[1] < maxExtents[1]) {
            // extra on bottom
            vPixelAdjustment = Math.round((maxExtents[1] - geoExtents[1]) / this.cellSize);
        }
        if(geoExtents[3] > maxExtents[3]) {
            // extra on top
			if(vPixelAdjustment != 0) {
				// if both top and bottom are over, split the difference
	            vPixelAdjustment += Math.round((maxExtents[3] - geoExtents[3]) / this.cellSize);
				vPixelAdjustment /= 2;
			} else {
	            vPixelAdjustment = Math.round((maxExtents[3] - geoExtents[3]) / this.cellSize);
			}
        }
		if(vPixelAdjustment != 0) {
            this.theInsideLayer.style.top = (safeParseInt(this.theInsideLayer.style.top) + vPixelAdjustment) + 'px';
        }
    }
};

/**
 * internal function to reuse extra images
 * take last image from each row and put it at the beginning
 */
kaMap.prototype.wrapR2L = function() {
    this.xOffset = this.xOffset - (this.nBuffer * this.tileWidth);

    var layers = this.aMaps[this.currentMap].getLayers();
    for( var k=0; k<layers.length; k++) {
        var d = layers[k].domObj;
        var refLeft = safeParseInt(d.childNodes[0].style.left);
        for (var j=0; j<this.nHigh; j++) {
            var imgLast = d.childNodes[((j+1)*this.nWide)-1];
            var imgNext = d.childNodes[j*this.nWide];

            imgLast.style.left = (refLeft - this.tileWidth) + 'px';
            imgLast.src = this.aPixel.src;
            d.removeChild(imgLast);
            d.insertBefore(imgLast, imgNext);
            if (layers[k].visible) {
                layers[k].setTile(imgLast);
            }
        }
    }
};

/**
 * internal function to reuse extra image
 * take first image from each row and put it at the end
 */
kaMap.prototype.wrapL2R = function() {
     this.xOffset = this.xOffset + (this.nBuffer*this.tileWidth);
    var layers = this.aMaps[this.currentMap].getLayers();
    for( var k=0; k<layers.length; k++) {
        var d = layers[k].domObj;
        var refLeft = safeParseInt(d.childNodes[this.nWide-1].style.left);
        for (var j=0; j<this.nHigh; j++) {
            var imgFirst = d.childNodes[j*this.nWide];
            var imgNext;
            /* need to use insertBefore to get a node at the end of a 'row'
             * but this doesn't work for the very last row :(*/
            if (j < this.nHigh-1) {
                imgNext = d.childNodes[((j+1)*this.nWide)];
            } else {
                imgNext = null;
            }

            imgFirst.style.left = (refLeft + this.tileWidth) + 'px';
            imgFirst.src = this.aPixel.src;

            d.removeChild(imgFirst);
            if (imgNext) {
                d.insertBefore(imgFirst, imgNext);
            } else {
                d.appendChild(imgFirst);
            }
            if (layers[k].visible) {
                layers[k].setTile(imgFirst);
            }
        }
    }
};

/**
 * internal function to reuse extra images
 * take top image from each column and put it at the bottom
 */
kaMap.prototype.wrapT2B = function() {
    this.yOffset = this.yOffset + (this.nBuffer*this.tileHeight);
    var layers = this.aMaps[this.currentMap].getLayers();
    for( var k=0; k<layers.length; k++) {
        var d = layers[k].domObj;
        var refTop = safeParseInt(d.childNodes[(this.nHigh*this.nWide)-1].style.top);
        for (var i=0; i<this.nWide; i++) {
            var imgBottom = d.childNodes[0];
            imgBottom.style.top = (refTop + this.tileHeight) + 'px';
            imgBottom.src = this.aPixel.src;
            d.removeChild(imgBottom);
            d.appendChild(imgBottom);
            if (layers[k].visible) {
                layers[k].setTile(imgBottom);
            }
        }
    }
};

/**
 * internal function to reuse extra images
 * take bottom image from each column and put it at the top
 */
kaMap.prototype.wrapB2T = function() {
    this.yOffset = this.yOffset - (this.nBuffer*this.tileHeight);
    var layers = this.aMaps[this.currentMap].getLayers();
    for( var k=0; k<layers.length; k++) {
        var d = layers[k].domObj;
        var refTop = safeParseInt(d.childNodes[0].style.top);
        for (var i=0; i<this.nWide; i++) {
            var imgTop = d.childNodes[(this.nHigh*this.nWide)-1];

            imgTop.style.top = (refTop - this.tileHeight) + 'px';
            imgTop.src = this.aPixel.src;

            d.removeChild(imgTop);
            d.insertBefore(imgTop, d.childNodes[0]);
            if (layers[k].visible) {
                layers[k].setTile(imgTop);
            }

        }
    }
};

/**
 * kaMap.addMap( oMap )
 *
 * add a new instance of _map to kaMap.  _map is an internal class that
 * represents a map file from the configuration file.  This function is
 * intended for internal use by the init.phtml script.
 *
 * oMap - object, an instance of _map
 */
kaMap.prototype.addMap = function( oMap ) {
    oMap.kaMap = this;
    this.aMaps[oMap.name] = oMap;
};

/**
 * kaMap.getMaps()
 *
 * return an array of all the _map objects that kaMap knows about.  These can
 * be used to generate controls to switch between maps and to get information
 * about the layers (groups) and scales available in a given map.
 */
kaMap.prototype.getMaps = function() {
    return this.aMaps;
};

/**
 * kaMap.getCurrentMap()
 *
 * returns the currently selected _map object.  This can be used to get
 * information about the layers (groups) and scales available in the current
 * map.
 */
kaMap.prototype.getCurrentMap = function() {
    return this.aMaps[this.currentMap];
};

/**
 * kaMap.selectMap( name )
 *
 * select one of the maps that kaMap knows about and re-initialize kaMap with
 * this new map.  This function returns true if name is valid and false if the
 * map is invalid.  Note that a return of true does not imply that the map is
 * fully active.  You must register for the KAMAP_MAP_INITIALIZED event since
 * the map initialization happens asynchronously.
 *
 * name - string, the name of the map to select
 * zoom - (optional) array of 3 (centerx, centery, scale) or 4 (minx, miny,
 *        maxx,maxy) values to zoom to.
 */
kaMap.prototype.selectMap = function( name ) {
    if (!this.aMaps[name]) {
        return false;
    } else {
        this.currentMap = name;
        var oMap = this.getCurrentMap();
        this.setBackgroundColor(oMap.backgroundColor);

        this.setMapLayers();
        if (arguments[1] && arguments[1].length == 3) {
            this.zoomTo(arguments[1][0], arguments[1][1], arguments[1][2]);
            oMap.aZoomTo.length = 0;
        } else if (oMap.aZoomTo.length != 0) {
            this.zoomTo(oMap.aZoomTo[0], oMap.aZoomTo[1], oMap.aZoomTo[2]);
            oMap.aZoomTo.length = 0;
        } else if (arguments[1] && arguments[1].length == 4) {
            this.zoomToExtents( arguments[1][0], arguments[1][1],
                                arguments[1][2], arguments[1][3] );
        } else {
            this.zoomToExtents( oMap.currentExtents[0], oMap.currentExtents[1],
                               oMap.currentExtents[2], oMap.currentExtents[3] );
        }
        this.triggerEvent( KAMAP_MAP_INITIALIZED, this.currentMap );
        return true;
    }
};

/*
 * internal function added by cappu
 * check wich layers are visible and checked visible
 * in legend for current scale and map in InsideLayer
 * If needed create append or remove mapLayer!
 */
kaMap.prototype.setMapLayers = function( ) {
    var oMap = this.getCurrentMap();
    //remove layers not to be drown at the selected scale this should be change to not remove the visible
    for(var i = this.theInsideLayer.childNodes.length - 1; i>=0; i-- ) {
        if (this.theInsideLayer.childNodes[i].className == 'mapLayer') {
            this.theInsideLayer.childNodes[i].appended=false;
            this.theInsideLayer.removeChild(this.theInsideLayer.childNodes[i]);        }
    }
   //now check layer and create or append
    layers=oMap.getLayers(); //get only visible and checked layers
    for( var i=0; i<layers.length; i++) {
        if(!layers[i].domObj) {
            var d = this.createMapLayer( layers[i].name );
            this.theInsideLayer.appendChild( d );
            d.appended=true;
            layers[i].domObj = d;
            layers[i].setOpacity( layers[i].opacity );
            layers[i].setZIndex( layers[i].zIndex );
            layers[i].setVisibility( layers[i].visible );
            this.nWide = 0;
            this.nHigh = 0;
            this.drawGroup(layers[i]);
        } else if (!layers[i].domObj.appended) {
            this.theInsideLayer.appendChild( layers[i].domObj );
            layers[i].domObj.appended=true;
            layers[i].setZIndex( layers[i].zIndex );
        }
    }
    return true;
};

/*
 * internal function added by cappu
 * this function force a layer create image
 */
kaMap.prototype.drawGroup = function(group) {
    var newViewportWidth = this.getObjectWidth(this.domObj);
    var newViewportHeight = this.getObjectHeight(this.domObj);

    if (this.viewportWidth == null) {
        this.theInsideLayer.style.top = (-1*this.nCurrentTop + this.yOrigin) + "px";
        this.theInsideLayer.style.left = (-1*this.nCurrentLeft + this.xOrigin) + "px";
        this.viewportWidth = newViewportWidth;
        this.viewportHeight = newViewportHeight;
    }
    var newWide = Math.ceil((newViewportWidth / this.tileWidth) + 2*this.nBuffer);
    var newHigh = Math.ceil((newViewportHeight / this.tileHeight) + 2*this.nBuffer);

    this.viewportWidth = newViewportWidth;
    this.viewportHeight = newViewportHeight;

    if (this.nHigh == 0 && this.nWide == 0) {
        this.nWide = newWide;
    }

    while (this.nHigh < newHigh) {
        this.appendRow(group);
    }
    while (this.nHigh > newHigh) {
        this.removeRow(group);
    }
    while (this.nWide < newWide) {
        this.appendColumn(group);
    }
    while (this.nWide > newWide) {
        this.removeColumn(group);
    }
    return true;
};

kaMap.prototype.createMapLayer = function( id ) {
    var d = document.createElement( 'div' );
    d.id = id;
    d.className = 'mapLayer';
    d.style.position = 'absolute';
    d.style.visibility = 'visible';
    d.style.left = '0px';
    d.style.top = '0px';
    d.style.width= '3000px';
    d.style.height = '3000px';
    d.appended= false;//added by cappu
    return d;
};

//modified by cappu
kaMap.prototype.addMapLayer = function( l ) {
    var map = this.getCurrentMap();
    map.addLayer(l);
    this.setMapLayers();
    this.paintLayer(l);
    this.triggerEvent( KAMAP_LAYERS_CHANGED, this.currentMap );
};

//added by cappu
kaMap.prototype.removeMapLayer = function( id ) {
    var map = this.getCurrentMap();
    var layer = map.getLayer(id);
    if (!layer) {
        return false;
    }
    if (map.removeLayer ( map.getLayer(id) )) {
        this.setMapLayers();
        this.triggerEvent( KAMAP_LAYERS_CHANGED, this.currentMap );
    }
};

kaMap.prototype.getCenter = function() {
    var deltaMouseX = this.nCurrentLeft - this.xOrigin + safeParseInt(this.theInsideLayer.style.left);
    var deltaMouseY = this.nCurrentTop - this.yOrigin +  safeParseInt(this.theInsideLayer.style.top);

    var vpTop = this.nCurrentTop - deltaMouseY;
    var vpLeft = this.nCurrentLeft - deltaMouseX;

    var vpCenterX = vpLeft + this.viewportWidth/2;
    var vpCenterY = vpTop + this.viewportHeight/2;

    return new Array( vpCenterX, vpCenterY );
};

/**
 * kaMap.getGeoExtents()
 *
 * returns an array of geographic extents for the current view in the form
 * (inx, miny, maxx, maxy)
 */
kaMap.prototype.getGeoExtents = function() {
    var minx = -1*(safeParseInt(this.theInsideLayer.style.left) - this.xOrigin) * this.cellSize;
    var maxx = minx + this.viewportWidth * this.cellSize;
    var maxy= (safeParseInt(this.theInsideLayer.style.top) - this.yOrigin) * this.cellSize;
    var miny= maxy - this.viewportHeight * this.cellSize;
    return [minx,miny,maxx,maxy];
};

/**
 * kaMap.getMetaExtents()
 *
 * returns an array of geographic extents for the loaded tiles in the form
 * (minx, miny, maxx, maxy)
 */
kaMap.prototype.getMetaExtents = function() {
    //use current extents if no layers visible
    var result = this.getGeoExtents();
    var oMap = this.getCurrentMap();
    layers=oMap.getLayers();
    for( var i=0; i<layers.length; i++) {
        //find first layer with a domObj
        if(layers[i].domObj) {
            var d = layers[i].domObj;
            //top left of first image should be top left of loaded tiles
            var pl = safeParseInt(d.childNodes[0].style.left);
            var pt = safeParseInt(d.childNodes[0].style.top);
            //convert to geographic
            var glt = this.pixToGeo(pl,pt,true);
            var left = -1*glt[0];
            var top = -1*glt[1];
            //bottom right is easy to calculate from this
            var right = left + this.nWide*this.tileWidth*this.cellSize;
            var bottom = top - this.nHigh*this.tileHeight*this.cellSize;
			//this is right because top and bottom are in the wrong order
            result = [left, bottom, right, top];
            break;
        }
    }
    return result;
};

kaMap.prototype.zoomIn = function() {
    this.zoomByFactor(this.aMaps[this.currentMap].zoomIn());
};

kaMap.prototype.zoomOut = function() {
    this.zoomByFactor(this.aMaps[this.currentMap].zoomOut());
};

kaMap.prototype.zoomToScale = function( scale ) {
    this.zoomByFactor(this.aMaps[this.currentMap].zoomToScale(scale));
};

kaMap.prototype.zoomByFactor = function( nZoomFactor ) {
    if (nZoomFactor == 1) {
        this.triggerEvent( KAMAP_NOTICE, "NOTICE: changing to current scale aborted");
        return;
    }

    this.cellSize = this.cellSize/nZoomFactor;
    this.setMapLayers();
    this.initializeLayers(nZoomFactor);

    this.triggerEvent( KAMAP_SCALE_CHANGED, this.getCurrentScale() );
    this.triggerEvent( KAMAP_EXTENTS_CHANGED, this.getGeoExtents() );
};

kaMap.prototype.getCurrentScale = function() {
    return this.aMaps[this.currentMap].aScales[this.aMaps[this.currentMap].currentScale];
};

kaMap.prototype.setLayerQueryable = function( name, bQueryable ) {
    this.aMaps[this.currentMap].setLayerQueryable( name, bQueryable );
};

kaMap.prototype.setLayerVisibility = function( name, bVisible ) {
    if(!this.loadUnchecked && bVisible) {
        layer=this.aMaps[this.currentMap].getLayer(name);
        layer.visible=true;
        this.setMapLayers();
        this.aMaps[this.currentMap].setLayerVisibility( name, bVisible );
        this.paintLayer(layer);
    } else {
        this.aMaps[this.currentMap].setLayerVisibility( name, bVisible );
    }
};

kaMap.prototype.setLayerOpacity = function( name, opacity ) {
    this.aMaps[this.currentMap].setLayerOpacity( name, opacity );
};

kaMap.prototype.registerEventID = function( eventID ) {
    return this.eventManager.registerEventID(eventID);
};

kaMap.prototype.registerForEvent = function( eventID, obj, func ) {
    return this.eventManager.registerForEvent(eventID, obj, func);
};

kaMap.prototype.deregisterForEvent = function( eventID, obj, func ) {
    return this.eventManager.deregisterForEvent(eventID, obj, func);
};

kaMap.prototype.triggerEvent = function( eventID /*pass additional arguments*/ ) {
    return this.eventManager.triggerEvent.apply( this.eventManager, arguments );
};

/**
 * special helper function to parse an integer value safely in case
 * it is represented in IEEE format (scientific notation).
 */
function safeParseInt( val ) {
    return Math.round(parseFloat(val));
};

/******************************************************************************
 * _map
 *
 * internal class used to store map objects coming from the init script
 *
 * szName - string, the layer name (or group name, in this case ;))
 *
 * szTitle - string, the human-readable title of the map
 *
 * nCurrentScale - integer, the current scale as an index into aszScales;
 *
 * aszScales - array, an array of scale values for zooming.  The first scale is
 *             assumed to be the default scale of the map
 *
 * aszLayers - array, an array of layer names and statuses.  The array is indexed by
 *             the layer name and the value is true or false for the status.
 *
 *****************************************************************************/
function _map(o) {
    this.aLayers = [];
    this.aZoomTo = [];
    this.kaMap = null;
    this.name = (typeof(o.name) != 'undefined') ? o.name : 'noname';
    this.title = (typeof(o.title) != 'undefined') ? o.title : 'no title';
    this.aScales = (typeof(o.scales) != 'undefined') ? o.scales : [1];
    this.currentScale = (typeof(o.currentScale) != 'undefined') ? parseFloat(o.currentScale) : 0;
    this.units = (typeof(o.units) != 'undefined') ? o.units : 5;
    this.resolution = (typeof(o.resolution) != 'undefined') ? o.resolution:72; //used in scale calculations
    this.defaultExtents = (typeof(o.defaultExtents) != 'undefined') ? o.defaultExtents:[];
    this.currentExtents = (typeof(o.currentExtents) != 'undefined') ? o.currentExtents:[];
    this.maxExtents = (typeof(o.maxExtents) != 'undefined') ? o.maxExtents : [];
    //this.backgroundColor = (typeof(o.backgroundColor) != 'undefined') ? o.backgroundColor : '#9BAFCD';
    //to be used for versioning the map file ...
    this.version = (typeof(o.version) != 'undefined') ? o.version : "";
};

_map.prototype.addLayer = function( layer ) {
    layer._map = this;
    layer.zIndex = this.aLayers.length;
    this.aLayers.push( layer );
};

//added by cappu
_map.prototype.removeLayer = function( l ) {
  var alayer=Array();
  for(i=0,a=0;i<this.aLayers.length;i++) {
      if(this.aLayers[i]!=l) {
          alayer[a]=this.aLayers[i];
          a++;
      }
  }
  this.aLayers=alayer;
  return true;
};

//modified by cappu return only layer querable and visible for current scale
_map.prototype.getQueryableLayers = function() {
    var r = [];
    var l = this.getLayers();
    for( var i=0; i<l.length; i++) {
        if (l[i].isQueryable()) {
            r.push(l[i]);
        }
    }
    return r;
};

//modified by cappu, return only layer visible and checked for current scale !!
_map.prototype.getLayers = function() {
    var r = [];
    for( var i=0; i<this.aLayers.length; i++) {
        if (this.aLayers[i].isVisible() &&
            (this.aLayers[i].visible || this.kaMap.loadUnchecked) ) {
            r.push(this.aLayers[i]);
        }
    }
    return r;
};

//added by cappu replace old getQueryableLayers
_map.prototype.getAllQueryableLayers = function() {
    var r = [];
    for( var i=0; i<this.aLayers.length; i++) {
        if (this.aLayers[i].isQueryable()) {
            r.push(this.aLayers[i]);
        }
    }
    return r;
};

//added by cappu replace old getLayers
_map.prototype.getAllLayers = function() {
    return this.aLayers;
};

_map.prototype.getLayer = function( name ) {
    for (var i=0; i<this.aLayers.length; i++) {
        if (this.aLayers[i].name == name) {
            return this.aLayers[i];
        }
    }
};

_map.prototype.getScales = function() {
    return this.aScales;
};

_map.prototype.zoomIn = function() {
    var nZoomFactor = 1;
    if (this.currentScale < this.aScales.length - 1) {
        nZoomFactor = this.aScales[this.currentScale]/this.aScales[this.currentScale+1];
        this.currentScale = this.currentScale + 1;
    }
    return nZoomFactor;
};

_map.prototype.zoomOut = function() {
    var nZoomFactor = 1;
    if (this.currentScale > 0) {
        nZoomFactor = this.aScales[this.currentScale]/this.aScales[this.currentScale-1];
        this.currentScale = this.currentScale - 1;
    }
    return nZoomFactor;
};

_map.prototype.zoomToScale = function( scale ) {
    var nZoomFactor = 1;
    for (var i=0; i<this.aScales.length; i++) {
        if (this.aScales[i] == scale) {
            nZoomFactor = this.aScales[this.currentScale]/scale;
            this.currentScale = parseInt(i);
        }
    }
    return nZoomFactor;
};

_map.prototype.setLayerQueryable = function( name, bQueryable ) {
    var layer = this.getLayer( name );
    if(typeof(layer) != 'undefined') {
        layer.setQueryable( bQueryable );
    }
};

_map.prototype.setLayerVisibility = function( name, bVisible ) {
    var layer = this.getLayer( name );
    if(typeof(layer) != 'undefined') {
        layer.setVisibility( bVisible );
    }
};

_map.prototype.setLayerOpacity = function( name, opacity ) {
    var layer = this.getLayer( name );
    if(typeof(layer) != 'undefined') {
        layer.setOpacity( opacity );
    }
};

_map.prototype.setDefaultExtents = function( minx, miny, maxx, maxy ){
    this.defaultExtents = [minx, miny, maxx, maxy];
    if (this.currentExtents.length == 0)
        this.setCurrentExtents( minx, miny, maxx, maxy );
};

_map.prototype.setCurrentExtents = function( minx, miny, maxx, maxy ) {
    this.currentExtents = [minx, miny, maxx, maxy];
};

_map.prototype.setMaxExtents = function( minx, miny, maxx, maxy ) {
    this.maxExtents = [minx, miny, maxx, maxy];
};

_map.prototype.setBackgroundColor = function( szBgColor ) {
    this.backgroundColor = szBgColor;
};

/******************************************************************************
 * _layer
 *
 * internal class used to store map layers within a map.  Map layers track
 * visibility of the layer in the user interface.  Parameters are passed
 * as an object with the following attributes:
 *
 * name - string, the name of the layer
 * visible - boolean, the current state of the layer (true is visible)
 * opacity - integer, between 0 (transparent) and 100 (opaque), controls opacity
 *           of the layer as a whole
 * imageformat - string, the format to request the tiles in for this layer.  Can
 *               be used to optimize file sizes for different layer types
 *               by using GIF for images with fewer colours and JPEG or PNG24
 *               for high-colour layers (such as raster imagery).
 *
 * queryable - boolean, is the layer queryable?  This is different from the
 *              layer being included in queries.  bQueryable marks a layer as
 *              being capable of being queried.  The layer also has to have
 *              it's query state turned on using setQueryable
 * scales     - array to containing the layer visibility for each scale
 * force    - force layer
 *****************************************************************************/
function _layer( o ) {
    this.domObj = null;
    this._map = null;
    this.name = (typeof(o.name) != 'undefined') ? o.name : 'unnamed';
    this.name2 = (typeof(o.name2) != 'undefined') ? o.name2 : 'unnamed';	// sakai
    this.visible = (typeof(o.visible) != 'undefined') ? o.visible : true;
    this.opacity = (typeof(o.opacity) != 'undefined') ? o.opacity : 100;
    this.imageformat = (typeof(o.imageformat) != 'undefined') ? o.imageformat : null;
    this.queryable = (typeof(o.queryable) != 'undefined') ? o.queryable : false;
    this.queryState = (typeof(o.queryable) != 'undefined') ? o.queryable : false;
    this.tileSource = (typeof(o.tileSource) != 'undefined') ? o.tileSource : 'auto';
    this.scales = (typeof(o.scales) != 'undefined') ? o.scales : new Array(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
	this.visibilityContorol = (typeof(o.visibilityContorol) != 'undefined') ? o.visibilityContorol : 0;
    this.toLoad=0;
    /* this is used to mark the last time a tile in this layer was redrawn so that
     * some caching on the server can still be used effectively.
     */
    var ts = new Date();
    this.timeStamp = Math.round(ts.getTime()/1000) + ts.getTimezoneOffset() * 60;
    this.redrawInterval = (typeof(o.redrawInterval) != 'undefined') ? o.redrawInterval : -1;
    
    this.refreshInterval = (typeof(o.refreshInterval) != 'undefined') ? o.refreshInterval : -1;
    if (this.refreshInterval > 0) {
        goQueueManager.enqueue( this.refreshInterval*1000, this, this.redraw );
    }
};

_layer.prototype.isQueryable = function() {
    return this.queryState;
};

_layer.prototype.setQueryable = function( bQueryable ) {
    if (this.queryable) {
        this.queryState = bQueryable;
    }
};

//added by  cappu check layer visibility at current scale
_layer.prototype.isVisible= function() {
    return (this.scales[this._map.currentScale]==1)? true:false;
};

/**
 * layer.setOpacity( amount )
 *
 * set a layer to be semi transparent.  Amount is a number between
 * 0 and 100 where 0 is fully transparent and 100 is fully opaque
 */
_layer.prototype.setOpacity = function( amount ) {
    this.opacity = amount;
    if (this.domObj) {
        this.domObj.style.opacity = amount/100;
        this.domObj.style.mozOpacity = amount/100;
        for(var i=0;i<this.domObj.childNodes.length;i++) {
            this.domObj.childNodes[i].style.filter = "Alpha(opacity="+amount+")";
        }
    }
};

_layer.prototype.setTile = function(img) {
    var l = safeParseInt(img.style.left) + this._map.kaMap.xOrigin;
    var t = safeParseInt(img.style.top) + this._map.kaMap.yOrigin;
    // dynamic imageformat
    var szImageformat = '';
    var src;
    var image_format = '';
    if (this.imageformat && this.imageformat != '') {
        image_format = this.imageformat;
        szImageformat = '&i='+image_format;
    }
    if(this.tileSource == 'cache') {
        var metaLeft = Math.floor(l/(this._map.kaMap.tileWidth * this._map.kaMap.metaWidth)) * this._map.kaMap.tileWidth * this._map.kaMap.metaWidth;
        var metaTop = Math.floor(t/(this._map.kaMap.tileHeight * this._map.kaMap.metaHeight)) * this._map.kaMap.tileHeight * this._map.kaMap.metaHeight;
        var metaTileId = 't' + metaTop + '/l' + metaLeft;
        var groupsDir = (this.name != '') ? this.name.replace(/\W/g, '_') : 'def';
        var cacheDir = this._map.kaMap.webCache + this._map.name + '/' + this._map.aScales[this._map.currentScale] + '/' + groupsDir + '/def/' + metaTileId;
        var tileId = "t" + t + "l" + l;
        // the following conversion of image format to image extension
        // works for JPEG, GIF, PNG, PNG24 - others may need different treatment
        var imageExtension = this.imageformat.toLowerCase().replace(/[\de]/g, '');
        src = cacheDir + "/" + tileId + "." + imageExtension;
    } else {
        var szVersion = '';
        if (this._map.version != '') {
            szVersion = '&version='+this._map.version;
        }
        var szForce = '';
        var szLayers = '';
        if (arguments[1]) {
            szForce = '&force=true';
        }
        var szTimestamp = '';
        if (this.tileSource == 'redraw' || this.tileSource == "refresh") {
            szTimestamp = '&ts='+this.timeStamp;
            if (this.redrawInterval) {
                szTimestamp = szTimestamp + '&interval='+this.redrawInterval;
            }
        }
        
        var szGroup = '&g='+img.layer.domObj.id;
        var szScale = '&s='+this._map.aScales[this._map.currentScale];
        var q = '?';
        if (this._map.kaMap.tileURL.indexOf('?') != -1) {
            if (this._map.kaMap.tileURL.slice(-1) != '&') {
                q = '&';
            } else {
                q = '';
            }
        }
        if (this.tileSource == 'nocache') {
            src = this._map.kaMap.server +
            this._map.kaMap.tileURL.replace('tile.phtml', 'tile_nocache.phtml') +
            q + 'map=' + this._map.name +
            '&t=' + t +
            '&l=' + l +
            szScale + szForce + szGroup + szImageformat;
            // tack on any variables for replacement
            if(typeof(this.replacementVariables) != 'undefined') {
                for(var key in this.replacementVariables) {
                    src += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(this.replacementVariables[key]);
                }
            }
        } else {
            src = this._map.kaMap.server +
            this._map.kaMap.tileURL +
            q + 'map=' + this._map.name +
            '&t=' + t +
            '&l=' + l +
            szScale + szForce + szGroup + szImageformat + szTimestamp + szVersion;
        }
    }
    if (img.src != src) {
        img.style.visibility = 'hidden';
        img.src = src;
    }
};

_layer.prototype.setVisibility = function( bVisible ) {
    this.visible = bVisible;
    if (this.domObj) {
        this.domObj.style.visibility = bVisible?'visible':'hidden';
        //horrid hack - this is needed in case any element contained
        //within the div has its visibility set ... it overrides the
        //style of the container!!!
        this.domObj.style.display = bVisible?'block':'none';
	    for( var i=0; i<this.domObj.childNodes.length; i++) {
	        this.setTile(this.domObj.childNodes[i]);
	    }
		this._map.kaMap.triggerEvent( KAMAP_LAYER_STATUS_CHANGED, this );
	}
};

_layer.prototype.setZIndex = function( zIndex ) {
    this.zIndex = zIndex;
    if (this.domObj) {
        this.domObj.style.zIndex = zIndex;
    }
};

//Set all layers tile added by cappu
_layer.prototype.setTileLayer = function() {
    this.loaded=0;
    for(i = 0; i < this.domObj.childNodes.length; i++) {
        img = this.domObj.childNodes[i];
        if(arguments[0]) {
            this.setTile(img, arguments[0]);
        }
        else {
            this.setTile(img);
        }
    }
};

/* redraw a layer completely, updating an internal timestamp that is passed as
 * an argument to the server.  If the tile data has changed, you'll get new
 * tiles.
 *
 * first, and only, argument to this function is the new update frequency, if
 * any.  If the update frequency is <= 0 then the layer will not be
 * automatically refreshed.
 */
_layer.prototype.redraw = function() {
    if (arguments[0]) {
        this.refreshInterval = arguments[0];
    }
    if (this.visible) {
        var ts = new Date();
        this.timeStamp = Math.round(ts.getTime()/1000) + ts.getTimezoneOffset() * 60;
        this.setTileLayer();
    }
    if (this.refreshInterval > 0) {
        goQueueManager.enqueue( this.refreshInterval*1000, this, this.redraw );
    }
};

/******************************************************************************
 * Event Manager class
 *
 * an internal class for managing generic events.  kaMap! uses the event
 * manager internally and exposes certain events to the application.
 *
 * the kaMap class provides wrapper functions that hide this implementation
 * useage:
 *
 * myKaMap.registerForEvent( gnSomeEventID, myObject, myFunction );
 * myKaMap.registerForEvent( 'SOME_EVENT', myObject, myFunction );
 *
 * myKaMap.deregisterForEvent( gnSomeEventID, myObject, myFunction );
 * myKaMap.deregisterForEvent( 'SOME_EVENT', myObject, myFunction );
 *
 * myObject is normally null but can be a javascript object to have myFunction
 * executed within the context of an object (becomes 'this' in the function).
 *
 *****************************************************************************/
function _eventManager( )
{
    this.events = [];
    this.lastEventID = 0;
}

_eventManager.prototype.registerEventID = function( eventID ) {
    var ev = new String(eventID);
    if (!this.events[eventID]) {
        this.events[eventID] = [];
    }
};

_eventManager.prototype.registerForEvent = function(eventID, obj, func) {
    var ev = new String(eventID);
    this.events[eventID].push( [obj, func] );
};

_eventManager.prototype.deregisterForEvent = function( eventID, obj, func ) {
    var ev = new String(eventID);
    var bResult = false;
    if (!this.events[eventID]) {
        return false;
    }

    for (var i=0;i<this.events[eventID].length;i++) {

        if (this.events[eventID][i][0] == obj &&
            this.events[eventID][i][1] == func) {
            this.events[eventID].splice(i,1);
            bResult = true;
        }
    }
    return bResult;
};

_eventManager.prototype.triggerEvent = function( eventID ) {
    var ev = new String(eventID);
    if (!this.events[eventID]) {
        return false;
    }

    var args = new Array();
    for(i=1; i<arguments.length; i++) {
        args[args.length] = arguments[i];
    }

    for (var i=0; i<this.events[eventID].length; i++) {
        this.events[eventID][i][1].apply( this.events[eventID][i][0],
                                          arguments );
    }
    return true;
};

/******************************************************************************
 * Queue Manager class
 *
 * an internal class for managing delayed execution of code.  This uses the
 * window.setTimeout interface but adds support for execution of functions
 * on objects
 *
 * The problem with setTimeout is that you need a reference to a global object
 * to do something useful in an object-oriented environment, and we don't
 * really have that here.  So the Queue Manager handles a stack of pending
 * delayed execution code and evaluates it when it comes due.  It can be
 * used exactly like window.setTimeout in that it returns an id that can
 * subsequently be used to clear the delayed code.
 *
 * To add something to the queue, call
 * var id = goQueueManager.enqueue( timeout, obj, func, args );
 *
 * timeout - time to delay (milliseconds)
 * obj - the object to execute the function within.  Can be null for global
 *       scope
 * func - the function to execute.  Note this is the function, not a string
 *        containing the function.
 * args - an array of values to be passed to the function.
 *
 * To remove a function from the queue, call goQueueManager.dequeue( id );
 *****************************************************************************/
var goQueueManager = new _queueManager();

function _queueManager() {
    this.queue = new Array();
}

_queueManager.prototype.enqueue = function( timeout, obj, func, args ) {
    var pos = this.queue.length;
    for (var i=0; i< this.queue.length; i++) {
        if (this.queue[i] == null) {
            pos = i;
            break;
        }
    }
    var id = window.setTimeout( "_queueManager_execute("+pos+")", timeout );
    this.queue[pos] = new Array( id, obj, func, args );
    return pos;
};

_queueManager.prototype.dequeue = function( pos ) {
    if (this.queue[pos] != null) {
        window.clearTimeout( this.queue[pos][0] );
        this.queue[pos] = null;
    }
};

function _queueManager_execute( pos) {
    if (goQueueManager.queue[pos] != null) {
        var obj = goQueueManager.queue[pos][1];
        var func = goQueueManager.queue[pos][2];
        if (goQueueManager.queue[pos][3] != null) {
            func.apply( obj, goQueueManager.queue[pos][3] );
        } else {
            func.apply( obj );
        }
        goQueueManager.queue[pos] = null;
    }
};
var charset="";
/**********************************************************************
 *
 * $Id: kaKeymap.js,v 1.21 2006/03/12 20:33:29 pspencer Exp $
 *
 * purpose: kaKeymap provides an overview or reference for navigational
 *          aid to the user.
 *
 * It works by displaying an image and overlaying a rectangular box that
 * indicates the current extents of the main kaMap view.  To accomplish this,
 * the image is associated with a set of geographic extents that it represents.
 * A keymap image is normally a small image that is representative of the full
 * area of the application's data, but with reduced detail (typically just
 * polygons and lines for countries and political boundaries).
 *
 * The default mode of operation uses MapServer only to get the reference
 * object image and extents from the map file.  Tracking of extents is done
 * purely on the client side.
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 * The original kaKeymap code was written by DM Solutions Group.  Lorenzo
 * Becchi and Andrea Cappugi contributed the code to make the keymap clickable
 * and draggable.
 *
 * TODO:
 *
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/******************************************************************************
 * kaKeymap
 *
 * class to handle the keymap
 *
 * oKaMap - the ka-Map instance to draw the keymap for
 * szID - string, the id of a div that will contain the keymap
 *
 *****************************************************************************/
function kaKeymap(oKaMap, szID ) {
    this.kaMap = oKaMap;
    this.domObj = this.kaMap.getRawObject(szID);
    this.domObj.kaKeymap=this;
    this.pxExtent =null;
    this.domExtents = null;
    this.aExtents = null;
    this.domImg = null;
    this.imgSrc = null;
    this.imgWidth = null;
    this.imgHeight = null;

	this.cx = null;
	this.cy = null;

    this.cellWidth = null;
    this.cellHeight = null;
    this.initialExtents = null;

    this.domObj.ondblclick= this.onclick;

    if ( this.domObj.captureEvents) {
        this.domObj.captureEvents(Event.DBLCLICK);
    }
    
    this.kaMap.registerForEvent( KAMAP_EXTENTS_CHANGED, this, this.update );
    this.kaMap.registerForEvent( KAMAP_MAP_INITIALIZED, this, this.initialize );
};

kaKeymap.prototype.initialize = function(id) {
    this.pxExtent = null;
    this.initialExtents = this.kaMap.getGeoExtents();
	var extents = this.kaMap.getGeoExtents();
	this.cx = (extents[0]+extents[2])/2;
	this.cy = (extents[1]+extents[3])/2;
	
    //call(this.kaMap.server+'/keymap.phtml?map='+this.kaMap.currentMap,this,this.draw);
	//call(this.kaMap.server+'/keymap.phtml?map='+this.kaMap.currentMap+"&x="+this.cx+"&y="+this.cy,this,this.draw);	// sakai
	var url = this.kaMap.server + "/keymap.phtml?map=" + this.kaMap.currentMap + "&x=" + this.cx + "&y=" + this.cy + "&callback=ICTMAP.kaKeymap.draw";
	var koJsr = new JSONscriptRequest(url);
    koJsr.buildScriptTag();
    koJsr.addScriptTag();
};

kaKeymap.prototype.draw = function( szResult ) {
    eval( szResult );
    this.cellWidth = (this.aExtents[2] - this.aExtents[0]) / this.imgWidth;
    this.cellHeight = (this.aExtents[3] - this.aExtents[1]) / this.imgHeight;
    //clear old keymap
    for(var i = this.domObj.childNodes.length - 1; i >= 0; i--)
    this.domObj.removeChild (this.domObj.childNodes[i]);
    
    this.domObj.style.width = this.imgWidth + "px";
    this.domObj.style.height = this.imgHeight + "px";
    this.width = this.imgWidth + "px";
    this.height = this.imgHeight + "px";
	
    //create an image to hold the keymap
    this.domImg = document.createElement( 'img' );
    //this.domImg.src = this.imgSrc + '&map='+this.kaMap.currentMap;
	this.domImg.src = this.imgSrc + '&map='+this.kaMap.currentMap+"&x="+this.cx+"&y="+this.cy;
    this.domImg.width = this.imgWidth;
    this.domImg.height = this.imgHeight;
    this.domObj.appendChild( this.domImg );
    
	//create a div to track the current extents
    this.domExtents = document.createElement( 'div' );
	this.domExtents.kaKeymap = this;
    this.domExtents.id="keymapDomExtents";
    this.domExtents.style.position = 'absolute';
    this.domExtents.style.border = '1px solid red';
    this.domExtents.style.top = "1px";
    this.domExtents.style.left = "1px";
    this.domExtents.style.width = "1px";
    this.domExtents.style.height = "1px";
    this.domExtents.style.backgroundColor = 'transparent';
    this.domExtents.style.visibility = 'visible';
	this.domObj.appendChild(this.domExtents);

    //create a div to allow click/drag of extents for nav
    this.domEvent = document.createElement( 'div' );
    this.domEvent.kaKeymap=this;

    this.domEvent.onmousedown= this.mousedown;
    this.domEvent.onmouseup= this.mouseup;
    this.domEvent.onmousemove= this.mousemove;
    this.domEvent.onmouseout= this.mouseup;
    if (this.domEvent.captureEvents) {
       this.domEvent.captureEvents(Event.MOUSEDOWN);
       this.domEvent.captureEvents(Event.MOUSEUP);
       this.domEvent.captureEvents(Event.MOUSEMOVE);
       this.domEvent.captureEvents(Event.MOUSEOUT);
    }

    this.domEvent.style.position = 'absolute';
    this.domEvent.id = 'keymapDomEvent';
    this.domEvent.style.border = '1px solid red';
    this.domEvent.style.top = "1px";
    this.domEvent.style.left = "1px";
    this.domEvent.style.width = "1px";
    this.domEvent.style.height = "1px";
    this.domEvent.style.backgroundColor = 'white';
    this.domEvent.style.visibility = 'visible';
    this.domEvent.style.opacity=0.01;
    this.domEvent.style.mozOpacity=0.01;
    this.domEvent.style.filter = "Alpha(opacity=0.01)";
    this.domObj.appendChild(this.domEvent);

    //changed use an image insetd divs to drow the cross air
    var d = document.createElement( 'img' );
    d.id="keymapCrossImage";
    d.src = this.kaMap.server+"common/images2/cross.png";
    d.style.position='absolute';
	d.style.top = '0px';
	d.style.left = '0px';
    d.style.width = "19px";
    d.style.height = "19px";
    d.style.visibility = 'hidden';

    this.domExtents.appendChild(d);
	this.domCross = d;

    if (this.initialExtents != null) {
        this.update( null, this.initialExtents);
    }
	
	//create btn to close open the submap
	this.btn = document.createElement("img");
	this.btn.src = this.kaMap.server + "common/images/minus.gif";
	this.btn.onclick = this.closeSubMap;
	this.btn.style.position="absolute";
	this.btn.style.right="1px";
	this.btn.style.top="1px";
	this.btn.style.cursor="pointer";
	this.btn.parentObj = this;
	this.dspFlg=1;
	this.domObj.appendChild(this.btn);
	this.btn.onclick();	//初期表示しない
};

kaKeymap.prototype.update = function( eventID, extents ) {
    if (!this.aExtents || !this.domExtents) {
        this.initialExtents = extents;
        return;
    }

    var left = (extents[0] - this.aExtents[0]) / this.cellWidth;
    var width = (extents[2] - extents[0]) / this.cellWidth;
    var top = -1 * (extents[3] - this.aExtents[3]) / this.cellHeight;
    var height = (extents[3] - extents[1]) / this.cellHeight;
	
	this.cx = (extents[0]+extents[2])/2;
	this.cy = (extents[1]+extents[3])/2;

    this.pxExtent = new Array(left,top,width,height);
    this.domExtents.style.top = parseInt(top+0.5)+"px";
    this.domExtents.style.left = parseInt(left+0.5)+"px";
    this.domEvent.style.top = parseInt(top+0.5)+"px";
    this.domEvent.style.left = parseInt(left+0.5)+"px";
    
    if (parseInt(width+0.5) < parseInt(this.domCross.style.width) ||
        parseInt(height+0.5) < parseInt(this.domCross.style.height) ) {
        //show crosshair and center on center of image
		var ix = parseInt(this.domCross.style.width)/2;
		var iy = parseInt(this.domCross.style.height)/2;
		
		var ox = width/2;
		var oy = height/2;
        
		this.domExtents.style.width = this.domCross.style.width;
        this.domExtents.style.height = this.domCross.style.height;
        this.domEvent.style.width = this.domCross.style.width;
        this.domEvent.style.height = this.domCross.style.height;
		this.domExtents.style.top = (parseInt(this.domExtents.style.top) -iy + oy) + 'px';
		this.domExtents.style.left = (parseInt(this.domExtents.style.left) -ix  + ox) + 'px';
        this.domEvent.style.top = (parseInt(this.domEvent.style.top) -iy + oy) + 'px';
        this.domEvent.style.left = (parseInt(this.domEvent.style.left) -ix + ox) + 'px';
        this.domCross.style.visibility = 'visible';
		this.domExtents.style.border = '1px solid white';
        this.domEvent.style.border = 'none';
    } else {
    	this.domExtents.style.width = parseInt(width+0.5) + "px";
	    this.domExtents.style.height = parseInt(height+0.5) + "px";
        this.domEvent.style.width = parseInt(width+0.5) + "px";
        this.domEvent.style.height = parseInt(height+0.5) + "px";
        this.domCross.style.visibility = 'hidden';
		this.domExtents.style.border = '1px solid red';
        this.domEvent.style.border = '1px solid red';
		this.domEvent.style.visibility = 'visible';
        this.domExtents.style.visibility = 'visible';
     }
	
	var domCx = this.domExtents.offsetLeft + getObjectWidth(this.domExtents)/2;
	var domCy = this.domExtents.offsetTop  + getObjectHeight(this.domExtents)/2;
	
	// sakai
	// リファレンスマップベース地図を更新
	//if(top < 0 || left < 0 || (top+height) > this.imgHeight || (left+width) > this.imgWidth){
	if(domCx < 0 || domCx > this.imgWidth || domCy < 0 || domCy > this.imgHeight){
		this.initialize();
		//console.log("renew referencemap");
		this.renewcnt++;
	}
	
};

/*click event on div kaKeymap*/
kaKeymap.prototype.onclick = function(e) {
    e = (e)?e:((event)?event:null); 
    this.kaKeymap.centerMap(e);
};

/*call aPixPos to calculate geografic position of click and recenter kamap map*/
kaKeymap.prototype.centerMap = function(e) {
    var pos= this.aPixPos( e.clientX, e.clientY );
    this.kaMap.zoomTo(pos[0],pos[1]);
};

/**
 * kaKeymap_aPixPos( x, y )
 *
 * try to calculate geoposition in kaKeymap
 *
 * x - int, the x page coord
 * y - int, the y page coord
 *
 * returns an array with geo positions
 */
kaKeymap.prototype.aPixPos = function( x, y ) {
    var obj = this.domObj;
    var offsetLeft = 0;
    var offsetTop = 0;
    while (obj) {
        offsetLeft += parseFloat(obj.offsetLeft);
        offsetTop += parseFloat(obj.offsetTop);
        obj = obj.offsetParent;
    }
    var pX = x  - offsetLeft  ;
    var pY = y  -  offsetTop  ;
    pX = parseFloat(this.aExtents[0] + (this.cellWidth *pX)); 
    pY = parseFloat(this.aExtents[3] - (this.cellHeight *pY));
    return [pX,pY];
};

kaKeymap.prototype.mousedown = function(e) {
     	getRawObject("pointinfo").style.visibility='hidden';	//sakai
     e = (e)?e:((event)?event:null);
     this.kaKeymap.domEvent.style.top= "0px";
     this.kaKeymap.domEvent.style.left= "0px";
     this.kaKeymap.domEvent.style.width =this.kaKeymap.domObj.style.width;
     this.kaKeymap.domEvent.style.height = this.kaKeymap.domObj.style.height;
     this.kaKeymap.domExtents.init=1;
     this.kaKeymap.domExtents.oX=e.clientX;
     this.kaKeymap.domExtents.oY=e.clientY;
     var amount= 50;
     this.kaKeymap.domExtents.style.backgroundColor = 'pink';
     this.kaKeymap.domExtents.style.opacity=amount/100;

//     this.kaKeymap.domObj.style.mozOpacity = amount/100;
    //Nasty IE effect (or bug?) when you apply a filter
    //to a layer, it clips the layer and we rely on the
    //contents being visible outside the layer bounds
    //for 'railroading' the tiles
    if (this.kaKeymap.kaMap.isIE4) {
        this.kaKeymap.domExtents.style.filter = "Alpha(opacity="+amount+")";        
    }
    e=null;
};

kaKeymap.prototype.mouseup = function(e) {
    if(this.kaKeymap.domExtents.init) {
        e = (e)?e:((event)?event:null); 
        this.kaKeymap.domExtents.style.backgroundColor = 'transparent';
        this.kaKeymap.domExtents.style.opacity=1;
        if (this.kaKeymap.kaMap.isIE4) {
            this.kaKeymap.domExtents.style.filter = "Alpha(opacity=100)";
        } 
        this.kaKeymap.domExtents.init=0;
        var cG=this.kaKeymap.geoCentCoord();
        this.kaKeymap.kaMap.zoomTo(cG[0],cG[1]);
    }
};

kaKeymap.prototype.mousemove = function(e) {
    e = (e)?e:((event)?event:null); 
    if(this.kaKeymap.domExtents.init) {
        var xMov=(this.kaKeymap.domExtents.oX-e.clientX);
        var yMov=(this.kaKeymap.domExtents.oY-e.clientY);

        var oX=this.kaKeymap.pxExtent[0];
        var oY=this.kaKeymap.pxExtent[1];
        var nX = oX-xMov;
        var nY = oY-yMov;
        this.kaKeymap.domExtents.oX= e.clientX;
        this.kaKeymap.domExtents.oY= e.clientY;
        this.kaKeymap.pxExtent[0] = nX;
        this.kaKeymap.pxExtent[1] = nY;
        if(this.kaKeymap.domCross.style.visibility == 'visible') {
            var ix = parseInt(this.kaKeymap.domCross.style.width)/2;
            var iy = parseInt(this.kaKeymap.domCross.style.height)/2;
            var ox =  this.kaKeymap.pxExtent[2]/2;
            var oy = this.kaKeymap.pxExtent[3]/2;

            this.kaKeymap.domExtents.style.top = parseInt((nY+0.5)-iy+oy) + "px";
            this.kaKeymap.domExtents.style.left = parseInt((nX+0.5)-ix+ox) + "px";
        } else {
            this.kaKeymap.domExtents.style.top = parseInt(nY+0.5) + "px";
            this.kaKeymap.domExtents.style.left = parseInt(nX+0.5) + "px";
        }
    }
};

/**
 * calculate the geographic position of div's center
 * Use pxExtent left top width height because the 
 * div's top left width and heigth (casted to int)
 * this avoid in calculation error due to ins casting
 **/
kaKeymap.prototype.geoCentCoord = function() {
       var cpX = this.pxExtent[0] + this.pxExtent[2]/2;
       var cpY = this.pxExtent[1] +  this.pxExtent[3]/2;
       var cX = this.aExtents[0] + (this.cellWidth *cpX);
       var cY = this.aExtents[3] - (this.cellHeight *cpY); 
      return [cX,cY];
};

kaKeymap.prototype.closeSubMap = function(){
	if(this.parentObj.dspFlg == 1){
		this.parentObj.domImg.style.display="none";
		this.parentObj.domExtents.style.display="none";
		this.parentObj.domEvent.style.display="none";
		this.parentObj.domObj.style.width="12px";
		this.parentObj.domObj.style.height="12px";
		this.parentObj.dspFlg = 0;
		this.src = this.parentObj.kaMap.server + "common/images/plus.gif";
	}else{
		this.parentObj.domImg.style.display="block";
		this.parentObj.domExtents.style.display="block";
		this.parentObj.domEvent.style.display="block";
		this.parentObj.domObj.style.width=this.parentObj.width;
		this.parentObj.domObj.style.height=this.parentObj.height;
		this.parentObj.dspFlg = 1;
		this.src = this.parentObj.kaMap.server + "common/images/minus.gif";
	}
};var charset="";
/**********************************************************************
 *
 * $Id: kaTool.js,v 1.34 2006/10/19 02:36:28 pspencer Exp $
 *
 * purpose: an API for kaMap tools with a default navigation tool provided
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 * The original kaTool code was written by DM Solutions Group.
 *
 * TODO:
 * 
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/*
 * includes code inspired by code in WindowManager.js
 * Copyright 2005 MetaCarta, Inc., released under the BSD License
 */

//globally 
var kaCurrentTool = null;

/**
 * @class
 * kaTool API.<br>
 * An API for building tools that work with kaMap.
 * To create a new tool, you need to have included this file first.  Next
 * create a function to instantiate your new tool.  All object construction
 * functions must include a parameter that references the kaMap object on which
 * they operate.<br>
 * The object construction function must call the kaTool constructor using the
 * following syntax:<br><br>
 * kaTool.apply( this, [oKaMap] );<br><br>
 * where oKaMap is the name of the parameter to the constructor function.
 * You should then set the tool's name (this.name) and overload any functions
 * for mouse handling etc.
 *
 * @constructor kaTool
 * kaTool is the base class for tools which operate on an instance of kaMap.
 * @param {Object} oKaMap the instance of kaMap on which this tool should operate
 */
function kaTool( oKaMap ) {
    /** the instance of kaMap on which this tool operates */
    this.kaMap = oKaMap;
    /** the name of this tool */
    this.name = 'kaTool';
    /** info tools get all events all the time */
    this.bInfoTool = false;
    
    // Default for mouse wheel: zoom in or out. (Mod D Badke)
    this.wheelPlus = new Array(oKaMap, oKaMap.zoomOut, null);
    this.wheelMinus = new Array(oKaMap, oKaMap.zoomIn, null);
    
    this.kaMap.registerTool( this );
};

/**
 * is this an info tool or a regular tool?
 */
kaTool.prototype.isInfoTool = function() {
    return this.bInfoTool;
};

/**
 * activate this tool.  Activating the tool causes any existing tools to be
 * deactivated.
 */
kaTool.prototype.activate = function() {
    this.kaMap.activateTool( this );
    document.kaCurrentTool = this;
};

/**
 * deactivate this tool.  
 */
kaTool.prototype.deactivate = function() {
    this.kaMap.deactivateTool( this );
    document.kaCurrentTool = null;
};

/**
 * handle mouse movement over the viewport of the kaMap.  This
  * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmousemove = function(e) {
    return false;
};

/**
 * handle mouse down events on the viewport of the kaMap.  This
  * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmousedown = function(e) {
    return false;
};

/**
 * handle mouse up events on the viewport of the kaMap.  This
  * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmouseup = function(e) {
    return false;
};

/**
 * handle mouse doubleclicks on the viewport of the kaMap.  This
 * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.ondblclick = function(e) {
    return false;
};

/**
 * Set the object and function to call when the mouse wheel
 * event triggers. The parameters are saved in the tool object
 * this is called for, and only affect that tool.
 * 
 * @param {array} plusSet  - parameters for positive wheel scroll
 * @param {array} minusSet - parameters for negative wheel scroll
 * 
 * plusSet and minusSet are arrays of structure:
 *   [0] - object to apply function for or null
 *   [1] - function to apply
 *   [2] - function arguments or null for no arguments
 * 
 * Set minusSet and/or plusSet to null to disable that scroll direction.
 * 
 * eg: --disable mouse wheel for navigator tool:
 * 				 myKaNavigator.setMouseWheel(null, null);
 * 
 *     --set navigator tool to zoom (same as default action):
 *         myKaNavigator.setMouseWheel([myKaMap, myKaMap.zoomIn, null],
 * 					 											     [myKaMap, myKaMap.zoomOut, null]);
 * 
 * (New D Badke)
 */
kaTool.prototype.setMouseWheel = function(minusSet, plusSet) {
	this.wheelMinus = minusSet;
	this.wheelPlus = plusSet;
};

/**
 * Handle mouse wheel events over the viewport of the kaMap.  This
 * applies a function set by the setMouseWheel function. If the function
 * is null, do nothing. (Mod D Badke)
 * 
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmousewheel = function(e) {
    e = (e)?e:((event)?event:null);
    var wheelDelta = e.wheelDelta ? e.wheelDelta : e.detail*-1;
    var wheelSet = null;
    if (wheelDelta > 0) 
    	wheelSet = this.wheelMinus;
    else
    	wheelSet = this.wheelPlus;
    
  	if (wheelSet) {
  		obj = (wheelSet[0]) ? wheelSet[0] : null;
  		func = (wheelSet[1]) ? wheelSet[1] : null;
  		args = (wheelSet[2]) ? wheelSet[2] : null;
  		if (func) {
			if (args) {
				func.apply(obj, args);
			} else{
			    func.apply(obj);
			}
  		}
    }
};

/**
 * adjust a page-relative pixel position into a kaMap relative
 * pixel position
 *
 * @param {Integer} x the x page coordinate to convert
 * @param {Integer} y the y page coordinate to convert
 * @return {Array} return an array containing the converted coordinates
 */
kaTool.prototype.adjustPixPosition = function( x, y ) {
    var obj = this.kaMap.domObj;
    var offsetLeft = 0;
    var offsetTop = 0;
    while (obj) {
        offsetLeft += parseInt(obj.offsetLeft);
        offsetTop += parseInt(obj.offsetTop);
        obj = obj.offsetParent;
    }
    
    var pX = parseInt(this.kaMap.theInsideLayer.style.left) + 
             offsetLeft - this.kaMap.xOrigin - x;
    var pY = parseInt(this.kaMap.theInsideLayer.style.top) + 
             offsetTop - this.kaMap.yOrigin - y;
             
    return [pX,pY];
};

/*
 * key press events are directed to the HTMLDocument rather than the
 * div on which we really wanted them to happen.  So we set the document
 * keypress handler to this function and redirect it to the kaMap core
 * keypress handler, which will eventually reach the onkeypress handler
 * of our current tool ... which by default is the keyboard navigation.
 *
 * To get the keyboard events in the first place, add the following when you
 * want the keypress events to be captured
 *
 * if (isIE4) document.onkeydown = kaTool_redirect_onkeypress;
 * document.onkeypress = kaTool_redirect_onkeypress;
 */
function kaTool_redirect_onkeypress(e) {
    if (document.kaCurrentTool) {
        document.kaCurrentTool.onkeypress(e);
    }
};

/**
 * handle keypress events.  Keypress events are normally dispatched
 * here rather than in a sub-class.
 * @param {Event} e the keypress event object
 */
kaTool.prototype.onkeypress = function(e) {
    e = (e)?e:((event)?event:null);
    if (e) {
        var charCode=(e.charCode)?e.charCode:e.keyCode;
        var b=true;
        var nStep = 16;
        switch(charCode) {
          case 38://up
            this.kaMap.moveBy(0,nStep);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 40:
            this.kaMap.moveBy(0,-nStep);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 37:
            this.kaMap.moveBy(nStep,0);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 39:
            this.kaMap.moveBy(-nStep,0);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 33:
            this.kaMap.slideBy(0, this.kaMap.viewportHeight/2);
            break;
          case 34:
            this.kaMap.slideBy(0,-this.kaMap.viewportHeight/2);
            break;
          case 36:
            this.kaMap.slideBy(this.kaMap.viewportWidth/2,0);
            break;
          case 35:
            this.kaMap.slideBy(-this.kaMap.viewportWidth/2,0);
            break;
          case 43: //ascii +
          case 61: //ascii =
            this.kaMap.zoomIn();
            break;
         case 45:
            this.kaMap.zoomOut();
            break;
          default:
            b=false;
        }
        if (b) {
            return this.cancelEvent(e);
        }
        return true;
    }
};

/**
 * handle the mouse moving over the kaMap viewport.  This is a method does
 * nothing and should be overloaded in a subclass
 * @param {Event} e the mouse event
 */
kaTool.prototype.onmouseover = function(e) {
    return false;
};

/**
 * handle the mouse leaving the kaMap viewport.  This is a method
 * releases the keypress handler and should be called from any
 * sub class that overloads this method.
 * @param {Event} e the mouse event
 */
kaTool.prototype.onmouseout = function(e) {
    if (this.kaMap.isIE4) {
        document.onkeydown = null;
    }
    document.onkeypress = null;
    return false;
};

/**
 * provide a cross-platform method of cancelling events, including
 * stopping of event bubbling and propagation.
 * @param {Event} e the event to cancel
 */
kaTool.prototype.cancelEvent = function(e) {
    e = (e)?e:((event)?event:null);
    e.cancelBubble = true;
    e.returnValue = false;
    if (e.stopPropogation) {
        e.stopPropogation();
    }
    if (e.preventDefault) {
        e.preventDefault();
    }
    return false;
};

/**
 * Construct a new kaNavigator instance on a given kaMap instance
 *
 * @class
 * kaNavigator is a general purpose navigation tool for kaMap instances.
 * It provides panning through click-and-drag, and various keyboard
 * navigation.
 *
 * @base kaTool
 * @constructor
 * @param {Object} oKaMap the kaMap instance to provide navigation for
 * @author Paul Spencer
 */
function kaNavigator( oKaMap ) {
    kaTool.apply( this, [oKaMap] );
    /** the name of this tool */
    this.name = 'kaNavigator';
    /** the cursor to use when the map is not being dragged */
	//this.cursorNormal = ["url('images/grab.cur'),move", '-moz-grab', 'grab', 'move'];
	this.cursorNormal = ['-moz-grab', 'grab', 'move'];
	/** the cursor to use when the map is being dragged */
	//this.cursorDrag = ["url('images/grabbing.cur'),move", '-moz-grabbing', 'grabbing', 'move'];
	this.cursorDrag = ['-moz-grabbing', 'grabbing', 'move'];
	/** the cursor to use over the map (by default) */
    this.cursor = this.cursorNormal;

    /** the image to use for this tool when it is active on the map */
    this.activeImage = this.kaMap.server + 'images/button_pan_3.png';

    /** the image to use for this tool when it is disabled */
    this.disabledImage = this.kaMap.server + 'images/button_pan_2.png';
    
    /** track the last x position of the mouse for panning */
    this.lastx = null;
    /** track the last y position of the mouse for panning */
    this.lasty = null;
    /** track whether the mouse is down or up for panning support */
    this.bMouseDown = false;
    
    for (var p in kaTool.prototype) {
        if (!kaNavigator.prototype[p])
            kaNavigator.prototype[p]= kaTool.prototype[p];
    }
};

/**
 * handle the mouse leaving the viewport.  If the mouse is down, stop
 * dragging.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmouseout = function(e) {
	e = (e)?e:((event)?event:null);
    if (!e.target) e.target = e.srcElement;
    if (e.target.id == this.kaMap.domObj.id) {
        this.bMouseDown = false;
        return kaTool.prototype.onmouseout.apply(this, [e]);
    }
};

/**
 * handle the mouse moving inside viewport.  If the mouse is down, move
 * the map.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmousemove = function(e) {
    e = (e)?e:((event)?event:null);
    
    if (!this.bMouseDown) {
        return false;
    }
    
    if (!this.kaMap.layersHidden) {
        this.kaMap.hideLayers();
    }
    var newTop = safeParseInt(this.kaMap.theInsideLayer.style.top);
    var newLeft = safeParseInt(this.kaMap.theInsideLayer.style.left);

    var x = e.pageX || (e.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
                (document.documentElement.scrollTop || document.body.scrollTop));
    newTop = newTop - this.lasty + y;
    newLeft = newLeft - this.lastx + x;

    this.kaMap.theInsideLayer.style.top=newTop + 'px';
    this.kaMap.theInsideLayer.style.left=newLeft + 'px';

    this.kaMap.checkWrap.apply(this.kaMap, []);

    this.lastx=x;
    this.lasty=y;
    return false;
};

/**
 * handle mouse down events.  Start tracking mouse movement for panning.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmousedown = function(e) {
    e = (e)?e:((event)?event:null);
    if (e.button==2) {
        return this.cancelEvent(e);
    } else {
		this.cursor = this.cursorDrag;
    	this.kaMap.setCursor(this.cursorDrag);
        if (this.kaMap.isIE4) {
            document.onkeydown = kaTool_redirect_onkeypress;
        }
        document.onkeypress = kaTool_redirect_onkeypress;
        
        this.bMouseDown=true;
        var x = e.pageX || (e.clientX +
             (document.documentElement.scrollLeft || document.body.scrollLeft));
        var y = e.pageY || (e.clientY +
             (document.documentElement.scrollTop || document.body.scrollTop));
        this.lastx=x;
        this.lasty=y;
        this.startx = this.lastx;
        this.starty = this.lasty;
        
        e.cancelBubble = true;
        e.returnValue = false;
        if (e.stopPropogation) e.stopPropogation();
        if (e.preventDefault) e.preventDefault();
        return false;
    }
};

var gDblClickTimer = null;
/**
 * handle the mouse up events.  Stop tracking mouse movement.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmouseup = function(e) {
	this.cursor = this.cursorNormal;
    this.kaMap.setCursor(this.cursorNormal);
	
    e = (e)?e:((event)?event:null);
    this.bMouseDown=false;
    var x = e.pageX || (e.clientX +
        (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
        (document.documentElement.scrollTop || document.body.scrollTop));
    if (Math.abs(x-this.startx) < 2 &&
        Math.abs(y-this.starty) < 2) {
        if (!gDblClickTimer) {
            gDblClickTimer = window.setTimeout(bind(this.dispatchMapClicked, this, x, y), 250);
        }
    } else {
        gDblClickTimer = null;
        this.kaMap.showLayers();
        this.kaMap.triggerEvent(KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents());        
    }
    return false;
};

kaNavigator.prototype.dispatchMapClicked = function(px,py) {
    var a = this.adjustPixPosition( px,py );
    var p = this.kaMap.pixToGeo( a[0],a[1] );
    gDblClickTimer=null;
    this.kaMap.triggerEvent(KAMAP_MAP_CLICKED, p);
};

/**
 * handle a double-click event by sliding the map to the point that was clicked.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.ondblclick = function(e) {
    if (gDblClickTimer) {
        window.clearTimeout(gDblClickTimer);
        gDblClickTimer = null;
    }
    e = (e)?e:((event)?event:null);
    var x = e.pageX || (e.clientX +
        (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
        (document.documentElement.scrollTop || document.body.scrollTop));
    var a = this.adjustPixPosition( x,y );
    var p = this.kaMap.pixToGeo( a[0], a[1] );
    this.kaMap.zoomTo(p[0],p[1]);
};

//TODO: this is a temporary patch until we add prototype/scriptaculous support.
function bind(m,o) {
    var __method = arguments[0];
    var __object = arguments[1];
    var args = [];
    for (var i=2; i<arguments.length; i++) { args.push(arguments[i]) }
    return function() { return __method.apply(__object, args); }
}var charset="";
/**********************************************************************
 *
 * $Id: kaQuery.js,v 1.14 2006/09/25 13:18:50 lbecchi Exp $
 *
 * purpose: a simple tool for supporting queries.  It just provides
 *          the user interface for defining the query point or 
 *          area and defers the actual query to the application
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 * KAMAP_MOUSE_STOPPED contributed by Sebastien Roch
 *
 * TODO:
 * 
 *   - implement a sample backend for query code
 *
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************
 *
 * To use this tool:
 * 
 * 1) add a script tag to your page
 * 
 * <script type="text/javascript" src="kaQuery.js"></script>
 * 
 * 2) create a new instance of kaQuery
 * 
 * myKaQuery = new kaQuery( myKaMap, KAMAP_RECT_QUERY );
 * 
 * or if you want to do something when mouse stops over the viewport (delay is 400ms here) :
 * 
 * myKaQuery = new kaQuery( myKaMap, KAMAP_MOUSE_STOPPED, 400 );
 * myKaQuery.activate();
 *
 * 3) provide some way of activating it ( not necessary with KAMAP_MOUSE_STOPPED, it's always activated)
 *    This example would allow switching between querying and navigating.
 * 
 * <input type="button" name="navigate" value="Navigate"
 *  onclick="myKaNavigator.activate()">
 * <input type="button" name="query" value="Query"
 *  onclick="myKaQuery.activate()">
 * 
 * 4) listen for the query event 
 * 
 * myKaMap.registerForEvent( KAMAP_QUERY, null, myQuery );
 * myKaMap.resgisterForEvent( KAMAP_MOUSE_STOPPED, null, myMouseStopped );
 * 
 * 5) and do something when the user requests a query
 * 
 * function myQuery( eventID, queryType, coords )
 * {
 *     alert( "QUERY: " + queryType + " " + coords );
 * }
 *
 * 
 * Querying actually does nothing except generate a KAMAP_QUERY event with 
 * the query type and coordinates passed as parameters to the event handler
 *
 * Signature of the query event handler is:
 *
 * function myQueryHandler( eventID, queryType, queryCoords )
 *
 * eventID: int, KAMAP_QUERY
 *
 * queryType: int, one of KAMAP_POINT_QUERY, KAMAP_RECT_QUERY or KAMAP_MOUSE_STOPPED
 *
 * queryCoords: array, array of two or four floating point coordinates
 *              depending on the query type
 *
 * You can affect the style of the zoom box by changing oQuery.domObj.style as
 * you would with any other HTML element (it's a div).
 *
 *****************************************************************************/
// the query event id
var KAMAP_QUERY = gnLastEventId ++;

// human names for the query types
var KAMAP_POINT_QUERY = 0;
var KAMAP_RECT_QUERY = 1;

// ********************** ADDED BY SEBASTIEN ROCH *************************** 
var KAMAP_MOUSE_STOPPED = 2;
// ************************** END MODIF ************************ 

/*
 *	Main function
 *	constructor : (oKaMap, type, [delay])
 *  If type is KAMAP_MOUSE_STOPPED, you have to set up the delay after
 *  which this event is triggered, or default is 500ms
*/
function kaQuery( oKaMap, type ) {
    kaTool.apply( this, [oKaMap] );
    this.type = type;
    // ********************** ADDED BY SEBASTIEN ROCH ***************************
    if(this.type == KAMAP_MOUSE_STOPPED){
	    this.bInfoTool = true;
	    // check arguments
	    if(arguments.length == 3){
    		this.delay = arguments[2];
    	} else {
    		alert("Incorrect nb of arguments for instance kaQuery. Delay will be set by default to 500ms");
    		this.delay = 500;
    	}
    }
    // ************************** END MODIF ************************ 
    this.name = 'kaQuery';
    this.cursor = 'help';
    
    this.startx = null;
    this.starty = null;
    this.endx = null;
    this.endy = null;
    this.bMouseDown = false;
    // ********************** ADDED BY SEBASTIEN ROCH ***************************
	// array for storing geo coords when mouse is stopped
	this.coords = new Array();
	// flag
	this.mouseStopped = false; 
    this.chrono = null;
    // ************************** END MODIF ************************ 
    
    //this is the HTML element that is visible
    this.domObj = document.createElement( 'div' );
    this.domObj.style.position = 'absolute';
    this.domObj.style.top = '0px';
    this.domObj.style.left = '0px';
    this.domObj.style.width = '1px';
    this.domObj.style.height = '1px';
    this.domObj.style.zIndex = 50;
    this.domObj.style.visibility = 'hidden';
    this.domObj.style.border = '1px solid red';
    this.domObj.style.backgroundColor = 'white';
    this.domObj.style.opacity = 0.50;
    this.domObj.style.mozOpacity = 0.50;
    this.domObj.style.filter = 'Alpha(opacity=50)';
    this.kaMap.theInsideLayer.appendChild( this.domObj );

    for (var p in kaTool.prototype) {
        if (!kaQuery.prototype[p])
            kaQuery.prototype[p]= kaTool.prototype[p];
    }
};

/*
 * draw a box representing the query region.
 *
 * kaQuery maintains the query region in four variables.  The variables are
 * assumed to be in pixel coordinates and are used to position the box.  If
 * any of the coordinates are null, clear the query box.
 */
kaQuery.prototype.drawZoomBox = function() {
    if (this.startx == null || this.starty == null ||
        this.endx == null || this.endy == null ) {
        this.domObj.style.visibility = 'hidden';
        this.domObj.style.top = '0px';
        this.domObj.style.left = '0px';
        this.domObj.style.width = '1px';
        this.domObj.style.height = '1px';
        return;
    }
    
    this.domObj.style.visibility = 'visible';
    if (this.endx < this.startx) {
        this.domObj.style.left = (this.endx - this.kaMap.xOrigin) + 'px';
        this.domObj.style.width = (this.startx - this.endx) + "px";
    }
    else {
        this.domObj.style.left = (this.startx - this.kaMap.xOrigin) + 'px';
        this.domObj.style.width = (this.endx - this.startx) + "px";
    }

    if (this.endy < this.starty) {
        this.domObj.style.top = (this.endy - this.kaMap.yOrigin) + 'px';
        this.domObj.style.height = (this.starty - this.endy) + "px";
    } else {
        this.domObj.style.top = (this.starty - this.kaMap.yOrigin) + 'px';
        this.domObj.style.height = (this.endy - this.starty) + "px";
    }
};

/**
 * kaQuery.onmousemove( e )
 *
 * called when the mouse moves over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaQuery.prototype.onmousemove = function(e) {
    e = (e)?e:((event)?event:null);
    
    // ********************** ADDED BY SEBASTIEN ROCH ***************************
    // don't return false if we are handling a KAMAP_MOUSE_STOPPED query
    if(this.type != KAMAP_MOUSE_STOPPED){
	    if (!this.bMouseDown) {
    	    return false;
    	}
    }
    // ************************** END MODIF ************************ 
    
    var x = e.pageX || (e.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
                (document.documentElement.scrollTop || document.body.scrollTop));
	
	// ********************** MODIFIED/ADDED BY SEBASTIEN ROCH ***************************
	var adjCoords = this.adjustPixPosition( x, y );
	
	if(this.type == KAMAP_MOUSE_STOPPED){
		// get geo position
		var p = this.kaMap.pixToGeo(adjCoords[0], adjCoords[1]); 
		this.coords[0] = p[0];
		this.coords[1] = p[1];
		
		// if chrono is ON, we reset it
		if(this.chrono != null)
			clearTimeout(this.chrono);
		
		// call the onmousestop function after a delay if mouse doesn't move anymore
		var t = this;
		if(this.mouseStopped == false){
			this.chrono = setTimeout(function(){t.onmousestop()}, this.delay);
		}
	}
	
    if (this.type == KAMAP_RECT_QUERY) {
        this.endx = -adjCoords[0];
        this.endy = -adjCoords[1];
        
        this.drawZoomBox();
    }
    // ************************** END MODIF ************************ 
    return false;
};

// ********************** MODIFIED/ADDED BY SEBASTIEN ROCH ***************************
/**
 * kaQuery.onmousestop()
 *
 * called if mouse is stopped during "this.delay"
 * 
 */
kaQuery.prototype.onmousestop = function(){
	// stop chrono
	clearTimeout(this.chrono);
	// update flag -> avoid calling the onmousestop function if it's already being called
	this.mouseStopped = true;
	this.kaMap.triggerEvent(KAMAP_MOUSE_STOPPED, this.type, this.coords);
	this.mouseStopped = false;
	return;
};
 // ************************** END MODIF ************************ 


/**
 * kaQuery.onmouseout( e )
 *
 * called when the mouse leaves theInsideLayer.  Terminate the query
 *
 * e - object, the event object or null (in ie)
 */
kaQuery.prototype.onmouseout = function(e) {
    e = (e)?e:((event)?event:null);
    
    // ********** MODIFIED/ADDED BY SEBASTIEN ROCH ******************
    clearTimeout(this.chrono);
    // ************************** END MODIF ************************ 
    
    if (!e.target) e.target = e.srcElement;
    if (e.target.id == this.kaMap.domObj.id) {
        this.bMouseDown = false;
        this.startx = this.endx = this.starty = this.endy = null;
        this.drawZoomBox();
        return kaTool.prototype.onmouseout.apply(this, [e]);
    }
};


/**
 * kaQuery.onmousedown( e )
 *
 * called when a mouse button is pressed over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaQuery.prototype.onmousedown = function(e) {
	e = (e)?e:((event)?event:null);
	
	// ********** MODIFIED/ADDED BY SEBASTIEN ROCH ******************
    // we "desactivate" clicks if type is KAMAP_MOUSE_STOPPED
	if(this.type != KAMAP_MOUSE_STOPPED){
	// ************************** END MODIF ************************
	    if (e.button==2) {
	        return this.cancelEvent(e);
	    }
	    else {
	        if (this.kaMap.isIE4)
	        	document.onkeydown = kaTool_redirect_onkeypress;
	        
	        document.onkeypress = kaTool_redirect_onkeypress;
	        
	        this.bMouseDown = true;
	        
	        var x = e.pageX || (e.clientX +
	              (document.documentElement.scrollLeft || document.body.scrollLeft));
	        var y = e.pageY || (e.clientY +
	                    (document.documentElement.scrollTop || document.body.scrollTop));
	        
	        var aPixPos = this.adjustPixPosition( x,y );
	        this.startx=this.endx = -aPixPos[0];
	        this.starty=this.endy = -aPixPos[1];
	        
	        this.drawZoomBox();
	        
	        e.cancelBubble = true;
	        e.returnValue = false;
	        if (e.stopPropagation) e.stopPropagation();
	        if (e.preventDefault) e.preventDefault();
	        return false;
	    }
	}
};

/**
 * kaQuery.onmouseup( e )
 *
 * called when a mouse button is clicked over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaQuery.prototype.onmouseup = function(e) {
	e = (e)?e:((event)?event:null);
	
	// ********** MODIFIED/ADDED BY SEBASTIEN ROCH ******************
    // we "desactivate" clicks if type is KAMAP_MOUSE_STOPPED
    if(this.type != KAMAP_MOUSE_STOPPED){
    // ************************** END MODIF ************************
	    var type = KAMAP_POINT_QUERY;
	    var start = this.kaMap.pixToGeo( -this.startx, -this.starty );
	    
	    var coords = start;
	    if (this.startx!=this.endx&&this.starty!=this.endy) {
	        type = KAMAP_RECT_QUERY;
	        coords = start.concat(this.kaMap.pixToGeo( -this.endx, -this.endy ));
	        if(coords[2] < coords[0]) {
	            //minx gt maxx than I invert values
	            var minx = coords[2];
	            var maxx = coords[0];
	            coords[0] = minx;
	            coords[2] = maxx;
	        }
	        if(coords[1] < coords[3]){
	            //miny gt maggiore than I invert values
	            var miny = coords[1];
	            var maxy = coords[3];
	            coords[3] = miny;
	            coords[1] = maxy;
	        }
	    }
	    this.kaMap.triggerEvent(KAMAP_QUERY, type, coords);
	    
	    this.startx = this.endx = this.starty = this.endy = null;
	    this.drawZoomBox();
	}        
	return false;
	    
};var charset="";
/*
JavaScript Scalebar for MapServer (scalebar.js)

Copyright (c) 2005 Tim Schaub of CommEn Space (http://www.commenspace.org)

This is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.

This software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this software; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

v1.3.1 - removed a typo that affected .sbBar with borders (thanks jlivni)
       - scalebar is now centered on .sbWrapper div by default, more css control
       - reduced likelihood of displaying very large numbers
       - added condition to deal with @import styles (thanks dokai)

*/

function ScaleBar(scaleDenominator) {
    // default properties
    // may be modified after construction
    // if modified after ScaleBar.place(), use ScaleBar.update()
    this.scaleDenominator = (scaleDenominator == null) ? 1 : scaleDenominator;
    this.displaySystem = 'metric'; // metric or english supported
    this.minWidth = 100; // pixels
    this.maxWidth = 200; // pixels
    this.divisions = 2;
    this.subdivisions = 2;
    this.showMinorMeasures = false;
    this.abbreviateLabel = false;
    this.singleLine = false;
    this.resolution = 72; // dpi
    this.align = 'center'; // left, center, or right supported
    // create scalebar elements
    this.container = document.createElement('div');
    this.container.className = 'sbWrapper';
    this.labelContainer = document.createElement('div');
    this.labelContainer.className = 'sbUnitsContainer';
    this.labelContainer.style.position = 'absolute';
    this.graphicsContainer = document.createElement('div');
    this.graphicsContainer.style.position = 'absolute';
    this.graphicsContainer.className = 'sbGraphicsContainer';
    this.numbersContainer = document.createElement('div');
    this.numbersContainer.style.position = 'absolute';
    this.numbersContainer.className = 'sbNumbersContainer';
    // private functions
    // put in some markers and bar pieces so style attributes can be grabbed
    // this is a solution for Safari support
    var markerMajor = document.createElement('div');
    markerMajor.className = 'sbMarkerMajor';
    this.graphicsContainer.appendChild(markerMajor);
    var markerMinor = document.createElement('div');
    markerMinor.className = 'sbMarkerMinor';
    this.graphicsContainer.appendChild(markerMinor);
    var barPiece = document.createElement('div');
    barPiece.className = 'sbBar';
    this.graphicsContainer.appendChild(barPiece);
    var barPieceAlt = document.createElement('div');
    barPieceAlt.className = 'sbBarAlt';
    this.graphicsContainer.appendChild(barPieceAlt);
}
ScaleBar.prototype.update = function(scaleDenominator) {
    if(scaleDenominator != null) {
        this.scaleDenominator = scaleDenominator;
    };
    // local functions (and object constructors)
    function HandsomeNumber(smallUglyNumber, bigUglyNumber, sigFigs) {
        var sigFigs = (sigFigs == null) ? 10 : sigFigs;
        var bestScore = Number.POSITIVE_INFINITY;
        var bestTieBreaker = Number.POSITIVE_INFINITY;
        // if all else fails, return a small ugly number
        var handsomeValue = smallUglyNumber;
        var handsomeNumDec = 3;
        // try the first three comely multiplicands (in order of comliness)
        for(var halvingExp = 0; halvingExp < 3; ++halvingExp) {
            var comelyMultiplicand = Math.pow(2, (-1 * halvingExp));
            var maxTensExp = Math.floor(Math.log(bigUglyNumber / comelyMultiplicand) / Math.LN10);
            for(var tensExp = maxTensExp; tensExp > (maxTensExp - sigFigs + 1); --tensExp) {
                var numDec = Math.max(halvingExp - tensExp, 0);
                var testMultiplicand = comelyMultiplicand * Math.pow(10, tensExp);
                // check if there is an integer multiple of testMultiplicand between smallUglyNumber and bigUglyNumber
                if((testMultiplicand * Math.floor(bigUglyNumber / testMultiplicand)) >= smallUglyNumber) {
                    // check if smallUglyNumber is an integer multiple of testMultiplicand
                    if(smallUglyNumber % testMultiplicand == 0) {
                        var testMultiplier = smallUglyNumber / testMultiplicand;
                    }
                    // otherwise go for the smallest integer multiple between small and big
                    else {
                        var testMultiplier = Math.floor(smallUglyNumber / testMultiplicand) + 1;
                    }
                    // test against the best (lower == better)
                    var testScore = testMultiplier + (2 * halvingExp);
                    var testTieBreaker = (tensExp < 0) ? (Math.abs(tensExp) + 1) : tensExp;
                    if((testScore < bestScore) || ((testScore == bestScore) && (testTieBreaker < bestTieBreaker))) {
                        bestScore = testScore;
                        bestTieBreaker = testTieBreaker;
                        handsomeValue = (testMultiplicand * testMultiplier).toFixed(numDec);
                        handsomeNumDec = numDec;
                    }
                }
            }
        }
        this.value = handsomeValue;
        this.score = bestScore;
        this.tieBreaker = bestTieBreaker;
        this.numDec = handsomeNumDec;
    };
    HandsomeNumber.prototype.toString = function() {
        return this.value.toString();
    };
    HandsomeNumber.prototype.valueOf = function() {
        return this.value;
    };
    function styleValue(aSelector, styleKey) {
        // returns an integer value associated with a particular selector and key
        // given a stylesheet with .someSelector {border: 2px solid red}
        // styleValue('.someSelector', 'borderWidth') returns 2
        var aValue = 0;
        if(document.styleSheets) {
            for(var sheetIndex = document.styleSheets.length - 1; sheetIndex >= 0; --sheetIndex) {
                var aSheet = document.styleSheets[sheetIndex];
                if(!aSheet.disabled) {
                    var allRules;
					try{
	                    if(typeof(aSheet.cssRules) == 'undefined') {
	                        if(typeof(aSheet.rules) == 'undefined') {
	                            // can't get rules, assume zero
	                            return 0;
	                        }
	                        else {
	                            allRules = aSheet.rules;
	                        }
	                    }
	                    else {
	                        allRules = aSheet.cssRules;
	                    }
					}catch(e){
						return 0;
					}
					if(!(allRules)) allRules = []; //GoogleChromeŃG[ɂȂsC
                    for(var ruleIndex = 0; ruleIndex < allRules.length; ++ruleIndex) {
                        var aRule = allRules[ruleIndex];
                        if(aRule.selectorText && (aRule.selectorText.toLowerCase() == aSelector.toLowerCase())) {
                            if(aRule.style[styleKey] != '') {
                                aValue = parseInt(aRule.style[styleKey]);
                            }
                        }
                    }
                }
            }
        }
        // if the styleKey was not found, the equivalent value is zero
        return aValue ? aValue : 0;
    };
    function formatNumber(aNumber, numDecimals) {
        numDecimals = (numDecimals) ? numDecimals : 0;
        var formattedInteger = '' + Math.round(aNumber);
        var thousandsPattern = /(-?[0-9]+)([0-9]{3})/;
        while(thousandsPattern.test(formattedInteger)) {
            formattedInteger = formattedInteger.replace(thousandsPattern, '$1,$2');
        }
        if(numDecimals > 0) {
            var formattedDecimal = Math.floor(Math.pow(10, numDecimals) * (aNumber - Math.round(aNumber)));
            if(formattedDecimal == 0) {
                return formattedInteger;
            }
            else {
                return formattedInteger + '.' + formattedDecimal;
            }
        }
        else {
            return formattedInteger;
        }
    };
    // update the container title (for displaying scale as a tooltip)
    this.container.title = 'scale 1:' + formatNumber(this.scaleDenominator);
    // measurementProperties holds display units, abbreviations,
    // and conversion to inches (since we're using dpi) - per measurement sytem
    var measurementProperties = new Object();
    measurementProperties.english = {
        units: ['miles', 'feet', 'inches'],
        abbr: ['mi', 'ft', 'in'],
        inches: [63360, 12, 1]
    };
    measurementProperties.metric = {
        units: ['kilometers', 'meters', 'centimeters'],
        abbr: ['km', 'm', 'cm'],
        inches: [39370.07874, 39.370079, 0.393701]
    };
    // check each measurement unit in the display system
    var comparisonArray = new Array();
    for(var unitIndex = 0; unitIndex < measurementProperties[this.displaySystem].units.length; ++unitIndex) {
        comparisonArray[unitIndex] = new Object();
        var pixelsPerDisplayUnit = this.resolution * measurementProperties[this.displaySystem].inches[unitIndex] / this.scaleDenominator;
        var minSDDisplayLength = (this.minWidth / pixelsPerDisplayUnit) / (this.divisions * this.subdivisions);
        var maxSDDisplayLength = (this.maxWidth / pixelsPerDisplayUnit) / (this.divisions * this.subdivisions);
        // add up scores for each marker (even if numbers aren't displayed)
        for(var valueIndex = 0; valueIndex < (this.divisions * this.subdivisions); ++valueIndex) {
            var minNumber = minSDDisplayLength * (valueIndex + 1);
            var maxNumber = maxSDDisplayLength * (valueIndex + 1);
            var niceNumber = new HandsomeNumber(minNumber, maxNumber);
            comparisonArray[unitIndex][valueIndex] = {value: (niceNumber.value / (valueIndex + 1)), score: 0, tieBreaker: 0, numDec: 0, displayed: 0};
            // now tally up scores for all values given this subdivision length
            for(var valueIndex2 = 0; valueIndex2 < (this.divisions * this.subdivisions); ++valueIndex2) {
                displayedValuePosition = niceNumber.value * (valueIndex2 + 1) / (valueIndex + 1);
                niceNumber2 = new HandsomeNumber(displayedValuePosition, displayedValuePosition);
                var isMajorMeasurement = ((valueIndex2 + 1) % this.subdivisions == 0);
                var isLastMeasurement = ((valueIndex2 + 1) == (this.divisions * this.subdivisions));
                if((this.singleLine && isLastMeasurement) || (!this.singleLine && (isMajorMeasurement || this.showMinorMeasures))) {
                    // count scores for displayed marker measurements
                    comparisonArray[unitIndex][valueIndex].score += niceNumber2.score;
                    comparisonArray[unitIndex][valueIndex].tieBreaker += niceNumber2.tieBreaker;
                    comparisonArray[unitIndex][valueIndex].numDec = Math.max(comparisonArray[unitIndex][valueIndex].numDec, niceNumber2.numDec);
                    comparisonArray[unitIndex][valueIndex].displayed += 1;
                }
                else {
                    // count scores for non-displayed marker measurements
                    comparisonArray[unitIndex][valueIndex].score += niceNumber2.score / this.subdivisions;
                    comparisonArray[unitIndex][valueIndex].tieBreaker += niceNumber2.tieBreaker / this.subdivisions;
                }
            }
            // adjust scores so numbers closer to 1 are preferred for display
            var scoreAdjustment = (unitIndex + 1) * comparisonArray[unitIndex][valueIndex].tieBreaker / comparisonArray[unitIndex][valueIndex].displayed;
            comparisonArray[unitIndex][valueIndex].score *= scoreAdjustment;
        }
    }
    // get the value (subdivision length) with the lowest cumulative score
    var subdivisionDisplayLength = null;
    var displayUnits = null;
    var displayUnitsAbbr = null;
    var subdivisionPixelLength = null;
    var bestScore = Number.POSITIVE_INFINITY;
    var bestTieBreaker = Number.POSITIVE_INFINITY;
    var numDec = 0;
    for(var unitIndex = 0; unitIndex < comparisonArray.length; ++unitIndex) {
        for(valueIndex in comparisonArray[unitIndex]) {
            if((comparisonArray[unitIndex][valueIndex].score < bestScore) || ((comparisonArray[unitIndex][valueIndex].score == bestScore) && (comparisonArray[unitIndex][valueIndex].tieBreaker < bestTieBreaker))) {
                bestScore = comparisonArray[unitIndex][valueIndex].score;
                bestTieBreaker = comparisonArray[unitIndex][valueIndex].tieBreaker;
                subdivisionDisplayLength = comparisonArray[unitIndex][valueIndex].value;
                numDec = comparisonArray[unitIndex][valueIndex].numDec;
                displayUnits = measurementProperties[this.displaySystem].units[unitIndex];
                displayUnitsAbbr = measurementProperties[this.displaySystem].abbr[unitIndex];
                pixelsPerDisplayUnit = this.resolution * measurementProperties[this.displaySystem].inches[unitIndex] / this.scaleDenominator;
                subdivisionPixelLength = pixelsPerDisplayUnit * subdivisionDisplayLength; // round before use in style
            }
        }
    }
    // determine offsets for graphic elements
    var xOffsetMarkerMajor = (styleValue('.sbMarkerMajor', 'borderLeftWidth') + styleValue('.sbMarkerMajor', 'width') + styleValue('.sbMarkerMajor', 'borderRightWidth')) / 2;
    var xOffsetMarkerMinor = (styleValue('.sbMarkerMinor', 'borderLeftWidth') + styleValue('.sbMarkerMinor', 'width') + styleValue('.sbMarkerMinor', 'borderRightWidth')) / 2;
    var xOffsetBar = (styleValue('.sbBar', 'borderLeftWidth') + styleValue('.sbBar', 'borderRightWidth')) / 2;
    var xOffsetBarAlt = (styleValue('.sbBarAlt', 'borderLeftWidth') + styleValue('.sbBarAlt', 'borderRightWidth')) / 2;
    // support for browsers without the Document.styleSheets property (Opera)
    if(!document.styleSheets) {
        // this is a two part hack, one for the offsets here and one for the css below
        xOffsetMarkerMajor = 0.5;
        xOffsetMarkerMinor = 0.5;
    }
    // clean out any old content from containers
    while(this.labelContainer.hasChildNodes()) {
        this.labelContainer.removeChild(this.labelContainer.firstChild);
    }
    while(this.graphicsContainer.hasChildNodes()) {
        this.graphicsContainer.removeChild(this.graphicsContainer.firstChild);
    }
    while(this.numbersContainer.hasChildNodes()) {
        this.numbersContainer.removeChild(this.numbersContainer.firstChild);
    }
    // create all divisions
    var aMarker, aBarPiece, numbersBox, xOffset;
    var alignmentOffset = {
        left: 0,
        center: (-1 * this.divisions * this.subdivisions * subdivisionPixelLength / 2),
        right: (-1 * this.divisions * this.subdivisions * subdivisionPixelLength)
    };
    var xPosition = 0 + alignmentOffset[this.align];
    var markerMeasure = 0;
    for(var divisionIndex = 0; divisionIndex < this.divisions; ++divisionIndex) {
        // set xPosition and markerMeasure to start of division
        xPosition = divisionIndex * this.subdivisions * subdivisionPixelLength;
        xPosition += alignmentOffset[this.align];
        markerMeasure = (divisionIndex == 0) ? 0 : ((divisionIndex * this.subdivisions) * subdivisionDisplayLength).toFixed(numDec);
        // add major marker
        aMarker = document.createElement('div');
        aMarker.className = 'sbMarkerMajor';
        aMarker.style.position = 'absolute';
        aMarker.style.overflow = 'hidden';
        aMarker.style.left = Math.round(xPosition - xOffsetMarkerMajor) + 'px';
        aMarker.appendChild(document.createTextNode(' '));
        this.graphicsContainer.appendChild(aMarker);
        // add initial measure
        if(!this.singleLine) {
            numbersBox = document.createElement('div');
            numbersBox.className = 'sbNumbersBox';
            numbersBox.style.position = 'absolute';
            numbersBox.style.overflow = 'hidden';
            numbersBox.style.textAlign = 'center';
            if(this.showMinorMeasures) {
                numbersBox.style.width = Math.round(subdivisionPixelLength * 2) + 'px';
                numbersBox.style.left = Math.round(xPosition - subdivisionPixelLength) + 'px';
            }
            else {
                numbersBox.style.width = Math.round(this.subdivisions * subdivisionPixelLength * 2) + 'px';
                numbersBox.style.left = Math.round(xPosition - (this.subdivisions * subdivisionPixelLength)) + 'px';
            }
            numbersBox.appendChild(document.createTextNode(markerMeasure));
            this.numbersContainer.appendChild(numbersBox);
        }
        // create all subdivisions
        for(var subdivisionIndex = 0; subdivisionIndex < this.subdivisions; ++subdivisionIndex) {
            aBarPiece = document.createElement('div');
            aBarPiece.style.position = 'absolute';
            aBarPiece.style.overflow = 'hidden';
            aBarPiece.style.width = Math.round(subdivisionPixelLength) + 'px';
            if((subdivisionIndex % 2) == 0) {
                aBarPiece.className = 'sbBar';
                aBarPiece.style.left = Math.round(xPosition - xOffsetBar) + 'px';
            }
            else {
                aBarPiece.className = 'sbBarAlt';
                aBarPiece.style.left = Math.round(xPosition - xOffsetBarAlt) + 'px';
            }
            aBarPiece.appendChild(document.createTextNode(' '));
            this.graphicsContainer.appendChild(aBarPiece);
            // add minor marker if not the last subdivision
            if(subdivisionIndex < (this.subdivisions - 1)) {
                // set xPosition and markerMeasure to end of subdivision
                xPosition = ((divisionIndex * this.subdivisions) + (subdivisionIndex + 1)) * subdivisionPixelLength;
                xPosition += alignmentOffset[this.align];
                markerMeasure = (divisionIndex * this.subdivisions + subdivisionIndex + 1) * subdivisionDisplayLength;
                aMarker = document.createElement('div');
                aMarker.className = 'sbMarkerMinor';
                aMarker.style.position = 'absolute';
                aMarker.style.overflow = 'hidden';
                aMarker.style.left = Math.round(xPosition - xOffsetMarkerMinor) + 'px';
                aMarker.appendChild(document.createTextNode(' '));
                this.graphicsContainer.appendChild(aMarker);
                if(this.showMinorMeasures && !this.singleLine) {
                    // add corresponding measure
                    numbersBox = document.createElement('div');
                    numbersBox.className = 'sbNumbersBox';
                    numbersBox.style.position = 'absolute';
                    numbersBox.style.overflow = 'hidden';
                    numbersBox.style.textAlign = 'center';
                    numbersBox.style.width = Math.round(subdivisionPixelLength * 2) + 'px';
                    numbersBox.style.left = Math.round(xPosition - subdivisionPixelLength) + 'px';
                    numbersBox.appendChild(document.createTextNode(markerMeasure));
                    this.numbersContainer.appendChild(numbersBox);
                }
            }
        }
    }
    // set xPosition and markerMeasure to end of divisions
    xPosition = (this.divisions * this.subdivisions) * subdivisionPixelLength;
    xPosition += alignmentOffset[this.align];
    markerMeasure = ((this.divisions * this.subdivisions) * subdivisionDisplayLength).toFixed(numDec);
    // add the final major marker
    aMarker = document.createElement('div');
    aMarker.className = 'sbMarkerMajor';
    aMarker.style.position = 'absolute';
    aMarker.style.overflow = 'hidden';
    aMarker.style.left = Math.round(xPosition - xOffsetMarkerMajor) + 'px';
    aMarker.appendChild(document.createTextNode(' '));
    this.graphicsContainer.appendChild(aMarker);
    // add final measure
    if(!this.singleLine) {
        numbersBox = document.createElement('div');
        numbersBox.className = 'sbNumbersBox';
        numbersBox.style.position = 'absolute';
        numbersBox.style.overflow = 'hidden';
        numbersBox.style.textAlign = 'center';
        if(this.showMinorMeasures) {
            numbersBox.style.width = Math.round(subdivisionPixelLength * 2) + 'px';
            numbersBox.style.left = Math.round(xPosition - subdivisionPixelLength) + 'px';
        }
        else {
            numbersBox.style.width = Math.round(this.subdivisions * subdivisionPixelLength * 2) + 'px';
            numbersBox.style.left = Math.round(xPosition - (this.subdivisions * subdivisionPixelLength)) + 'px';
        }
        numbersBox.appendChild(document.createTextNode(markerMeasure));
        this.numbersContainer.appendChild(numbersBox);
    }
    // add content to the label container
    var labelBox = document.createElement('div');
    labelBox.style.position = 'absolute';
    var labelText;
    if(this.singleLine) {
        labelText = markerMeasure;
        labelBox.className = 'sbLabelBoxSingleLine';
        labelBox.style.top = '-0.6em';
        labelBox.style.left = (xPosition + 10) + 'px';
    }
    else {
        labelText = '';
        labelBox.className = 'sbLabelBox';
        labelBox.style.textAlign = 'center';
        labelBox.style.width = Math.round(this.divisions * this.subdivisions * subdivisionPixelLength) + 'px';
        labelBox.style.left = Math.round(alignmentOffset[this.align]) + 'px';
        labelBox.style.overflow = 'hidden';
    }
    if(this.abbreviateLabel) {
        labelText += ' ' + displayUnitsAbbr;
    }
    else {
        labelText += ' ' + displayUnits;
    }
    labelBox.appendChild(document.createTextNode(labelText));
    this.labelContainer.appendChild(labelBox);
    // support for browsers without the Document.styleSheets property (Opera)
    if(!document.styleSheets) {
        // override custom css with default
        var defaultStyle = document.createElement('style');
        defaultStyle.type = 'text/css';
        var styleText = '.sbBar {top: 0px; background: #666666; height: 1px; border: 0;}';
        styleText += '.sbBarAlt {top: 0px; background: #666666; height: 1px; border: 0;}';
        styleText += '.sbMarkerMajor {height: 7px; width: 1px; background: #666666; border: 0;}';
        styleText += '.sbMarkerMinor {height: 5px; width: 1px; background: #666666; border: 0;}';
        styleText += '.sbLabelBox {top: -16px;}';
        styleText += '.sbNumbersBox {top: 7px;}';
        defaultStyle.appendChild(document.createTextNode(styleText));
        document.getElementsByTagName('head').item(0).appendChild(defaultStyle);
    }
    // append the child containers to the parent container
    this.container.appendChild(this.graphicsContainer);
    this.container.appendChild(this.labelContainer);
    this.container.appendChild(this.numbersContainer);
};
ScaleBar.prototype.place = function(elementId) {
    if(elementId == null) {
        document.body.appendChild(this.container);
    }
    else {
        var anElement = document.getElementById(elementId);
        if(anElement != null) {
            anElement.appendChild(this.container);
        }
    }
    this.update();
};
var charset="";
/**********************************************************************
 *
 * $Id: kaRubberZoom.js,v 1.4 2006/07/20 12:04:32 lbecchi Exp $
 *
 * purpose: a rubber zoom.
 *
 * author: Lorenzo Becchi and Paul Spencer (pspencer@dmsolutions.ca) (bug 1494)
 *
 * TODO:
 * 
 *   - 
 *
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************
 *
 * To use this tool:
 * 
* 1) add a script tag to your page
 * 
 * <script type="text/javascript" src="kaRubberZoom.js"></script>
 * 
 * 2) create a new instance of kaRubberZoom
 * 
 * myKaRubberZoom = new kaRubberZoom( myKaMap );
 * 
 *
 *****************************************************************************/



/**
 * kaRubberZoom constructor
 *
 * construct a new kaRubberZoom object of a given type for a given kaMap instance
 *
 * oKaMap - a kaMap instance
 *
 * type - int, one of KAMAP_POINT_QUERY or KAMAP_RECT_QUERY.  If the type is
 *        KAMAP_POINT_QUERY then only point queries are allowed.  If the type
 *        is KAMAP_RECT_QUERY then point or rectangle queries are possible.
 */
function kaRubberZoom( oKaMap) {
    kaTool.apply( this, [oKaMap] );
    this.name = 'kaRubberZoom';
    //this.cursor = 'help';
	this.cursor = 'crosshair';
    
    //this is the HTML element that is visible
    this.domObj = document.createElement( 'div' );
    this.domObj.style.position = 'absolute';
    this.domObj.style.top = '0px';
    this.domObj.style.left = '0px';
    this.domObj.style.width = '1px';
    this.domObj.style.height = '1px';
    this.domObj.style.zIndex = 100;
    this.domObj.style.visibility = 'hidden';
    this.domObj.style.border = '1px solid blue';
    this.domObj.style.backgroundColor = 'white';
    this.domObj.style.opacity = 0.50;
    this.domObj.style.mozOpacity = 0.50;
    this.domObj.style.filter = 'Alpha(opacity=50)';
    this.kaMap.theInsideLayer.appendChild( this.domObj );

    this.startx = null;
    this.starty = null;
    this.endx = null;
    this.endy = null;
    this.bMouseDown = false;
    this.RubberZooming = false;
    this.dataOver = false;
    
    for (var p in kaTool.prototype) {
        if (!kaRubberZoom.prototype[p])
            kaRubberZoom.prototype[p]= kaTool.prototype[p];
    }
};

/*
 * draw a box representing the query region.
 *
 * kaRubberZoom maintains the query region in four variables.  The variables are
 * assumed to be in pixel coordinates and are used to position the box.  If
 * any of the coordinates are null, clear the query box.
 */
kaRubberZoom.prototype.drawZoomBox = function() {
    if (this.startx == null || this.starty == null ||
        this.endx == null || this.endy == null ) {
        this.domObj.style.visibility = 'hidden';
        this.domObj.style.top = '0px';
        this.domObj.style.left = '0px';
        this.domObj.style.width = '1px';
        this.domObj.style.height = '1px';
        return;
    }
    
    this.domObj.style.visibility = 'visible';
    if (this.endx < this.startx) {
        this.domObj.style.left = (this.endx - this.kaMap.xOrigin) + 'px';
        this.domObj.style.width = (this.startx - this.endx) + "px";
    } else {
        this.domObj.style.left = (this.startx - this.kaMap.xOrigin) + 'px';
        this.domObj.style.width = (this.endx - this.startx) + "px";
    }

    if (this.endy < this.starty) {
        this.domObj.style.top = (this.endy - this.kaMap.yOrigin) + 'px';
        this.domObj.style.height = (this.starty - this.endy) + "px";
    } else {
        this.domObj.style.top = (this.starty - this.kaMap.yOrigin) + 'px';
        this.domObj.style.height = (this.endy - this.starty) + "px";
    }
};

/**
 * kaRubberZoom.onmouseout( e )
 *
 * called when the mouse leaves theInsideLayer.  Terminate the query
 *
 * e - object, the event object or null (in ie)
 */
kaRubberZoom.prototype.onmouseout = function(e) {
    e = (e)?e:((event)?event:null);
    if (!e.target) e.target = e.srcElement;
    if (e.target.id == this.kaMap.domObj.id) {
        this.bMouseDown = false;
	    this.RubberZooming = false;
        this.startx = this.endx = this.starty = this.endy = null;
        this.drawZoomBox();
        return kaTool.prototype.onmouseout.apply(this, [e]);
    }
};

/**
 * kaRubberZoom.onmousemove( e )
 *
 * called when the mouse moves over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaRubberZoom.prototype.onmousemove = function(e) {
    e = (e)?e:((event)?event:null);
    
    if (!this.bMouseDown) {
	    this.RubberZooming = false;
        return false;
    }
    
    var x = e.pageX || (e.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
                (document.documentElement.scrollTop || document.body.scrollTop));
    //if (this.type == KAMAP_RECT_QUERY) {
        var aPixPos = this.adjustPixPosition( x, y );
        
        this.endx=-aPixPos[0];
        this.endy=-aPixPos[1];
        
        this.drawZoomBox();
   // }
    return false;
}
;
/**
 * kaRubberZoom.onmousedown( e )
 *
 * called when a mouse button is pressed over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaRubberZoom.prototype.onmousedown = function(e) {
    e = (e)?e:((event)?event:null);
	if(this.dataOver){
		return;
	}
    if (e.button==2) {
        return this.cancelEvent(e);
    } else {
        if (this.kaMap.isIE4) document.onkeydown = kaTool_redirect_onkeypress;
        document.onkeypress = kaTool_redirect_onkeypress;
        
        this.bMouseDown=true;
	    this.RubberZooming = true;
        var x = e.pageX || (e.clientX +
              (document.documentElement.scrollLeft || document.body.scrollLeft));
        var y = e.pageY || (e.clientY +
                    (document.documentElement.scrollTop || document.body.scrollTop));
        var aPixPos = this.adjustPixPosition( x,y );
        this.startx=this.endx=-aPixPos[0];
        this.starty=this.endy=-aPixPos[1];
        
        this.drawZoomBox();
        
        e.cancelBubble = true;
        e.returnValue = false;
        if (e.stopPropogation) e.stopPropogation();
        if (e.preventDefault) e.preventDefault();
        return false;
    }
};

/**
 * kaRubberZoom.onmouseup( e )
 *
 * called when a mouse button is clicked over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaRubberZoom.prototype.onmouseup = function(e) {
    e = (e)?e:((event)?event:null);

	if(this.dataOver){
		return;
	}
	var type = KAMAP_POINT_QUERY;
    var start = this.kaMap.pixToGeo( -this.startx, -this.starty );
    
    var coords = start;
    if (this.startx!=this.endx&&this.starty!=this.endy) {
        type = KAMAP_RECT_QUERY;
        coords = start.concat(this.kaMap.pixToGeo( -this.endx, -this.endy ));
        if(coords[2] < coords[0]) {
            //minx gt maxx than I invert values
            var minx = coords[2];
            var maxx = coords[0];
            coords[0] = minx;
            coords[2] = maxx;
        }
        if(coords[1] < coords[3]){
            //miny gt maggiore than I invert values
            var miny = coords[1];
            var maxy = coords[3];
            coords[3] = miny;
            coords[1] = maxy;
        }
    }
    //this.kaMap.triggerEvent(KAMAP_QUERY, type, coords);
    
    this.startx = this.endx = this.starty = this.endy = null;
    this.drawZoomBox();
    //(minx, miny, maxx, maxy)
    
    if(coords[2] && coords[0] && coords[3] && coords[1]){
    		//Rubber Zoom
    		this.kaMap.zoomToExtents(coords[0],coords[1],coords[2],coords[3]  );
    	} else if (coords[0] && coords[1]){
    		//single click
    		this.kaMap.zoomIn();
    		this.kaMap.zoomTo(coords[0],coords[1]);
    	}
	this.RubberZooming = false;
    return false;
};var charset="";
/**********************************************************************
 *
 * $Id: kaMouseTracker.js,v 1.1 2006/07/20 13:47:11 pspencer Exp $
 *
 * purpose: a simple tool for tracking mouse movement over the map
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************
 *
 * To use this tool:
 * 
* 1) add a script tag to your page
 * 
 * <script type="text/javascript" src="kaMouseTracker.js"></script>
 * 
 * 2) create a new instance of kaMouseTracker
 * 
 * myTracker = new kaMouseTracker( myKaMap );
 * myTracker.activate();
 * 
 * 3) listen for the tracker event 
 * 
 * myKaMap.registerForEvent( KAMAP_MOUSE_TRACKER, null, myMouseMoved );
 * 
 * 4) and do something when the user requests a query
 * 
 * function myMouseMoved( eventID, coords )
 * {
 *     var pos = 'lon: ' + coords.x + ', lat: ' + coords.y;
 *     document.getElementById('mousePosition').innerHTML = pos;
 * }
 * 
 * Mouse position is reported in the coordinate system of the map.
 *
 *****************************************************************************/

// the mouse tracker event id
var KAMAP_MOUSE_TRACKER = gnLastEventId ++;

/**
 * kaMouseTracker constructor
 *
 * construct a new kaMouseTracker object for a given kaMap instance
 *
 * oKaMap - a kaMap instance
 */
function kaMouseTracker( oKaMap ) {
    kaTool.apply( this, [oKaMap] );
    this.name = 'kaMouseTracker';
    this.bInfoTool = true;
    
    for (var p in kaTool.prototype) {
        if (!kaMouseTracker.prototype[p])
            kaMouseTracker.prototype[p]= kaTool.prototype[p];
    }
};

/**
 * kaMouseTracker.onmousemove( e )
 *
 * called when the mouse moves over theInsideLayer.
 *
 * e - object, the event object or null (in ie)
 */
kaMouseTracker.prototype.onmousemove = function(e) {
    e = (e)?e:((event)?event:null);
    
    var x = e.pageX || (e.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
                (document.documentElement.scrollTop || document.body.scrollTop));
    var a = this.adjustPixPosition( x,y );
    var p = this.kaMap.pixToGeo( a[0], a[1] );
    this.kaMap.triggerEvent(KAMAP_MOUSE_TRACKER, {x:p[0], y:p[1]});
    return false;
};var charset="";
/**********************************************************************
 *
 * $Id: kaSearch.js,v 1.2 2006/08/08 20:50:41 lbecchi Exp $
 *
 * purpose: search system for ka-Map (bug 1509)
 *         
 *
 * author: Paul Spencer, Lorenzo Becchi & Andrea Cappugi
 *
 * TODO:
 *   - 
 * 
 **********************************************************************
 *
 * Copyright (c)  2006, ominiverdi.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/******************************************************************************
 * kaSearch - 
 *
 * To use kaSearch:
 * 
 * 1) add a script tag to your page:
 * 
 *   <script type="text/javascript" src="tools/kaSearch.js"></script>
 * 
 * 2) create a new instance of kaSearch
 * 
 *   var toolTip = new kaSearch( oMap);
 * 
 * 
 *
 * 
 *
 *****************************************************************************/
 
 function kaSearch( oKaMap ){
    this.kaMap = oKaMap;
    
    this.image = null;

    this.domObj = null;
    
    this.tooltip = new kaToolTip(oKaMap);
    
    
    this.init();


 };
 

kaSearch.prototype.init = function(){

	this.tooltip.setTipImage(this.kaMap.server + 'common/images2/tip-yellow.png',-6,-19);

};


kaSearch.prototype.search=function(search_query){
    if (search_query.length <= 0){
    alert("Input search string!");
    }
    if (search_query.length > 0)
    {
        var agt = navigator.userAgent.toLowerCase();
        var is_ie = (agt.indexOf('msie') != -1);
        var is_ie5 = (agt.indexOf('msie 5') != -1);
       
        element = document.getElementById ('searchres');
        element.innerHTML = "<h3>Processing search.<br>Please wait...</h3><hr>";
        element.className = "visible";
        function handle_do_search ()
        {
            if (xmlhttp.readyState == 4)//request completed
            {
                if (xmlhttp.status == 200)//request successful
                {
                    element.innerHTML = xmlhttp.responseText;
                }
                else
                {
                    alert ('No server answer!');
                }
            }
        }
       
        var xmlhttp = null;
        if (is_ie)
        {
            var control = (is_ie5) ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP";
            try
            {
                xmlhttp = new ActiveXObject(control);
                xmlhttp.onreadystatechange = handle_do_search;
            } catch(e)
            {
                alert("You need to enable active scripting and activeX controls");
            }
        }
        else
        {
            xmlhttp = new XMLHttpRequest();
            xmlhttp.onload = handle_do_search;
            xmlhttp.onerror = handle_do_search;
        }
        //call for xsearch.phtml results - sending link
        searchstring=encodeURIComponent(search_query);// encoding searchstring for link

        xmlhttp.open('GET', "tools/search/kaSearch.phtml?xmlRequest=true&map="+this.kaMap.getCurrentMap().name+"&searchstring="+searchstring, true);
        xmlhttp.send(null);
    }

};
var charset="";
/**********************************************************************
 *
 * $Id: kaToolTip.js,v 1.3 2006/08/08 20:51:35 lbecchi Exp $
 *
 * purpose: manage simple tool tips for ka-Map (bug 1374)
 *         
 *
 * author: Lorenzo Becchi & Andrea Cappugi
 *
 * TODO:
 *   - 
 * 
 **********************************************************************
 *
 * Copyright (c)  2006, ominiverdi.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/******************************************************************************
 * kaToolTip - 
 *
 * To use kaToolTip:
 * 
 * 1) add a script tag to your page:
 * 
 *   <script type="text/javascript" src="tools/kaToolTip.js"></script>
 * 
 * 2) create a new instance of kaToolTip
 * 
 *   var toolTip = new kaToolTip( oMap);
 * 
 * 3) if you want you can set an image (as the tip pointer)
 * 
 *   var offsetX=-6;//offset to move the image left-right
 *   var offsetY=-19;//offset to move the image top-bottom
 *   toolTip.setTipImage('images/tip-red.png',offsetX,offsetY);
 * 
 * 4) Set text
 * 
 *   toolTip.setText('Some text inside the tooltip');
 * 
 * 6) add it to the map
 * 
 *   toolTip.move(x,y);  //pixel coords
 * 
 * or by geo coords:
 * 
 *  toolTip.moveGeo(x,y); //geo coords
 * 
 * 7) hide the tooltip
 * 
 *  toolTip.move();
 * 
 *
 * 
 *
 *****************************************************************************/
 
 function kaToolTip( oKaMap ){
    this.kaMap = oKaMap;
    
    this.image = null;

    this.domObj = null;
    
    this.viewport = this.kaMap.domObj;
    
    this.visible= false;
    
    this.init();


 };
 
/**
 * wmsLayer.addRequestParameter( name, parameter )
 *
 * add a parameter to the baseURL safely by checking to see if the parameter
 * exists already.  This is an internal function not intended to be used
 * by other code.
 */
kaToolTip.prototype.init = function(){
	this.domObj = document.createElement('div');
	this.domObj.setAttribute('id', 'toolTip');
	
	this.minZindex = 1;
	this.coordX = null;
	this.coordY = null;
	
	
	this.viewport.appendChild(this.domObj);	
	this.domObj.style.position='absolute';

	/*Style features*/
	this.move();
	this.domObj.toolTip=this;
	this.domObj.style.zIndex=this.minZindex;

	
	/*Position features*/
	//this.domObj.onclick=this.onclick;
	
	this.setText('Wait a moment please!');
	this.kaMap.registerForEvent( KAMAP_MAP_CLICKED, this, this.onclick );
	this.kaMap.registerForEvent( KAMAP_EXTENTS_CHANGED, this, this.extentChanged );
	

};


kaToolTip.prototype.onclick=function(e){
 e = (e)?e:((event)?event:null);
this.move();

};

kaToolTip.prototype.setText = function(text){
	
	this.domObj.innerHTML = text;
		
};

kaToolTip.prototype.setTipImage = function(url,offsetX,offsetY){
	offsetX = (offsetX)?offsetX:0;
	offsetY = (offsetX)?offsetY:0;
	image = document.createElement('img');
	image.src=url;
	image.setAttribute('id', 'toolTipImage');
	image.style.position='absolute';
	image.style.zIndex=this.minZindex++;
	image.style.top='-200px';
	image.style.left='-200px';
	image.offsetX=offsetX;
	image.offsetY=offsetY;
	
	this.image = 	image;
	
	
	this.viewport.appendChild(image);
	
	
};

//move the tooltip using geo coords
kaToolTip.prototype.moveGeo = function(){
//(int [x],int [y])
	var x = parseInt(arguments[0]);
	var	y = parseInt(arguments[1]);
	var pixPos = this.kaMap.geoToPix(x,y);
	var nPixPos = this.kaMap.currentTool.adjustPixPosition( pixPos[0]*(-1), pixPos[1]*(-1) );
	var newX =nPixPos[0];
	var newY = nPixPos[1];
	
	this.move(newX,newY);
};

//move the tooltip in pixel space
kaToolTip.prototype.move = function(){
 
 // (int [x],int [y],bool [noRecenter])
 	var x = 0;
	var y = 0;
	var aPixPos = 0;
	var geoPix = 0;
	var noRecenter = false;
	
	if(arguments.length<2){
		

		/*original position*/
		//this.domObj.style.top='-'+getObjectHeight(this.domObj)+'px';
		//this.domObj.style.left= '-'+getObjectWidth(this.domObj)+'px';
		
		this.visible = false;
		
		this.domObj.style.top='-10000px';
		this.domObj.style.left= '-10000px';
		
		aPixPos = this.kaMap.currentTool.adjustPixPosition( parseInt(x) , parseInt(y) );
		var geoCoords = this.kaMap.pixToGeo( aPixPos[0],aPixPos[1]);
		this.coordX = geoCoords[0];
		this.coordY = geoCoords[1];
		
		//if(this.image)this.image.style.top = '-'+getObjectHeight(this.domObj)+'px';
		//if(this.image)this.image.style.left = '-'+getObjectWidth(this.domObj)+'px';
		if(this.image)this.image.style.top = '-100000px';
		if(this.image)this.image.style.left = '-100000px';
		//alert('move to 0');
	
	} else {
		
		x = parseInt(arguments[0]);
		y = parseInt(arguments[1]);
		
		this.visible = true;
		
		//alert('move to:' + x +' ' + y);
		
		aPixPos = this.kaMap.currentTool.adjustPixPosition( parseInt(x) , parseInt(y) );
		var geoCoords = this.kaMap.pixToGeo( aPixPos[0],aPixPos[1]);
		this.coordX = geoCoords[0];
		this.coordY = geoCoords[1];
		
		//alert('coords: '+this.coordX + ' ' +this.coordY);
		
		this.domObj.style.top=y-10+'px';//
		this.domObj.style.left=x-(getObjectWidth(this.domObj)/2)+'px';
		if(this.image)this.image.style.top = (y+this.image.offsetY)+'px';
		if(this.image)this.image.style.left = (x+this.image.offsetX)+'px';
		
		//adesso calcolo se il div sta dentro il viewport 
	 	if((arguments[2])&&arguments[2]==true)noRecenter = true;
	 	if(!noRecenter)this.recenter(this.domObj);	
	}
	

};

kaToolTip.prototype.adjustPosition = function(x,y){
 
var ny =parseInt(this.domObj.style.top)+y;
var nx =parseInt(this.domObj.style.left)+x;
	    
		this.domObj.style.top=ny+'px';//
		this.domObj.style.left=nx+'px';
		if(this.image)this.image.style.top = (parseInt(this.image.style.top)+y)+'px';
		if(this.image)this.image.style.left =(parseInt(this.image.style.left)+x)+'px';


};

kaToolTip.prototype.recenter=function(tip){


	//misuro le diemensioni in pix del tip
	var tipWidth = getObjectWidth(tip);
	var tipHeight = getObjectHeight(tip);
	var tipTop = parseInt(tip.style.top);
	var tipLeft= parseInt(tip.style.left);
	
	//prendo i dati del viewport
	var viewportWheight = tip.toolTip.kaMap.viewportHeight; 
	var viewportWidth   = tip.toolTip.kaMap.viewportWidth;
	//calcolo le posizioni di ogni angolo del tip sul viewport
	
	var topSlide=1;
	var leftSlide=1;
	if((tipTop+tipHeight)>viewportWheight) topSlide=(tipTop+tipHeight)-viewportWheight;
	
	if((tipLeft+tipWidth)>viewportWidth) leftSlide=(tipLeft+tipWidth)-viewportWidth;
	if(tipLeft<0) leftSlide=tipLeft-20;
	if(tipTop<0) topSlide=tipTop-20;
	if(topSlide!=1 || leftSlide!=1){
		
		 tip.toolTip.kaMap.slideBy(-(leftSlide+10), -(topSlide+10));
		  
		 tip.toolTip.adjustPosition(-(leftSlide+10), -(topSlide+10));
	 }

};


kaToolTip.prototype.extentChanged=function(){
	
	
	var pixPos = this.kaMap.geoToPix(this.coordX,this.coordY);
	var nPixPos = this.kaMap.currentTool.adjustPixPosition( pixPos[0]*(-1), pixPos[1]*(-1) );
	var newX =nPixPos[0];
	var newY = nPixPos[1];

	if(this.visible)this.move(newX,newY,true);
};


function encodeMyHtml(string) {
  encodedHtml = escape(string);
  encodedHtml = encodedHtml.replace("/","%2F");
  encodedHtml = encodedHtml.replace(/\?/g,"%3F");
  encodedHtml = encodedHtml.replace(/=/g,"%3D");
  encodedHtml = encodedHtml.replace(/&/g,"%26");
  encodedHtml = encodedHtml.replace(/@/g,"%40");
  return encodedHtml;
};
  
function urlDecode(sz){
	return unescape(sz).replace(/\+/g," ");
};
var charset="";
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
//   different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
//   width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
//   Quirks mode will draw the canvas using border-box. Either change your
//   doctype to HTML5
//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
//   or use Box Sizing Behavior from WebFX
//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.

// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {

(function() {

  // alias some functions to make (compiled) code shorter
  var m = Math;
  var mr = m.round;
  var ms = m.sin;
  var mc = m.cos;
  var abs = m.abs;
  var sqrt = m.sqrt;

  // this is used for sub pixel precision
  var Z = 10;
  var Z2 = Z / 2;

  /**
   * This funtion is assigned to the <canvas> elements as element.getContext().
   * @this {HTMLElement}
   * @return {CanvasRenderingContext2D_}
   */
  function getContext() {
    return this.context_ ||
        (this.context_ = new CanvasRenderingContext2D_(this));
  }

  var slice = Array.prototype.slice;

  /**
   * Binds a function to an object. The returned function will always use the
   * passed in {@code obj} as {@code this}.
   *
   * Example:
   *
   *   g = bind(f, obj, a, b)
   *   g(c, d) // will do f.call(obj, a, b, c, d)
   *
   * @param {Function} f The function to bind the object to
   * @param {Object} obj The object that should act as this when the function
   *     is called
   * @param {*} var_args Rest arguments that will be used as the initial
   *     arguments when the function is called
   * @return {Function} A new function that has bound this
   */
  function bind(f, obj, var_args) {
    var a = slice.call(arguments, 2);
    return function() {
      return f.apply(obj, a.concat(slice.call(arguments)));
    };
  }

  var G_vmlCanvasManager_ = {
    init: function(opt_doc) {
      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
        var doc = opt_doc || document;
        // Create a dummy element so that IE will allow canvas elements to be
        // recognized.
        doc.createElement('canvas');
        doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
      }
    },

    init_: function(doc) {
      // create xmlns
      if (!doc.namespaces['g_vml_']) {
        doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
                           '#default#VML');

      }
      if (!doc.namespaces['g_o_']) {
        doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
                           '#default#VML');
      }

      // Setup default CSS.  Only add one style sheet per document
      if (!doc.styleSheets['ex_canvas_']) {
        var ss = doc.createStyleSheet();
        ss.owningElement.id = 'ex_canvas_';
        ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
            // default size is 300x150 in Gecko and Opera
            'text-align:left;width:300px;height:150px}' +
            'g_vml_\\:*{behavior:url(#default#VML)}' +
            'g_o_\\:*{behavior:url(#default#VML)}';

      }

      // find all canvas elements
      var els = doc.getElementsByTagName('canvas');
      for (var i = 0; i < els.length; i++) {
        this.initElement(els[i]);
      }
    },

    /**
     * Public initializes a canvas element so that it can be used as canvas
     * element from now on. This is called automatically before the page is
     * loaded but if you are creating elements using createElement you need to
     * make sure this is called on the element.
     * @param {HTMLElement} el The canvas element to initialize.
     * @return {HTMLElement} the element that was created.
     */
    initElement: function(el) {
      if (!el.getContext) {

        el.getContext = getContext;

        // Remove fallback content. There is no way to hide text nodes so we
        // just remove all childNodes. We could hide all elements and remove
        // text nodes but who really cares about the fallback content.
        el.innerHTML = '';

        // do not use inline function because that will leak memory
        el.attachEvent('onpropertychange', onPropertyChange);
        el.attachEvent('onresize', onResize);

        var attrs = el.attributes;
        if (attrs.width && attrs.width.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setWidth_(attrs.width.nodeValue);
          el.style.width = attrs.width.nodeValue + 'px';
        } else {
          el.width = el.clientWidth;
        }
        if (attrs.height && attrs.height.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setHeight_(attrs.height.nodeValue);
          el.style.height = attrs.height.nodeValue + 'px';
        } else {
          el.height = el.clientHeight;
        }
        //el.getContext().setCoordsize_()
      }
      return el;
    }
  };

  function onPropertyChange(e) {
    var el = e.srcElement;

    switch (e.propertyName) {
      case 'width':
        el.style.width = el.attributes.width.nodeValue + 'px';
        el.getContext().clearRect();
        break;
      case 'height':
        el.style.height = el.attributes.height.nodeValue + 'px';
        el.getContext().clearRect();
        break;
    }
  }

  function onResize(e) {
    var el = e.srcElement;
    if (el.firstChild) {
      el.firstChild.style.width =  el.clientWidth + 'px';
      el.firstChild.style.height = el.clientHeight + 'px';
    }
  }

  G_vmlCanvasManager_.init();

  // precompute "00" to "FF"
  var dec2hex = [];
  for (var i = 0; i < 16; i++) {
    for (var j = 0; j < 16; j++) {
      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
    }
  }

  function createMatrixIdentity() {
    return [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
  }

  function matrixMultiply(m1, m2) {
    var result = createMatrixIdentity();

    for (var x = 0; x < 3; x++) {
      for (var y = 0; y < 3; y++) {
        var sum = 0;

        for (var z = 0; z < 3; z++) {
          sum += m1[x][z] * m2[z][y];
        }

        result[x][y] = sum;
      }
    }
    return result;
  }

  function copyState(o1, o2) {
    o2.fillStyle     = o1.fillStyle;
    o2.lineCap       = o1.lineCap;
    o2.lineJoin      = o1.lineJoin;
    o2.lineWidth     = o1.lineWidth;
    o2.miterLimit    = o1.miterLimit;
    o2.shadowBlur    = o1.shadowBlur;
    o2.shadowColor   = o1.shadowColor;
    o2.shadowOffsetX = o1.shadowOffsetX;
    o2.shadowOffsetY = o1.shadowOffsetY;
    o2.strokeStyle   = o1.strokeStyle;
    o2.globalAlpha   = o1.globalAlpha;
    o2.arcScaleX_    = o1.arcScaleX_;
    o2.arcScaleY_    = o1.arcScaleY_;
    o2.lineScale_    = o1.lineScale_;
  }

  function processStyle(styleString) {
    var str, alpha = 1;

    styleString = String(styleString);
    if (styleString.substring(0, 3) == 'rgb') {
      var start = styleString.indexOf('(', 3);
      var end = styleString.indexOf(')', start + 1);
      var guts = styleString.substring(start + 1, end).split(',');

      str = '#';
      for (var i = 0; i < 3; i++) {
        str += dec2hex[Number(guts[i])];
      }

      if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
        alpha = guts[3];
      }
    } else {
      str = styleString;
    }

    return {color: str, alpha: alpha};
  }

  function processLineCap(lineCap) {
    switch (lineCap) {
      case 'butt':
        return 'flat';
      case 'round':
        return 'round';
      case 'square':
      default:
        return 'square';
    }
  }

  /**
   * This class implements CanvasRenderingContext2D interface as described by
   * the WHATWG.
   * @param {HTMLElement} surfaceElement The element that the 2D context should
   * be associated with
   */
  function CanvasRenderingContext2D_(surfaceElement) {
    this.m_ = createMatrixIdentity();

    this.mStack_ = [];
    this.aStack_ = [];
    this.currentPath_ = [];

    // Canvas context properties
    this.strokeStyle = '#000';
    this.fillStyle = '#000';

    this.lineWidth = 1;
    this.lineJoin = 'miter';
    this.lineCap = 'butt';
    this.miterLimit = Z * 1;
    this.globalAlpha = 1;
    this.canvas = surfaceElement;

    var el = surfaceElement.ownerDocument.createElement('div');
    el.style.width =  surfaceElement.clientWidth + 'px';
    el.style.height = surfaceElement.clientHeight + 'px';
    el.style.overflow = 'hidden';
    el.style.position = 'absolute';
    surfaceElement.appendChild(el);

    this.element_ = el;
    this.arcScaleX_ = 1;
    this.arcScaleY_ = 1;
    this.lineScale_ = 1;
  }

  var contextPrototype = CanvasRenderingContext2D_.prototype;
  contextPrototype.clearRect = function() {
    this.element_.innerHTML = '';
  };

  contextPrototype.beginPath = function() {
    // TODO: Branch current matrix so that save/restore has no effect
    //       as per safari docs.
    this.currentPath_ = [];
  };

  contextPrototype.moveTo = function(aX, aY) {
    var p = this.getCoords_(aX, aY);
    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.lineTo = function(aX, aY) {
    var p = this.getCoords_(aX, aY);
    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});

    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
                                            aCP2x, aCP2y,
                                            aX, aY) {
    var p = this.getCoords_(aX, aY);
    var cp1 = this.getCoords_(aCP1x, aCP1y);
    var cp2 = this.getCoords_(aCP2x, aCP2y);
    bezierCurveTo(this, cp1, cp2, p);
  };

  // Helper function that takes the already fixed cordinates.
  function bezierCurveTo(self, cp1, cp2, p) {
    self.currentPath_.push({
      type: 'bezierCurveTo',
      cp1x: cp1.x,
      cp1y: cp1.y,
      cp2x: cp2.x,
      cp2y: cp2.y,
      x: p.x,
      y: p.y
    });
    self.currentX_ = p.x;
    self.currentY_ = p.y;
  }

  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
    // the following is lifted almost directly from
    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes

    var cp = this.getCoords_(aCPx, aCPy);
    var p = this.getCoords_(aX, aY);

    var cp1 = {
      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
    };
    var cp2 = {
      x: cp1.x + (p.x - this.currentX_) / 3.0,
      y: cp1.y + (p.y - this.currentY_) / 3.0
    };

    bezierCurveTo(this, cp1, cp2, p);
  };

  contextPrototype.arc = function(aX, aY, aRadius,
                                  aStartAngle, aEndAngle, aClockwise) {
    aRadius *= Z;
    var arcType = aClockwise ? 'at' : 'wa';

    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
    var yStart = aY + ms(aStartAngle) * aRadius - Z2;

    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;

    // IE won't render arches drawn counter clockwise if xStart == xEnd.
    if (xStart == xEnd && !aClockwise) {
      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
                       // that can be represented in binary
    }

    var p = this.getCoords_(aX, aY);
    var pStart = this.getCoords_(xStart, yStart);
    var pEnd = this.getCoords_(xEnd, yEnd);

    this.currentPath_.push({type: arcType,
                           x: p.x,
                           y: p.y,
                           radius: aRadius,
                           xStart: pStart.x,
                           yStart: pStart.y,
                           xEnd: pEnd.x,
                           yEnd: pEnd.y});

  };

  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
  };

  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
    var oldPath = this.currentPath_;
    this.beginPath();

    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.stroke();

    this.currentPath_ = oldPath;
  };

  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
    var oldPath = this.currentPath_;
    this.beginPath();

    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.fill();

    this.currentPath_ = oldPath;
  };

  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
    var gradient = new CanvasGradient_('gradient');
    gradient.x0_ = aX0;
    gradient.y0_ = aY0;
    gradient.x1_ = aX1;
    gradient.y1_ = aY1;
    return gradient;
  };

  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
                                                   aX1, aY1, aR1) {
    var gradient = new CanvasGradient_('gradientradial');
    gradient.x0_ = aX0;
    gradient.y0_ = aY0;
    gradient.r0_ = aR0;
    gradient.x1_ = aX1;
    gradient.y1_ = aY1;
    gradient.r1_ = aR1;
    return gradient;
  };

  contextPrototype.drawImage = function(image, var_args) {
    var dx, dy, dw, dh, sx, sy, sw, sh;

    // to find the original width we overide the width and height
    var oldRuntimeWidth = image.runtimeStyle.width;
    var oldRuntimeHeight = image.runtimeStyle.height;
    image.runtimeStyle.width = 'auto';
    image.runtimeStyle.height = 'auto';

    // get the original size
    var w = image.width;
    var h = image.height;

    // and remove overides
    image.runtimeStyle.width = oldRuntimeWidth;
    image.runtimeStyle.height = oldRuntimeHeight;

    if (arguments.length == 3) {
      dx = arguments[1];
      dy = arguments[2];
      sx = sy = 0;
      sw = dw = w;
      sh = dh = h;
    } else if (arguments.length == 5) {
      dx = arguments[1];
      dy = arguments[2];
      dw = arguments[3];
      dh = arguments[4];
      sx = sy = 0;
      sw = w;
      sh = h;
    } else if (arguments.length == 9) {
      sx = arguments[1];
      sy = arguments[2];
      sw = arguments[3];
      sh = arguments[4];
      dx = arguments[5];
      dy = arguments[6];
      dw = arguments[7];
      dh = arguments[8];
    } else {
      throw Error('Invalid number of arguments');
    }

    var d = this.getCoords_(dx, dy);

    var w2 = sw / 2;
    var h2 = sh / 2;

    var vmlStr = [];

    var W = 10;
    var H = 10;

    // For some reason that I've now forgotten, using divs didn't work
    vmlStr.push(' <g_vml_:group',
                ' coordsize="', Z * W, ',', Z * H, '"',
                ' coordorigin="0,0"' ,
                ' style="width:', W, 'px;height:', H, 'px;position:absolute;');

    // If filters are necessary (rotation exists), create them
    // filters are bog-slow, so only create them if abbsolutely necessary
    // The following check doesn't account for skews (which don't exist
    // in the canvas spec (yet) anyway.

    if (this.m_[0][0] != 1 || this.m_[0][1]) {
      var filter = [];

      // Note the 12/21 reversal
      filter.push('M11=', this.m_[0][0], ',',
                  'M12=', this.m_[1][0], ',',
                  'M21=', this.m_[0][1], ',',
                  'M22=', this.m_[1][1], ',',
                  'Dx=', mr(d.x / Z), ',',
                  'Dy=', mr(d.y / Z), '');

      // Bounding box calculation (need to minimize displayed area so that
      // filters don't waste time on unused pixels.
      var max = d;
      var c2 = this.getCoords_(dx + dw, dy);
      var c3 = this.getCoords_(dx, dy + dh);
      var c4 = this.getCoords_(dx + dw, dy + dh);

      max.x = m.max(max.x, c2.x, c3.x, c4.x);
      max.y = m.max(max.y, c2.y, c3.y, c4.y);

      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
                  filter.join(''), ", sizingmethod='clip');")
    } else {
      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
    }

    vmlStr.push(' ">' ,
                '<g_vml_:image src="', image.src, '"',
                ' style="width:', Z * dw, 'px;',
                ' height:', Z * dh, 'px;"',
                ' cropleft="', sx / w, '"',
                ' croptop="', sy / h, '"',
                ' cropright="', (w - sx - sw) / w, '"',
                ' cropbottom="', (h - sy - sh) / h, '"',
                ' />',
                '</g_vml_:group>');

    this.element_.insertAdjacentHTML('BeforeEnd',
                                    vmlStr.join(''));
  };

  contextPrototype.stroke = function(aFill) {
    var lineStr = [];
    var lineOpen = false;
    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
    var color = a.color;
    var opacity = a.alpha * this.globalAlpha;

    var W = 10;
    var H = 10;

    lineStr.push('<g_vml_:shape',
                 ' filled="', !!aFill, '"',
                 ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
                 ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
                 ' stroked="', !aFill, '"',
                 ' path="');

    var newSeq = false;
    var min = {x: null, y: null};
    var max = {x: null, y: null};

    for (var i = 0; i < this.currentPath_.length; i++) {
      var p = this.currentPath_[i];
      var c;

      switch (p.type) {
        case 'moveTo':
          c = p;
          lineStr.push(' m ', mr(p.x), ',', mr(p.y));
          break;
        case 'lineTo':
          lineStr.push(' l ', mr(p.x), ',', mr(p.y));
          break;
        case 'close':
          lineStr.push(' x ');
          p = null;
          break;
        case 'bezierCurveTo':
          lineStr.push(' c ',
                       mr(p.cp1x), ',', mr(p.cp1y), ',',
                       mr(p.cp2x), ',', mr(p.cp2y), ',',
                       mr(p.x), ',', mr(p.y));
          break;
        case 'at':
        case 'wa':
          lineStr.push(' ', p.type, ' ',
                       mr(p.x - this.arcScaleX_ * p.radius), ',',
                       mr(p.y - this.arcScaleY_ * p.radius), ' ',
                       mr(p.x + this.arcScaleX_ * p.radius), ',',
                       mr(p.y + this.arcScaleY_ * p.radius), ' ',
                       mr(p.xStart), ',', mr(p.yStart), ' ',
                       mr(p.xEnd), ',', mr(p.yEnd));
          break;
      }


      // TODO: Following is broken for curves due to
      //       move to proper paths.

      // Figure out dimensions so we can do gradient fills
      // properly
      if (p) {
        if (min.x == null || p.x < min.x) {
          min.x = p.x;
        }
        if (max.x == null || p.x > max.x) {
          max.x = p.x;
        }
        if (min.y == null || p.y < min.y) {
          min.y = p.y;
        }
        if (max.y == null || p.y > max.y) {
          max.y = p.y;
        }
      }
    }
    lineStr.push(' ">');

    if (!aFill) {
      var lineWidth = this.lineScale_ * this.lineWidth;

      // VML cannot correctly render a line if the width is less than 1px.
      // In that case, we dilute the color to make the line look thinner.
      if (lineWidth < 1) {
        opacity *= lineWidth;
      }

      lineStr.push(
        '<g_vml_:stroke',
        ' opacity="', opacity, '"',
        ' joinstyle="', this.lineJoin, '"',
        ' miterlimit="', this.miterLimit, '"',
        ' endcap="', processLineCap(this.lineCap), '"',
        ' weight="', lineWidth, 'px"',
        ' color="', color, '" />'
      );
    } else if (typeof this.fillStyle == 'object') {
      var fillStyle = this.fillStyle;
      var angle = 0;
      var focus = {x: 0, y: 0};

      // additional offset
      var shift = 0;
      // scale factor for offset
      var expansion = 1;

      if (fillStyle.type_ == 'gradient') {
        var x0 = fillStyle.x0_ / this.arcScaleX_;
        var y0 = fillStyle.y0_ / this.arcScaleY_;
        var x1 = fillStyle.x1_ / this.arcScaleX_;
        var y1 = fillStyle.y1_ / this.arcScaleY_;
        var p0 = this.getCoords_(x0, y0);
        var p1 = this.getCoords_(x1, y1);
        var dx = p1.x - p0.x;
        var dy = p1.y - p0.y;
        angle = Math.atan2(dx, dy) * 180 / Math.PI;

        // The angle should be a non-negative number.
        if (angle < 0) {
          angle += 360;
        }

        // Very small angles produce an unexpected result because they are
        // converted to a scientific notation string.
        if (angle < 1e-6) {
          angle = 0;
        }
      } else {
        var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
        var width  = max.x - min.x;
        var height = max.y - min.y;
        focus = {
          x: (p0.x - min.x) / width,
          y: (p0.y - min.y) / height
        };

        width  /= this.arcScaleX_ * Z;
        height /= this.arcScaleY_ * Z;
        var dimension = m.max(width, height);
        shift = 2 * fillStyle.r0_ / dimension;
        expansion = 2 * fillStyle.r1_ / dimension - shift;
      }

      // We need to sort the color stops in ascending order by offset,
      // otherwise IE won't interpret it correctly.
      var stops = fillStyle.colors_;
      stops.sort(function(cs1, cs2) {
        return cs1.offset - cs2.offset;
      });

      var length = stops.length;
      var color1 = stops[0].color;
      var color2 = stops[length - 1].color;
      var opacity1 = stops[0].alpha * this.globalAlpha;
      var opacity2 = stops[length - 1].alpha * this.globalAlpha;

      var colors = [];
      for (var i = 0; i < length; i++) {
        var stop = stops[i];
        colors.push(stop.offset * expansion + shift + ' ' + stop.color);
      }

      // When colors attribute is used, the meanings of opacity and o:opacity2
      // are reversed.
      lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
                   ' method="none" focus="100%"',
                   ' color="', color1, '"',
                   ' color2="', color2, '"',
                   ' colors="', colors.join(','), '"',
                   ' opacity="', opacity2, '"',
                   ' g_o_:opacity2="', opacity1, '"',
                   ' angle="', angle, '"',
                   ' focusposition="', focus.x, ',', focus.y, '" />');
    } else {
      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
                   '" />');
    }

    lineStr.push('</g_vml_:shape>');

    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
  };

  contextPrototype.fill = function() {
    this.stroke(true);
  }

  contextPrototype.closePath = function() {
    this.currentPath_.push({type: 'close'});
  };

  /**
   * @private
   */
  contextPrototype.getCoords_ = function(aX, aY) {
    var m = this.m_;
    return {
      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
    }
  };

  contextPrototype.save = function() {
    var o = {};
    copyState(this, o);
    this.aStack_.push(o);
    this.mStack_.push(this.m_);
    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
  };

  contextPrototype.restore = function() {
    copyState(this.aStack_.pop(), this);
    this.m_ = this.mStack_.pop();
  };

  function matrixIsFinite(m) {
    for (var j = 0; j < 3; j++) {
      for (var k = 0; k < 2; k++) {
        if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
          return false;
        }
      }
    }
    return true;
  }

  function setM(ctx, m, updateLineScale) {
    if (!matrixIsFinite(m)) {
      return;
    }
    ctx.m_ = m;

    if (updateLineScale) {
      // Get the line scale.
      // Determinant of this.m_ means how much the area is enlarged by the
      // transformation. So its square root can be used as a scale factor
      // for width.
      var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
      ctx.lineScale_ = sqrt(abs(det));
    }
  }

  contextPrototype.translate = function(aX, aY) {
    var m1 = [
      [1,  0,  0],
      [0,  1,  0],
      [aX, aY, 1]
    ];

    setM(this, matrixMultiply(m1, this.m_), false);
  };

  contextPrototype.rotate = function(aRot) {
    var c = mc(aRot);
    var s = ms(aRot);

    var m1 = [
      [c,  s, 0],
      [-s, c, 0],
      [0,  0, 1]
    ];

    setM(this, matrixMultiply(m1, this.m_), false);
  };

  contextPrototype.scale = function(aX, aY) {
    this.arcScaleX_ *= aX;
    this.arcScaleY_ *= aY;
    var m1 = [
      [aX, 0,  0],
      [0,  aY, 0],
      [0,  0,  1]
    ];

    setM(this, matrixMultiply(m1, this.m_), true);
  };

  contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
    var m1 = [
      [m11, m12, 0],
      [m21, m22, 0],
      [dx,  dy,  1]
    ];

    setM(this, matrixMultiply(m1, this.m_), true);
  };

  contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
    var m = [
      [m11, m12, 0],
      [m21, m22, 0],
      [dx,  dy,  1]
    ];

    setM(this, m, true);
  };

  /******** STUBS ********/
  contextPrototype.clip = function() {
    // TODO: Implement
  };

  contextPrototype.arcTo = function() {
    // TODO: Implement
  };

  contextPrototype.createPattern = function() {
    return new CanvasPattern_;
  };

  // Gradient / Pattern Stubs
  function CanvasGradient_(aType) {
    this.type_ = aType;
    this.x0_ = 0;
    this.y0_ = 0;
    this.r0_ = 0;
    this.x1_ = 0;
    this.y1_ = 0;
    this.r1_ = 0;
    this.colors_ = [];
  }

  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
    aColor = processStyle(aColor);
    this.colors_.push({offset: aOffset,
                       color: aColor.color,
                       alpha: aColor.alpha});
  };

  function CanvasPattern_() {}

  // set up externs
  G_vmlCanvasManager = G_vmlCanvasManager_;
  CanvasRenderingContext2D = CanvasRenderingContext2D_;
  CanvasGradient = CanvasGradient_;
  CanvasPattern = CanvasPattern_;

})();

} // if
var charset="";

/* This notice must be untouched at all times.
wz_jsgraphics.js    v. 2.31
The latest version is available at
http://www.walterzorn.com
or http://www.devira.com
or http://www.walterzorn.de

Copyright (c) 2002-2004 Walter Zorn. All rights reserved.
Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
Last modified: 28. 3. 2005

Performance optimizations for Internet Explorer
by Thomas Frank and John Holdsworth.
fillPolygon method implemented by Matthieu Haller.

High Performance JavaScript Graphics Library.
Provides methods
- to draw lines, rectangles, ellipses, polygons
  with specifiable line thickness,
- to fill rectangles and ellipses
- to draw text.
NOTE: Operations, functions and branching have rather been optimized
to efficiency and speed than to shortness of source code.

LICENSE: LGPL

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (LGPL) as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,
or see http://www.gnu.org/copyleft/lesser.html
*/


var jg_ihtm, jg_ie, jg_fast, jg_dom, jg_moz,
jg_n4 = (document.layers && typeof document.classes != "undefined");


function chkDHTM(x, i)
{
	x = document.body || null;
	jg_ie = x && typeof x.insertAdjacentHTML != "undefined";
	jg_dom = (x && !jg_ie &&
		typeof x.appendChild != "undefined" &&
		typeof document.createRange != "undefined" &&
		typeof (i = document.createRange()).setStartBefore != "undefined" &&
		typeof i.createContextualFragment != "undefined");
	jg_ihtm = !jg_ie && !jg_dom && x && typeof x.innerHTML != "undefined";
	jg_fast = jg_ie && document.all && !window.opera;
	jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";
}


function pntDoc()
{
	this.wnd.document.write(jg_fast? this.htmRpc() : this.htm);
	this.htm = '';
}


function pntCnvDom()
{
	var x = document.createRange();
	x.setStartBefore(this.cnv);
	x = x.createContextualFragment(jg_fast? this.htmRpc() : this.htm);
	this.cnv.appendChild(x);
	this.htm = '';
}


function pntCnvIe()
{
	this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this.htmRpc() : this.htm);
	this.htm = '';
}


function pntCnvIhtm()
{
	this.cnv.innerHTML += this.htm;
	this.htm = '';
}


function pntCnv()
{
	this.htm = '';
}


function mkDiv(x, y, w, h)
{
	this.htm += '<div style="position:absolute;'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:' + w + 'px;'+
		'height:' + h + 'px;'+
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';"><\/div>';
}


function mkDivIe(x, y, w, h)
{
	this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';
}


function mkDivPrt(x, y, w, h)
{
	this.htm += '<div style="position:absolute;'+
		'border-left:' + w + 'px solid ' + this.color + ';'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:0px;'+
		'height:' + h + 'px;'+
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';"><\/div>';
}


function mkLyr(x, y, w, h)
{
	this.htm += '<layer '+
		'left="' + x + '" '+
		'top="' + y + '" '+
		'width="' + w + '" '+
		'height="' + h + '" '+
		'bgcolor="' + this.color + '"><\/layer>\n';
}


var regex =  /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;
function htmRpc()
{
	return this.htm.replace(
		regex,
		'<div style="overflow:hidden;position:absolute;background-color:'+
		'$1;left:$2;top:$3;width:$4;height:$5"></div>\n');
}


function htmPrtRpc()
{
	return this.htm.replace(
		regex,
		'<div style="overflow:hidden;position:absolute;background-color:'+
		'$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');
}


function mkLin(x1, y1, x2, y2)
{
	if (x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1;

	if (dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx,
		ox = x;
		while ((dx--) > 0)
		{
			++x;
			if (p > 0)
			{
				this.mkDiv(ox, y, x-ox, 1);
				y += yIncr;
				p += pru;
				ox = x;
			}
			else p += pr;
		}
		this.mkDiv(ox, y, x2-ox+1, 1);
	}

	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy,
		oy = y;
		if (y2 <= y1)
		{
			while ((dy--) > 0)
			{
				if (p > 0)
				{
					this.mkDiv(x++, y, 1, oy-y+1);
					y += yIncr;
					p += pru;
					oy = y;
				}
				else
				{
					y += yIncr;
					p += pr;
				}
			}
			this.mkDiv(x2, y2, 1, oy-y2+1);
		}
		else
		{
			while ((dy--) > 0)
			{
				y += yIncr;
				if (p > 0)
				{
					this.mkDiv(x++, oy, 1, y-oy);
					p += pru;
					oy = y;
				}
				else p += pr;
			}
			this.mkDiv(x2, oy, 1, y2-oy+1);
		}
	}
}


function mkLin2D(x1, y1, x2, y2)
{
	if (x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1;

	var s = this.stroke;
	if (dx >= dy)
	{
		if (s-3 > 0)
		{
			var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;
			_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
		}
		else var _s = s;
		var ad = Math.ceil(s/2);

		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx,
		ox = x;
		while ((dx--) > 0)
		{
			++x;
			if (p > 0)
			{
				this.mkDiv(ox, y, x-ox+ad, _s);
				y += yIncr;
				p += pru;
				ox = x;
			}
			else p += pr;
		}
		this.mkDiv(ox, y, x2-ox+ad+1, _s);
	}

	else
	{
		if (s-3 > 0)
		{
			var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;
			_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
		}
		else var _s = s;
		var ad = Math.round(s/2);

		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy,
		oy = y;
		if (y2 <= y1)
		{
			++ad;
			while ((dy--) > 0)
			{
				if (p > 0)
				{
					this.mkDiv(x++, y, _s, oy-y+ad);
					y += yIncr;
					p += pru;
					oy = y;
				}
				else
				{
					y += yIncr;
					p += pr;
				}
			}
			this.mkDiv(x2, y2, _s, oy-y2+ad);
		}
		else
		{
			while ((dy--) > 0)
			{
				y += yIncr;
				if (p > 0)
				{
					this.mkDiv(x++, oy, _s, y-oy+ad);
					p += pru;
					oy = y;
				}
				else p += pr;
			}
			this.mkDiv(x2, oy, _s, y2-oy+ad+1);
		}
	}
}


function mkLinDott(x1, y1, x2, y2)
{
	if (x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1,
	drw = true;
	if (dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx;
		while ((dx--) > 0)
		{
			if (drw) this.mkDiv(x, y, 1, 1);
			drw = !drw;
			if (p > 0)
			{
				y += yIncr;
				p += pru;
			}
			else p += pr;
			++x;
		}
		if (drw) this.mkDiv(x, y, 1, 1);
	}

	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy;
		while ((dy--) > 0)
		{
			if (drw) this.mkDiv(x, y, 1, 1);
			drw = !drw;
			y += yIncr;
			if (p > 0)
			{
				++x;
				p += pru;
			}
			else p += pr;
		}
		if (drw) this.mkDiv(x, y, 1, 1);
	}
}


function mkOv(left, top, width, height)
{
	var a = width>>1, b = height>>1,
	wod = width&1, hod = (height&1)+1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	ox = 0, oy = b,
	aa = (a*a)<<1, bb = (b*b)<<1,
	st = (aa>>1)*(1-(b<<1)) + bb,
	tt = (bb>>1) - aa*((b<<1)-1),
	w, h;
	while (y > 0)
	{
		if (st < 0)
		{
			st += bb*((x<<1)+3);
			tt += (bb<<1)*(++x);
		}
		else if (tt < 0)
		{
			st += bb*((x<<1)+3) - (aa<<1)*(y-1);
			tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
			w = x-ox;
			h = oy-y;
			if (w&2 && h&2)
			{
				this.mkOvQds(cx, cy, -x+2, ox+wod, -oy, oy-1+hod, 1, 1);
				this.mkOvQds(cx, cy, -x+1, x-1+wod, -y-1, y+hod, 1, 1);
			}
			else this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, oy-h+hod, w, h);
			ox = x;
			oy = y;
		}
		else
		{
			tt -= aa*((y<<1)-3);
			st -= (aa<<1)*(--y);
		}
	}
	this.mkDiv(cx-a, cy-oy, a-ox+1, (oy<<1)+hod);
	this.mkDiv(cx+ox+wod, cy-oy, a-ox+1, (oy<<1)+hod);
}


function mkOv2D(left, top, width, height)
{
	var s = this.stroke;
	width += s-1;
	height += s-1;
	var a = width>>1, b = height>>1,
	wod = width&1, hod = (height&1)+1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	aa = (a*a)<<1, bb = (b*b)<<1,
	st = (aa>>1)*(1-(b<<1)) + bb,
	tt = (bb>>1) - aa*((b<<1)-1);

	if (s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))
	{
		var ox = 0, oy = b,
		w, h,
		pxl, pxr, pxt, pxb, pxw;
		while (y > 0)
		{
			if (st < 0)
			{
				st += bb*((x<<1)+3);
				tt += (bb<<1)*(++x);
			}
			else if (tt < 0)
			{
				st += bb*((x<<1)+3) - (aa<<1)*(y-1);
				tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
				w = x-ox;
				h = oy-y;

				if (w-1)
				{
					pxw = w+1+(s&1);
					h = s;
				}
				else if (h-1)
				{
					pxw = s;
					h += 1+(s&1);
				}
				else pxw = h = s;
				this.mkOvQds(cx, cy, -x+1, ox-pxw+w+wod, -oy, -h+oy+hod, pxw, h);
				ox = x;
				oy = y;
			}
			else
			{
				tt -= aa*((y<<1)-3);
				st -= (aa<<1)*(--y);
			}
		}
		this.mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);
		this.mkDiv(cx+a+wod-s+1, cy-oy, s, (oy<<1)+hod);
	}

	else
	{
		var _a = (width-((s-1)<<1))>>1,
		_b = (height-((s-1)<<1))>>1,
		_x = 0, _y = _b,
		_aa = (_a*_a)<<1, _bb = (_b*_b)<<1,
		_st = (_aa>>1)*(1-(_b<<1)) + _bb,
		_tt = (_bb>>1) - _aa*((_b<<1)-1),

		pxl = new Array(),
		pxt = new Array(),
		_pxb = new Array();
		pxl[0] = 0;
		pxt[0] = b;
		_pxb[0] = _b-1;
		while (y > 0)
		{
			if (st < 0)
			{
				st += bb*((x<<1)+3);
				tt += (bb<<1)*(++x);
				pxl[pxl.length] = x;
				pxt[pxt.length] = y;
			}
			else if (tt < 0)
			{
				st += bb*((x<<1)+3) - (aa<<1)*(y-1);
				tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
				pxl[pxl.length] = x;
				pxt[pxt.length] = y;
			}
			else
			{
				tt -= aa*((y<<1)-3);
				st -= (aa<<1)*(--y);
			}

			if (_y > 0)
			{
				if (_st < 0)
				{
					_st += _bb*((_x<<1)+3);
					_tt += (_bb<<1)*(++_x);
					_pxb[_pxb.length] = _y-1;
				}
				else if (_tt < 0)
				{
					_st += _bb*((_x<<1)+3) - (_aa<<1)*(_y-1);
					_tt += (_bb<<1)*(++_x) - _aa*(((_y--)<<1)-3);
					_pxb[_pxb.length] = _y-1;
				}
				else
				{
					_tt -= _aa*((_y<<1)-3);
					_st -= (_aa<<1)*(--_y);
					_pxb[_pxb.length-1]--;
				}
			}
		}

		var ox = 0, oy = b,
		_oy = _pxb[0],
		l = pxl.length,
		w, h;
		for (var i = 0; i < l; i++)
		{
			if (typeof _pxb[i] != "undefined")
			{
				if (_pxb[i] < _oy || pxt[i] < oy)
				{
					x = pxl[i];
					this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, _oy+hod, x-ox, oy-_oy);
					ox = x;
					oy = pxt[i];
					_oy = _pxb[i];
				}
			}
			else
			{
				x = pxl[i];
				this.mkDiv(cx-x+1, cy-oy, 1, (oy<<1)+hod);
				this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
				ox = x;
				oy = pxt[i];
			}
		}
		this.mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);
		this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
	}
}


function mkOvDott(left, top, width, height)
{
	var a = width>>1, b = height>>1,
	wod = width&1, hod = height&1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
	st = (aa2>>1)*(1-(b<<1)) + bb,
	tt = (bb>>1) - aa2*((b<<1)-1),
	drw = true;
	while (y > 0)
	{
		if (st < 0)
		{
			st += bb*((x<<1)+3);
			tt += (bb<<1)*(++x);
		}
		else if (tt < 0)
		{
			st += bb*((x<<1)+3) - aa4*(y-1);
			tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
		}
		else
		{
			tt -= aa2*((y<<1)-3);
			st -= aa4*(--y);
		}
		if (drw) this.mkOvQds(cx, cy, -x, x+wod, -y, y+hod, 1, 1);
		drw = !drw;
	}
}


function mkRect(x, y, w, h)
{
	var s = this.stroke;
	this.mkDiv(x, y, w, s);
	this.mkDiv(x+w, y, s, h);
	this.mkDiv(x, y+h, w+s, s);
	this.mkDiv(x, y+s, s, h-s);
}


function mkRectDott(x, y, w, h)
{
	this.drawLine(x, y, x+w, y);
	this.drawLine(x+w, y, x+w, y+h);
	this.drawLine(x, y+h, x+w, y+h);
	this.drawLine(x, y, x, y+h);
}


function jsgFont()
{
	this.PLAIN = 'font-weight:normal;';
	this.BOLD = 'font-weight:bold;';
	this.ITALIC = 'font-style:italic;';
	this.ITALIC_BOLD = this.ITALIC + this.BOLD;
	this.BOLD_ITALIC = this.ITALIC_BOLD;
}
var Font = new jsgFont();


function jsgStroke()
{
	this.DOTTED = -1;
}
var Stroke = new jsgStroke();


function jsGraphics(id, wnd)
{
	this.setColor = new Function('arg', 'this.color = arg.toLowerCase();');

	this.setStroke = function(x)
	{
		this.stroke = x;
		if (!(x+1))
		{
			this.drawLine = mkLinDott;
			this.mkOv = mkOvDott;
			this.drawRect = mkRectDott;
		}
		else if (x-1 > 0)
		{
			this.drawLine = mkLin2D;
			this.mkOv = mkOv2D;
			this.drawRect = mkRect;
		}
		else
		{
			this.drawLine = mkLin;
			this.mkOv = mkOv;
			this.drawRect = mkRect;
		}
	};


	this.setPrintable = function(arg)
	{
		this.printable = arg;
		if (jg_fast)
		{
			this.mkDiv = mkDivIe;
			this.htmRpc = arg? htmPrtRpc : htmRpc;
		}
		else this.mkDiv = jg_n4? mkLyr : arg? mkDivPrt : mkDiv;
	};


	this.setFont = function(fam, sz, sty)
	{
		this.ftFam = fam;
		this.ftSz = sz;
		this.ftSty = sty || Font.PLAIN;
	};


	this.drawPolyline = this.drawPolyLine = function(x, y, s)
	{
		for (var i=0 ; i<x.length-1 ; i++ )
			this.drawLine(x[i], y[i], x[i+1], y[i+1]);
	};


	this.fillRect = function(x, y, w, h)
	{
		this.mkDiv(x, y, w, h);
	};


	this.drawPolygon = function(x, y)
	{
		this.drawPolyline(x, y);
		this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);
	};


	this.drawEllipse = this.drawOval = function(x, y, w, h)
	{
		this.mkOv(x, y, w, h);
	};


	this.fillEllipse = this.fillOval = function(left, top, w, h)
	{
		var a = (w -= 1)>>1, b = (h -= 1)>>1,
		wod = (w&1)+1, hod = (h&1)+1,
		cx = left+a, cy = top+b,
		x = 0, y = b,
		ox = 0, oy = b,
		aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
		st = (aa2>>1)*(1-(b<<1)) + bb,
		tt = (bb>>1) - aa2*((b<<1)-1),
		pxl, dw, dh;
		if (w+1) while (y > 0)
		{
			if (st < 0)
			{
				st += bb*((x<<1)+3);
				tt += (bb<<1)*(++x);
			}
			else if (tt < 0)
			{
				st += bb*((x<<1)+3) - aa4*(y-1);
				pxl = cx-x;
				dw = (x<<1)+wod;
				tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
				dh = oy-y;
				this.mkDiv(pxl, cy-oy, dw, dh);
				this.mkDiv(pxl, cy+oy-dh+hod, dw, dh);
				ox = x;
				oy = y;
			}
			else
			{
				tt -= aa2*((y<<1)-3);
				st -= aa4*(--y);
			}
		}
		this.mkDiv(cx-a, cy-oy, w+1, (oy<<1)+hod);
	};


/* fillPolygon method, implemented by Matthieu Haller.
This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.
C source of GD 1.8.4 found at http://www.boutell.com/gd/

THANKS to Kirsten Schulz for the polygon fixes!

The intersection finding technique of this code could be improved
by remembering the previous intertersection, and by using the slope.
That could help to adjust intersections to produce a nice
interior_extrema. */
	this.fillPolygon = function(array_x, array_y)
	{
		var i;
		var y;
		var miny, maxy;
		var x1, y1;
		var x2, y2;
		var ind1, ind2;
		var ints;

		var n = array_x.length;

		if (!n) return;


		miny = array_y[0];
		maxy = array_y[0];
		for (i = 1; i < n; i++)
		{
			if (array_y[i] < miny)
				miny = array_y[i];

			if (array_y[i] > maxy)
				maxy = array_y[i];
		}
		for (y = miny; y <= maxy; y++)
		{
			var polyInts = new Array();
			ints = 0;
			for (i = 0; i < n; i++)
			{
				if (!i)
				{
					ind1 = n-1;
					ind2 = 0;
				}
				else
				{
					ind1 = i-1;
					ind2 = i;
				}
				y1 = array_y[ind1];
				y2 = array_y[ind2];
				if (y1 < y2)
				{
					x1 = array_x[ind1];
					x2 = array_x[ind2];
				}
				else if (y1 > y2)
				{
					y2 = array_y[ind1];
					y1 = array_y[ind2];
					x2 = array_x[ind1];
					x1 = array_x[ind2];
				}
				else continue;

				 // modified 11. 2. 2004 Walter Zorn
				if ((y >= y1) && (y < y2))
					polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

				else if ((y == maxy) && (y > y1) && (y <= y2))
					polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
			}
			polyInts.sort(integer_compare);
			for (i = 0; i < ints; i+=2)
				this.mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);
		}
	};


	this.drawString = function(txt, x, y)
	{
		this.htm += '<div style="position:absolute;white-space:nowrap;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'font-family:' +  this.ftFam + ';'+
			'font-size:' + this.ftSz + ';'+
			'color:' + this.color + ';' + this.ftSty + '">'+
			txt +
			'<\/div>';
	};


/* drawStringRect() added by Rick Blommers.
Allows to specify the size of the text rectangle and to align the
text both horizontally (e.g. right) and vertically within that rectangle */
	this.drawStringRect = function(txt, x, y, width, halign)
	{
		this.htm += '<div style="position:absolute;overflow:hidden;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'width:'+width +'px;'+
			'text-align:'+halign+';'+
			'font-family:' +  this.ftFam + ';'+
			'font-size:' + this.ftSz + ';'+
			'color:' + this.color + ';' + this.ftSty + '">'+
			txt +
			'<\/div>';
	};


	this.drawImage = function(imgSrc, x, y, w, h)
	{
		this.htm += '<div style="position:absolute;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'width:' +  w + ';'+
			'height:' + h + ';">'+
			'<img src="' + imgSrc + '" width="' + w + '" height="' + h + '">'+
			'<\/div>';
	};


	this.clear = function()
	{
		this.htm = "";
		if (this.cnv) this.cnv.innerHTML = this.defhtm;
	};


	this.mkOvQds = function(cx, cy, xl, xr, yt, yb, w, h)
	{
		this.mkDiv(xr+cx, yt+cy, w, h);
		this.mkDiv(xr+cx, yb+cy, w, h);
		this.mkDiv(xl+cx, yb+cy, w, h);
		this.mkDiv(xl+cx, yt+cy, w, h);
	};

	this.setStroke(1);
	this.setFont('verdana,geneva,helvetica,sans-serif', String.fromCharCode(0x31, 0x32, 0x70, 0x78), Font.PLAIN);
	this.color = '#000000';
	this.htm = '';
	this.wnd = wnd || window;

	if (!(jg_ie || jg_dom || jg_ihtm)) chkDHTM();
	if (typeof id != 'string' || !id) this.paint = pntDoc;
	else
	{
		this.cnv = document.all? (this.wnd.document.all[id] || null)
			: document.getElementById? (this.wnd.document.getElementById(id) || null)
			: null;
		this.defhtm = (this.cnv && this.cnv.innerHTML)? this.cnv.innerHTML : '';
		this.paint = jg_dom? pntCnvDom : jg_ie? pntCnvIe : jg_ihtm? pntCnvIhtm : pntCnv;
	}

	this.setPrintable(false);
}



function integer_compare(x,y)
{
	return (x < y) ? -1 : ((x > y)*1);
}
var charset="";
/******************************************************************************
 * kaXmlOverlay - XML server side generated overlay for kaMap.
 *
 * Piergiorgio Navone 
 *
 * $Id: kaXmlOverlay.js,v 1.4 2006/08/08 13:17:55 pspencer Exp $
 *****************************************************************************/
 
/******************************************************************************
 * BEGIN section in Wiki syntax
 
=kaXmlOverlay Quick HOW-TO=

* '''1''' Import scripts in your page:

 <script type="text/javascript" src="xhr.js"></script>
 <script type="text/javascript" src="excanvas.js"></script>
 <script type="text/javascript" src="wz_jsgraphics.js"></script>
 <script type="text/javascript" src="XMLOverlay/kaXmlOverlay.js"></script>

* '''2''' Let ka-Map initialize itself: the next steps should wait at lest the KAMAP_MAP_INITIALIZED event.

* '''3''' Create a kaXmlOverlay object:

 myXmlOverlay = new kaXmlOverlay( ICTMAP, 250 );

* '''4''' Add some objects on the overlay layer. There are two ways to do that

** Call the loadXml method: this method load an XML document from the web server.

 myXmlOverlay.loadXml('points.xml');

** Write a JavaScript function to add your objects:

 var my_point = myXmlOverlay.addNewPoint('Point ID', longuitude, latitude);
 var my_symbol = new kaXmlSymbol();
 my_symbol.size = 12;
 my_symbol.color = '#ff0000';
 my_point.addGraphic(my_symbol);


* '''5''' To have a periodic update:

 myInterval = setInterval("myMovingOverlay.loadXml('xmlget.phtml')",5000);


--------------------------------------------

= kaXmlOverlay Reference=

This document describe the interface of the JavaScript kaXmlOverlay library as well as the XLM documents describing overlays. The document is divided in tree sections:

# A summary of JavaScript objects and functions
# The definition of the XML
# An in deep description of attributes common to both XML and JavaScript functions


== JavaScript API==

In this section there is a list of main classes with methods an properties that you ca use to programmatically add overlays to your map.
A detailed an updated documentation for each function is maintained as JavaDoc like comments in the source code.


=== Class kaXmlOverlay===

This class represent a map layer where is possible to add overlays.
To instantiate this class use the constructor
 
 kaXmlOverlay( oKaMap, xml_url )
;oKaMap: A kaMap object
;zIndex: The z index of the layer


To load an XML document with overlay description call the method

 kaXmlOverlay.prototype.loadXml = function(xml_url)
;xml_url: URL of th XML with points to plot


To add a new point to an overlay

 kaXmlOverlay.prototype.addNewPoint = function(pid, x, y)
;pid: Point ID
;x: X geo-coordinate
;y: Y geo-coordinate
;return: A kaXmlPoint object with the given point ID.


To retrieve an existing point from an overlay call

 kaXmlOverlay.prototype.getPointObject = function(pid)
;pid: Point ID
;return: The kaXmlPoint object given the point ID. null if not found.


To remove one or more points from the overlay

kaXmlOverlay.prototype.removePoint = function( pid )
;pid: Point ID or a regexp. If pid is null or not present remove all points.


=== Class kaXmlPoint===
A kaXmlPoint represents a group of graphic object on the overlay layer. The point is placed on the map at specified geographic coordinates. A point can be moved on the map without the need of redrawing all its graphic objects. 

To instantiate a new point don't use the constructor but call the ''kaXmlOverlay.addNewPoint()'' function.


To place or move a kaXmlPoint on the map call

 kaXmlPoint.prototype.setPosition = function( x, y )
;x: X geo-coordinate
;y: Y geo-coordinate


To clear all graphics associated with the point call the method

 kaXmlPoint.prototype.clear = function()


To add graphic objects to a point use the method

 kaXmlPoint.prototype.addGraphic = function( obj )
;obj: an object of type kaXmlSymbol, kaXmlIcon, kaXmlLabel, kaXmlLinestring or kaXmlPolygon


To manually set the HTML content of a kaXmlPoint use the method

 kaXmlPoint.prototype.setInnerHtml = function(ihtml)
;ihtml: A string containing the HTML

This function delete any other content of the point.



=== Graphic objects classes===
The graphic objects that can be displayed are:

* kaXmlSymbol
* kaXmlLabel
* kaXmlIcon
* kaXmlLinestring
* kaXmlPolygon

All this classes have a constructor without parameters and different attributes: the attributes are described in the following of the document.

To use one of these objects create a new instance, configure it setting its properties ad add it to a ''kaXmlPoint'' with the method ''addGraphic''.



'''Using CANVAS for vector graphics'''

Symbols, linestrings and polygons are drawn using <canvas>. To change this behaviour and use
the previous implementation (drawgeom.phtml and wz_jsgraphcs) use

 xmlOverlayUseCanvas = false;


== XML Document Type Definition==

----------


 <!ELEMENT overlay (delete*, point*)>
 
 <!-- 
 	Delete from the overlay layer one or more points. If the atribute 'id' is present it's 
 	used as a regular expression to match point id to be deleted. If 'id' is not given 
 	deletes all points.
 -->
 <!ELEMENT delete EMPTY>
 
 <!--
 	Define a point with a given ID. If the ID exists it's moved to the new position
 	otherwise it is drawn on the map.
 	In order to redraw an existing point to change some attribute in the rendering
 	let include the attribute redraw="true" or a <delete> element. 
  -->
 <!ELEMENT point (ihtml?, symbol*, icon*, label*, linestring*, polygon*)>
 
 <!-- 
 	Insert arbitrary HTML in the point DIV.
 -->
 <!ELEMENT ihtml (#PCDATA)>
 
 
 <!ELEMENT symbol EMPTY>
 <!ELEMENT icon EMPTY>


 <!-- 
 	The content of the label element is the text of label.
 -->
 <!ELEMENT label (#PCDATA)>

 <!-- 
 	The content of the linestring element is a list of coordinates in the form:
 		x0 y0, x1 y1, [...], xn yn
 -->
 <!ELEMENT linestring EMPTY>
 
 <!-- 
 	The content of the polygon element is a list of coordinates in the form:
 		x0 y0, x1 y1, [...], xn yn
 -->
 <!ELEMENT polygon EMPTY>
 
 <!ATTLIST delete id CDATA #IMPLIED>
 
 <!ATTLIST point id CDATA #REQUIRED>
 <!ATTLIST point x CDATA #REQUIRED>
 <!ATTLIST point y CDATA #REQUIRED>
 <!ATTLIST point redraw (false|true) "false">
 
 <!ATTLIST symbol shape CDATA #IMPLIED>
 <!ATTLIST symbol size CDATA #IMPLIED>
 <!ATTLIST symbol color CDATA #IMPLIED>
 <!ATTLIST symbol bcolor CDATA #IMPLIED>
 <!ATTLIST symbol stroke CDATA #IMPLIED>
 <!ATTLIST symbol opacity CDATA #IMPLIED>
 
 <!ATTLIST icon src CDATA #REQUIRED>
 <!ATTLIST icon w CDATA #REQUIRED>
 <!ATTLIST icon h CDATA #REQUIRED>
 <!ATTLIST icon px CDATA #IMPLIED>
 <!ATTLIST icon py CDATA #IMPLIED>
 <!ATTLIST icon opacity CDATA #IMPLIED>
 
 <!ATTLIST label color CDATA #IMPLIED>
 <!ATTLIST label boxcolor CDATA #IMPLIED>
 <!ATTLIST label w CDATA #IMPLIED>
 <!ATTLIST label h CDATA #IMPLIED>
 <!ATTLIST label px CDATA #IMPLIED>
 <!ATTLIST label py CDATA #IMPLIED>
 <!ATTLIST label fsize CDATA #IMPLIED>
 <!ATTLIST label font CDATA #IMPLIED>
 
 <!ATTLIST linestring color CDATA #IMPLIED>
 <!ATTLIST linestring stroke CDATA #IMPLIED>
 <!ATTLIST linestring opacity CDATA #IMPLIED>

 <!ATTLIST polygon color CDATA #IMPLIED>
 <!ATTLIST polygon bcolor CDATA #IMPLIED>
 <!ATTLIST polygon stroke CDATA #IMPLIED>
 <!ATTLIST polygon opacity CDATA #IMPLIED>

----------


=== XML document example===

 <overlay>
  <point x="7435386.24" y="6172463.1" id="p1">
    <label>just a label</label>
    <symbol shape="bullet" size="10" opacity="1" color="#FF0000" />
  </point>
 </overlay>

== Overlay objects attributes==

=== POINT (<point>)===

The POINT is the father of all objects you can display on the overlay layer.
Wherever you want dislay someting on the overlay layer you have to define a
POINT than add to the POINT icons, symbols, labels, etc.

'''POINT attributes:'''

;id: (string, mandatory) This string is used to identify the point. It's needed to translate, delete, redraw the POINT.
;x: (number, required) The X coordinate in map units.
;y: (number, required) The Y coordinate in map units.


=== SYMBOL (kaXmlSymbol, <symbol>)===
A symbol is a graphic element drawn at POINT coordinates. It's similar to an icon, but it has a parametric color and size.

'''SYMBOL attributes:'''

;shape: (string, optional) The shape of the symbol. Today implementation allows only the shapes ''bullet'' and ''square''.
;color: (string, optional) The fill color of the symbol (HTML syntax).
;bcolor: (string, optional) Border color (HTML syntax).
;size: (integer, optional) The size in pixels of the symbol.
;stroke: (integer, optional) Line width in pixels.
;opacity: (number, optional) 1.0 is opaque, 0.0 is fully transparent.


=== ICON (kaXmlIcon, <icon>)===
An icon drawn at POINT coordinates. The image is defined with an URL. Width and height of the image must be provided, because the icon will be centred at POINT coordinates.

'''ICON attributes'''

;src: (string, required) The relative or absolute URL of the image
;w: (integer, required) Width of the image in pixels
;h: (integer, required) Height of the image in pixels
;px: (integer, optional) Horizontal offset in pixels (positive to move the icon on the right).
;py: (integer, optional) Vertical offset in pixels (negative to rise the icon).
;opacity: (number, optional) 1.0 is opaque, 0.0 is fully transparent.

=== LABEL (kaXmlLabel, <label>)===
A text label is written near the POINT. POINT coordinates represent the top-left corner of the LABEL.

'''LABEL attributes'''

;color: (string, optional) Text color (HTML syntax).
;boxcolor: (string, optional) Background color behind the text (HTML syntax).
;w: (integer, optional) Width of the label in pixels.
;h: (integer, optional) Height of the label in pixels.
;px: (integer, optional) Horizontal offset in pixels (positive to move the label on the right).
;py: (integer, optional) Vertical offset in pixels (negative to rise the label).
;font: (string, optional) The text font (HTML syntax).
;fsize: (string, optional) Font size (HTML syntax).
;text: (string, required) The label text: this attribute is present only in JavaScript: in the XML syntax the text is the content of the <label> element.


=== LINESTRING (kaXmlLinestring, <linestring>)===
This element represent a geographic feature, a single line in geographic coordinates that will be scaled with the map.
The coordinates of the line must be expressed a string in the form

 x0 y0, x1 y1, [...], xn yn

The coordinates string is the text node of the XML element. In JavaScript the coordinates string is passed
to the object with the method readCoordinates().

'''LINESTRING attributes'''

;color: (string, optional) Line color (HTML syntax).
;stroke: (integer, optional) Line width in pixels.
;opacity: (number, optional) 1.0 is opaque, 0.0 is fully transparent.


=== POLYGON (kaXmlPolygon, <polygon>)===
This element represent a geographic feature, a single polygon in geographic coordinates that will be scaled with the map.

'''POLYGON attributes'''

;color: (string, optional) Surface color (HTML syntax).
;bcolor: (string, optional) Border color (HTML syntax).
;stroke: (integer, optional) Border width in pixels.
;opacity: (number, optional) 1.0 is opaque, 0.0 is fully transparent.

---------------------------------------------------

= FAQs=

''Error: xmlDocument has no properties''

;: The XML is served with a wrong mime type by your web server. It should have a mime type "text/xml". Configure your server to associate ".xml" files with the correct mime, or, if you generate the XML dynamically, use a directive to set the mime type.


''In IE6 with excanvas.js canvas are not displayed''

;: The HTML page must begin with
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

---------------------------------------------------

= TODOs=
* Evaluate the use of custom onclick or ondblclick events on points
* Add a tooltip for overlay points
* Make the label management smarter

 
 * END section in Wiki syntax
 *****************************************************************************/

/**
 * kaXmlOverlay( oKaMap, xml_url )
 *
 * oKaMap 	A kaMap object
 * zIndex	The z index of the layer
 */
function kaXmlOverlay( oKaMap, zIndex )
{
    kaTool.apply( this, [oKaMap] );
    this.name = 'kaXmlOverlay';

    for (var p in kaTool.prototype)
    {
        if (!kaXmlOverlay.prototype[p]) 
            kaXmlOverlay.prototype[p]= kaTool.prototype[p];
    }
    
	this.urlBase = null;
    //this.urlBase = this.kaMap.server;
    //this.urlBase += (this.urlBase!=''&&this.urlBase.substring(-1)!='/')?'':'/';
	
	// The list of overlay points
	this.ovrObjects = new Array();   
	
	// The cavas of the overlay layer
	this.z_index = zIndex;
	this.overlayCanvas = this.kaMap.createDrawingCanvas( zIndex );
	
	// Register for events
    this.kaMap.registerForEvent( KAMAP_SCALE_CHANGED, this, this.scaleChanged );
	
}

kaXmlOverlay.prototype.scaleChanged = function( eventID, mapName ) {
	if (this.ovrObjects == null) return;
	for (var i=0; i < this.ovrObjects.length; i++) {
		if (this.ovrObjects[i]) this.ovrObjects[i].rescale();
	}
};

/**
 * Remove the overlay layer and free resources user by overlay objects.
 */
kaXmlOverlay.prototype.remove = function() {
    this.kaMap.deregisterForEvent( KAMAP_SCALE_CHANGED, this, this.scaleChanged );
	this.removePoint();
	this.kaMap.removeDrawingCanvas(this.overlayCanvas);
};


/**
 * Load XML from the server and update the overlay.
 *
 * xml_url	URL of th XML with points to plot
 */
kaXmlOverlay.prototype.loadXml = function(xml_url) {
	// The URL of the XML
	this.xmlOvrUrl = this.urlNormalize(xml_url);
	
	call(this.xmlOvrUrl,this,this.loadXmlCallback);
};

/**
 * initializeの後にurlBaseにURLをセットしておく
 */
kaXmlOverlay.prototype.setBaseUrl = function(){
    this.urlBase = this.kaMap.server;
    this.urlBase += (this.urlBase!=''&&this.urlBase.substring(-1)!='/')?'':'/';
}

//API化によるクロスドメイン対応（JSON化)
kaXmlOverlay.prototype.loadXml2 = function(xml_url) {
	// The URL of the XML
	this.setBaseUrl();
	this.xmlOvrUrl = this.urlNormalize(xml_url);
	var oJsr = new JSONscriptRequest(this.xmlOvrUrl+'&callback=jsonPointCallback');
    oJsr.buildScriptTag();
    oJsr.addScriptTag();
};


function jsonPointCallback(data){
	if(typeof(oJsr) != "undefined") oJsr.removeScriptTag();

	ICTMAP.myXmlOverlay.loadXmlDoc2(data);
}
	
/**
 * Defines the DOMParser object for IE
 */
if (typeof DOMParser == "undefined") {
	DOMParser = function () {};

   DOMParser.prototype.parseFromString = function (str, contentType) {
      if (typeof ActiveXObject != "undefined") {
         var d = new ActiveXObject("MSXML.DomDocument");
         d.loadXML(str);
         return d;
      } else if (typeof XMLHttpRequest != "undefined") {
         var req = new XMLHttpRequest;
         req.open("GET", "data:" + (contentType || "application/xml") +
                         ";charset=utf-8," + encodeURIComponent(str), false);
         if (req.overrideMimeType) {
            req.overrideMimeType(contentType);
         }
         req.send(null);
         return req.responseXML;
      }
	};
}

kaXmlOverlay.prototype.loadXmlCallback = function(xml_string) {
	var xmlDocument =  (new DOMParser()).parseFromString(xml_string, "text/xml");
	this.loadXmlDoc(xmlDocument);
};

kaXmlOverlay.prototype.loadXmlDoc = function(xmlDocument) {
//alert("loadXmlDoc");
	var objDomTree = xmlDocument.documentElement;
	
	var dels = objDomTree.getElementsByTagName("delete");
	for (var i=0; i<dels.length; i++) {
		// read the id attribute
		var a_id = dels[i].getAttributeNode("id");
		if (a_id == null) {
			// delete all points
			this.removePoint();
		} else {
			this.removePoint(a_id.value);
		}
	}
	
	var need_update = false;
		
	var points = objDomTree.getElementsByTagName("point");
	for (var i=0; i<points.length; i++) {
		// read the mandatory attributes
		var a_pid = points[i].getAttributeNode("id");
		if (a_pid == null) {
			continue;
		}
		var pid = a_pid.value;
		var np = this.getPointObject(pid);
		if (np == null) {
			
			var sid = points[i].getAttributeNode("sid");	// sakai
			var sid_value = "";
			if(sid != null){
				sid_value = sid.value;
			}
			// Create a new point
			np = new kaXmlPoint(pid,this,sid_value);
			this.ovrObjects.push(np);
		}

		np.parse(points[i]);
		need_update = true;
	}
	
	
	/*if(getRawObject("loadingmsg")){		// sakai ローディングメッセージを消す
		getRawObject("loadingmsg").style.display = 'none';
	}*/
	
	if (need_update) this.kaMap.updateObjects();
};

// JSON対応
kaXmlOverlay.prototype.loadXmlDoc2 = function(jsondata) {
	var need_update = false;
	var data = jsondata.data;
	for (var i=0; i<data.length; i++) {
		// read the mandatory attributes
		var a_pid = data[i].id;
		if (a_pid == null) {
			continue;
		}
		//var pid = a_pid.value;
		var pid = a_pid;
		var np = this.getPointObject(pid);
		if (np == null) {
			var sid = data[i].sid;	// sakai
			var sid_value = "";
			if(sid != null){
				sid_value = sid;
			}
			// Create a new point
			np = new kaXmlPoint(pid,this,sid_value);
			this.ovrObjects.push(np);
		}

		np.parse2(data[i]);
		need_update = true;
	}
	
	
	/*if(getRawObject("loadingmsg")){		// sakai ローディングメッセージを消す
		getRawObject("loadingmsg").style.display = 'none';
	}*/
	
	if (need_update) this.kaMap.updateObjects();
};

/**
 * 
 */
kaXmlOverlay.prototype.urlNormalize = function(url) {
	if (url == null) return "";
	//if (url.match(/^\//) != '/') {
	if (url.match(/^[\/]/) != '/') {		
		return this.urlBase+url;
	}
	return url;
};
 
/**
 * pid		Point ID
 * return The DIV object of the given point ID. null if not found.
 */
kaXmlOverlay.prototype.getDiv = function(pid) {
	var div_id = this.getDivId(pid);
	return getRawObject(div_id);
};

/**
 * pid		Point ID
 * return The kaXmlPoint object given the point ID. null if not found.
 */
kaXmlOverlay.prototype.getPointObject = function(pid) {
	for (var i=0; i < this.ovrObjects.length; i++) {
		if (this.ovrObjects[i] != null && this.ovrObjects[i].pid == pid) {
			return this.ovrObjects[i];
	 	};
	};
	return null;
};

/**
 * Instantiate a new kaXmlPoint adn add it to the overlay. If the PID
 * already exists it's deleted and recreated.
 *
 * pid		Point ID
 * x			X Coordinate
 * y			Y Coordinate
 * opts		EventFunc
 * return A kaXmlPoint object with the given point ID.
 */
kaXmlOverlay.prototype.addNewPoint = function(pid,x,y,opts,pointName) {
	this.removePoint(pid);
	//var np = new kaXmlPoint(pid,this,"",opts,pointName);
	var np = new kaXmlPoint(pid,this,pid,opts,pointName);
	np.placeOnMap(x,y);
	this.ovrObjects.push(np);
	return np;
};

/**
 * pid		Point ID
 * return the DIV id given the point ID
 */
kaXmlOverlay.prototype.getDivId = function(pid) {
	return 'xmlovr_'+pid+'_div';
};

/**
 * Remove one or more point div from the map.
 * If pid is null or not present remove all points.
 *
 * pid		Point ID or a regexp 
 */
kaXmlOverlay.prototype.removePoint = function( pid ,idtype) {
	if ( (this.removePoint.arguments.length < 1) || (pid == null) ) {
		for (var i=this.ovrObjects.length; i-- > 0; ) {
			if (this.ovrObjects[i] != null) {
				this.ovrObjects[i].removeFromMap();
				delete this.ovrObjects[i];
				this.ovrObjects[i] = null;
			}
			this.ovrObjects.splice(i,1); 
		}
		//this.ovrObjects = new Array();	// sakai
	} else if(this.removePoint.arguments.length == 2){	// sakai
		var re = new RegExp("^"+idtype);
		for (var i=this.ovrObjects.length; i-- > 0; ) {
			if (this.ovrObjects[i] != null) {
				if (re.test(this.ovrObjects[i].pid)) {
					this.ovrObjects[i].removeFromMap();
					delete this.ovrObjects[i];
					this.ovrObjects[i] = null;
					this.ovrObjects.splice(i,1);
				}
			} else {
				this.ovrObjects.splice(i,1);
			}
		}
	} else {
		//var re = new RegExp(pid);
		for (var i=this.ovrObjects.length; i-- > 0; ) {
			if (this.ovrObjects[i] != null) {
				//if (re.test(this.ovrObjects[i].pid)) {
				if (re == pid){
					this.ovrObjects[i].removeFromMap();
					delete this.ovrObjects[i];
					this.ovrObjects[i] = null;
					this.ovrObjects.splice(i,1);
				}
			} else {
				this.ovrObjects.splice(i,1);
			}
		}
	}
};
 

/**
 * Base class for all graphics elements.
 */
function kaXmlGraphicElement() {}

/**
 * Initialize the graphics element from an XML element
 *
 * point			The parent kaXmlPoint object
 * domElement	The XML DOM element that describe the graphic
 */
kaXmlGraphicElement.prototype.parseElement = function(point, domElement) {};

/**
 * Draw the graphics element
 *
 * point		The parent kaXmlPoint object
 */
kaXmlGraphicElement.prototype.draw = function(point) {};

/**
 * Draw the graphics element
 *
 * point		The parent kaXmlPoint object
 */
kaXmlGraphicElement.prototype.rescale = function(point) {};

/**
 * Dispose the resources allocated in the graphics element
 *
 * point		The parent kaXmlPoint object
 */
kaXmlGraphicElement.prototype.remove = function(point) {};


/**
 * Construct a symbol 
 */
function kaXmlSymbol() {
	kaXmlGraphicElement.apply(this);
	if (_BrowserIdent_hasCanvasSupport())
		kaXmlSymbol.prototype['draw'] = kaXmlSymbol.prototype['draw_canvas'];
	else
		kaXmlSymbol.prototype['draw'] = kaXmlSymbol.prototype['draw_js'];
		
    for (var p in kaXmlGraphicElement.prototype) {
        if (!kaXmlSymbol.prototype[p]) 
            kaXmlSymbol.prototype[p]= kaXmlGraphicElement.prototype[p];
    }
	
	this.shape = "bullet";
	this.size = 10;
    this.stroke = 1;
	this.color = null;
	this.bcolor = null;
	this.opacity = 1;
	
	this.canvas = null;
	this.ldiv = null;
}

kaXmlSymbol.prototype.remove = function(point) {
	this.canvas = null;
	this.ldiv = null;	
};

kaXmlSymbol.prototype.parseElement = function(point, domElement) {
	this.shape = domElement.getAttribute("shape");
	this.size = parseInt(domElement.getAttribute("size"));
	var c = domElement.getAttribute("color");
	if (c != null) this.color = c;
	var c = domElement.getAttribute("bcolor");
	if (c != null) this.bcolor = c;
	c = parseFloat(domElement.getAttribute("opacity"));
	if(! isNaN(c)) this.opacity = c; 
	c = parseInt(domElement.getAttribute("stroke"));
	if (! isNaN(c)) this.stroke = c;
};

kaXmlSymbol.prototype.draw_js = function(point) {
	var jsgObject = new jsGraphics(point.divId); 
	var d = this.size / 2;     

	jsgObject.setStroke(this.stroke);

	if (this.shape == 'square') {
	
		if (this.color) {
			jsgObject.setColor(this.color);
			jsgObject.fillRect(-d, -d, this.size, this.size);
		}	
		if (this.bcolor) {
			jsgObject.setColor(this.bcolor);
			jsgObject.fillRect(-d, -d, this.size, this.size);
		}	
		
	} else {
		
		if (this.color) {
			jsgObject.setColor(this.color);
			jsgObject.fillEllipse(-d, -d, this.size, this.size);
		}	
		if (this.bcolor) {
			jsgObject.setColor(this.bcolor);
			jsgObject.drawEllipse(-d, -d, this.size, this.size);
		}	
	}
	
	jsgObject.paint();
};

kaXmlSymbol.prototype.draw_canvas = function(point) {
	var d = Math.floor((this.size + this.stroke) / 2);     
	
	if (this.canvas == null) {
		this.ldiv = document.createElement( 'div' );
		this.ldiv.style.position = 'absolute';
	    this.ldiv.style.left = -d+'px';
	    this.ldiv.style.top = -d+'px';
		point.div.appendChild(this.ldiv);
		this.canvas = _BrowserIdent_newCanvas(this.ldiv);
		_BrowserIdent_setCanvasHW(this.canvas,d*2,d*2);
	} 
	
	var ctx = _BrowserIdent_getCanvasContext(this.canvas);
	ctx.save();
	//alert("Point("+point.pid+") Size("+this.size+") D("+d+")");
	
	ctx.translate(d,d);
	ctx.globalAlpha = this.opacity;
	ctx.lineWidth = this.stroke;
	if (this.bcolor) ctx.strokeStyle = this.bcolor;	
	if (this.color) ctx.fillStyle = this.color;
	
	if (this.shape == 'square') {
		if (this.color) ctx.fillRect(-this.size/2.0,-this.size/2.0,this.size,this.size);
		if (this.bcolor) ctx.strokeRect(-this.size/2.0,-this.size/2.0,this.size,this.size);
	} else {
		ctx.beginPath();
		ctx.arc(0,0,this.size/2.0,0,Math.PI*2,false);
		if (this.color) ctx.fill();	
		if (this.bcolor) ctx.stroke();	
	}
	ctx.restore();
};

/**
 * Construct a geographic feature
 */
function kaXmlFeature( point ) {
	kaXmlGraphicElement.apply(this);
    for (var p in kaXmlGraphicElement.prototype) {
        if (!kaXmlFeature.prototype[p]) 
            kaXmlFeature.prototype[p]= kaXmlGraphicElement.prototype[p];
    }
    
    this.stroke = 1;
    this.color = null;
    this.bcolor = null;
    this.opacity = 1;

	this.cxmin = 0;
	this.cymax = 0;
	this.cymin = 0;
	this.cxmax = 0;
	this.coords = "";
	this.img = null;
	this.canvas = null;
	this.ldiv = null;	
	this.xn = null;
	this.yn = null;
	
	// Calculate the min cellSize
	var map = point.xml_overlay.kaMap.getCurrentMap();
	var scales = map.getScales();
	this.maxScale = scales[scales.length - 1];
	this.mcs = point.xml_overlay.kaMap.cellSize / (point.xml_overlay.kaMap.getCurrentScale() / this.maxScale);
}

kaXmlFeature.prototype.remove = function(point) {
	this.img = null;
	this.canvas = null;
	this.ldiv = null;
	this.coords = null;	
	this.xn.splice(0);
	this.yn.splice(0);
};

	
kaXmlFeature.prototype.parseElement = function(point, domElement) {
	var t;
	t = parseInt(domElement.getAttribute("stroke"));
	if (! isNaN(t)) this.stroke = t;
	t = domElement.getAttribute("color");
	if (t != null) this.color = t;
	t = domElement.getAttribute("bcolor");
	if (t != null) this.bcolor = t;
	t = parseFloat(domElement.getAttribute("opacity"));
	if(! isNaN(t)) this.opacity = t; 
	
	var text = "";
	if (domElement.firstChild != null) {
		text = domElement.firstChild.data;
		this.readCoordinates(point, text);	
	}
};
/**
 * Read the feature coordinates from a string 
 *
 *   x0 y0, x1 y1, [...], xn yn
 */
kaXmlFeature.prototype.readCoordinates = function(point, text) {
	var cx = new Array();
	var cy = new Array();
	var pp = text.split(',');
	var i;
	for (i=0; i<pp.length; i++) {
		var s = pp[i];
		var xy = s.match(/[-\+\d\.]+/g);
		if (xy != null) {
			var x=parseFloat(xy[0]);
			var y=parseFloat(xy[1]);
			cx.push(x);
			cy.push(y);
		}
	}
	
	this.setCoordinates(point,cx,cy);
};

/**
 * Set the coordinates of the feature.
 * 
 * xArray	Ordered array of x coordinates (float)
 * yArray	Ordered array of y coordinates (float)
 */
kaXmlFeature.prototype.setCoordinates = function(point, xArray, yArray) {
	this.cxmin = 0;
	this.cymax = 0;
	this.cymin = 0;
	this.cxmax = 0;
	this.coords = "";
	var i;
	for (i=0; i<xArray.length; i++) {
		var x=xArray[i];
		var y=yArray[i];
		if (i==0 || x<this.cxmin) this.cxmin = x;
		if (i==0 || y>this.cymax) this.cymax = y;
		if (i==0 || y<this.cymin) this.cymin = y;
		if (i==0 || x>this.cxmax) this.cxmax = x;
	}
	
	this.xn = new Array();
	this.yn = new Array();
	
	// Normalize the coordinates
	for (i=0; i<xArray.length; i++) {
		var x = (xArray[i] - this.cxmin) / this.mcs;
		var y = (this.cymax - yArray[i]) / this.mcs;
		if (i>0) this.coords += ",";
			this.coords += Math.round(x)+","+Math.round(y);
		this.xn.push(x);
		this.yn.push(y);
	}
};

kaXmlFeature.prototype.rescale = function(point) {
	this.draw(point);
};


/**
 * Construct a linestring 
 */
function kaXmlLinestring( point ) {
	kaXmlFeature.apply(this, [point]);
	
	if (_BrowserIdent_hasCanvasSupport())
		kaXmlLinestring.prototype['draw'] = kaXmlLinestring.prototype['draw_canvas'];
	else
		kaXmlLinestring.prototype['draw'] = kaXmlLinestring.prototype['draw_server'];	
	
    for (var p in kaXmlFeature.prototype) {
        if (!kaXmlLinestring.prototype[p]) 
            kaXmlLinestring.prototype[p]= kaXmlFeature.prototype[p];
    }
}

kaXmlLinestring.prototype.draw_server = function(point) {
	var xy = point.xml_overlay.kaMap.geoToPix( this.cxmin, this.cymax );
	var x0 = xy[0];
	var y0 = xy[1];
	
	xy = point.xml_overlay.kaMap.geoToPix( point.div.lon, point.div.lat );
	var xr = xy[0];
	var yr = xy[1];
	
	var border = 5;
	
	if (this.img == null) {
    		this.img = document.createElement( 'img' );
	    point.div.appendChild( this.img );
	    this.img.style.position = 'absolute';
	}
	
    this.img.style.top = (y0 - yr - border)+'px';
    this.img.style.left = (x0 - xr - border)+'px';
    var scf = point.xml_overlay.kaMap.getCurrentScale() / this.maxScale;
    var it = _BrowserIdent_getPreferredImageType();
    var u = point.xml_overlay.kaMap.server+"/XMLOverlay/drawgeom.phtml?gt=L&st="+this.stroke+"&bp="+border+"&sc="+scf+"&cl="+this.coords;
    if (this.color != null) u += "&lc="+escape(this.color);
    if (it == "P") {
    		u += "&it=P";
    } else {
    		u += "&it=G";
    }
    if (_BrowserIdent_getPreferredOpacity() == "server") {
    		if (this.opacity < 1) u += "&op="+(this.opacity*100);
    } else {
    		if (this.opacity < 1) _BrowserIdent_setOpacity(this.img, this.opacity);
    }
    this.img.src = u;
};

kaXmlLinestring.prototype.draw_canvas = function(point) {
	var xy = point.xml_overlay.kaMap.geoToPix( this.cxmin, this.cymax );
	var x0 = xy[0];
	var y0 = xy[1];
	
	xy = point.xml_overlay.kaMap.geoToPix( this.cxmax, this.cymin );
	var x1 = xy[0];
	var y1 = xy[1];
	
	xy = point.xml_overlay.kaMap.geoToPix( point.div.lon, point.div.lat );
	var xr = xy[0];
	var yr = xy[1];
	
	var border = 5;
    var scf = point.xml_overlay.kaMap.getCurrentScale() / this.maxScale;
	
	var sizex = (x1 - x0) + (border*2);
	var sizey = (y1 - y0) + (border*2);
	
	if (this.canvas == null) {
		this.ldiv = document.createElement( 'div' );
		this.ldiv.style.position = 'absolute';
		point.div.appendChild(this.ldiv);
		this.canvas = _BrowserIdent_newCanvas(this.ldiv);
	} 
	
    this.ldiv.style.left = (x0 - xr - border)+'px';
	this.ldiv.style.top = (y0 - yr - border)+'px';
	_BrowserIdent_setCanvasHW(this.canvas,sizey,sizex);
	
	var ctx = _BrowserIdent_getCanvasContext(this.canvas);
	ctx.save();
	ctx.clearRect(0, 0, sizex, sizey);
	ctx.translate(border,border);
	ctx.strokeStyle = this.color;
	ctx.globalAlpha = this.opacity;
	ctx.lineWidth = this.stroke;
	ctx.beginPath();
	ctx.moveTo(this.xn[0]/scf, this.yn[0]/scf);
	
	var i;
	for (i=1; i<this.xn.length; i++) {
		ctx.lineTo(this.xn[i]/scf, this.yn[i]/scf);
	}
	ctx.stroke();
	ctx.restore();
};

/**
 * Construct a Polygon from the XML element
 */
function kaXmlPolygon( point ) {
	kaXmlFeature.apply(this, [point]);
	
	if (_BrowserIdent_hasCanvasSupport())
		kaXmlPolygon.prototype['draw'] = kaXmlPolygon.prototype['draw_canvas'];
	else
		kaXmlPolygon.prototype['draw'] = kaXmlPolygon.prototype['draw_server'];
	
    for (var p in kaXmlFeature.prototype) {
        if (!kaXmlPolygon.prototype[p]) 
            kaXmlPolygon.prototype[p]= kaXmlFeature.prototype[p];
    }
}

kaXmlPolygon.prototype.draw_server = function(point) {
	var xy = point.xml_overlay.kaMap.geoToPix( this.cxmin, this.cymax );
	var x0 = xy[0];
	var y0 = xy[1];
	
	xy = point.xml_overlay.kaMap.geoToPix( point.div.lon, point.div.lat );
	var xr = xy[0];
	var yr = xy[1];
	
	var border = 5;
	
	if (this.img == null) {
    		this.img = document.createElement( 'img' );
	    this.img.style.position = 'absolute';
	    point.div.appendChild( this.img );
	}
	
    var scf = point.xml_overlay.kaMap.getCurrentScale() / this.maxScale;
    var it = _BrowserIdent_getPreferredImageType();
    var u = point.xml_overlay.kaMap.server+"/XMLOverlay/drawgeom.phtml?gt=P&st="+this.stroke+"&bp="+border+"&sc="+scf+"&cl="+this.coords;
    if (this.color != null) u += "&fc="+escape(this.color);
    if (this.bcolor != null && this.bcolor != "") u += "&lc="+escape(this.bcolor);
    if (it == "P") {
    		u += "&it=P";
    } else {
    		u += "&it=G";
    }
    if (_BrowserIdent_getPreferredOpacity() == "server") {
    		if (this.opacity < 1) u += "&op="+(this.opacity*100);
    } else {
    		if (this.opacity < 1) _BrowserIdent_setOpacity(this.img, this.opacity);
    }
    
    this.img.style.top = (y0 - yr - border)+'px';
    this.img.style.left = (x0 - xr - border)+'px';
    
    this.img.src = u;
};

kaXmlPolygon.prototype.draw_canvas = function(point) {
	var xy = point.xml_overlay.kaMap.geoToPix( this.cxmin, this.cymax );
	var x0 = xy[0];
	var y0 = xy[1];
	
	xy = point.xml_overlay.kaMap.geoToPix( this.cxmax, this.cymin );
	var x1 = xy[0];
	var y1 = xy[1];
	
	xy = point.xml_overlay.kaMap.geoToPix( point.div.lon, point.div.lat );
	var xr = xy[0];
	var yr = xy[1];
	
	var border = 5;
    var scf = point.xml_overlay.kaMap.getCurrentScale() / this.maxScale;
	
	var sizex = (x1 - x0) + (border*2);
	var sizey = (y1 - y0) + (border*2);
	
	if (this.canvas == null) {
		this.ldiv = document.createElement( 'div' );
		this.ldiv.style.position = 'absolute';
		point.div.appendChild(this.ldiv);
		this.canvas = _BrowserIdent_newCanvas(this.ldiv);
	} 
	
    this.ldiv.style.left = (x0 - xr - border)+'px';
	this.ldiv.style.top = (y0 - yr - border)+'px';
	_BrowserIdent_setCanvasHW(this.canvas,sizey,sizex);
	
	var ctx = _BrowserIdent_getCanvasContext(this.canvas);
	ctx.save();
	ctx.clearRect(0, 0, sizex, sizey);
	ctx.translate(border,border);
    if (this.color != null) ctx.fillStyle = this.color;
    if (this.bcolor != null && this.bcolor != "") ctx.strokeStyle = this.bcolor;
	ctx.globalAlpha = this.opacity;
	ctx.lineWidth = this.stroke;
	ctx.beginPath();
	ctx.moveTo(this.xn[0]/scf, this.yn[0]/scf);
	
	var i;
	for (i=1; i<this.xn.length; i++) {
		ctx.lineTo(this.xn[i]/scf, this.yn[i]/scf);
	}
	
	if (this.color != null) ctx.fill();
	if (this.bcolor != null && this.bcolor != "") ctx.stroke();
	ctx.restore();
};

/**
 * Construct a label from the XML element
 */
function kaXmlLabel() {
	kaXmlGraphicElement.apply(this);
    for (var p in kaXmlGraphicElement.prototype) {
        if (!kaXmlLabel.prototype[p]) 
            kaXmlLabel.prototype[p]= kaXmlGraphicElement.prototype[p];
    }
	
	this.text = "";
	this.color = "#AB1805";
	this.boxcolor = "#FFFFFF";
	//this.w = 64;
	this.w = 0;
	//this.h = 24;
	this.h = 0;
	this.xoff = 0;
	this.yoff = 0;
	this.fsize = "12px";
	this.font = "Arial";
	this.ldiv = null;
	this.ltxt = null;
}

kaXmlLabel.prototype.remove = function(point) {
	this.canvas = null;
	this.ldiv = null;	
	this.ltxt = null;
};

kaXmlLabel.prototype.parseElement = function(point, domElement) {
	if (domElement.firstChild != null) {
		this.text = domElement.firstChild.data;
	}

	var t;		
	t = domElement.getAttribute("color");
	if (t != null) {
		this.color = t;
	}
	//this.boxcolor = domElement.getAttribute("boxcolor");
	t = parseInt(domElement.getAttribute("w"));
	if (!isNaN(t)) {
		this.w = t;
	}
	t = parseInt(domElement.getAttribute("h"));
	if (!isNaN(t)) {
		this.h = t;
	}
	t = parseInt(domElement.getAttribute("px"));
	if (!isNaN(t)) {
		this.xoff = t;
	}
	t = parseInt(domElement.getAttribute("py"));
	if (!isNaN(t)) {
		this.yoff = t;
	}
	t = domElement.getAttribute("fsize");
	if (t != null) {
		this.fsize = t;
	}
	t = domElement.getAttribute("font");
	if (t != null) {
		this.font = t;
	}
};

kaXmlLabel.prototype.parseElement2 = function(point, data) {
	if (data != null) {
		this.text = data.label;
	}

	var t;		
	t = data.color;
	if (t != null) {
		this.color = t;
	}
	//this.boxcolor = domElement.getAttribute("boxcolor");
	t = parseInt(data.w);
	if (!isNaN(t)) {
		this.w = t;
	}
	t = parseInt(data.h);
	if (!isNaN(t)) {
		this.h = t;
	}
	t = parseInt(data.px);
	if (!isNaN(t)) {
		this.xoff = t;
	}
	t = parseInt(data.py);
	if (!isNaN(t)) {
		this.yoff = t;
	}
	t = data.fsize;
	if (t != null) {
		this.fsize = t;
	}
	t = data.font;
	if (t != null) {
		this.font = t;
	}
};

kaXmlLabel.prototype.draw = function(point) {
	var x = this.xoff;
	var y = this.yoff;
	
	this.ldiv = document.createElement( 'div' );
	//this.ldiv.setAttribute('class','pointlabel');
    this.ldiv.style.left = x+'px';
    this.ldiv.style.top = y+'px';

	this.ldiv.style.fontFamily = this.font;
	this.ldiv.style.fontSize = this.fsize;
	this.ldiv.style.textAlign = 'left';
	this.ldiv.style.color = this.color;
	this.ldiv.style.position = 'absolute';
	
	if(point.pointtype == "KIHON"){
		this.ldiv.style.display = "none";
		this.ldiv.id = "label_"+point.divId;
	}
	
	if (this.boxcolor != null) this.ldiv.style.backgroundColor = this.boxcolor;
	if (this.w>0) this.ldiv.style.width = this.w+'px';
	else this.ldiv.style.whiteSpace = 'nowrap';
	if (this.h>0) this.ldiv.style.height = this.h+'px';

	
	this.ltxt = document.createTextNode(this.text);
	this.ldiv.appendChild( this.ltxt );
	point.div.appendChild( this.ldiv );
};

/**
 * Construct an icon
 */
function kaXmlIcon() {
	kaXmlGraphicElement.apply(this);
	if (_BrowserIdent_hasCanvasSupport())
		//kaXmlIcon.prototype['draw'] = kaXmlIcon.prototype['draw_canvas'];		// アイコンの描画をdraw_plainに統一 sakai
		kaXmlIcon.prototype['draw'] = kaXmlIcon.prototype['draw_plain'];
	else
		kaXmlIcon.prototype['draw'] = kaXmlIcon.prototype['draw_plain'];
    for (var p in kaXmlGraphicElement.prototype) {
        if (!kaXmlIcon.prototype[p]) 
            kaXmlIcon.prototype[p]= kaXmlGraphicElement.prototype[p];
    }
    
	this.icon_src = null;
	this.icon_w = 0;
	this.icon_h = 0;
	this.xoff = 0;
	this.yoff = 0;
	this.rot = 0;
	this.ldiv = null;	
	this.img = null;	
	this.canvas = null;
}

kaXmlIcon.prototype.remove = function(point) {
	this.ldiv = null;	
	this.canvas = null;
	if (this.img) this.img.onload = null;
	this.img = null;	
};

kaXmlIcon.prototype.parseElement = function(point, domElement) {
	this.icon_src = point.xml_overlay.urlNormalize(domElement.getAttribute("src"));
	this.icon_w = parseInt(domElement.getAttribute("w"));
	this.icon_h = parseInt(domElement.getAttribute("h"));
	var t;
	t = parseInt(domElement.getAttribute("px"));
	if (!isNaN(t)) {
		this.xoff = t;
	}
	t = parseInt(domElement.getAttribute("py"));
	if (!isNaN(t)) {
		this.yoff = t;
	}
	t = parseInt(domElement.getAttribute("rot"));
	if (!isNaN(t)) {
		this.rot = t;
	}
};

kaXmlIcon.prototype.parseElement2 = function(point, data) {
	this.icon_src = point.xml_overlay.urlNormalize(data.src);
	this.icon_w = parseInt(data.w);
	this.icon_h = parseInt(data.h);
	var t;
	t = parseInt(data.px);
	if (!isNaN(t)) {
		this.xoff = t;
	}
	t = parseInt(data.py);
	if (!isNaN(t)) {
		this.yoff = t;
	}
	t = parseInt(data.rot);
	if (!isNaN(t)) {
		this.rot = t;
	}
};

kaXmlIcon.prototype.draw_canvas = function(point) {
	var dx = -this.icon_w / 2 + this.xoff;     
	var dy = -this.icon_h / 2 + this.yoff;     
	
	if (this.canvas == null) {
		this.ldiv = document.createElement( 'div' );
		this.ldiv.style.position = 'absolute';
		this.ldiv.style.top = dy+'px';
		this.ldiv.style.left = dx+'px';
		this.ldiv.style.zIndex = 400;
		point.div.appendChild(this.ldiv);
		this.canvas = _BrowserIdent_newCanvas(this.ldiv);
		_BrowserIdent_setCanvasHW(this.canvas,this.icon_h*2,this.icon_w*2);
	}

	var ctx = _BrowserIdent_getCanvasContext(this.canvas);
	ctx.save();
    ctx.translate(-dx,-dy);
    ctx.rotate(this.rot * Math.PI/180);
    this.img = new Image();
    this.img.src = this.icon_src;
    var timg = this.img;
    var tw = this.icon_w;
    var th = this.icon_h;
	//this.img.onload = function() {	// IEだと1度読み込むと2度目のonloadが起きないコメントアウト sakai
	//alert("icon img onload");
		ctx.drawImage(timg, dx, dy, tw, th);
		ctx.restore();
	//}
};

kaXmlIcon.prototype.draw_plain = function(point) {
	var dx = -this.icon_w / 2 + this.xoff;
	var dy = -this.icon_h / 2 + this.yoff;
	
    this.ldiv = document.createElement( 'div' );
    this.ldiv.style.position = 'absolute';
    this.ldiv.style.top = dy+'px';
    this.ldiv.style.left = dx+'px';

    this.img = document.createElement( 'img' );
    this.img.src = this.icon_src;
    //img.class = 'png24';
    this.img.width = this.icon_w;
    this.img.height = this.icon_h;
	
	// sakai
	if(point.pointtype == "KIHON"){				// 標準ポイント
		this.ldiv.onmouseover = function(){
			var tmp = getRawObject("kihonlabel");
			var x = point.div.offsetLeft;
			var y = point.div.offsetTop;
			tmp.style.top = y + "px";
			tmp.style.left = (x+12) + "px";
			tmp.style.display = 'inline';
			tmp.innerHTML = getRawObject("label_"+point.divId).innerHTML;
			point.div.canvas.appendChild(tmp);
		};
		this.ldiv.onmouseout = function(){
			var tmp = getRawObject("kihonlabel");
			tmp.style.display = 'none';
			//getRawObject("label_"+point.divId).style.display = "none";
		};
		this.img.style.cursor = 'pointer';
		this.ldiv.style.zIndex=251;
		this.img.style.zIndex=252;
		this.img.style.position="absolute";
	}else if(point.onclickflg){					// ユーザポイント
		this.ldiv.onmouseover = function(res,flg){
			if(flg != 1){
				getRawObject('namelist').style.display = 'none';
			}
			//point.div.style.zoom = 1.8;
			var num = point.pid.substr(1);
			if(flg != 1){
				searchSamePoint(point.div);
			}
		};
		ICTMAP.iconMouseOver[point.sid] = this.ldiv.onmouseover;
		
		this.ldiv.onmouseout = function(){
			point.div.style.zoom = 1;
			var num = point.pid.substr(1);
			//getRawObject("datalist"+num).style.borderBottom = "dotted 1px #072F49";
		};
		ICTMAP.iconMouseOut[point.sid] = this.ldiv.onmouseout;
		
		this.ldiv.onclick = function(){
			//clearOverlaysymbolhtml();
			//clickIconEvent(point);
			if(typeof(point.opts.onclick) == "function"){
				point.opts.onclick(point.pid);
			}else if(point.opts.infoWindowHtml != null && point.opts.infoWindowHtml != ""){
				clickIconEvent(point,point.opts.infoWindowHtml);
			}else if(point.opts.infoWindowUrl != null && point.opts.infoWindowUrl != ""){
				clickIconEvent(point,"",point.opts.infoWindowUrl);
			}else if(point.opts.infoIframeWindowSrc != null && point.opts.infoIframeWindowSrc != ""){
				clickIconEvent(point,"","",point.opts.infoIframeWindowSrc,point.opts.infoIframeWidth,point.opts.infoIframeHeight);
			}
		};
		ICTMAP.iconClick[point.sid] = this.ldiv.onclick;
		ICTMAP.IctMap.arrOnclick[ICTMAP.IctMap.arrOnclickIndex] = this.ldiv.onclick;
		ICTMAP.IctMap.arrOnclickIndex++;
		
		this.img.style.cursor = 'pointer';
		this.ldiv.style.zIndex=501;
		this.img.style.zIndex=502;
		this.img.style.position="absolute";
	}
    this.ldiv.appendChild( this.img );
    point.div.appendChild( this.ldiv );
};

/**
 * アイコンにマウスが乗ったときに同じポイントに登録アイコンがないか調べる
 */
function searchSamePoint(aobj){
	var x = aobj.style.left;
	var y = aobj.style.top;
	var tmpid = aobj.id;
	var len = ICTMAP.aObjects.length;
	var dst = [];
	for (var i=0; i<len; i++) {
		obj = ICTMAP.aObjects[i];
		objid = obj.id;
		if(objid.match(/^xmlovr_user_.*_div$/) != null){
			if(objid != tmpid){
				if (obj.style.left == x) {
					if(obj.style.top == y){
						dst.push(obj)
					}
				}
			}
		}
	};
	dispNameList(aobj,dst);
};

/**
 * 同一ポイントの名称を表示する
 */
function dispNameList(aobj,arrObj){
	var dst = "";
	var len = arrObj.length;
	var canvas = getRawObject("namelist");
	canvas.innerHTML = "";
	var a = createLink(aobj);
	if(a != null){
		canvas.appendChild(a);
	}
	if(len > 0){
		//var dst = aobj.sid;
		for(i=0;i<len;i++){
			tmpobj = arrObj[i];
			//dst += ","+tmpobj.sid;
			var a = createLink(tmpobj);
			if(a != null){
				canvas.appendChild(a);
			}
		};
		/*var url = ICTMAP.server + "disp_samepointname.phtml";
		var pars = "geomid=" + dst;
		url += "?" + pars;
		call(url,null,function(res){
			var tgtObj = getRawObject("namelist");
			tgtObj.innerHTML = res;
			tgtObj.style.display='block';
		});*/
	}
	canvas.style.top=aobj.offsetTop + "px";
	canvas.style.left=aobj.offsetLeft + "px";
	aobj.canvas.appendChild(canvas);
	canvas.style.display='block';

	canvas.onmouseover = function(){
		myKaRubberZoom.dataOver = true;
	}
	canvas.onmouseout = function(){
		myKaRubberZoom.dataOver = false;
	}
	/*canvas.onmouseover = null;
	if(!myKaRubberZoom.RubberZooming){
		canvas.onmouseover = function(){
			switchMode('toolPan');
		}
	}*/
};

function createLink(point){
	var obj = document.createElement("a");
	obj.setAttribute("href","javascript:void('0')");
	obj.onclick = (ICTMAP.iconClick[point.sid]) ? ICTMAP.iconClick[point.sid] : null;
	if(point.pointName != null && point.pointName.length > 0){
		var objText = document.createTextNode(point.pointName);
		obj.appendChild(objText);
		return obj;
	}else{
		return null;
	}
}

/**
 * アイコンクリック時に呼び出されるイベント sakai
 */
function clickIconEvent(point,html,url,iframeSrc,iframeWidth,iframeHeight){
	getRawObject('namelist').style.display='none';
	var tmp = getRawObject("pointinfo");
	var x = point.div.offsetTop;
	var y = point.div.offsetLeft;
	tmp.style.top = x + "px";
	tmp.style.left = (y - 50) + "px";
	tmp.style.visibility = 'visible';
	tmp.style.display = 'block';
	
	tmp.onmouseover = function(){
		myKaRubberZoom.dataOver = true;
	}
	tmp.onmouseout = function(){
		myKaRubberZoom.dataOver = false;
	}
	
	var batsuUrl = point.xml_overlay.urlBase + "common/images/batsu.gif";

	point.div.canvas.appendChild(tmp);
	$("infobox").style.width = "298px";
	if(html != null && html != ""){
		var tgtObj = getRawObject("infoboxmemo");
			tgtObj.innerHTML = "<div class=\"overlaysymbolhtmlclose\"><a href=\"javascript:clearOverlaysymbolhtml();\" style=\"cursor:pointer;\"><img src=\""+batsuUrl+"\" alt=\"閉じる\"></a></div>";
			tgtObj.innerHTML += html;
			slidePoint(point);
	}else if(url != null && url != ""){
		var tgtObj = getRawObject("infoboxmemo");
			tgtObj.innerHTML = "loading .....";
			
			/*var pars = "";
			var objajax = new Ajax.Request(url,{
					method: "get",
					parameters: pars,
					onComplete:function(ores){
							$("infoboxmemo").innerHTML = "<div class=\"overlaysymbolhtmlclose\"><a href=\"javascript:clearOverlaysymbolhtml();\" style=\"cursor:pointer;\">閉じる</a></div>";
							$("infoboxmemo").innerHTML += ores.responseText;
							slidePoint(point);
						}
				});
		   */
		call(url,null,function(res){
			var tgtObj = getRawObject("infoboxmemo");
			tgtObj.innerHTML = "<div class=\"overlaysymbolhtmlclose\"><a href=\"javascript:clearOverlaysymbolhtml();\" style=\"cursor:pointer;\"><img src=\""+batsuUrl+"\" alt=\"閉じる\"></a></div>";
			tgtObj.innerHTML += res;
			slidePoint(point);
		 });
	}else if(iframeSrc != null && iframeSrc != ""){
		var xsize = "";
		var ysize = "";
		if(iframeWidth !=null && iframeWidth !=""){
			xsize= " width:" + (iframeWidth-20) + "px;";
			$("infobox").style.width = iframeWidth + "px";
		}
		if(iframeHeight !=null && iframeHeight !=""){
			ysize=" height:" + (iframeHeight-20) + "px;";
			$("infobox").style.height = iframeHeight + "px";
		}
		var stylesrc = "";
		if(xsize != "" || ysize != ""){
			stylesrc = "style=\"" + xsize + ysize + "\"";
		}
		var tgtObj = getRawObject("infoboxmemo");
			tgtObj.innerHTML = "<div class=\"overlaysymbolhtmlclose\"><a href=\"javascript:clearOverlaysymbolhtml();\" style=\"cursor:pointer;\"><img src=\""+batsuUrl+"\" alt=\"閉じる\"></a></div>";
			tgtObj.innerHTML += "<iframe frameborder=\"0\" src=\""+ iframeSrc +"\" class=\"fukiIframe\" " + stylesrc + "></iframe>";
			slidePoint(point);
	}
};

function slidePoint(point){
	boxTop = getTopPos("infobox",ICTMAP.IctMap.CONST_VIEWPORT_ID);
	boxLeft = getLeftPos("infobox",ICTMAP.IctMap.CONST_VIEWPORT_ID);
	boxRight = boxLeft+getObjectWidth("infobox");
	boxBottom = getTopPos("infobox",ICTMAP.IctMap.CONST_VIEWPORT_ID)+getObjectHeight("infobox")+20;
	vy = point.xml_overlay.kaMap.viewportHeight;
	vx = point.xml_overlay.kaMap.viewportWidth;

	//alert("boxLeft="+boxLeft+"boxRight="+boxRight+"boxBottom="+boxBottom+"vy="+vy+"vx="+vx);

	var slideY = 0,slideX = 0;
	if(boxTop < 10) slideY = -(boxTop) + 50;
	if(boxBottom > vy) slideY = -((boxBottom-vy)+80);
	if(boxLeft < 10){
		slideX = -(boxLeft)+10;
	}else if(boxRight > vx){
		slideX = -((boxRight-vx)+30);
	}
	if(vx < 500 || vy < 500){
		return;
	}
	//alert("slideX="+slideX);
	//alert("slideY="+slideY);
	if(slideY != 0 || slideX != 0){
		point.xml_overlay.kaMap.slideBy(slideX,slideY);	// 地図を移動
		point.xml_overlay.kaMap.automove = true;
	}
	
};

function popuppoint(id,flg){
	obj = "xmlovr_p"+id+"_div";
	var tgtObj = getRawObject(obj);
	if(flg){
		if(tgtObj) tgtObj.style.zoom = 1.8;
	}else{
		if(tgtObj) tgtObj.style.zoom = 1;
	}
};

function getTopPos(inputObjname,toboj){
  inputObj = getRawObject(inputObjname);
  var returnValue = inputObj.offsetTop;
  while((inputObj = inputObj.offsetParent) != null){
  	returnValue += inputObj.offsetTop;
  	if(inputObj.id == toboj){
		break;
	}
  }
  return returnValue;
};
function getLeftPos(inputObjname,toboj){
  inputObj = getRawObject(inputObjname);
  var returnValue = inputObj.offsetLeft;
  while((inputObj = inputObj.offsetParent) != null){
  	if(inputObj.id == toboj){
		break;
	}
  	returnValue += inputObj.offsetLeft;
  }
  return returnValue;
};
/**
 * This object is a single point on the overlay.
 * The object hold the div and all the stuff to draw and move the point 
 * (symbol, label, icon, etc.).
 *
 * pid			The point ID (string)
 * xml_overlay	The kaXmlOverlay object owner of this point
 * opts         EventFunc
 */
function kaXmlPoint(pid, xml_overlay,sid,opts,pointName) {
	this.xml_overlay = xml_overlay;
	this.pid = pid;
	
	this.opts = opts;
	
	this.divId = this.xml_overlay.getDivId(pid);
	this.geox = 0;
	this.geoy = 0;
	this.shown = false;
	
	this.graphics = new Array();
	
	this.div = document.createElement('div');
	this.div.setAttribute('id', this.divId);

	if(!pid.match(/^user_[0-9]*/)){		// 標準ポイント
		this.onclickflg = false;
		this.pointtype = "KIHON";
	}else{								// ユーザポイント
		this.pointtype = "USER";
	}
	
	if(this.pointtype == "KIHON"){
		this.div.setAttribute('class', 'overlaysymbol');
		this.div.style.zIndex=250;
	}else if(this.pointtype == "USER"){
		this.div.setAttribute('class', 'usersymbol');
		this.div.style.zIndex=500;
	}
	
	if(this.opts != null){
		//this.div.setAttribute('class', 'overlaysymbol');
		this.onclickflg = true;
	}

	this.sid = sid;
	this.div.sid = sid;
	this.div.pointName = pointName;
};

function clearOverlaysymbolhtml(){
	/*$$(".overlaysymbolhtml").each(function(overlaysymbolhtml) {
		Element.remove(overlaysymbolhtml);
	});*/
	getRawObject("pointinfo").style.visibility = 'hidden';
	getRawObject("pointinfo").style.display = 'none';
	getRawObject("infoboxmemo").innerHTML = "";
	myKaRubberZoom.dataOver = false;
};

/**
 * Show the point in the specified geo-position.
 */
kaXmlPoint.prototype.placeOnMap = function( x, y ) {
	if (!this.shown) {
		this.geox = x;
		this.geoy = y;
		this.xml_overlay.kaMap.addObjectGeo( this.xml_overlay.overlayCanvas, x, y, this.div );
		this.shown = true;
	} 
};

/**
 * Delete the point.
 */
kaXmlPoint.prototype.removeFromMap = function( ) {
	if (this.shown) {
		this.xml_overlay.kaMap.removeObject( this.div );
		this.shown = false;
	}
	
	var i;
	for (i=0; i<this.graphics.length; i++) {
		this.graphics[i].remove(this);
	}
	
	this.graphics.splice(0);
	
	this.div = null;
	this.xml_overlay = null;
};

/**
 * Move the point in the specified geo-position.
 */
kaXmlPoint.prototype.setPosition = function( x, y ) {
	if (this.shown) {
		this.geox = x;
		this.geoy = y;
		this.div.lat = y;
		this.div.lon = x;
	}
};

/**
 * Add a new kaXmlGraphicElement to this kaXmlPoint.
 * kaXmlGraphicElement subclasses are:
 *  
 *  kaXmlSymbol
 *  kaXmlIcon
 *  kaXmlLabel
 *  kaXmlLinestring
 *  kaXmlPolygon
 *
 * obj	an object of class kaXmlGraphicElement
 */
kaXmlPoint.prototype.addGraphic = function( obj ) {
		this.graphics.push(obj);
		obj.draw(this);
};

/**
 * Clear all the graphic elements of this kaXmlPoint.
 */
kaXmlPoint.prototype.clear = function() {
	this.div.innerHTML = "";
	this.graphics.length = 0;
	//this.graphics = new Array();
};

/**
 * Set the HTML content of this kaXmlPoint.
 * This function delete any other content of the point.
 *
 * ihtml		A string containing the HTML
 */
kaXmlPoint.prototype.setInnerHtml = function(ihtml) {
	this.clear();
	this.div.innerHTML = ihtml;
};

/**
 * Parse the XML fragment describing the point. Then draw or translate
 * the point on the map.
 *
 * point_element	 A DOM element <point>
 */
kaXmlPoint.prototype.parse = function(point_element) {

	var i;
	var x = parseFloat(point_element.getAttribute("x"));
	var y = parseFloat(point_element.getAttribute("y"));
	var redraw_a = point_element.getAttribute("redraw");
	var redraw = false;
	if (redraw_a == "true")	redraw = true;
			
	if (!this.shown) {
		this.placeOnMap(x,y);
		this.shown = true;
	} else {
		this.setPosition(x,y);
		
		// Need redraw?
		if (!redraw) return;
		
		// clear and redraw the point
		this.clear();
	}
		
	// look for ihtml element
	var ihtml_element = point_element.getElementsByTagName("ihtml");
	for (i=0; i<ihtml_element.length; i++) {
		this.div.innerHTML = ihtml_element[i].firstChild.nodeValue;
	}
	
	var t;
	var elements;
	
	// look for symbol element
	elements = point_element.getElementsByTagName("symbol");
	for (i=0; i<elements.length; i++) {
		t = new kaXmlSymbol();
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
	
	// look for icon element
	elements = point_element.getElementsByTagName("icon");
	for (i=0; i<elements.length; i++) {
		t = new kaXmlIcon();
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}

	// look for label element
	elements = point_element.getElementsByTagName("label");
	for (i=0; i<elements.length; i++) {
		t = new kaXmlLabel();
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
	
	// look for linestring element
	elements = point_element.getElementsByTagName("linestring");
	for (i=0; i<elements.length; i++) {
		t = new kaXmlLinestring(this);
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
	
	// look for polygon element
	elements = point_element.getElementsByTagName("polygon");
	for (i=0; i<elements.length; i++) {
		t = new kaXmlPolygon(this);
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
};

/**
 * Parse the XML fragment describing the point. Then draw or translate
 * the point on the map.
 *
 * point_element	 A JSON element <point>
 */
kaXmlPoint.prototype.parse2 = function(point_element) {
	var i;
	var x = parseFloat(point_element.x);
	var y = parseFloat(point_element.y);
	var redraw_a = point_element.redraw;
	var redraw = false;
	if (redraw_a == "true")	redraw = true;
			
	if (!this.shown) {
		this.placeOnMap(x,y);
		this.shown = true;
	} else {
		this.setPosition(x,y);
		
		// Need redraw?
		if (!redraw) return;
		
		// clear and redraw the point
		this.clear();
	}
	
	/*
	// look for ihtml element
	var ihtml_element = point_element.ihtml;
	for (i=0; i<ihtml_element.length; i++) {
		this.div.innerHTML = ihtml_element[i].firstChild.nodeValue;
	}
	
	var t;
	var elements;
	
	// look for symbol element
	elements = point_element.symbol;
	for (i=0; i<elements.length; i++) {
		t = new kaXmlSymbol();
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
	*/
	
	// look for icon element
	elements = point_element.icon;
	for (i=0; i<elements.length; i++) {
		t = new kaXmlIcon();
		t.parseElement2(this, elements[i]);
		this.addGraphic(t);
	}

	// look for label element
	elements = point_element.label;
	for (i=0; i<elements.length; i++) {
		t = new kaXmlLabel();
		t.parseElement2(this, elements[i]);
		this.addGraphic(t);
	}
	
	/*
	// look for linestring element
	elements = point_element.linestring;
	for (i=0; i<elements.length; i++) {
		t = new kaXmlLinestring(this);
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
	
	// look for polygon element
	elements = point_element.polygon;
	for (i=0; i<elements.length; i++) {
		t = new kaXmlPolygon(this);
		t.parseElement(this, elements[i]);
		this.addGraphic(t);
	}
	   */
};

kaXmlPoint.prototype.rescale = function(point_element) {
	var i;
	for (i=0; i<this.graphics.length; i++) {
		this.graphics[i].rescale(this);
	}
};

/**************************************************************/


var _BrowserIdent_browser = null;
var _BrowserIdent_version = null;
var _BrowserIdent_place = 0;
var _BrowserIdent_thestring = null;
var _BrowserIdent_detect = null;

function _BrowserIdent() {
	_BrowserIdent_detect = navigator.userAgent.toLowerCase();

	if (_BrowserIdent_checkIt('konqueror')) {
		_BrowserIdent_browser = "Konqueror";
	} else if (_BrowserIdent_checkIt('safari')) _BrowserIdent_browser = "Safari";
	else if (_BrowserIdent_checkIt('omniweb')) _BrowserIdent_browser = "OmniWeb";
	else if (_BrowserIdent_checkIt('opera')) _BrowserIdent_browser = "Opera"
	else if (_BrowserIdent_checkIt('webtv')) _BrowserIdent_browser = "WebTV";
	else if (_BrowserIdent_checkIt('icab')) _BrowserIdent_browser = "iCab";
	else if (_BrowserIdent_checkIt('msie')) _BrowserIdent_browser = "Internet Explorer";
	else if (_BrowserIdent_checkIt('firefox')) _BrowserIdent_browser = "Firefox";
	else if (!_BrowserIdent_checkIt('compatible')) {
		_BrowserIdent_browser = "Netscape Navigator"
		_BrowserIdent_version = _BrowserIdent_detect.charAt(8);
	} else _BrowserIdent_browser = "An unknown browser";

	if (!_BrowserIdent_version) _BrowserIdent_version = _BrowserIdent_detect.charAt(_BrowserIdent_place + _BrowserIdent_thestring.length);
	
	//alert(navigator.userAgent+"\nBrowser["+_BrowserIdent_browser+"] Version["+_BrowserIdent_version+"]");
};

function _BrowserIdent_checkIt(string) {
	_BrowserIdent_place = _BrowserIdent_detect.indexOf(string) + 1;
	_BrowserIdent_thestring = string;
	return _BrowserIdent_place;
};

function _BrowserIdent_setOpacity(imageobject, opacity) {
	if (opacity == undefined || opacity >= 1) return '';
	if (_BrowserIdent_browser == "Netscape Navigator")
		imageobject.style.MozOpacity=opacity;
	else if (_BrowserIdent_browser == "Internet Explorer" && parseInt(this.version)>=4) {
		//filter: alpha(opacity=50);
		var tmp = imageobject.style.cssText;
		tmp = "filter: alpha(opacity="+(opacity*100)+");" + tmp;
		imageobject.style.cssText = tmp;
	} else {
		var tmp = imageobject.style.cssText;
		tmp = "opacity: "+opacity+";" + tmp;	
		imageobject.style.cssText = tmp;
	}
};

function _BrowserIdent_getPreferredImageType() {
	if (_BrowserIdent_browser == "Netscape Navigator") return "P";
	else if (_BrowserIdent_browser == "Opera") return "P";
	else if (_BrowserIdent_browser == "Firefox") return "P";
	else if (_BrowserIdent_browser == "Safari") return "P";
	else if (_BrowserIdent_browser == "Konqueror") return "P";
	else return "G"
};

function _BrowserIdent_getPreferredOpacity() {
	if (_BrowserIdent_browser == "Netscape Navigator") return "server";
	else if (_BrowserIdent_browser == "Firefox") return "server";
	else if (_BrowserIdent_browser == "Opera") return "server";
	else if (_BrowserIdent_browser == "Konqueror") return "server";
	else return "client"
};

var xmlOverlayUseCanvas = true;

function _BrowserIdent_hasCanvasSupport() {

	if (! xmlOverlayUseCanvas) return false;
	
	if (_BrowserIdent_browser == "Internet Explorer") return true;
	if (_BrowserIdent_browser == "Firefox") return true;
	if (_BrowserIdent_browser == "Safari") return true;
	//if (_BrowserIdent_browser == "Konqueror") return true;
	//if (_BrowserIdent_browser == "Opera") return true;
	
	return false;
};

function _BrowserIdent_newCanvas(parentNode) {
	var el = document.createElement('canvas');
	parentNode.appendChild(el);
	if (typeof G_vmlCanvasManager != "undefined") {
		el = G_vmlCanvasManager.initElement(el);
	}
	return el;
};

function _BrowserIdent_getCanvasContext(canvas) {
	return canvas.getContext('2d');
};

function _BrowserIdent_setCanvasHW(canvas, height, width) {
		canvas.width = width; 
		canvas.height = height;
};

_BrowserIdent();
var charset="";
// jsr_class.js
//
// JSONscriptRequest -- a simple class for making HTTP requests
// using dynamically generated script tags and JSON
//
// Author: Jason Levitt
// Date: December 7th, 2005
//
// A SECURITY WARNING FROM DOUGLAS CROCKFORD:
// "The dynamic <script> tag hack suffers from a problem. It allows a page 
// to access data from any server in the web, which is really useful. 
// Unfortunately, the data is returned in the form of a script. That script 
// can deliver the data, but it runs with the same authority as scripts on 
// the base page, so it is able to steal cookies or misuse the authorization 
// of the user with the server. A rogue script can do destructive things to 
// the relationship between the user and the base server."
//
// So, be extremely cautious in your use of this script.
//
//
// Sample Usage:
//
// <script type="text/javascript" src="jsr_class.js"></script>
// 
// function callbackfunc(jsonData) {
//      alert('Latitude = ' + jsonData.ResultSet.Result[0].Latitude + 
//            '  Longitude = ' + jsonData.ResultSet.Result[0].Longitude);
//      aObj.removeScriptTag();
// }
//
// request = 'http://api.local.yahoo.com/MapsService/V1/geocode?appid=YahooDemo&
//            output=json&callback=callbackfunc&location=78704';
// aObj = new JSONscriptRequest(request);
// aObj.buildScriptTag();
// aObj.addScriptTag();
//
//


// Constructor -- pass a REST request URL to the constructor
//
function JSONscriptRequest(fullUrl) {
    // REST request path
    this.fullUrl = fullUrl; 
    // Keep IE from caching requests
    this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
    // Get the DOM location to put the script tag
    this.headLoc = document.getElementsByTagName("head").item(0);
    // Generate a unique script tag id
    this.scriptId = 'JscriptId' + JSONscriptRequest.scriptCounter++;
};

// Static script ID counter
JSONscriptRequest.scriptCounter = 1;

// buildScriptTag method
//
JSONscriptRequest.prototype.buildScriptTag = function () {

    // Create the script tag
    this.scriptObj = document.createElement("script");
    
    // Add script object attributes
    this.scriptObj.setAttribute("type", "text/javascript");
    this.scriptObj.setAttribute("charset", "utf-8");
    this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
    this.scriptObj.setAttribute("id", this.scriptId);
};
 
// removeScriptTag method
// 
JSONscriptRequest.prototype.removeScriptTag = function () {
    // Destroy the script tag
    if(this.scriptObj) this.headLoc.removeChild(this.scriptObj);  
};

// addScriptTag method
//
JSONscriptRequest.prototype.addScriptTag = function () {
    // Create the script tag
    this.headLoc.appendChild(this.scriptObj);
};
