// -----------------------------------------------------------------------------
// ASTER GDEM client engine / page : search
// -----------------------------------------------------------------------------

// global members
var contentsHowtoTitle;
var contentsHowtoContents;
var contentsHowtoTitleDirectly;
var contentsHowtoContentsDirectly;
var contentsHowtoTitlePolygon;
var contentsHowtoContentsPolygon;
var contentsHowtoTitleShapefile;
var contentsHowtoContentsShapefile;
var contentsHowtoTitleRegion;
var contentsHowtoContentsRegion;
var messageDoFixPolygon;
var messageDoFixRegion;
var messageDoClearAllSelectedTile;
var messageInvalidVertex;
var messageNoShapefile;
var messageInvalidShapefile;
var messageRegionNorthernEdge;
var messageRegionSouthernEdge;
var messageRegionWesternEdge;
var messageRegionEasternEdge;
var messageNoRegionValue;
var messageNotNumericRegionValue;
var messageTooSmallRegionValue;
var messageTooLargeRegionValue;
var messageInvalidRegionValue;
var messageRegionLatitudeSame;
var messageRegionNotNorthern;
var messageRegionLongitudeSame;
var messageTileSelectingFailed;
var messageServerError;
var searchBoxElement;
var actionRadioButtonSetSearchTab;
var tabSearchDirectElement;
var tabSearchPolygonElement;
var tabSearchShapefileElement;
var tabSearchRegionElement;
var checkboxSearchDirect;
var buttonSearchPolygonStart;
var buttonSearchPolygonOk;
var buttonSearchPolygonClear;
var formSearchShapefile;
var textboxSearchShapefile;
var iframeShapefileUploadResult;
var pulldownSearchRegionLatitudeNorthernEdge;
var textboxSearchRegionLatitudeNorthernEdge;
var pulldownSearchRegionLatitudeSouthernEdge;
var textboxSearchRegionLatitudeSouthernEdge;
var pulldownSearchRegionLongitudeWesternEdge;
var textboxSearchRegionLongitudeWesternEdge;
var pulldownSearchRegionLongitudeEasternEdge;
var textboxSearchRegionLongitudeEasternEdge;
var mapBoxBorderElement;
var checkboxShowMesh;
var linkMapManipulation;
var buttonClear;
var buttonComplete;
var accelerationSteps64;

function initializePage()
{
	// get search page parameters from cookie
	var lastMapMagnification = getCookieValue(GD_PAGE_MAP_MAGNIFICATION);
	if(lastMapMagnification == null) lastMapMagnification = 1;
	else
	{
		lastMapMagnification = parseFloat(lastMapMagnification);
		if(isNaN(lastMapMagnification)) lastMapMagnification = 1;
		else
		{
			if(lastMapMagnification < 1) lastMapMagnification = 1;
			if(32 < lastMapMagnification) lastMapMagnification = 32;
		}
	}
	var lastMapOffsetX = getCookieValue(GD_PAGE_MAP_OFFSET_X);
	if(lastMapOffsetX == null) lastMapOffsetX = -1;
	else
	{
		lastMapOffsetX = parseFloat(lastMapOffsetX);
		if(isNaN(lastMapOffsetX)) lastMapOffsetX = -1;
		else
		{
			while(lastMapOffsetX < 0) lastMapOffsetX += 360;
			while(360 <= lastMapOffsetX) lastMapOffsetX -= 360;
		}
	}
	var lastMapOffsetY = getCookieValue(GD_PAGE_MAP_OFFSET_Y);
	if(lastMapOffsetY == null) lastMapOffsetY = -1;
	else
	{
		lastMapOffsetY = parseFloat(lastMapOffsetY);
		if(isNaN(lastMapOffsetY)) lastMapOffsetY = -1;
		else
		{
			if(lastMapOffsetY < 0) lastMapOffsetY = -1;
			if(166 < lastMapOffsetY) lastMapOffsetY = -1;
		}
	}
	var lastDoShowMesh = getCookieValue(GD_PAGE_MAP_IS_MESH_SHOWING);
	if(lastDoShowMesh == null) lastDoShowMesh = false;
	else
	{
		if(lastDoShowMesh == "yes") lastDoShowMesh = true;
		else lastDoShowMesh = false;
	}
	var lastCurrentTagIndex = getCookieValue(GD_PAGE_SEARCH_OPERATION_TAG_INDEX);
	if(lastCurrentTagIndex == null) lastCurrentTagIndex = 0;
	else
	{
		lastCurrentTagIndex = parseInt(lastCurrentTagIndex);
		if(isNaN(lastCurrentTagIndex)) lastCurrentTagIndex = 0;
		{
			if(lastCurrentTagIndex < 0) lastCurrentTagIndex = 0;
			if(3 < lastCurrentTagIndex) lastCurrentTagIndex = 0;
		}
	}
	//alert(lastMapMagnification);
	//alert(lastMapOffsetX);
	//alert(lastMapOffsetY);
	//alert(lastDoShowMesh);
	//alert(lastCurrentTagIndex);

	// create howto control
	contentsHowtoTitle = document.getElementById("contents_howto_title");
	contentsHowtoContents = document.getElementById("contents_howto_contents");
	contentsHowtoTitleDirectly = document.getElementById("contents_howto_title_directly");
	contentsHowtoContentsDirectly = document.getElementById("contents_howto_contents_directly");
	contentsHowtoTitlePolygon = document.getElementById("contents_howto_title_polygon");
	contentsHowtoContentsPolygon = document.getElementById("contents_howto_contents_polygon");
	contentsHowtoTitleShapefile = document.getElementById("contents_howto_title_shapefile");
	contentsHowtoContentsShapefile = document.getElementById("contents_howto_contents_shapefile");
	contentsHowtoTitleRegion = document.getElementById("contents_howto_title_region");
	contentsHowtoContentsRegion = document.getElementById("contents_howto_contents_region");

	// get dynamic message
	messageDoFixPolygon = document.getElementById("message_do_fix_polygon").innerHTML;
	messageDoFixRegion = document.getElementById("message_do_fix_region").innerHTML;
	messageDoClearAllSelectedTile = document.getElementById("message_do_clear_all_selected_tile").innerHTML;
	messageInvalidVertex = document.getElementById("message_invalid_vertex").innerHTML;
	messageNoShapefile = document.getElementById("message_no_shapefile").innerHTML;
	messageInvalidShapefile = document.getElementById("message_invalid_shapefile").innerHTML;
	messageRegionNorthernEdge = document.getElementById("message_region_northern_edge").innerHTML;
	messageRegionSouthernEdge = document.getElementById("message_region_southern_edge").innerHTML;
	messageRegionWesternEdge = document.getElementById("message_region_western_edge").innerHTML;
	messageRegionEasternEdge = document.getElementById("message_region_eastern_edge").innerHTML;
	messageNoRegionValue = document.getElementById("message_no_region_value").innerHTML;
	messageNotNumericRegionValue = document.getElementById("message_not_numeric_region_value").innerHTML;
	messageTooSmallRegionValue = document.getElementById("message_too_small_region_value").innerHTML;
	messageTooLargeRegionValue = document.getElementById("message_too_large_region_value").innerHTML;
	messageInvalidRegionValue = document.getElementById("message_invalid_region_value").innerHTML;
	messageRegionLatitudeSame = document.getElementById("message_region_latitude_same").innerHTML;
	messageRegionNotNorthern = document.getElementById("message_region_not_northern").innerHTML;
	messageRegionLongitudeSame = document.getElementById("message_region_longitude_same").innerHTML;
	messageTileSelectingFailed = document.getElementById("message_tile_selecting_failed").innerHTML;
	messageServerError = document.getElementById("message_server_error").innerHTML;

	// prepare acceleration step table
	prepareAccelerationSteps64();

	// get search box element
	searchBoxElement = document.getElementById("search_box");

	// create tab button
	actionRadioButtonSetSearchTab =
		new ActionRadioButtonSet("radiobutton_search_direct", "radiobutton_search_polygon", "radiobutton_search_shapefile", "radiobutton_search_region",
		function(actionRadioButtonSet) {searchTabOperation(actionRadioButtonSet.selectedIndex);});

	// get search operation tab elements and initialize
	tabSearchDirectElement = document.getElementById("tab_search_direct");
	tabSearchDirectElement.style.visibility = "hidden";
	tabSearchPolygonElement = document.getElementById("tab_search_polygon");
	tabSearchPolygonElement.style.visibility = "hidden";
	tabSearchShapefileElement = document.getElementById("tab_search_shapefile");
	tabSearchShapefileElement.style.visibility = "hidden";
	tabSearchRegionElement = document.getElementById("tab_search_region");
	tabSearchRegionElement.style.visibility = "hidden";

	// set tab status
	actionRadioButtonSetSearchTab.select(lastCurrentTagIndex);

	// create control [direct]
	checkboxSearchDirect = createActionCheckBox("checkbox_search_direct", changeSearchDirectSelecting);

	// create control [polygin]
	buttonSearchPolygonStart = createActionButton("button_search_polygon_start", startDrawPolygon);
	buttonSearchPolygonOk = createActionButton("button_search_polygon_ok", terminateDrawPolygon);
	buttonSearchPolygonClear = createActionButton("button_search_polygon_clear", cancelDrawPolygon);
	setVisible(buttonSearchPolygonOk.buttonElement, false);
	setVisible(buttonSearchPolygonClear.buttonElement, false);

	// create control [shape file]
	formSearchShapefile = document.getElementById("form_search_shapefile");
	textboxSearchShapefile = document.getElementById("file_search_shapefile");
	createActionButton("button_search_shapefile_ok", terminateSpecifyShapefile);
	iframeShapefileUploadResult = document.getElementById("iframe_shapefile_upload_result");

	// create control [region]
	pulldownSearchRegionLatitudeNorthernEdge = document.getElementById("pulldown_search_region_latitude_northern_edge");
	textboxSearchRegionLatitudeNorthernEdge = document.getElementById("textbox_search_region_latitude_northern_edge");
	pulldownSearchRegionLatitudeSouthernEdge = document.getElementById("pulldown_search_region_latitude_southern_edge");
	textboxSearchRegionLatitudeSouthernEdge = document.getElementById("textbox_search_region_latitude_southern_edge");
	pulldownSearchRegionLongitudeWesternEdge = document.getElementById("pulldown_search_region_longitude_western_edge");
	textboxSearchRegionLongitudeWesternEdge = document.getElementById("textbox_search_region_longitude_western_edge");
	pulldownSearchRegionLongitudeEasternEdge = document.getElementById("pulldown_search_region_longitude_eastern_edge");
	textboxSearchRegionLongitudeEasternEdge = document.getElementById("textbox_search_region_longitude_eastern_edge");
	createActionButton("button_search_region_ok", terminateSpecifyRegion);

	// get map box element
	mapBoxBorderElement = document.getElementById("search_map_box_border");

	// prepare zoom bar
	prepareZoomBar();

	// prepare map type selector
//	prepareMapTypeSelector();	// disable NUM

	// create show mesh button
	checkboxShowMesh = createActionCheckBox("checkbox_search_show_mesh", changeSearchShowMesh);

	// prepare map manipulation link
	prepareMapManipulationLink();

	// create clear button
	buttonClear = createActionButton("button_search_clear", clearTileSelection);
	buttonClear.setEnablement(false);

	// create scroll buttons
	var buttonScrollUp = createActionButton("button_scroll_up", null);
	buttonScrollUp.buttonMouseDownFunction = mapScrollUp;
	buttonScrollUp.buttonMouseUpFunction = mapStopScroll;
	var buttonScrollDown = createActionButton("button_scroll_down", null);
	buttonScrollDown.buttonMouseDownFunction = mapScrollDown;
	buttonScrollDown.buttonMouseUpFunction = mapStopScroll;
	var buttonScrollLeft = createActionButton("button_scroll_left", null);
	buttonScrollLeft.buttonMouseDownFunction = mapScrollLeft;
	buttonScrollLeft.buttonMouseUpFunction = mapStopScroll;
	var buttonScrollRight = createActionButton("button_scroll_right", null);
	buttonScrollRight.buttonMouseDownFunction = mapScrollRight;
	buttonScrollRight.buttonMouseUpFunction = mapStopScroll;

	// initialize mouse position indicator
	initializeMousePositionIndicator();

	// create complete button
	buttonComplete = createActionButton("button_search_complete", transferToTileListPage);
	buttonComplete.setEnablement(false);

	// initialize map
	initializeMap();
	showMapWithAnchorZooming(lastMapMagnification, ANCHOR_CENTER, ANCHOR_CENTER);
	moveZoomSlider(mapMagnification);
	showZoomMagnificationValue(mapMagnification);
	if((lastMapOffsetX != -1) && (lastMapOffsetY != -1))
	{
		showMapWithOffset(lastMapOffsetX, lastMapOffsetY);
	}
	if(lastDoShowMesh == true)
	{
		checkboxShowMesh.setChecked(true);
		doShowMesh = true;
		reshowMap();
	}

	// prepare clicked position offsets
	prepareClickedPositionOffsets();

	// initialize tile selection
	initializeTileSelection();
}
function prepareAccelerationSteps64()
{
	accelerationSteps64 = new Array();
	var stepCount = 64;
	var totalStepUnit = (((stepCount / 2) + 1) * stepCount) / 2;
	var stepPos = 0;
	for(var i = 0; i < stepCount; i++)
	{
		stepPos += (i < (stepCount / 2))? (i + 1): (stepCount - i);
		accelerationSteps64[i] = stepPos / totalStepUnit;
	}
	//console.info(totalStepUnit);
	//for(var i = 0; i < stepCount; i++) console.info("[" + i + "] : " + accelerationSteps64[i]);
}
function prepareMapManipulationLink()
{
	// get link to map manipulation page element
	linkMapManipulation = document.getElementById("link_map_manipulation");

	// open sub window
	var subWindowStyle = "width=800,height=600" +
		",resizable=no";
//		",location=yes" +
//		",scrollbars=yes";
	var linkToMapManipulationPage = function(e)
	{
		var subWindow = window.open("./map_manipulation.jsp", "sub", subWindowStyle);
		subWindow.focus();
	}
	addListener(linkMapManipulation, "click", linkToMapManipulationPage, false);
}

// page management
var isTransferringToTileListPage = false;
function transferToTileListPage(actionButton)
{
	isTransferringToTileListPage = true;
	if(mapSelectedTiles == null)
	{
		transferPage("gdServlet/SelectTile");
		return;
	}
	var savedFunction = function()
	{
		transferPage("gdServlet/SelectTile");
	}
	var postData = createSelectedTilesParameterText(true);
	setTileList("gdServletAsyn/SetTileList", postData, savedFunction);
}
function unloadedFunction(e)
{
	savePageParam();
	if(isTransferringToTileListPage == false)
	{
		if(mapSelectedTiles != null)
		{
			var postData = createSelectedTilesParameterText(false);
			setTileList("gdServletAsyn/SetTileList", postData, null);
		}
	}
}
addListener(window, "unload", unloadedFunction, false);
function tileListProcessAtChangingLanguage()
{
	var savedFunction = function()
	{
		window.location.reload();
	}
	var postData = createSelectedTilesParameterText(false);
	setTileList("gdServletAsyn/SetTileList", postData, savedFunction);
}
var GD_PAGE_MAP_MAGNIFICATION = "_gd_map_magnification";
var GD_PAGE_MAP_OFFSET_X = "_gd_map_offset_x";
var GD_PAGE_MAP_OFFSET_Y = "_gd_map_offset_y";
var GD_PAGE_MAP_IS_MESH_SHOWING = "_gd_map_is_mesh_showing";
var GD_PAGE_SEARCH_OPERATION_TAG_INDEX = "_gd_search_operation_tag_index";
function savePageParam()
{
	// register search page parameters in cookie
	setCookieValue(GD_PAGE_MAP_MAGNIFICATION, mapMagnification, 180);
	setCookieValue(GD_PAGE_MAP_OFFSET_X, mapOffsetX, 180);
	setCookieValue(GD_PAGE_MAP_OFFSET_Y, mapOffsetY, 180);
	setCookieValue(GD_PAGE_MAP_IS_MESH_SHOWING, doShowMesh? "yes": "no", 180);
	setCookieValue(GD_PAGE_SEARCH_OPERATION_TAG_INDEX, currentTagIndex, 180);
}

// search tab operation
var currentTagIndex;
function searchTabOperation(index)
{
	cancelDirectOperation();
	cancelPolygonOperation();
	cancelRegionOperation();
	switch(index)
	{
		case 0:
			contentsHowtoTitle.innerHTML = contentsHowtoTitleDirectly.innerHTML;
			contentsHowtoContents.innerHTML = contentsHowtoContentsDirectly.innerHTML;
			tabSearchDirectElement.style.visibility = "visible";
			tabSearchPolygonElement.style.visibility = "hidden";
			tabSearchShapefileElement.style.visibility = "hidden";
			tabSearchRegionElement.style.visibility = "hidden";
			break;
		case 1:
			contentsHowtoTitle.innerHTML = contentsHowtoTitlePolygon.innerHTML;
			contentsHowtoContents.innerHTML = contentsHowtoContentsPolygon.innerHTML;
			tabSearchDirectElement.style.visibility = "hidden";
			tabSearchPolygonElement.style.visibility = "visible";
			tabSearchShapefileElement.style.visibility = "hidden";
			tabSearchRegionElement.style.visibility = "hidden";
			break;
		case 2:
			contentsHowtoTitle.innerHTML = contentsHowtoTitleShapefile.innerHTML;
			contentsHowtoContents.innerHTML = contentsHowtoContentsShapefile.innerHTML;
			tabSearchDirectElement.style.visibility = "hidden";
			tabSearchPolygonElement.style.visibility = "hidden";
			tabSearchShapefileElement.style.visibility = "visible";
			tabSearchRegionElement.style.visibility = "hidden";
			break;
		case 3:
			contentsHowtoTitle.innerHTML = contentsHowtoTitleRegion.innerHTML;
			contentsHowtoContents.innerHTML = contentsHowtoContentsRegion.innerHTML;
			tabSearchDirectElement.style.visibility = "hidden";
			tabSearchPolygonElement.style.visibility = "hidden";
			tabSearchShapefileElement.style.visibility = "hidden";
			tabSearchRegionElement.style.visibility = "visible";
			break;
	}
	currentTagIndex = index;
}

// zoom bar
var ZINDEX_ZOOM_BUTTON = 10;
var ZINDEX_ZOOM_SLIDER = 10;
var ZINDEX_ZOOM_OPERATION_AREA = 20;
var zoomBarElement;
var labelZoomBarStatus;
function prepareZoomBar()
{
	zoomBarElement = document.getElementById("zoom_bar");
	var zoomOut = function(actionButton)
	{
		if(mapMagnification == 1) return;
		var newMapMagnification = mapMagnification * 0.9;
		changeMapMagnification(newMapMagnification);
	}
	var buttonZoomOut = createActionButton("zoom_bar_button_zoom_out", zoomOut);
	buttonZoomOut.buttonElement.style.zIndex = ZINDEX_ZOOM_BUTTON;
	var zoomIn = function(actionButton)
	{
		if(mapMagnification == 32) return;
		var newMapMagnification = mapMagnification * 1.1;
		changeMapMagnification(newMapMagnification);
	}
	var buttonZoomIn = createActionButton("zoom_bar_button_zoom_in", zoomIn);
	buttonZoomIn.buttonElement.style.zIndex = ZINDEX_ZOOM_BUTTON;
	createZoomSliderElement();
	createZoomOperationElement();
	labelZoomBarStatus = new Label("zoom_bar_status");
}
function changeMapMagnification(newMapMagnification)
{
	if(newMapMagnification < 1) newMapMagnification = 1;
	if(32 < newMapMagnification) newMapMagnification = 32;
	moveZoomSlider(newMapMagnification);
	showMapWithAnchorZooming(newMapMagnification, ANCHOR_CENTER, ANCHOR_CENTER);
	showZoomMagnificationValue(newMapMagnification);
}
var ZOOM_OPERATION_AREA_WIDTH = 223;
var ZOOM_OPERATION_AREA_HEIGHT = 20;
var ZOOM_OPERATION_AREA_LEFT = 20;
var ZOOM_OPERATION_AREA_TOP = 0;
var ZOOM_OPERATION_AREA_LEFT_MARGIN = 3;
var ZOOM_OPERATION_AREA_SPAN = 215;
var ZOOM_SLIDER_WIDTH = 8;
var ZOOM_SLIDER_HEIGHT = 20;
function createZoomOperationElement()
{
	// create zoom bar operation area
	var zoomBarOperationElement = document.createElement("div");
	zoomBarOperationElement.style.position = "absolute";
	setElementSize(zoomBarOperationElement, ZOOM_OPERATION_AREA_WIDTH, ZOOM_OPERATION_AREA_HEIGHT);
	setElementPosition(zoomBarOperationElement, ZOOM_OPERATION_AREA_LEFT, ZOOM_OPERATION_AREA_TOP);
	zoomBarOperationElement.style.zIndex = ZINDEX_ZOOM_OPERATION_AREA;
	zoomBarOperationElement.style.backgroundColor = "#FFFFFF";	// for IE
	setOpacity(zoomBarOperationElement, 0);					// for IE

	// decide zoom operation area left position
	var mapBoxBorderPosition = getElementPosition(mapBoxBorderElement);
	var zoomBarPosition = getElementPosition(zoomBarElement);
	var zoomBarOperationElementLeft = mapBoxBorderPosition.left + zoomBarPosition.left + ZOOM_OPERATION_AREA_LEFT;
	zoomBarOperationElementLeft += 2;	// for IE

	// slider position check
	function isSliderPosition(posX)
	{
		var zoomSliderPosition = getElementPosition(zoomSliderElement);
		var sliderPosX = zoomSliderPosition.left - ZOOM_OPERATION_AREA_LEFT;
		if((sliderPosX <= posX) && (posX < (sliderPosX + ZOOM_SLIDER_WIDTH))) return true;
		else return false;
	}

	// get magnification from zoom bar position
	function getMagnificationFromZoombarPosition(posX)
	{
		// get current magnification
		var magnificationRate = ((posX - ZOOM_OPERATION_AREA_LEFT_MARGIN) * 5) / ZOOM_OPERATION_AREA_SPAN;
		if(magnificationRate < 0) magnificationRate = 0;
		if(5 < magnificationRate) magnificationRate = 5;
		var magnification = Math.pow(2, magnificationRate);
		return magnification;
	}

	// mouse down event handler
	var isZoomSliderDragging = false;
	var zoomOperationMouseDown = function(e)
	{
		var posX = e.clientX - zoomBarOperationElementLeft;
		if(isSliderPosition(posX) == false)
		{
			var magnification = getMagnificationFromZoombarPosition(posX)
			moveZoomSlider(magnification);
			showMapWithAnchorZooming(magnification, ANCHOR_CENTER, ANCHOR_CENTER);
			showZoomMagnificationValue(magnification);
			return;
		}
		isZoomSliderDragging = true;
		addListener(zoomBarOperationElement, "mouseup", zoomOperationMouseUp, false);
		addListener(zoomBarOperationElement, "mouseout", zoomOperationMouseUp, false);
		stopEventBubblingAndDefaultAction(e);
	}
	addListener(zoomBarOperationElement, "mousedown", zoomOperationMouseDown, false);

	// mouse move event handler
	var zoomOperationMouseMove = function(e)
	{
		var posX = e.clientX - zoomBarOperationElementLeft;
		if(isZoomSliderDragging == false)
		{
			if(isSliderPosition(posX) == true) zoomBarOperationElement.style.cursor = "pointer";
			else zoomBarOperationElement.style.cursor = "default";
			return;
		}
		var magnification = getMagnificationFromZoombarPosition(posX)
		moveZoomSlider(magnification);
		showZoomMagnificationValue(magnification);
		stopEventBubblingAndDefaultAction(e);
	}
	addListener(zoomBarOperationElement, "mousemove", zoomOperationMouseMove, false);

	// mouse up or out event handler
	var zoomOperationMouseUp = function(e)
	{
		isZoomSliderDragging = false;
		removeListener(zoomBarOperationElement, "mouseup", zoomOperationMouseUp, false);
		removeListener(zoomBarOperationElement, "mouseout", zoomOperationMouseUp, false);
		var posX = e.clientX - zoomBarOperationElementLeft;
		var magnification = getMagnificationFromZoombarPosition(posX)
		moveZoomSlider(magnification);
		showMapWithAnchorZooming(magnification, ANCHOR_CENTER, ANCHOR_CENTER);
		showZoomMagnificationValue(magnification);
		stopEventBubblingAndDefaultAction(e);
	}
	zoomBarElement.appendChild(zoomBarOperationElement);
}
var ZOOM_SLIDER_X_FROM = 20;
var ZOOM_SLIDER_X_TO = 235;
var ZOOM_SLIDER_Y = 0;
var zoomSliderElement;
function createZoomSliderElement()
{
	zoomSliderElement = document.createElement("div");
	zoomSliderElement.style.position = "absolute";
	setElementSize(zoomSliderElement, ZOOM_SLIDER_WIDTH, ZOOM_SLIDER_HEIGHT);
	setElementPosition(zoomSliderElement, ZOOM_SLIDER_X_FROM, ZOOM_SLIDER_Y);
	zoomSliderElement.style.zIndex = ZINDEX_ZOOM_SLIDER;
	zoomSliderElement.style.cursor = "pointer";
	zoomSliderElement.style.backgroundImage = "url(./images/zoom_bar_slider.png)";
	zoomBarElement.appendChild(zoomSliderElement);
}
function moveZoomSlider(magnification)
{
	var newZoomSliderX = Math.log(magnification) / Math.LN2;
	if(newZoomSliderX < 0) newZoomSliderX = 0;
	if(5 < newZoomSliderX) newZoomSliderX = 5;
	newZoomSliderX = Math.round((newZoomSliderX * (ZOOM_SLIDER_X_TO - ZOOM_SLIDER_X_FROM)) / 5);
	newZoomSliderX += ZOOM_SLIDER_X_FROM;
	setElementPosition(zoomSliderElement, newZoomSliderX, ZOOM_SLIDER_Y);
}
function showZoomMagnificationValue(magnification)
{
	labelZoomBarStatus.setText((Math.round(magnification * 10) / 10) + "x");
}

// map type selector
var MAP_TYPE_INDEX_DEM = 0;
var MAP_TYPE_INDEX_NUM = 1;
var actionRadioButtonSelectMapType;
var currentMapTypeIndex = MAP_TYPE_INDEX_DEM;
function prepareMapTypeSelector()
{
	// create map type select button set
	var changeMapType = function(actionRadioButtonSet)
	{
		currentMapTypeIndex = actionRadioButtonSet.selectedIndex;
		if(!mapAreaElement) return;
		reshowMap();
	}
	actionRadioButtonSelectMapType =
		new ActionRadioButtonSet("radiobutton_search_dem", "radiobutton_search_num", changeMapType);
	actionRadioButtonSelectMapType.select(MAP_TYPE_INDEX_DEM);
}

// mesh control
var doShowMesh = false;
function changeSearchShowMesh(actionCheckBox)
{
	doShowMesh = actionCheckBox.isDown? true: false;
	reshowMap();
}

// scroll map
var SCROLL_PIXEL = 10;
var SCROLL_INTERVAL = 30;
var timerScroll = null;
function getScrollOffsetDegree()
{
	// get pixel per degree at current magnification
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

	// decide scroll offset degree and return
	return scrollOffset = SCROLL_PIXEL / pixelPerDegree;
}
function getScrollLimitLower()
{
	// get pixel per degree at current magnification
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

	// decide scroll limit of lower and return
	return DEGREE_HEIGHT - (MAP_AREA_HEIGHT / pixelPerDegree);
}
function mapScrollUp(actionButton)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// execute scroll
	var scrollOffset = getScrollOffsetDegree();
	var scrollFunction = function()
	{
		var newMapOffsetY = mapOffsetY - scrollOffset
		if(newMapOffsetY < 0) newMapOffsetY = 0;
		showMapWithOffset(mapOffsetX, newMapOffsetY);
	}
	timerScroll = window.setInterval(scrollFunction, SCROLL_INTERVAL);
}
function mapScrollDown(actionButton)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// execute scroll
	var scrollOffset = getScrollOffsetDegree();
	var scrollLimitLower = getScrollLimitLower();
	var scrollFunction = function()
	{
		var newMapOffsetY = mapOffsetY + scrollOffset
		if(scrollLimitLower < newMapOffsetY) newMapOffsetY = scrollLimitLower;
		showMapWithOffset(mapOffsetX, newMapOffsetY);
	}
	timerScroll = window.setInterval(scrollFunction, SCROLL_INTERVAL);
}
function mapScrollLeft(actionButton)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// execute scroll
	var scrollOffset = getScrollOffsetDegree();
	var scrollFunction = function()
	{
		showMapWithOffset(mapOffsetX - scrollOffset, mapOffsetY);
	}
	timerScroll = window.setInterval(scrollFunction, SCROLL_INTERVAL);
}
function mapScrollRight(actionButton)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// execute scroll
	var scrollOffset = getScrollOffsetDegree();
	var scrollFunction = function()
	{
		showMapWithOffset(mapOffsetX + scrollOffset, mapOffsetY);
	}
	timerScroll = window.setInterval(scrollFunction, SCROLL_INTERVAL);
}
function mapStopScroll(actionButton)
{
	if(timerScroll) window.clearInterval(timerScroll);
	timerScroll = null;
}

// show mouse position
var labelMousePositionJp;
var labelMousePositionNsJp;
var labelMousePositionYDegreeJp;
var labelMousePositionYMinuteJp;
var labelMousePositionEwJp;
var labelMousePositionXDegreeJp;
var labelMousePositionXMinuteJp;
var labelMousePosition;
var labelMousePositionYDegree;
var labelMousePositionYMinute;
var labelMousePositionNs;
var labelMousePositionXDegree;
var labelMousePositionXMinute;
var labelMousePositionEw;
function initializeMousePositionIndicator()
{
	// create mouse position indicator
	labelMousePositionJp = document.getElementById("mouse_position_jp");
	labelMousePositionNsJp = new Label("mouse_position_ns_jp");
	labelMousePositionYDegreeJp = new Label("mouse_position_y_degree_jp");
	labelMousePositionYMinuteJp = new Label("mouse_position_y_minute_jp");
	labelMousePositionEwJp = new Label("mouse_position_ew_jp");
	labelMousePositionXDegreeJp = new Label("mouse_position_x_degree_jp");
	labelMousePositionXMinuteJp = new Label("mouse_position_x_minute_jp");
	labelMousePosition = document.getElementById("mouse_position");
	labelMousePositionYDegree = new Label("mouse_position_y_degree");
	labelMousePositionYMinute = new Label("mouse_position_y_minute");
	labelMousePositionNs = new Label("mouse_position_ns");
	labelMousePositionXDegree = new Label("mouse_position_x_degree");
	labelMousePositionXMinute = new Label("mouse_position_x_minute");
	labelMousePositionEw = new Label("mouse_position_ew");
	if(language == LANGUAGE_JP) setVisible(labelMousePosition, false);
	else setVisible(labelMousePositionJp, false);
}
function showMousePosition(x, y)
{
	// get pixel per degree at current magnification
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

	// get mouse position degree
	var degreeX = mapOffsetX + (x / pixelPerDegree) - 25;
	while(degreeX < 0) {degreeX += 360};
	degreeX %= 360;
	var degreeY = mapOffsetY + (y / pixelPerDegree);

	// show degree
	var isEast = true;
	if(180 < degreeX)
	{
		isEast = false;
		degreeX = 360 - degreeX;
	}
	var degreeXDegree = Math.floor(degreeX);
	var degreeXMinute = Math.round((degreeX - degreeXDegree) * 60);
	var isNorth = true;
	if(degreeY < 83)
	{
		degreeY = 83 - degreeY;
	}
	else
	{
		isNorth = false;
		degreeY -= 83;
	}
	var degreeYDegree = Math.floor(degreeY);
	var degreeYMinute = Math.round((degreeY - degreeYDegree) * 60);
	var mousePositionText;
	if(language == LANGUAGE_JP)
	{
		labelMousePositionNsJp.setText(isNorth? "北緯": "南緯");
		labelMousePositionYDegreeJp.setText(degreeYDegree + "度");
		labelMousePositionYMinuteJp.setText(degreeYMinute + "分");
		labelMousePositionEwJp.setText(isEast? "東経": "西経");
		labelMousePositionXDegreeJp.setText(degreeXDegree + "度");
		labelMousePositionXMinuteJp.setText(degreeXMinute + "分");
	}
	else
	{
		labelMousePositionYDegree.setText(degreeYDegree);
		labelMousePositionYMinute.setText(degreeYMinute + "'");
		labelMousePositionNs.setText(isNorth? "&nbsp;N": "&nbsp;S");
		labelMousePositionXDegree.setText(degreeXDegree);
		labelMousePositionXMinute.setText(degreeXMinute + "'");
		labelMousePositionEw.setText(isEast? "&nbsp;E": "&nbsp;W");
	}
}

// show map
var clickedPositionOffsetX;
var clickedPositionOffsetY;
var mapBoxElement;
function prepareClickedPositionOffsets()
{
	mapBoxElement = document.getElementById("search_map_box");
	var mapBoxPosition = getElementPosition(mapBoxElement);
	var mapBoxBorderPosition = getElementPosition(mapBoxBorderElement);
	clickedPositionOffsetX = mapBoxBorderPosition.left + mapBoxPosition.left;
	clickedPositionOffsetY =  + mapBoxBorderPosition.top + mapBoxPosition.top;
	clickedPositionOffsetX += 1;	// by border
	clickedPositionOffsetY += 1;	// by border
	if(isBrowser_IE_appName())
	{
		clickedPositionOffsetX += 2;	// by border
		clickedPositionOffsetY += 1;	// by border
	}
}
function getClickedPositionOnMap(x, y)
{
	var scrollPosition = getScrollPosition(window);
	var position = new Object();
	position.x = x - clickedPositionOffsetX + scrollPosition.left;
	position.y = y - clickedPositionOffsetY + scrollPosition.top;
	return position;
}
var isDragging = false;
var dragStartMap;
var dragStartX;
var dragStartY;
var scrollLimitYFrom;
var scrollLimitYTo;
function mouseDownOnMap(e)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// toggle tile selection at direct operation
	if(isDirectSelecting == true)
	{
		var position = getClickedPositionOnMap(e.clientX, e.clientY);
		//alert(position.x + "/" + position.y);
		toggleSelectionOfTile(position.x, position.y);
		return;
	}

	// get clicked point at polygon drawing
	if(isPolygonDrawing == true)
	{
		var position = getClickedPositionOnMap(e.clientX, e.clientY);
		//alert(position.x + "/" + position.y);
		addNewPolygonVertex(position.x, position.y);
		return;
	}

	// start drag
	isDragging = true;

	// change cursor
	setOperationCursor(OPERATION_CURSOR_HAND_CLOSE);

	// remember drag start map position
	dragStartMap = getElementPosition(mapElement);
	//console.info(dragStartMap.left + "/" + dragStartMap.top);

	// get pixel per degree at current magnification
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

	// decide scroll limit first
	scrollLimitYFrom = (mapOffsetY * pixelPerDegree) + dragStartMap.top;
	scrollLimitYTo = scrollLimitYFrom - (DEGREE_HEIGHT * pixelPerDegree) + MAP_AREA_HEIGHT;
	//console.info(scrollLimitYFrom + "/" + scrollLimitYTo);

	// remember drag start mouse position
	dragStartX = e.clientX;
	dragStartY = e.clientY;

	// add listeners
	//console.info("start drag");
	addListener(mapOperationSheetElement, "mouseup", terminateDragMap, false);
	addListener(mapOperationSheetElement, "mouseout", terminateDragMap, false);

	// stop event bubbling and default event action
	stopEventBubblingAndDefaultAction(e);
	return false;
}
function mouseMoveOnMap(e)
{
	// get mouse position
	var position = getClickedPositionOnMap(e.clientX, e.clientY);

	// show mouse position
	showMousePosition(position.x, position.y);

	// sense position at non-dragging
	if(isDragging == false)
	{
		// toggle tile selection at direct operation
		if(isDirectSelecting == true)
		{
			changeCursorAtDirectSelection(position.x, position.y);
			return;
		}
		return;
	}

	// move map
	var newMapX = dragStartMap.left + e.clientX - dragStartX;
	var newMapY = dragStartMap.top + e.clientY - dragStartY;
	//console.info(newMapX + "/" + newMapY);

	// restrict scroll
	if(scrollLimitYFrom < newMapY) newMapY = scrollLimitYFrom;
	if(newMapY < scrollLimitYTo) newMapY = scrollLimitYTo;

	// reset map offset in accordance with new position
	setElementPosition(mapElement, newMapX, newMapY);

	// stop event bubbling and default event action
	stopEventBubblingAndDefaultAction(e);
	return false;
}
function terminateDragMap(e)
{
	// terminate drag
	isDragging = false;

	// reset cursor
	setOperationCursor(OPERATION_CURSOR_HAND_OPEN);

	// remove listeners
	//console.info("terminate drag");
	removeListener(mapOperationSheetElement, "mouseup", terminateDragMap, false);
	removeListener(mapOperationSheetElement, "mouseout", terminateDragMap, false);

	// get pixel per degree at current magnification
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

	var anchorDifferenceX = (e.clientX - dragStartX) / pixelPerDegree;
	var anchorDifferenceY = (e.clientY - dragStartY) / pixelPerDegree;
	//console.info(anchorDifferenceX + "/" + anchorDifferenceY);

	// decide new map offset
	mapOffsetX -= anchorDifferenceX;
	mapOffsetY -= anchorDifferenceY;

	// restrict scroll
	if(mapOffsetY < 0) mapOffsetY = 0;
	var offsetLimit = DEGREE_HEIGHT - (MAP_AREA_HEIGHT / pixelPerDegree);
	if(offsetLimit < mapOffsetY) mapOffsetY = offsetLimit;

	// reshow map
	reshowMap();

	// stop event bubbling and default event action
	stopEventBubblingAndDefaultAction(e);
	return false;
}
var timerIdDoubleClickZoom = null;
var DOUBLE_CLICK_ZOOM_STEP = 70;
function doubleClickOnMap(e)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// ignore at map operationg
	if((isDirectSelecting == true) || (isPolygonDrawing == true)) return;

	// get double click position
	var position = getClickedPositionOnMap(e.clientX, e.clientY);
	//console.info(position.x + "/" + position.y);

	// zoom map
	var zoomCount = 0;
	var doubleClickZoom = function()
	{
		zoomCount++;
		if((DOUBLE_CLICK_ZOOM_STEP <= zoomCount) || (mapMagnification == 32))
		{
			window.clearInterval(timerIdDoubleClickZoom);
			timerIdDoubleClickZoom = null;
			return;
		}
		var rate;
		if(zoomCount <= (DOUBLE_CLICK_ZOOM_STEP / 2)) rate = 1 + (zoomCount * 0.001);
		else rate = 1 + ((DOUBLE_CLICK_ZOOM_STEP - zoomCount) * 0.001);
		var newMapMagnification = mapMagnification * rate;
		if(32 < newMapMagnification) newMapMagnification = 32;
		moveZoomSlider(newMapMagnification);
		showMapWithAnchorZooming(newMapMagnification, position.x, position.y);
		showZoomMagnificationValue(newMapMagnification);
	}
	timerIdDoubleClickZoom = window.setInterval(doubleClickZoom, 10);

	// stop event bubbling and default event action
    stopEventBubblingAndDefaultAction(e);
	return false;
}
function cancelDoubleClickZoom()
{
	if(timerIdDoubleClickZoom != null)
	{
		window.clearInterval(timerIdDoubleClickZoom);
		timerIdDoubleClickZoom = null;
	}
}
function wheelOnMap(e)
{
	// cancel double click zoom
	cancelDoubleClickZoom();

	// get wheel delta and mouse position
	var wheelDelta;
	if(window.event && window.event.wheelDelta)
	{
		wheelDelta = window.event.wheelDelta;
	}
	else if(e.wheelDelta)
	{
		wheelDelta = e.wheelDelta;
	}
	else
	{
		wheelDelta = e.detail * (-1);
	}
	var position = getClickedPositionOnMap(e.clientX, e.clientY);
	//console.info(wheelDelta + "/" + position.x + "/" + position.y);

	// zoom map at cursor
	if(wheelDelta < 0)
	{
		if(mapMagnification == 1)
		{
		    stopEventBubblingAndDefaultAction(e);
			return;
		}
		var newMapMagnification = mapMagnification * 0.9;
		if(newMapMagnification < 1) newMapMagnification = 1;
	}
	else if(0 < wheelDelta)
	{
		if(mapMagnification == 32)
		{
		    stopEventBubblingAndDefaultAction(e);
			return;
		}
		var newMapMagnification = mapMagnification * 1.1;
		if(32 < newMapMagnification) newMapMagnification = 32;
	}
	else return;
	moveZoomSlider(newMapMagnification);
	showMapWithAnchorZooming(newMapMagnification, position.x, position.y);
	showZoomMagnificationValue(newMapMagnification);

	// stop event bubbling and default event action
    stopEventBubblingAndDefaultAction(e);
	return false;
}
var ZINDEX_MAP = 10;
var ZINDEX_MAP_PANE = 11;
var ZINDEX_MAP_TILE = 12;
var ZINDEX_MAP_MESH = 13;
var ZINDEX_DRAWABLE = 14;
var ZINDEX_OPERATION_SHEET = 20;
var MAP_AREA_WIDTH = 720;		// area width pixel	
var MAP_AREA_HEIGHT = 332;		// area height pixel
var mapAreaElement = null;
var mapElement;
var mapOperationSheetElement;
function initializeMap()
{
	// get map area element
	mapAreaElement = document.getElementById("search_map_area");

	// create map element
	mapElement = document.createElement("div");
	mapElement.style.position = "absolute";
	setElementPosition(mapElement, 0, 0);
	mapElement.style.zIndex = ZINDEX_MAP;
	mapAreaElement.appendChild(mapElement);

	// create map operation sheet element
	mapOperationSheetElement = document.createElement("div");
	mapOperationSheetElement.style.position = "absolute";
	setElementSize(mapOperationSheetElement, MAP_AREA_WIDTH, MAP_AREA_HEIGHT);
	mapOperationSheetElement.style.zIndex = ZINDEX_OPERATION_SHEET;
	setOperationCursor(OPERATION_CURSOR_HAND_OPEN);
	mapOperationSheetElement.style.backgroundColor = "#FFFFFF";	// for IE
	setOpacity(mapOperationSheetElement, 0);					// for IE
	addListener(mapOperationSheetElement, "mousedown", mouseDownOnMap, false);
	addListener(mapOperationSheetElement, "mousemove", mouseMoveOnMap, false);
	addListener(mapOperationSheetElement, "dblclick", doubleClickOnMap, false);
	addMouseWheelListener(mapOperationSheetElement, wheelOnMap, false);
	mapAreaElement.appendChild(mapOperationSheetElement);
}
var OPERATION_CURSOR_HAND_OPEN = 0;
var OPERATION_CURSOR_HAND_CLOSE = 1;
var OPERATION_CURSOR_DIRECT_UNAVAIL = 10;
var OPERATION_CURSOR_DIRECT_PLUS = 11;
var OPERATION_CURSOR_DIRECT_MINUS = 12;
var OPERATION_CURSOR_DRAW = 20;
preLoadImage("./cursors/hand_open.cur");
preLoadImage("./cursors/hand_close.cur");
preLoadImage("./cursors/direct_unavail.cur");
preLoadImage("./cursors/direct_plus.cur");
preLoadImage("./cursors/direct_minus.cur");
var cursorTypeCurrent = null;
function setOperationCursor(cursorType)
{
	if(cursorType == cursorTypeCurrent) return;
	switch(cursorType)
	{
		case OPERATION_CURSOR_HAND_OPEN:
			mapOperationSheetElement.style.cursor = "url(./cursors/hand_open.cur), pointer"
			break;
		case OPERATION_CURSOR_HAND_CLOSE:
			mapOperationSheetElement.style.cursor = "url(./cursors/hand_close.cur), pointer"
			break;
		case OPERATION_CURSOR_DIRECT_UNAVAIL:
			mapOperationSheetElement.style.cursor = "url(./cursors/direct_unavail.cur), pointer"
			break;
		case OPERATION_CURSOR_DIRECT_PLUS:
			mapOperationSheetElement.style.cursor = "url(./cursors/direct_plus.cur), pointer"
			break;
		case OPERATION_CURSOR_DIRECT_MINUS:
			mapOperationSheetElement.style.cursor = "url(./cursors/direct_minus.cur), pointer"
			break;
		case OPERATION_CURSOR_DRAW:
			mapOperationSheetElement.style.cursor = "crosshair";
			break;
	}
	cursorTypeCurrent = cursorType;
}
var PIXEL_PER_DEGREE = 2;		// pixel per degree at 1x
var MAP_PANE_WIDTH = 180;		// image tile width pixel
var MAP_PANE_HEIGHT = 166;		// image tile height pixel
var DEGREE_WIDTH = 360;			// degree width
var DEGREE_HEIGHT = 166;		// degree height
var PANE_COUNT_X_1X = MAP_AREA_WIDTH / MAP_PANE_WIDTH;
var PANE_COUNT_Y_1X = MAP_AREA_HEIGHT / MAP_PANE_HEIGHT;
var DEGREE_PER_TILE_WIDTH = 1;
var DEGREE_PER_TILE_HEIGHT = 1;
var SURPLUS_SHOWING_PANE = 4;
var MINIMUM_MESH_SHOWING_MAGNIFICATION = 4;
var mapMagnification = 1;		// 1...32
var mapMagnificationBase = 1;	// 1, 2, 4, 8, 16, 32
var mapOffsetX = 0;				// 0...<360
var mapOffsetY = 0;				// 0...<166
var imageStepFactor = Math.sqrt(1.5);	// sqrt(1.0...<4.0)
var imageStep1 = 1 * imageStepFactor;
var imageStep2 = 2 * imageStepFactor;
var imageStep4 = 4 * imageStepFactor;
var imageStep8 = 8 * imageStepFactor;
var imageStep16 = 16 * imageStepFactor;
//var imageStep1 = 32 * imageStepFactor;	// useless
var mapPanesDem1 = null;
var mapPanesDem2 = null;
var mapPanesDem4 = null;
var mapPanesDem8 = null;
var mapPanesDem16 = null;
var mapPanesDem32 = null;
var mapPanesNum1 = null;
var mapPanesNum2 = null;
var mapPanesNum4 = null;
var mapPanesNum8 = null;
var mapPanesNum16 = null;
var mapPanesNum32 = null;
var mapPanesCurrent = null;
var mapPanesMesh1 = null;
var mapPanesMesh2 = null;
var mapPanesMesh4 = null;
var mapPanesMesh8 = null;
var mapPanesMesh16 = null;
var mapPanesMesh32 = null;
var mapPanesMeshCurrent = null;
var paneCountXCurrent = null;
var paneIndexXFromCurrent = null;
var paneIndexYFromCurrent = null;
var paneIndexXToCurrent = null;
var paneIndexYToCurrent = null;
var mapSelectedTiles = null;
var tileWidthCurrent = -1;
var tileHeightCurrent = -1;
var tileDisplayOffsetXCurrent = 0;
var tileDisplayOffsetYCurrent = 0;
var tileIndexXFromCurrent = null;
var tileIndexYFromCurrent = null;
var tileIndexXToCurrent = null;
var tileIndexYToCurrent = null;
function reshowMap()
{
	showMap(SHOW_MAP_MODE_RESHOW, null, null, null, null, null);
}
function showMapWithAnchorZooming(newMapMagnification, anchorXScreen, anchorYScreen)
{
	showMap(SHOW_MAP_MODE_ANCHOR_ZOOMING, newMapMagnification, anchorXScreen, anchorYScreen, null, null);
}
function showMapWithOffsetZooming(newMapMagnification, newMapOffsetX, newMapOffsetY)
{
	showMap(SHOW_MAP_MODE_OFFSET_ZOOMING, newMapMagnification, null, null, newMapOffsetX, newMapOffsetY);
}
function showMapWithOffset(newMapOffsetX, newMapOffsetY)
{
	showMap(SHOW_MAP_MODE_OFFSET, null, null, null, newMapOffsetX, newMapOffsetY);
}
var SHOW_MAP_MODE_RESHOW = 0;
var SHOW_MAP_MODE_ANCHOR_ZOOMING = 1;
var SHOW_MAP_MODE_OFFSET_ZOOMING = 2;
var SHOW_MAP_MODE_OFFSET = 3;
var ANCHOR_CENTER = -1;
function showMap(showMapMode, newMapMagnification, anchorXScreen, anchorYScreen, newMapOffsetX, newMapOffsetY)
{
	// get pixel per degree at current magnification
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

	// get degree of showing region at current magnification
	var degreeWidth = DEGREE_WIDTH / mapMagnification;
	var degreeHeight = DEGREE_HEIGHT / mapMagnification;
	//console.info(degreeWidth + "/" + degreeHeight);

	// in case magnification changed at anchor
	if(showMapMode == SHOW_MAP_MODE_ANCHOR_ZOOMING)
	{
		// get anchor position on screen
		if(anchorXScreen == ANCHOR_CENTER) anchorXScreen = MAP_AREA_WIDTH / 2;
		if(anchorYScreen == ANCHOR_CENTER) anchorYScreen = MAP_AREA_HEIGHT / 2;
		//console.info(anchorXScreen + "/" + anchorYScreen);

		// get anchor degree
		var anchorX = anchorXScreen / pixelPerDegree;
		var anchorY = anchorYScreen / pixelPerDegree;
		//console.info(anchorX + "/" + anchorY);
		anchorX += mapOffsetX;
		anchorY += mapOffsetY;
		//console.info(anchorX + "/" + anchorY);

		// change magnification
		mapMagnification = newMapMagnification;

		// get pixel per degree at new magnification
		pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

		// get degree of showing region at new magnification
		degreeWidth = DEGREE_WIDTH / mapMagnification;
		degreeHeight = DEGREE_HEIGHT / mapMagnification;
		//console.info(degreeWidth + "/" + degreeHeight);

		// reset map offset in accordance with new magnification
		var anchorDistanceX = anchorXScreen / pixelPerDegree;
		var anchorDistanceY = anchorYScreen / pixelPerDegree;
		//console.info(anchorDistanceX + "/" + anchorDistanceY);
		mapOffsetX = anchorX - anchorDistanceX;
		if(mapOffsetX < 0) mapOffsetX += 360;
		if(360 <= mapOffsetX) mapOffsetX -= 360;
		mapOffsetY = anchorY - anchorDistanceY;
		if(mapOffsetY < 0) mapOffsetY = 0;
		if(DEGREE_HEIGHT < (mapOffsetY + degreeHeight)) mapOffsetY = DEGREE_HEIGHT - degreeHeight;
		//console.info(mapOffsetX + "/" + mapOffsetY);

		// redraw at polygon drawing
		if(isPolygonDrawing == true) redrawPolygon();

		// reshow specified region box
		if(specifiedRegionBoxElement != null) showSpecifiedRegionBox();
	}

	// in case magnification changed with scroll
	if(showMapMode == SHOW_MAP_MODE_OFFSET_ZOOMING)
	{
		// change magnification
		mapMagnification = newMapMagnification;

		// get pixel per degree at new magnification
		pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;

		// get degree of showing region at new magnification
		degreeWidth = DEGREE_WIDTH / mapMagnification;
		degreeHeight = DEGREE_HEIGHT / mapMagnification;
		//console.info(degreeWidth + "/" + degreeHeight);

		// change map offset
		mapOffsetX = newMapOffsetX;
		mapOffsetY = newMapOffsetY;

		// redraw at polygon drawing
		if(isPolygonDrawing == true) redrawPolygon();

		// reshow specified region box
		if(specifiedRegionBoxElement != null) showSpecifiedRegionBox();
	}

	// in case execute scroll without magnification changing
	if(showMapMode == SHOW_MAP_MODE_OFFSET)
	{
		// change map offset
		mapOffsetX = newMapOffsetX;
		mapOffsetY = newMapOffsetY;

		// redraw at polygon drawing
		if(isPolygonDrawing == true) redrawPolygon();

		// reshow specified region box
		if(specifiedRegionBoxElement != null) showSpecifiedRegionBox();
	}

	// decide base magnification
	if(mapMagnification < imageStep1) mapMagnificationBase = 1;
	else if(mapMagnification < imageStep2) mapMagnificationBase = 2;
	else if(mapMagnification < imageStep4) mapMagnificationBase = 4;
	else if(mapMagnification < imageStep8) mapMagnificationBase = 8
	else if(mapMagnification < imageStep16) mapMagnificationBase = 16;
	else mapMagnificationBase = 32;

	// get pane count
	var paneCountX = PANE_COUNT_X_1X * mapMagnificationBase;
	var paneCountY = PANE_COUNT_Y_1X * mapMagnificationBase;

	// decide target pane indexes
	var degreePerPaneWidth = DEGREE_WIDTH / paneCountX;
	var degreePerPaneHeight = DEGREE_HEIGHT / paneCountY;
	//console.info(degreePerPaneWidth + "/" + degreePerPaneHeight);
	var paneIndexXFrom = Math.floor(mapOffsetX / degreePerPaneWidth);
	var paneIndexYFrom = Math.floor(mapOffsetY / degreePerPaneHeight);
	var paneIndexXTo = Math.ceil((mapOffsetX + degreeWidth) / degreePerPaneWidth) - 1;
	var paneIndexYTo = Math.ceil((mapOffsetY + degreeHeight) / degreePerPaneHeight) - 1;
	//console.info(paneIndexXFrom + "/" + paneIndexYFrom + "/" + paneIndexXTo + "/" + paneIndexYTo);

	// get pane size to display
	var paneWidth = (MAP_PANE_WIDTH * mapMagnification) / mapMagnificationBase;
	var paneHeight = (MAP_PANE_HEIGHT * mapMagnification) / mapMagnificationBase;

	// get left-top pane position to display
	var paneLeftX = paneIndexXFrom * degreePerPaneWidth;
	var paneTopY = paneIndexYFrom * degreePerPaneHeight;
	var paneDisplayOffsetX = (paneLeftX - mapOffsetX) * pixelPerDegree;
	var paneDisplayOffsetY = (paneTopY - mapOffsetY) * pixelPerDegree;
	paneDisplayOffsetX -= paneWidth * paneIndexXFrom;
	paneDisplayOffsetY -= paneHeight * paneIndexYFrom;
	//console.info(paneDisplayOffsetX + "/" + paneDisplayOffsetY);
	var displayOffset = getElementPosition(mapElement);
	paneDisplayOffsetX -= displayOffset.left;
	paneDisplayOffsetY -= displayOffset.top;
	//console.info(paneDisplayOffsetX + "/" + paneDisplayOffsetY);

	// decide mesh showing
	var doShowMeshActually = doShowMesh;
	if(mapMagnification < MINIMUM_MESH_SHOWING_MAGNIFICATION)
	{
		if(checkboxShowMesh.isEnabled == true) checkboxShowMesh.setEnablement(false);
		doShowMeshActually = false;
	}
	else
	{
		if(checkboxShowMesh.isEnabled == false) checkboxShowMesh.setEnablement(true);
	}

	// decide map pane collection
	var mapPanes = null;
	var mapMeshPanes = null;
	switch(mapMagnificationBase)
	{
		case 1:
			if(currentMapTypeIndex == MAP_TYPE_INDEX_DEM)
			{
				if(!mapPanesDem1) mapPanesDem1 = new Array();
				mapPanes = mapPanesDem1;
			}
			else if(currentMapTypeIndex == MAP_TYPE_INDEX_NUM)
			{
				if(!mapPanesNum1) mapPanesNum1 = new Array();
				mapPanes = mapPanesNum1;
			}
			else return;
			if(doShowMeshActually == true)
			{
				if(!mapPanesMesh1) mapPanesMesh1 = new Array();
				mapMeshPanes = mapPanesMesh1;
			}
			break;
		case 2:
			if(currentMapTypeIndex == MAP_TYPE_INDEX_DEM)
			{
				if(!mapPanesDem2) mapPanesDem2 = new Array();
				mapPanes = mapPanesDem2;
			}
			else if(currentMapTypeIndex == MAP_TYPE_INDEX_NUM)
			{
				if(!mapPanesNum2) mapPanesNum2 = new Array();
				mapPanes = mapPanesNum2;
			}
			else return;
			if(doShowMeshActually == true)
			{
				if(!mapPanesMesh2) mapPanesMesh2 = new Array();
				mapMeshPanes = mapPanesMesh2;
			}
			break;
		case 4:
			if(currentMapTypeIndex == MAP_TYPE_INDEX_DEM)
			{
				if(!mapPanesDem4) mapPanesDem4 = new Array();
				mapPanes = mapPanesDem4;
			}
			else if(currentMapTypeIndex == MAP_TYPE_INDEX_NUM)
			{
				if(!mapPanesNum4) mapPanesNum4 = new Array();
				mapPanes = mapPanesNum4;
			}
			else return;
			if(doShowMeshActually == true)
			{
				if(!mapPanesMesh4) mapPanesMesh4 = new Array();
				mapMeshPanes = mapPanesMesh4;
			}
			break;
		case 8:
			if(currentMapTypeIndex == MAP_TYPE_INDEX_DEM)
			{
				if(!mapPanesDem8) mapPanesDem8 = new Array();
				mapPanes = mapPanesDem8;
			}
			else if(currentMapTypeIndex == MAP_TYPE_INDEX_NUM)
			{
				if(!mapPanesNum8) mapPanesNum8 = new Array();
				mapPanes = mapPanesNum8;
			}
			else return;
			if(doShowMeshActually == true)
			{
				if(!mapPanesMesh8) mapPanesMesh8 = new Array();
				mapMeshPanes = mapPanesMesh8;
			}
			break;
		case 16:
			if(currentMapTypeIndex == MAP_TYPE_INDEX_DEM)
			{
				if(!mapPanesDem16) mapPanesDem16 = new Array();
				mapPanes = mapPanesDem16;
			}
			else if(currentMapTypeIndex == MAP_TYPE_INDEX_NUM)
			{
				if(!mapPanesNum16) mapPanesNum16 = new Array();
				mapPanes = mapPanesNum16;
			}
			else return;
			if(doShowMeshActually == true)
			{
				if(!mapPanesMesh16) mapPanesMesh16 = new Array();
				mapMeshPanes = mapPanesMesh16;
			}
			break;
		case 32:
			if(currentMapTypeIndex == MAP_TYPE_INDEX_DEM)
			{
				if(!mapPanesDem32) mapPanesDem32 = new Array();
				mapPanes = mapPanesDem32;
			}
			else if(currentMapTypeIndex == MAP_TYPE_INDEX_NUM)
			{
				if(!mapPanesNum32) mapPanesNum32 = new Array();
				mapPanes = mapPanesNum32;
			}
			else return;
			if(doShowMeshActually == true)
			{
				if(!mapPanesMesh32) mapPanesMesh32 = new Array();
				mapMeshPanes = mapPanesMesh32;
			}
			break;
	}

	// expand showing pane
	paneIndexXFrom -= SURPLUS_SHOWING_PANE;
	paneIndexXTo += SURPLUS_SHOWING_PANE;
	if(paneCountX <= (paneIndexXTo - paneIndexXFrom))
	{
		var supplementableCount = (paneIndexXTo - paneIndexXFrom + 1) - paneCountX;
		var reduceLeft = Math.floor(supplementableCount / 2);
		paneIndexXFrom += reduceLeft;
		paneIndexXTo -= (supplementableCount - reduceLeft);
	}
	paneIndexYFrom -= SURPLUS_SHOWING_PANE;
	if(paneIndexYFrom < 0) paneIndexYFrom = 0;
	paneIndexYTo += SURPLUS_SHOWING_PANE;
	if(paneCountY <= paneIndexYTo) paneIndexYTo = paneCountY - 1;

	// show map panes
	var showingPaneX = Math.floor((paneWidth * paneIndexXFrom) + paneDisplayOffsetX);
	for(var indexX = paneIndexXFrom; indexX <= paneIndexXTo; indexX++)
	{
		var mapIndexX = indexX;
		while(mapIndexX < 0) {mapIndexX += paneCountX};
		mapIndexX %= paneCountX;
		if(!mapPanes[mapIndexX]) mapPanes[mapIndexX] = new Array();
		var mapPaneLine = mapPanes[mapIndexX];
		if(doShowMeshActually == true)
		{
			if(!mapMeshPanes[mapIndexX]) mapMeshPanes[mapIndexX] = new Array();
			var mapPaneMeshLine = mapMeshPanes[mapIndexX];
		}
		var nextPaneX = Math.floor((paneWidth * (indexX + 1)) + paneDisplayOffsetX);
		var showingPaneY = Math.floor((paneHeight * paneIndexYFrom) + paneDisplayOffsetY);
		for(var y = paneIndexYFrom; y <= paneIndexYTo; y++)
		{
			var nextPaneY = Math.floor((paneHeight * (y + 1)) + paneDisplayOffsetY);
			var showingPaneWidth = nextPaneX - showingPaneX;
			var showingPaneHeight = nextPaneY - showingPaneY;
			if(!mapPaneLine[y])
			{
				mapPaneLine[y] = createMapPaneImage(mapMagnificationBase, mapIndexX, y);
			}
			showMapPane(mapPaneLine[y], showingPaneX, showingPaneY, showingPaneWidth, showingPaneHeight);
			if(doShowMeshActually == true)
			{
				if(!mapPaneMeshLine[y])
				{
					mapPaneMeshLine[y] = createMapPaneMeshImage(mapMagnificationBase, mapIndexX, y);
				}
				showMapPane(mapPaneMeshLine[y], showingPaneX, showingPaneY, showingPaneWidth, showingPaneHeight);
			}
			showingPaneY = nextPaneY;
		}
		showingPaneX = nextPaneX;
	}

	// hide disused map panes
	var paneMapIndexXFrom = paneIndexXFrom;
	while(paneMapIndexXFrom < 0) {paneMapIndexXFrom += paneCountX};
	paneMapIndexXFrom %= paneCountX;
	var paneMapIndexXTo = paneIndexXTo;
	while(paneMapIndexXTo < 0) {paneMapIndexXTo += paneCountX};
	paneMapIndexXTo %= paneCountX;
	if(mapPanesCurrent != null)
	{
		if(mapPanesCurrent == mapPanes)
		{
			for(var indexX = paneIndexXFromCurrent; indexX <= paneIndexXToCurrent; indexX++)
			{
				var mapIndexX = indexX;
				while(mapIndexX < 0) {mapIndexX += paneCountXCurrent};
				mapIndexX %= paneCountXCurrent;
				if(!mapPanesCurrent[mapIndexX]) continue;
				var mapPaneLine = mapPanesCurrent[mapIndexX];
				for(var y = paneIndexYFromCurrent; y <= paneIndexYToCurrent; y++)
				{
					if(!mapPaneLine[y]) continue;
					if(y < paneIndexYFrom) {hideMapPane(mapPaneLine[y]); continue;}
					if(paneIndexYTo < y) {hideMapPane(mapPaneLine[y]); continue;}
					if(paneMapIndexXFrom < paneMapIndexXTo)
					{
						if((mapIndexX < paneMapIndexXFrom) || (paneMapIndexXTo < mapIndexX)) {hideMapPane(mapPaneLine[y]); continue;}
					}
					else if(paneMapIndexXTo < paneMapIndexXFrom)
					{
						if((paneMapIndexXTo < mapIndexX) && (mapIndexX < paneMapIndexXFrom)) {hideMapPane(mapPaneLine[y]); continue;}
					}
				}
			}
		}
		else hideMapPanes(mapPanesCurrent);
	}
	if(mapPanesMeshCurrent != null)
	{
		if(mapPanesMeshCurrent == mapMeshPanes)
		{
			for(var indexX = paneIndexXFromCurrent; indexX <= paneIndexXToCurrent; indexX++)
			{
				var mapIndexX = indexX;
				while(mapIndexX < 0) {mapIndexX += paneCountXCurrent};
				mapIndexX %= paneCountXCurrent;
				if(!mapPanesMeshCurrent[mapIndexX]) continue;
				var mapPaneMeshLine = mapPanesMeshCurrent[mapIndexX];
				for(var y = paneIndexYFromCurrent; y <= paneIndexYToCurrent; y++)
				{
					if(!mapPaneMeshLine[y]) continue;
					if(y < paneIndexYFrom) {hideMapPane(mapPaneMeshLine[y]); continue;}
					if(paneIndexYTo < y) {hideMapPane(mapPaneMeshLine[y]); continue;}
					if(paneMapIndexXFrom < paneMapIndexXTo)
					{
						if((mapIndexX < paneMapIndexXFrom) || (paneMapIndexXTo < mapIndexX)) {hideMapPane(mapPaneMeshLine[y]); continue;}
					}
					else if(paneMapIndexXTo < paneMapIndexXFrom)
					{
						if((paneMapIndexXTo < mapIndexX) && (mapIndexX < paneMapIndexXFrom)) {hideMapPane(mapPaneMeshLine[y]); continue;}
					}
				}
			}
		}
		else hideMapPanes(mapPanesMeshCurrent);
	}

	// preserve map showing factors
	mapPanesCurrent = mapPanes;
	mapPanesMeshCurrent = mapMeshPanes;
	paneCountXCurrent = paneCountX;
	paneIndexXFromCurrent = paneIndexXFrom;
	paneIndexYFromCurrent = paneIndexYFrom;
	paneIndexXToCurrent = paneIndexXTo;
	paneIndexYToCurrent = paneIndexYTo;

	// decide target tile indexes
	var tileIndexXFrom = Math.floor(mapOffsetX / DEGREE_PER_TILE_WIDTH);
	var tileIndexYFrom = Math.floor(mapOffsetY / DEGREE_PER_TILE_HEIGHT);
	var tileIndexXTo = Math.ceil((mapOffsetX + degreeWidth) / DEGREE_PER_TILE_WIDTH) - 1;
	var tileIndexYTo = Math.ceil((mapOffsetY + degreeHeight) / DEGREE_PER_TILE_HEIGHT) - 1;
	//console.info(tileIndexXFrom + "/" + tileIndexYFrom + "/" + tileIndexXTo + "/" + tileIndexYTo);

	// get tile size to display
	var tileWidth = PIXEL_PER_DEGREE * mapMagnification;
	var tileHeight = PIXEL_PER_DEGREE * mapMagnification;

	// get left-top tile position to display
	var tileLeftX = tileIndexXFrom * DEGREE_PER_TILE_WIDTH;
	var tileTopY = tileIndexYFrom * DEGREE_PER_TILE_HEIGHT;
	var tileDisplayOffsetX = (tileLeftX - mapOffsetX) * pixelPerDegree;
	var tileDisplayOffsetY = (tileTopY - mapOffsetY) * pixelPerDegree;
	//console.info(tileDisplayOffsetX + "/" + tileDisplayOffsetY);
	tileDisplayOffsetX -= tileWidth * tileIndexXFrom;
	tileDisplayOffsetY -= tileHeight * tileIndexYFrom;
	//console.info(tileDisplayOffsetX + "/" + tileDisplayOffsetY);

	// prepare selected tile collection
	if(!mapSelectedTiles) mapSelectedTiles = new Array();

	// show and hide map tiles
	var tileMapIndexXFrom = tileIndexXFrom;
	while(tileMapIndexXFrom < 0) {tileMapIndexXFrom += 360};
	tileMapIndexXFrom %= 360;
	var tileMapIndexXTo = tileIndexXTo;
	while(tileMapIndexXTo < 0) {tileMapIndexXTo += 360};
	tileMapIndexXTo %= 360;
	for(var i = 0, n = mapSelectedTiles.length; i < n; i++)
	{
		var mapTileElement = mapSelectedTiles[i];
		var doMap = false;
		if(tileIndexYFrom <= mapTileElement.indexY)
		{
			if(mapTileElement.indexY <= tileIndexYTo)
			{
				if(tileMapIndexXFrom < tileMapIndexXTo)
				{
					if((tileMapIndexXFrom <= mapTileElement.indexX) && (mapTileElement.indexX <= tileMapIndexXTo)) doMap = true;
				}
				else if(tileMapIndexXTo < tileMapIndexXFrom)
				{
					if((mapTileElement.indexX <= tileMapIndexXTo) || (tileMapIndexXFrom <= mapTileElement.indexX)) doMap = true;
				}
				else doMap = true;
			}
		}
		if(doMap == false)
		{
			if(mapTileElement.isMapped == true) hideMapTile(mapTileElement);
			continue;
		}
		showMapTile(mapTileElement, tileWidth, tileHeight, mapTileElement.indexX, mapTileElement.indexY, tileDisplayOffsetX, tileDisplayOffsetY, displayOffset);
	}

	// preserve tile showing factors
	tileWidthCurrent = tileWidth;
	tileHeightCurrent = tileHeight;
	tileDisplayOffsetXCurrent = tileDisplayOffsetX;
	tileDisplayOffsetYCurrent = tileDisplayOffsetY;
	tileIndexXFromCurrent = tileIndexXFrom;
	tileIndexYFromCurrent = tileIndexYFrom;
	tileIndexXToCurrent = tileIndexXTo;
	tileIndexYToCurrent = tileIndexYTo;
}
var imageLoadCount = 0;
var imageLoadedCount = 0;
function createMapPaneImage(mapMagnificationBase, x, y)
{
	// create map pane and image element
	var mapPaneElement = document.createElement("div");
	setVisible(mapPaneElement, false);
	mapPaneElement.style.position = "absolute";
	mapPaneElement.style.zIndex = ZINDEX_MAP_PANE;
	var imageElement = document.createElement("img");
	var imageLoaded = function(e)
	{
		setVisible(mapPaneElement, true);
	}
	addListener(imageElement, "load", imageLoaded);
	imageElement.src = makeupMapPaneImageFileName(mapMagnificationBase, x, y);
	mapPaneElement.appendChild(imageElement);
	mapPaneElement.imageElement = imageElement;
	mapPaneElement.isMapped = false;
	mapPaneElement.paneX = -1;
	mapPaneElement.paneY = -1;
	mapPaneElement.paneWidth = -1;
	mapPaneElement.paneHeight = -1;
	return mapPaneElement;
}
function makeupMapPaneImageFileName(mapMagnificationBase, x, y)
{
	var mapType = (currentMapTypeIndex != MAP_TYPE_INDEX_DEM)? "num": "dem";
	var filePathName = "./datas/" + mapType + "/" +
		mapMagnificationBase + "x/m_" + intToString(x, 3) + "_" + intToString(y, 3) + ".jpg";
	//console.info(filePathName);
	return filePathName;
}
function createMapPaneMeshImage(mapMagnificationBase, x, y)
{
	// create map pane and image element
	var mapPaneElement = document.createElement("div");
	setVisible(mapPaneElement, false);
	mapPaneElement.style.position = "absolute";
	mapPaneElement.style.zIndex = ZINDEX_MAP_MESH;
	setOpacity(mapPaneElement, 50);
	var imageElement = document.createElement("img");
	var imageLoaded = function(e)
	{
		setVisible(mapPaneElement, true);
	}
	addListener(imageElement, "load", imageLoaded);
	imageElement.src = makeupMapPaneMeshImageFileName(mapMagnificationBase, x, y);
	mapPaneElement.appendChild(imageElement);
	mapPaneElement.imageElement = imageElement;
	mapPaneElement.isMapped = false;
	mapPaneElement.paneX = -1;
	mapPaneElement.paneY = -1;
	mapPaneElement.paneWidth = -1;
	mapPaneElement.paneHeight = -1;
	return mapPaneElement;
}
function makeupMapPaneMeshImageFileName(mapMagnificationBase, x, y)
{
	var filePathName = "./datas/mesh/" +
		mapMagnificationBase + "x/m_" + intToString(x, 3) + "_" + intToString(y, 3) + ".png";
	//console.info(filePathName);
	return filePathName;
}
function showMapPane(mapPaneElement, paneX, paneY, paneWidth, paneHeight)
{
	if(mapPaneElement.isMapped == false)
	{
		mapPaneElement.isMapped = true;
		mapElement.appendChild(mapPaneElement);
	}
	if((mapPaneElement.paneX != paneX) || (mapPaneElement.paneY != paneY))
	{
		mapPaneElement.paneX = paneX;
		mapPaneElement.paneY = paneY;
		setElementPosition(mapPaneElement, paneX, paneY);
	}
	if((mapPaneElement.paneWidth != paneWidth) || (mapPaneElement.paneHeight != paneHeight))
	{
		mapPaneElement.paneWidth = paneWidth;
		mapPaneElement.paneHeight = paneHeight;
		mapPaneElement.imageElement.width = (mapMagnificationBase == 1)? paneWidth * 2: paneWidth;
		mapPaneElement.imageElement.height = paneHeight;
	}
}
function hideMapPanes(mapPanes)
{
	if(mapPanes == null) return;
	for(x in mapPanes)
	{
		var mapPaneLine = mapPanes[x];
		for(y in mapPaneLine)
		{
			hideMapPane(mapPaneLine[y]);
		}
	}
}
function hideMapPane(mapPaneElement)
{
	if(mapPaneElement.isMapped == true)
	{
		mapPaneElement.isMapped = false;
		mapElement.removeChild(mapPaneElement);
	}
}
function createMapTile(indexX, indexY)
{
	// create map tile element
	var mapTileElement = document.createElement("div");
	mapTileElement.style.position = "absolute";
	mapTileElement.style.zIndex = ZINDEX_MAP_TILE;
	mapTileElement.style.fontSize = "1px";
//	var mapTileFaceElement = document.createElement("div");
//	mapTileFaceElement.style.width = "100%";
//	mapTileFaceElement.style.height = "100%";
//	mapTileFaceElement.style.fontSize = "1px";
//	mapTileElement.appendChild(mapTileFaceElement);
//	mapTileElement.mapTileFaceElement = mapTileFaceElement;
	mapTileElement.isMapped = false;
	mapTileElement.indexX = indexX;
	mapTileElement.indexY = indexY;
//	mapTileElement.tileX = -1;
//	mapTileElement.tileY = -1;
//	mapTileElement.tileWidth = -1;
//	mapTileElement.tileHeight = -1;
	mapSelectedTiles.push(mapTileElement);
	return mapTileElement;
}
function destroyMapTile(targetMapTileElement)
{
	for(var i = 0, n = mapSelectedTiles.length; i < n; i++)
	{
		var mapTileElement = mapSelectedTiles[i];
		if(mapTileElement.indexX != targetMapTileElement.indexX) continue;
		if(mapTileElement.indexY != targetMapTileElement.indexY) continue;
		removeElementFromArray(mapSelectedTiles, i);
		break;
	}
}
function mapSingleTile(mapTileElement)
{
	var tileMapIndexXFrom = tileIndexXFromCurrent;
	while(tileMapIndexXFrom < 0) {tileMapIndexXFrom += 360};
	tileMapIndexXFrom %= 360;
	var tileMapIndexXTo = tileIndexXToCurrent;
	while(tileMapIndexXTo < 0) {tileMapIndexXTo += 360};
	tileMapIndexXTo %= 360;
	var indexX = mapTileElement.indexX;
	var indexY = mapTileElement.indexY;
	var doMap = false;
	if(tileIndexYFromCurrent <= indexY)
	{
		if(indexY <= tileIndexYToCurrent)
		{
			if(tileMapIndexXFrom < tileMapIndexXTo)
			{
				if((tileMapIndexXFrom <= indexX) && (indexX <= tileMapIndexXTo)) doMap = true;
			}
			else if(tileMapIndexXTo < tileMapIndexXFrom)
			{
				if((indexX <= tileMapIndexXTo) || (tileMapIndexXFrom <= indexX)) doMap = true;
			}
			else doMap = true;
		}
	}
	if(doMap == false)
	{
		hideMapTile(mapTileElement);
		return;
	}
	var displayOffset = getElementPosition(mapElement);
	showMapTile(mapTileElement, tileWidthCurrent, tileHeightCurrent, indexX, indexY, tileDisplayOffsetXCurrent, tileDisplayOffsetYCurrent, displayOffset);
}
function showMapTile(mapTileElement, tileWidth, tileHeight, indexX, indexY, tileDisplayOffsetX, tileDisplayOffsetY, displayOffset)
{
	// show tile
	if(mapTileElement.isMapped == false)
	{
		mapTileElement.isMapped = true;
		mapElement.appendChild(mapTileElement);
	}

	// get tile position
	var showingTileX = (tileWidth * indexX) + tileDisplayOffsetX;
	var showingTileY = (tileHeight * indexY) + tileDisplayOffsetY;
	var rotationShift = MAP_AREA_WIDTH * mapMagnification;
	if((showingTileX + tileWidth) < 0)
	{
		while((showingTileX + tileWidth) < 0) showingTileX += rotationShift;
	}
	else if(rotationShift <= (showingTileX + tileWidth))
	{
		while(rotationShift <= (showingTileX + tileWidth)) showingTileX -= rotationShift;
	}
	showingTileX = Math.floor(showingTileX - displayOffset.left);
	showingTileY = Math.floor(showingTileY - displayOffset.top);

	// set tile position
	setElementPosition(mapTileElement, showingTileX, showingTileY);

	// get next tile position
	var nextTileX = (tileWidth * (indexX + 1)) + tileDisplayOffsetX;
	var nextTileY = (tileHeight * (indexY + 1)) + tileDisplayOffsetY;
	if((nextTileX + tileWidth) < 0)
	{
		while((nextTileX + tileWidth) < 0) nextTileX += rotationShift;
	}
	else if(rotationShift <= (nextTileX + tileWidth))
	{
		while(rotationShift <= (nextTileX + tileWidth)) nextTileX -= rotationShift;
	}
	nextTileX = Math.floor(nextTileX - displayOffset.left);
	nextTileY = Math.floor(nextTileY - displayOffset.top);

	// set tile size
	var showingTileWidth = nextTileX - showingTileX;
	var showingTileHeight = nextTileY - showingTileY;
	setElementSize(mapTileElement, showingTileWidth, showingTileHeight);
}
function hideMapTile(mapTileElement)
{
	if(mapTileElement.isMapped == true)
	{
		mapTileElement.isMapped = false;
		mapElement.removeChild(mapTileElement);
	}
}
var INDICATE_TILE_SELECTED = 0;
var INDICATE_TILE_NEW = 1;
var SELECTED_TILE_COLOR = "#3366FF";	// pale
//var SELECTED_TILE_COLOR = "#FF0000";	// dev
//var SELECTED_TILE_COLOR = "#AA3333";	// warm
var SELECTED_TILE_OPACITY = 50;
var FLASH_TILE_COLOR = "#DD6666";
//var FLASH_TILE_COLOR = "#FF6666";
var FLASH_TILE_OPACITY = 100;
var TILE_FLASH_STEP = 10;
function indicateTile(mapTileElement, indicateType, terminatedFunction)
{
	if(indicateType == INDICATE_TILE_SELECTED)
	{
		mapTileElement.style.backgroundColor = SELECTED_TILE_COLOR;
		setOpacity(mapTileElement, SELECTED_TILE_OPACITY);
//		mapTileElement.mapTileFaceElement.style.border = "1px solid #000000";
//		setOpacity(mapTileElement.mapTileFaceElement, 100);
		return;
	}

	if(indicateType == INDICATE_TILE_NEW)
	{
		setOpacity(mapTileElement, 0);
		mapTileElement.style.backgroundColor = FLASH_TILE_COLOR;
		var step = 0;
		var tileFlash = function()
		{
			step++;
			if(TILE_FLASH_STEP <= step)
			{
				window.clearInterval(timerIdTileFlash);
				mapTileElement.style.backgroundColor = SELECTED_TILE_COLOR;
				setOpacity(mapTileElement, SELECTED_TILE_OPACITY);
				if(terminatedFunction) terminatedFunction();
				return;
			}
			setOpacity(mapTileElement, (step * FLASH_TILE_OPACITY) / TILE_FLASH_STEP);
		}
		var timerIdTileFlash = window.setInterval(tileFlash, 30);
		return;
	}
}
var TILE_FADE_STEP = 10;
function fadeTile(mapTileElement, terminatedFunction)
{
	var step = 0;
	var tileFade = function()
	{
		step++;
		if(TILE_FADE_STEP <= step)
		{
			window.clearInterval(timerIdTileFade);
			if(terminatedFunction) terminatedFunction();
			return;
		}
		setOpacity(mapTileElement, ((TILE_FLASH_STEP - step) * SELECTED_TILE_OPACITY) / TILE_FLASH_STEP);
	}
	var timerIdTileFade = window.setInterval(tileFade, 50);
}

// [direct] operation
var isDirectSelecting = false;
function changeSearchDirectSelecting(actionCheckBox)
{
	isDirectSelecting = actionCheckBox.isDown? true: false;
	if(isDirectSelecting == false) setOperationCursor(OPERATION_CURSOR_HAND_OPEN);
}
function changeCursorAtDirectSelection(x, y)
{
	var indexX = screenXToTileIndex(x);
	var indexY = screenYToTileIndex(y);
	if((isVaildTile(indexX, indexY) == false) || (mapMagnification < 4))
	{
		setOperationCursor(OPERATION_CURSOR_DIRECT_UNAVAIL);
		return;
	}
	for(var i = 0, n = mapSelectedTiles.length; i < n; i++)
	{
		var mapTileElement = mapSelectedTiles[i];
		if(mapTileElement.indexX != indexX) continue;
		if(mapTileElement.indexY != indexY) continue;
		setOperationCursor(OPERATION_CURSOR_DIRECT_MINUS);
		return;
	}
	setOperationCursor(OPERATION_CURSOR_DIRECT_PLUS);
}
function toggleSelectionOfTile(x, y)
{
	var indexX = screenXToTileIndex(x);
	var indexY = screenYToTileIndex(y);
	//console.info(indexX + "/" + indexY);
	if((isVaildTile(indexX, indexY) == false) || (mapMagnification < 4)) return;
	var mapTileElement = getSelectedMapTileElement(indexX, indexY);
	if(mapTileElement != null)
	{
		var fadedFunction = function()
		{
			setOperationCursor(OPERATION_CURSOR_DIRECT_PLUS);
			hideMapTile(mapTileElement);
			destroyMapTile(mapTileElement);
			showTileCount();
			checkSelectedTileCount();
		}
		fadeTile(mapTileElement, fadedFunction);
	}
	else
	{
		mapTileElement = createMapTile(indexX, indexY);
		mapSingleTile(mapTileElement);
		var indicatedFunction = function()
		{
			setOperationCursor(OPERATION_CURSOR_DIRECT_MINUS);
			showTileCount();
			checkSelectedTileCount();
		}
		indicateTile(mapTileElement, INDICATE_TILE_NEW, indicatedFunction);
	}
}
function cancelDirectOperation()
{
	if(isDirectSelecting == true)
	{
		isDirectSelecting = false;
		checkboxSearchDirect.setChecked(false);
		setOperationCursor(OPERATION_CURSOR_HAND_OPEN);
	}
}

// [polygon] operation
var isPolygonDrawing = false;
var polygonVertexes = new Array();
function startDrawPolygon(actionButton)
{
	setVisible(buttonSearchPolygonStart.buttonElement, false);
	setVisible(buttonSearchPolygonOk.buttonElement, true);
	setVisible(buttonSearchPolygonClear.buttonElement, true);
	isPolygonDrawing = true;
	setOperationCursor(OPERATION_CURSOR_DRAW);
	clearPolygon();
}
function addNewPolygonVertex(x, y)
{
	// get current vertex count
	var vertexCount = polygonVertexes.length;

	// create new vertex and add to array
	var vertex = new Object();
	vertex.x = screenXToDegree(x);
	if(1 <= vertexCount)
	{
		// get showing span
		var screenLeftDegree = mapOffsetX - 25;
		var screenRightDegree = screenLeftDegree + (DEGREE_WIDTH / mapMagnification);
		while(screenLeftDegree < 0) {screenLeftDegree += 360; screenRightDegree += 360;}
		while(360 <= screenLeftDegree) {screenLeftDegree -= 360; screenRightDegree -= 360;}
		//console.info(screenLeftDegree + "/" + screenRightDegree);

		// check last vertext visibility and manage new vertex
		var lastVertex = polygonVertexes[vertexCount - 1];
		var isLastVertextVisible = false;
		var lastVertexX = lastVertex.x;
		//console.info(vertex.x + "#" + lastVertexX)
		if((screenLeftDegree <= lastVertexX) && (lastVertexX < screenRightDegree))
		{
			if(vertex.x < screenLeftDegree) vertex.x += 360;
			isLastVertextVisible = true;
		}
		else
		{
			lastVertexX += 360;
			if((screenLeftDegree <= lastVertexX) && (lastVertexX < screenRightDegree))
			{
				if(screenRightDegree <= (vertex.x + 360)) vertex.x -= 360;
				isLastVertextVisible = true;
			}
		}
		if(isLastVertextVisible == false)
		{
			if(lastVertex.x < vertex.x)
			{
				if((lastVertex.x + 360 - vertex.x) < (vertex.x - lastVertex.x)) vertex.x -= 360;
			}
			else if(vertex.x < lastVertex.x)
			{
				if((vertex.x + 360 - lastVertex.x) < (lastVertex.x - vertex.x)) vertex.x += 360;
			}
		}
	}
	vertex.y = screenYToDegree(y);
	vertex.linePointElements = new Array();
	//console.info(x + "/" + vertex.x + "/" + degreeXToScreen(vertex.x));
	polygonVertexes.push(vertex);
	vertexCount++;

	// draw start point or side line
	if(vertexCount == 1) drawStartPoint(vertex);
	else if(2 <= vertexCount) drawSingleLine(polygonVertexes[vertexCount - 2], vertex);
	checkDrawnVertexCount();
}
function drawStartPoint(vertex)
{
	var scrollPos = getElementPosition(mapElement);
	var linePointElement =
		drawLinePoint(degreeXToScreen(vertex.x) - scrollPos.left, degreeYToScreen(vertex.y) - scrollPos.top);
	vertex.linePointElements.push(linePointElement);
}
function drawSingleLine(vertexFrom, vertexTo)
{
	var scrollPos = getElementPosition(mapElement);

	// decide span
	var spanX = vertexTo.x - vertexFrom.x;
	var spanXAbs = Math.abs(spanX);
	var spanY = vertexTo.y - vertexFrom.y;
	var spanYAbs = Math.abs(spanY);
	var span = (spanXAbs > spanYAbs)? spanXAbs: spanYAbs;
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;
	span *= pixelPerDegree;
	//console.info("span : " + span);
	for(var i = 1; i <= span; i++)
	{
		var pointX = vertexFrom.x + ((spanX * i) / span);
		var pointY = vertexFrom.y + ((spanY * i) / span);
		var linePointElement =
			drawLinePoint(degreeXToScreen(pointX) - scrollPos.left, degreeYToScreen(pointY) - scrollPos.top);
		vertexTo.linePointElements.push(linePointElement);
	}
}
function redrawPolygon()
{
	//var scrollPos = getElementPosition(mapElement);
	var vertexCount = polygonVertexes.length;
	if(1 <= vertexCount)
	{
		var vertex = polygonVertexes[0];
		var linePointElements = vertex.linePointElements;
		for(var j = linePointElements.length - 1; 0 <= j; j--)
		{
			mapElement.removeChild(linePointElements[j]);
			linePointElements[j] = null;
			linePointElements.pop();
		}
		drawStartPoint(vertex);
	}
	for(var vertexIndex = 1; vertexIndex < vertexCount; vertexIndex++)
	{
		var vertexFrom = polygonVertexes[vertexIndex - 1];
		var vertexTo = polygonVertexes[vertexIndex];
		var linePointElements = vertexTo.linePointElements;
		for(var j = linePointElements.length - 1; 0 <= j; j--)
		{
			mapElement.removeChild(linePointElements[j]);
			linePointElements[j] = null;
			linePointElements.pop();
		}
		drawSingleLine(vertexFrom, vertexTo);
	}
	if(2 <= vertexCount)
	{
		var vertexFrom = polygonVertexes[vertexCount - 1];
		var vertexTo = polygonVertexes[0];
		var linePointElements = vertexTo.linePointElements;
		if(1 < linePointElements.length)
		{
			for(var j = linePointElements.length - 1; 0 <= j; j--)
			{
				mapElement.removeChild(linePointElements[j]);
				linePointElements[j] = null;
				linePointElements.pop();
			}
			drawSingleLine(vertexFrom, vertexTo);
		}
	}
}
function clearPolygon()
{
	for(var i = polygonVertexes.length - 1; 0 <= i; i--)
	{
		var vertex = polygonVertexes[i];
		var linePointElements = vertex.linePointElements;
		for(var j = linePointElements.length - 1; 0 <= j; j--)
		{
			mapElement.removeChild(linePointElements[j]);
			linePointElements[j] = null;
			linePointElements.pop();
		}
		polygonVertexes.pop();
	}
	checkDrawnVertexCount();
}
var POLYGON_LINE_WIDTH = 2;
var POLYGON_LINE_COLOR = "#FF0000";
var POLYGON_LINE_OPACITY = 50;
function drawLinePoint(x, y)
{
	var pointElement = document.createElement("div");
	pointElement.style.position = "absolute";
	setElementSize(pointElement, POLYGON_LINE_WIDTH, POLYGON_LINE_WIDTH);
	setElementPosition(pointElement, x, y);
	pointElement.style.zIndex = ZINDEX_DRAWABLE;
	pointElement.style.backgroundColor = POLYGON_LINE_COLOR;
	pointElement.style.fontSize = "1px";
	setOpacity(pointElement, POLYGON_LINE_OPACITY);
	mapElement.appendChild(pointElement);
	return pointElement;
}
function checkDrawnVertexCount()
{
	buttonSearchPolygonOk.setEnablement((2 < polygonVertexes.length)? true: false);
}
function terminateDrawPolygon(actionButton)
{
	// close polygon
	var vertexCount = polygonVertexes.length;
	drawSingleLine(polygonVertexes[vertexCount - 1], polygonVertexes[0]);

	var okFunction = function()
	{
		// get applicable tiles
		var postData = "";
		for(var i = 0, n = polygonVertexes.length; i < n; i++)
		{
			var vertex = polygonVertexes[i];
			if(0 < i) postData += "&";
			postData += "_gd_search_polygon_x_" + i + "=" + encodeURIComponent(vertex.x);
			postData += "&";
			postData += "_gd_search_polygon_y_" + i + "=" + encodeURIComponent(vertex.y);
		}
		getTileList("gdServletAsyn/GetTileList_Polygon", postData);
		clearPolygon();
		escapeFromPolygonDrawing();
	}
	var cancelFunction = function()
	{
		clearPolygon();
		checkDrawnVertexCount();
	}
	doConfirm(searchBoxElement, 470, 110, 300, 50, messageDoFixPolygon, okFunction, cancelFunction);
}
function cancelDrawPolygon(actionButton)
{
	clearPolygon();
	escapeFromPolygonDrawing();
}
function escapeFromPolygonDrawing()
{
	setVisible(buttonSearchPolygonStart.buttonElement, true);
	setVisible(buttonSearchPolygonOk.buttonElement, false);
	setVisible(buttonSearchPolygonClear.buttonElement, false);
	isPolygonDrawing = false;
	setOperationCursor(OPERATION_CURSOR_HAND_OPEN);
}
function cancelPolygonOperation()
{
	if(isPolygonDrawing == true)
	{
		cancelDrawPolygon(null);
	}
}

// [shape file] operation
var isUploading = false;
function terminateSpecifyShapefile(actionButton)
{
	var submittedFunction = function(e)
	{
		if(isUploading == false) return;
		isUploading = false;
		getTileList("gdServletAsyn/GetTileList_Shapefile", "");
	}
	addListener(iframeShapefileUploadResult, "load", submittedFunction, false);
	formSearchShapefile.action = "gdServletAsyn/GetTileList_Shapefile_Upload";
	isUploading = true;
	formSearchShapefile.submit();
}

// [region] operation
function terminateSpecifyRegion(actionButton)
{
	// check and get rgion specifications
	if(checkAndGetRegionSpecifications() == false) return;

	// show specified region
	showSpecifiedRegion();

	var okFunction = function()
	{
		// get applicable tiles
		var latitudeNorthernEdge = Math.floor(regionLatitudeNorthernEdge);
		if(latitudeNorthernEdge == regionLatitudeNorthernEdge) latitudeNorthernEdge--;
		var latitudeSouthernEdge = Math.floor(regionLatitudeSouthernEdge);
		var longitudeWesternEdge = Math.floor(regionLongitudeWesternEdge);
		var longitudeEasternEdge = Math.floor(regionLongitudeEasternEdge);
		if(longitudeEasternEdge == regionLongitudeEasternEdge) longitudeEasternEdge--;
		var postData = "_gd_search_latitude_northern_edge=" + encodeURIComponent(latitudeNorthernEdge) +
			"&_gd_search_latitude_southern_edge=" + encodeURIComponent(latitudeSouthernEdge) +
			"&_gd_search_longitude_western_edge=" + encodeURIComponent(longitudeWesternEdge) +
			"&_gd_search_longitude_eastern_edge=" + encodeURIComponent(longitudeEasternEdge);
		getTileList("gdServletAsyn/GetTileList_Region", postData);
		destroySpecifiedRegionBox();
	}
	doConfirm(searchBoxElement, 470, 110, 300, 50, messageDoFixRegion, okFunction, null);
}
var regionLatitudeNorthernEdge;
var regionLatitudeSouthernEdge;
var regionLongitudeWesternEdge;
var regionLongitudeEasternEdge;
var degreeLatitudeNorthernEdge;
var degreeLatitudeSouthernEdge;
var degreeLongitudeWesternEdge;
var degreeLongitudeEasternEdge;
function checkAndGetRegionSpecifications()
{
	// get specified latitude northern edge
	regionLatitudeNorthernEdge = getRegionValue(textboxSearchRegionLatitudeNorthernEdge.value, 0, 83, messageRegionSouthernEdge);
	if(regionLatitudeNorthernEdge < 0) return false;
	if(pulldownSearchRegionLatitudeNorthernEdge.value == "S") regionLatitudeNorthernEdge *= (-1);

	// get specified latitude southern edge
	regionLatitudeSouthernEdge = getRegionValue(textboxSearchRegionLatitudeSouthernEdge.value, 0, 83, messageRegionNorthernEdge);
	if(regionLatitudeSouthernEdge < 0) return false;
	if(pulldownSearchRegionLatitudeSouthernEdge.value == "S") regionLatitudeSouthernEdge *= (-1);

	// check latitude relativity
	if(regionLatitudeNorthernEdge == regionLatitudeSouthernEdge) {showOperationError(messageRegionLatitudeSame); return false;}
	if(regionLatitudeNorthernEdge < regionLatitudeSouthernEdge) {showOperationError(messageRegionNotNorthern); return false;}

	// get specified longitude western edge
	regionLongitudeWesternEdge = getRegionValue(textboxSearchRegionLongitudeWesternEdge.value, 0, 180, messageRegionWesternEdge);
	if(regionLongitudeWesternEdge < 0) return false;
	if(pulldownSearchRegionLongitudeWesternEdge.value == "W") regionLongitudeWesternEdge *= (-1);

	// get specified longitude eastern edge
	regionLongitudeEasternEdge = getRegionValue(textboxSearchRegionLongitudeEasternEdge.value, 0, 180, messageRegionEasternEdge);
	if(regionLongitudeEasternEdge < 0) return false;
	if(pulldownSearchRegionLongitudeEasternEdge.value == "W") regionLongitudeEasternEdge *= (-1);

	// check longitude relativity
	if(regionLongitudeWesternEdge == regionLongitudeEasternEdge) {showOperationError(messageRegionLongitudeSame); return false;}

	// convert to client degree
	degreeLatitudeNorthernEdge = 83 - regionLatitudeSouthernEdge;
	degreeLatitudeSouthernEdge = 83 - regionLatitudeNorthernEdge;
	degreeLongitudeWesternEdge = (0 <= regionLongitudeWesternEdge)? regionLongitudeWesternEdge: regionLongitudeWesternEdge + 360;
	degreeLongitudeWesternEdge += 25;
	degreeLongitudeWesternEdge %= 360;
	degreeLongitudeEasternEdge = (0 <= regionLongitudeEasternEdge)? regionLongitudeEasternEdge: regionLongitudeEasternEdge + 360;
	degreeLongitudeEasternEdge += 25;
	degreeLongitudeEasternEdge %= 360;
	return true;
}
function getRegionValue(text, minValue, maxValue, valueTypeCaption)
{
	if(text.length <= 0)
	{
		showOperationError(valueTypeCaption + messageNoRegionValue);
		return -1;
	}
	if(isNaN(text) == true)
	{
		showOperationError(valueTypeCaption + messageNotNumericRegionValue);
		return -1;
	}
	var value = parseFloat(text);
	if(value < minValue)
	{
		showOperationError(valueTypeCaption + messageTooSmallRegionValue);
		return -1;
	}
	if(maxValue < value)
	{
		showOperationError(valueTypeCaption + messageTooLargeRegionValue);
		return -1;
	}
	return value;
}
function showSpecifiedRegion()
{
	// create specified region box
	var newRegionBox = false;
	if(specifiedRegionBoxElement == null)
	{
		createSpecifiedRegionBox();
		newRegionBox = true;
	}

	// make visible region box
	autoScrollForNewRegion();

	// show specified region box
	showSpecifiedRegionBox();

	// show new region box
	if(newRegionBox == true)
	{
		mapElement.appendChild(specifiedRegionBoxElement);
	}
}
var REGION_AUTO_SCROLL_MARGIN = 0.5;
function autoScrollForNewRegion()
{
	// revise longitude value
	var degreeLongitudeEasternEdgeRevised = degreeLongitudeEasternEdge;
	if(degreeLongitudeEasternEdgeRevised < degreeLongitudeWesternEdge) degreeLongitudeEasternEdgeRevised += 360;

	// get region size
	var regionWidth = degreeLongitudeEasternEdgeRevised - degreeLongitudeWesternEdge;
	var regionHeight = degreeLatitudeNorthernEdge - degreeLatitudeSouthernEdge;

	// decide showing span
	var showingSpanLongitudeWesternEdgeStandard = degreeLongitudeWesternEdge - (regionWidth * REGION_AUTO_SCROLL_MARGIN);
	var showingSpanLongitudeEasternEdgeStandard = degreeLongitudeEasternEdgeRevised + (regionWidth * REGION_AUTO_SCROLL_MARGIN);
	var showingSpanLatitudeNorthernEdgeStandard = degreeLatitudeNorthernEdge + (regionHeight * REGION_AUTO_SCROLL_MARGIN);
	if(DEGREE_HEIGHT < showingSpanLatitudeNorthernEdgeStandard) showingSpanLatitudeNorthernEdgeStandard = DEGREE_HEIGHT;
	var showingSpanLatitudeSouthernEdgeStandard = degreeLatitudeSouthernEdge - (regionHeight * REGION_AUTO_SCROLL_MARGIN);
	if(showingSpanLatitudeSouthernEdgeStandard < 0) showingSpanLatitudeSouthernEdgeStandard = 0;

	// decide new magnification
	var mapMagnificationX = DEGREE_WIDTH / (showingSpanLongitudeEasternEdgeStandard - showingSpanLongitudeWesternEdgeStandard);;
	var mapMagnificationY = DEGREE_HEIGHT / (showingSpanLatitudeNorthernEdgeStandard - showingSpanLatitudeSouthernEdgeStandard);
	var newMapMagnification = (mapMagnificationX < mapMagnificationY)? mapMagnificationX: mapMagnificationY;
	if(newMapMagnification < 1) newMapMagnification = 1;
	if(32 < newMapMagnification) newMapMagnification = 32;

	// decide new offset
	var newMapOffsetX = (showingSpanLongitudeEasternEdgeStandard + showingSpanLongitudeWesternEdgeStandard) / 2;
	var newMapOffsetY = (showingSpanLatitudeSouthernEdgeStandard + showingSpanLatitudeNorthernEdgeStandard) / 2;
	var degreeWidth = DEGREE_WIDTH / newMapMagnification;
	var degreeHeight = DEGREE_HEIGHT / newMapMagnification;
	newMapOffsetX -= (degreeWidth / 2);
	newMapOffsetY -= (degreeHeight / 2);
	if(newMapOffsetY < 0) newMapOffsetY = 0;

	// zoom map
	moveZoomSlider(newMapMagnification);
	showMapWithOffsetZooming(newMapMagnification, newMapOffsetX, newMapOffsetY);
	showZoomMagnificationValue(newMapMagnification);
}
var SPECIFIED_REGION_LINE_WIDTH = 1;
var SPECIFIED_REGION_LINE_STYLE = "dotted";
var SPECIFIED_REGION_LINE_COLOR = "#FF0000";
var SPECIFIED_REGION_LINE_OPACITY = 70;
var specifiedRegionBoxElement = null;
function createSpecifiedRegionBox()
{
	specifiedRegionBoxElement = document.createElement("div");
	specifiedRegionBoxElement.style.position = "absolute";
	specifiedRegionBoxElement.style.zIndex = ZINDEX_DRAWABLE;
	specifiedRegionBoxElement.style.borderWidth = SPECIFIED_REGION_LINE_WIDTH + "px";
	specifiedRegionBoxElement.style.borderStyle = SPECIFIED_REGION_LINE_STYLE;
	specifiedRegionBoxElement.style.borderColor = SPECIFIED_REGION_LINE_COLOR;
	setOpacity(specifiedRegionBoxElement, SPECIFIED_REGION_LINE_OPACITY);
}
function destroySpecifiedRegionBox()
{
	mapElement.removeChild(specifiedRegionBoxElement);
	specifiedRegionBoxElement = null;
}
function showSpecifiedRegionBox()
{
	//console.info(degreeLatitudeNorthernEdge + " - " + degreeLatitudeSouthernEdge + " / " + degreeLongitudeWesternEdge + " - " + degreeLongitudeEasternEdge);
	var pixelPerDegree = PIXEL_PER_DEGREE * mapMagnification;
	var x = (degreeLongitudeWesternEdge - mapOffsetX) * pixelPerDegree;
	var y = (degreeLatitudeSouthernEdge - mapOffsetY) * pixelPerDegree;
	var degreeLongitudeEasternEdgeRevised = degreeLongitudeEasternEdge;
	if(degreeLongitudeEasternEdgeRevised < degreeLongitudeWesternEdge) degreeLongitudeEasternEdgeRevised += 360;
	var width = Math.floor(((degreeLongitudeEasternEdgeRevised - mapOffsetX) * pixelPerDegree) - x);
	var height = Math.floor(((degreeLatitudeNorthernEdge - mapOffsetY) * pixelPerDegree) - y);
	var scrollPos = getElementPosition(mapElement);
	x = Math.floor(x) - scrollPos.left;
	while(x < 0) x += (720 * mapMagnification);
	y = Math.floor(y) - scrollPos.top;
	//console.info(x + "," + y + " * " + width + "," + height);
	setElementSize(specifiedRegionBoxElement, width, height);
	setElementPosition(specifiedRegionBoxElement, x, y);
}
function cancelRegionOperation()
{
	if(specifiedRegionBoxElement != null)
	{
		destroySpecifiedRegionBox();
	}
}

// convertors
function screenXToTileIndex(x)
{
	// x position on screen to tile index
	var degree = (x / PIXEL_PER_DEGREE / mapMagnification) + mapOffsetX;
	while(degree < 0) degree += 360;
	while(360 <= degree) degree -= 360;
	return Math.floor(degree / DEGREE_PER_TILE_WIDTH);
}
function screenYToTileIndex(y)
{
	// y position on screen to tile index
	var degree = (y / PIXEL_PER_DEGREE / mapMagnification) + mapOffsetY;
	return Math.floor(degree / DEGREE_PER_TILE_WIDTH);
}
function screenXToDegree(x)
{
	// x position on screen to degree(0...<360)
	var degree = (x / PIXEL_PER_DEGREE / mapMagnification) + mapOffsetX - 25;
	while(degree < 0) degree += 360;
	while(360 <= degree) degree -= 360;
	return degree;
}
function screenYToDegree(y)
{
	// y position on screen to degree(-83...83)
	return ((y / PIXEL_PER_DEGREE / mapMagnification) + mapOffsetY - 83) * (-1);
}
function degreeXToScreen(degreeX)
{
	// degree(0...<360) to x position on screen
	var x = (degreeX - mapOffsetX + 25) * PIXEL_PER_DEGREE * mapMagnification;
	var mapAreaWidth = MAP_AREA_WIDTH * mapMagnification;
	while(x < 0) x += mapAreaWidth;
	while(mapAreaWidth < x) x -= mapAreaWidth;
	return x;
}
function degreeYToScreen(degreeY)
{
	// degree(-83...83) to y position on screen
	return ((degreeY * (-1)) - mapOffsetY + 83) * PIXEL_PER_DEGREE * mapMagnification;
}

// selected tiles management
var labelTileCount;
function initializeTileSelection()
{
	// initialize tile count indicator
	labelTileCount = new Label("tile_count");
	if(mapSelectedTiles != null) labelTileCount.setText(mapSelectedTiles.length);

	// get tile mask at page start
	getTileMask("datas/mesh/tile_mask");

	// get selected tile list at page start
	getTileList("gdServletAsyn/GetSelectedTileList", "");
}
function getSelectedMapTileElement(indexX, indexY)
{
	// search selected tile element
	for(var i = 0, n = mapSelectedTiles.length; i < n; i++)
	{
		var mapTileElement = mapSelectedTiles[i];
		if(mapTileElement.indexX != indexX) continue;
		if(mapTileElement.indexY != indexY) continue;
		return mapTileElement;
	}
	return null;
}
function showTileCount()
{
	labelTileCount.setText(mapSelectedTiles.length);
}
function checkSelectedTileCount()
{
	var isSomeSelectedTile = (0 < mapSelectedTiles.length)? true: false;
	buttonClear.setEnablement(isSomeSelectedTile);
	buttonComplete.setEnablement(isSomeSelectedTile);
}
var tileMask = null;
function getTileMask(servlet)
{
	var loadedFunction = function(maskDataBase64)
	{
		// get tile mask
		if(maskDataBase64 == null) {return;}
		tileMask = base64Decode(maskDataBase64);
		//console.info(maskDataBase64.length + "/" + tileMask.length);
	}
	httpRequestWithData(servlet + "?" + getCashlessQuery(), loadedFunction, "", false);
}
function isVaildTile(indexX, indexY)
{
	var mask = tileMask[(indexY * (DEGREE_WIDTH / 8)) + Math.floor(indexX / 8)];
	mask = (mask >> (indexX % 8)) & 0x01;
	return mask? true: false;
}
function getTileList(servlet, postData)
{
	startProcessingIndication();
	if(!postData) postData = "";
	var loadedFunction = function(xmlData)
	{
		// get tile list
		hideProcessingIndication();
		if(xmlData == null) {return;}
		var dataNodes = xmlData.getElementsByTagName("TileList");
		if(!dataNodes)
		{
			communicationError("E0");
			return;
		}
		var result = getFirstNodeValueByTagName(dataNodes[0], "Result");
		if(result != "0")
		{
			if(result < 100) showOperationError(getErrorMessage(result));
			else showServerError(getErrorMessage(result));
			return;
		}
		var tileNodes = dataNodes[0].getElementsByTagName("Tile");
		for(var i = 0; i < tileNodes.length; i++)
		{
			var indexX = parseInt(getFirstNodeValueByTagName(tileNodes[i], "X"));
			var indexY = parseInt(getFirstNodeValueByTagName(tileNodes[i], "Y"));
			if(isVaildTile(indexX, indexY) == false) continue;
			if(getSelectedMapTileElement(indexX, indexY) == null)
			{
				var mapTileElement = createMapTile(indexX, indexY);
				mapSingleTile(mapTileElement);
				indicateTile(mapTileElement, INDICATE_TILE_SELECTED, null);
			}
		}
		reshowMap();
		showTileCount();
		checkSelectedTileCount();
	}
	httpRequestWithData(servlet + "?" + getCashlessQuery(), loadedFunction, postData, true);
}
function setTileList(servlet, postData, terminatedFunction)
{
	if(!postData) postData = "";
	var savedFunction = function(xmlData)
	{
		// get tile list
		if(xmlData == null) {return;}
		var dataNodes = xmlData.getElementsByTagName("TileList");
		if(!dataNodes)
		{
			communicationError("E0");
			return;
		}
		var result = getFirstNodeValueByTagName(dataNodes[0], "Result");
		if(result != "0")
		{
			showServerError(getErrorMessage(result));
			return;
		}
		if(terminatedFunction) terminatedFunction();
	}
	httpRequestWithData(servlet + "?" + getCashlessQuery(), savedFunction, postData, true);
}
function getErrorMessage(result)
{
	switch(result)
	{
		case "10":
			return messageInvalidVertex;
		case "20":
			return messageNoShapefile;
		case "21":
			return messageInvalidShapefile;
		case "30":
			return messageRegionNorthernEdge + messageNoRegionValue;
		case "31":
			return messageRegionSouthernEdge + messageNoRegionValue;
		case "32":
			return messageRegionWesternEdge + messageNoRegionValue;
		case "33":
			return messageRegionEasternEdge + messageNoRegionValue;
		case "34":
			return messageRegionNorthernEdge + messageInvalidRegionValue;
		case "35":
			return messageRegionSouthernEdge + messageInvalidRegionValue;
		case "36":
			return messageRegionWesternEdge + messageInvalidRegionValue;
		case "37":
			return messageRegionEasternEdge + messageInvalidRegionValue;
		case "100":
			return messageTileSelectingFailed;
	}
	return messageServerError;
}
function clearTileSelection(actionButton)
{
	if(mapSelectedTiles.length <= 0) return;
	var okFunction = function()
	{
		for(var i = 0, n = mapSelectedTiles.length; i < n; i++)
		{
			var mapTileElement = mapSelectedTiles[i];
			hideMapTile(mapTileElement);
		}
		for(var i = mapSelectedTiles.length - 1; 0 <= i; i--)
		{
			mapSelectedTiles[i] = null;
			mapSelectedTiles.pop();
		}
		showTileCount();
		checkSelectedTileCount();
	}
	doConfirm(searchBoxElement, 470, 157, 300, 50, messageDoClearAllSelectedTile, okFunction, null);
}
function createSelectedTilesParameterText(doMakePacket)
{
	var tiles = "_gd_tiles=";
	for(var i = 0, n = mapSelectedTiles.length; i < n; i++)
	{
		var mapTileElement = mapSelectedTiles[i];
		tiles += mapTileElement.indexX + "_" + mapTileElement.indexY + ",";
	}
	if(doMakePacket == true) tiles += "&_gd_do_make_packet=yes";
	return tiles;
}

// message to operator
function showOperationError(message)
{
	showMessage(searchBoxElement, 470, 110, 300, 50, message);
}
function showServerError(message)
{
	showMessage(searchBoxElement, 255, 250, 300, 50, message);
}

// show processing indicator
var ZINDEX_PROCESSING_INDICATOR = 9990;
var processingIndicatorElement = null;
//var PROCESSING_ICON_WIDTH = 32;
//var PROCESSING_ICON_HEIGHT = 32;
var PROCESSING_ICON_WIDTH = 200;
var PROCESSING_ICON_HEIGHT = 25;
if(language == LANGUAGE_JP) preLoadImage("./images/processing_message_jp.png");
else preLoadImage("./images/processing_message_en.png");
function startProcessingIndication()
{
	// create processing indicator
	if(processingIndicatorElement == null)
	{
		processingIndicatorElement = document.createElement("div");
		processingIndicatorElement.style.position = "absolute";
		setElementPosition(processingIndicatorElement, 0, 0);
		var elementSize = getElementSize(mapBoxElement);
		setElementSize(processingIndicatorElement, elementSize.width, elementSize.height);
		processingIndicatorElement.style.zIndex = ZINDEX_PROCESSING_INDICATOR;
		//processingIndicatorElement.style.backgroundColor = "#000000";
		setOpacity(processingIndicatorElement, 80);
		processingIndicatorElement.style.cursor = "wait";
		var imageElement = document.createElement("img");
		imageElement.style.position = "absolute";
		setElementPosition(imageElement,
			(elementSize.width - PROCESSING_ICON_WIDTH) / 2,
			(elementSize.height - PROCESSING_ICON_HEIGHT) / 2);
		setElementSize(imageElement, PROCESSING_ICON_WIDTH, PROCESSING_ICON_HEIGHT);
		//imageElement.src = "images/processing_icon.gif";
		if(language == LANGUAGE_JP) imageElement.src = "./images/processing_message_jp.png";
		else imageElement.src = "./images/processing_message_en.png";
		imageElement.style.cursor = "wait";
		processingIndicatorElement.appendChild(imageElement);
	}
	mapBoxElement.appendChild(processingIndicatorElement);
	disablePage();
	document.body.style.cursor = "wait";
	if(coverElement) coverElement.style.cursor = "wait";
}
function hideProcessingIndication()
{
	if(coverElement) coverElement.style.cursor = "default";
	document.body.style.cursor = "default";
	enablePage();
	mapBoxElement.removeChild(processingIndicatorElement);
}
