var netmap         = null;
var addressSearch  = null;
var g_lat          =  35.683346;
var g_lon          = 139.773368;
var g_scale        = 5;		//初期スケール
var g_range        = 500;		//検索範囲
var g_line         = 20;		//一覧表示件数
var g_page         = 0;			//表示中のページ番号(0～)
var g_pageTop      = 0;			//表示中のページ切り替えボタンの先頭ページ番号
var g_mapVisiblity = 1;			//地図の初期表示状態
var g_types        = [];		//初期選択状態に設定する店舗コード(大分類)
var g_innerShops   = [];		//検索範囲内店舗情報リスト(no, groupNo, groupCount, shopObj)
var g_outerShops   = [];		//検索範囲外店舗情報リスト(緯度経度をキーとしたハッシュ)
var g_typeCode     = {};		//店種コード(小分類)->店種名

var g_maxPages     = 8;			//ページ切り替えリンク最大表示数
var g_baloon       = null;		//バルーン
var g_tooltip      = null;		//ツールチップ
var g_lastMapCenter= {};		//最後の地図中心座標
var g_iconLayer    = null;		//NETMAP地図上の店舗アイコンレイヤー

var MAX_TT_SHOP_COUNT = 20;		//店舗アイコンツールチップ最大表示店舗数

//店舗種別選択チェックボックスID(check_type_に連結)
var g_all_types
 = ['all', '01','02','03','04','05','06','07','08','09','10','11','12','13'];

//店舗一覧テーブルHTML
var g_slTable = "<table class='search_list' cellspacing='0' cellpadding='0'>";
var g_slThead = "<thead>"
				 + "<tr><th CLASS='no'>No.</th><th CLASS='type' COLSPAN='2'>店種</th><th CLASS='name'>名称</th><th CLASS='address'>住所</th><th CLASS='tel'>TEL</th><th CLASS='distance'>距離</th></tr>"
				 + "</thead>";

//店舗一覧[new]アイコン				 
var g_newImgTag = "<img SRC='/bv/images/mark_new.gif' alt='新規' title='新規' WIDTH='34' HEIGHT='23' BORDER='0'>";

var g_rangeButton = [	//範囲検索ボタン(200/500/1000)
	{range:200,
	 title:"200m範囲",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_reach_200_on.gif",
	   off:"/bv/images/btn_reach_200.gif"},
	{range:500,
	 title:"500m範囲",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_reach_500_on.gif",
	   off:"/bv/images/btn_reach_500.gif"},
	{range:1000,
	 title:"1000m範囲",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_reach_1000_on.gif",
	   off:"/bv/images/btn_reach_1000.gif"},
	{range:2000,
	 title:"2000m範囲",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_reach_2000_on.gif",
	   off:"/bv/images/btn_reach_2000.gif"},
   	{range:5000,
	 title:"5000m範囲",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_reach_5000_on.gif",
	   off:"/bv/images/btn_reach_5000.gif"}


];

var g_lineButton = [	//一覧表示件数ボタン(20/30/40)
	{count:20,
	 title:"20件表示",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_list_20_on.gif",
	   off:"/bv/images/btn_list_20.gif"},
	{count:30,
	 title:"30件表示",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_list_30_on.gif",
	   off:"/bv/images/btn_list_30.gif"},
	{count:40,
	 title:"40件表示",
	 width:44, height:24, border:0,
	    on:"/bv/images/btn_list_40_on.gif",
	   off:"/bv/images/btn_list_40.gif"}
];

/**
 * 地図上の店舗アイコン処理.
 *
 *	@param	shop	店舗情報
 *	@param	img		店舗アイコン(img or div)
 */
function ShopObj(shop, img)
{
	/**
	 * 指定の文字列配列で、ツールチップ用HTMLをセット.
	 *
	 *	@param	names	文字列配列
	 */
	this.updateTooltipShopNames = function(names)
	{
		this.html = names.join('<br>');
	};

	/**
	 * 店舗の緯度経度からIDを構築.
	 */	 	
	this.getLatLonID = function()
	{
		return makeLatLonID(this.shop.lat, this.shop.lon);
	};
		
	this.onMouseOver = function(enter)
	{
		//ツールチップ表示処理
		ShopObj.processMouseOver(
			enter, this.shop.lon, this.shop.lat, this.html);
	};
	
	this.onMouseDown = function()
	{
		ShopObj.processMouseDown();
	};

	this.onMouseUp = function()
	{
		ShopObj.processMouseUp();
	};

	this.onMouseClick = function()
	{
		//クリックでのバルーン表示が抑制されているか確認
		var disableBaloon = ShopObj.disableBaloon;
		ShopObj.disableBaloon = false;
		
		if (disableBaloon)
			return;

		if (!netmap) return;

		//すでに表示済みなら何もしない
		if (g_baloon && g_baloon.shopObj == this)
			return;
			
		//バルーン再構築
		clearTooltip();
		clearBaloon();

		//店舗情報を表示		
		var tmp = [];
		tmp.push("<table class='baloon'>");
		for (var i = shop.no; i < shop.no + shop.groupCount; i++)
		{
			tmp.push("<tr>");
			tmp.push(td('title_top',   '店種'));
			tmp.push(td('content_top', g_typeCode[g_innerShops[i].type]));
			tmp.push("</tr>");

			tmp.push("<tr>");
			tmp.push(td('title',   '名称'));
			tmp.push(td('content', g_innerShops[i].name));
			tmp.push("</tr>");

			tmp.push("<tr>");
			tmp.push(td('title',   '住所'));
			tmp.push(td('content', g_innerShops[i].address));
			tmp.push("</tr>");

			tmp.push("<tr>");
			tmp.push(td('title',   'TEL'));
			tmp.push(td('content', g_innerShops[i].tel));
			tmp.push("</tr>");
		}
		tmp.push("</table>");

		g_baloon = new Baloon();
		g_baloon.shopObj = this;
		g_baloon.create(el('mapframe'),
			this.shop.lon, this.shop.lat, tmp.join(''), netmap);
	};

	this.shop = shop;
	this.img  = img;

	this.html = '';	//ツールチップ表示HTML

	//ツールチップテキスト構築(店舗名を連結)
	//※検索範囲外の情報があればそれを使い、密集地のアイコン表示に対応
	var llid = makeLatLonID(shop.lat, shop.lon);
	if (g_outerShops[llid])
	{
		this.updateTooltipShopNames(g_outerShops[llid][2]);
	}
	else
	{
		//検索範囲外情報が無ければそのままグループ化された店舗情報を表示
		for (var i = shop.no; i < shop.no + shop.groupCount; i++)
			this.html += g_innerShops[i].name + '<br>';
	}

	img.onmouseover = (function(obj) {return function() {obj.onMouseOver(true);};})(this);
	img.onmouseout  = (function(obj) {return function() {obj.onMouseOver(false);};})(this);
	img.onmousedown = (function(obj) {return function() {obj.onMouseDown();};})(this);
	img.onmouseup   = (function(obj) {return function() {obj.onMouseUp();};})(this);
	img.onclick     = (function(obj) {return function() {obj.onMouseClick();};})(this);
}

/**
 * マウスイン、アウトの共通処理.
 *
 *	@param	enter	true:マウスイン/false:マウスアウト
 *	@param	lon		経度
 *	@param	lat		緯度
 *	@param	html	ツールチップ表示用HTML
 */
ShopObj.processMouseOver = function(enter, lon, lat, html)
{
	if (!netmap) return;

	if (enter)
	{
		clearTooltip();
			
		if (g_baloon == null && !ShopObj.dragging)
		{
			//アイコンに関連付けられた店名をツールチップっぽく表示
			g_tooltip = new Tooltip();
			g_tooltip.create(
				el('mapframe'), lon, lat, html, netmap);
		}
	}
	else
	{
		//ツールチップ消去
		clearTooltip();
	}
};

/**
 * マウスダウン、アップの共通処理.
 */
ShopObj.processMouseDown = function()
{
	//マウスダウンのタイミングでツールチップ、バルーン消去
	clearTooltip();
	clearBaloon();

	//ドラッグ中とし、クリック位置を保存
	ShopObj.dragging     = true;
	ShopObj.lastPosition = netmap ? netmap.getCenter() : {};
};

ShopObj.processMouseUp = function()
{
	//ドラッグ終了、地図の中心座標を比較し、ドラッグ有り無しを検知。
	//ドラッグされていれば、直後のバルーン表示を抑制
	var last = ShopObj.lastPosition;
	ShopObj.dragging     = false;
	ShopObj.lastPosition = null;
	
	if (netmap && last && last.lat && last.lon)
	{
		var pos = netmap.getCenter();
		
		ShopObj.disableBaloon = pos.lat != last.lat || pos.lon != last.lon;
	}
};

ShopObj.dragging      = false;
ShopObj.disableBaloon = false;
ShopObj.lastPosition  = null;


/**
 * ツールチップウインドウ.
 */
function Tooltip()
{
	this.parent = null;	//親DOM要素

	/**
	 * ツールチップウインドウ作成.
	 */
	this.create = function(parent, lon, lat, html, netmap)
	{
		if (!parent || !netmap)
			return;

		//divで構築
		this.parent = parent;
		this.div    = createElementWith(parent, 'div', 'tooltip', UNSELECTABLE);

		var div = this.div;
		div.innerHTML = html;

		//地図内に収まるように位置を変更
		var mapSize = netmap.getPixelSize();
		var pos     = netmap.getPixelPoint(lon, lat);
		var w       = parseInt(netmap.myKaMap.getObjectWidth(div));
		var h       = parseInt(netmap.myKaMap.getObjectHeight(div));
		var x       = pos.x;
		var y       = pos.y;

		var lr = x + w < mapSize.width;		//left(1) or right(0)
		var tu = y + h < mapSize.height;	//top(1) or under(0)

		var cursorSize = 16;
		x = lr ? x + cursorSize : x - w;
		y = tu ? y + cursorSize : y - h;

		div.style.left = x + 'px';
		div.style.top  = y + 'px';
	};
	
	/**
	 * ツールチップウインドウ破棄.
	 */
	this.remove = function()
	{
		if (this.parent && this.div)
		{
			this.parent.removeChild(this.div);
			delete this.div;

			this.div = null;
		}
	};
}

/**
 * バルーンウインドウ.
 */
function Baloon()
{
	this.parent     = null;	//親DOM要素
	this.contentDiv = null;	//バルーンのコンテンツ格納div
	this.closeDiv   = null;	//バルーンのクローズボタンdiv
	
	/**
	 * バルーンウインドウ作成.
	 */
	this.create = function(parent, lon, lat, html, netmap)
	{
		if (!parent || !netmap)
			return;

		this.parent = parent;
		
		//地図内に収まるように噴出し位置を変更
		var mapSize = netmap.getPixelSize();
		var mapPos  = netmap.getPixelPoint(lon, lat);
		var x       = mapPos.x + 4;
		var y       = mapPos.y + 4;
		var w       = 300;
		var h       = 200;
		
		var lr = x + w < mapSize.width;		//left(1) or right(0)
		var tu = y + h < mapSize.height;	//top(1) or under(0)
		
		if (!lr) x -= w;
		if (!tu) y -= h;

		//ベースのdiv
		//※バルーンはテキストを表示するのでそれを選択可能とするため親divの
		//  選択属性は設定しない
		this.baloon = createElementWith(parent, 'div', 'baloon');

		var baloon = this.baloon;
		baloon.style.position = 'absolute';
		baloon.style.left     = x + 'px';
		baloon.style.top      = y + 'px';
		baloon.style.width    = w + 'px';
		baloon.style.height   = h + 'px';
		baloon.style.zIndex   = 100;

		//画像要素を配置
		createElementWith(baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_1', UNSELECTABLE);
		this.closeDiv = createElementWith(
						  baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_2', UNSELECTABLE);
		createElementWith(baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_3', UNSELECTABLE);
		createElementWith(baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_4', UNSELECTABLE);
		this.contentDiv = createElementWith(
						  baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_5');
		createElementWith(baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_6', UNSELECTABLE);
		createElementWith(baloon, 'div', 'baloonL' + (tu ? 'T' : 'U') + '_7', UNSELECTABLE);
		createElementWith(baloon, 'div', 'baloon' +
								(lr ? 'L' : 'R') + (tu ? 'T' : 'U') + '_8', UNSELECTABLE);
								
		//閉じるボタン
		this.closeDiv.onclick = (function(obj) {
            return function(e) {obj.onClickClose(e);};
        })(this);
		
		this.contentDiv.innerHTML = html;
	};
	
	/**
	 * バルーンウインドウ破棄.
	 */
	this.remove = function()
	{
		if (this.parent && this.baloon)
		{
			this.parent.removeChild(this.baloon);
			delete this.baloon;

			this.baloon = null;
		}
	};
	
	/**
	 * クローズボタンハンドラ.
	 */
	this.onClickClose = function(e)
	{
		this.remove();
		
		g_baloon = null;
	};
}

/**
 * window.onload.
 */
window.onload = function()
{
	//住所検索エンジン初期化
	g_addressSearch = new NetmapOption.AddressSearch();
	
	searchAddress(g_lon, g_lat);
	
	//検索範囲、一覧表示件数切り替えボタン初期化
	updateRangeButton();
	updateLineButton();

	//地図の初期表示状態	
	setMapVisibility(g_mapVisiblity);
	
	//店舗種別選択チェックの初期表示状態
	initTypeCheckbox();

	//初期ページ番号を正規化
	g_page = Math.max(0, Math.min(g_page,
					Math.ceil(g_innerShops.length / g_line)));
	g_pageTop = g_maxPages * Math.floor(g_page / g_maxPages);

	//初期データを元に、加盟店一覧、アイコン更新(ページのリセット不要)
	searchShopListCallback(g_innerShops, true)
	
	//タイマーによるスクロール監視開始
	onTimer();
}

/**
 * NETMAP初期化.
 */
function initNetmap()
{
	if (netmap)
		return;
		
	//Netmapオブジェクトの設定
	netmap = new Netmap('map', {lat:g_lat, lon: g_lon, scale: g_scale});
	netmap.enableKeyboardInterface(false);
	netmap.enableMouseWheel(false);

	//インデックスマップを表示
	netmap.addIndexMap('indexmap');

	//コントローラーを追加
	netmap.addController();

	//スケールバーを追加
	netmap.addScalebar();
	
	//イベントハンドラ
	netmap.addListener(Netmap.INITIALIZED,     onNetmapInitialized);
	netmap.addListener(Netmap.EXTENTS_CHANGED, onNetmapExtentsChanged);
	netmap.addListener(Netmap.SCALE_CHANGED,   onNetmapScaleChanged);
	netmap.addListener(Netmap.CANVAS_EXTENTS_CHANGED,
											onNetmapCanvasExtentsChanged);
	netmap.addListener(Netmap.CLICKED,         onNetmapClicked);
}

/**
 * 店舗種別選択チェックの初期表示状態.
 */
function initTypeCheckbox()
{
	//すべてチェックオフ
	for (var i = 0; i < g_all_types.length; i++)
		setCheck('check_type_' + g_all_types[i], false);

	//指定の状態にセット
	if (g_types.length == 0 || contains(g_types, '00'))
	{
		//すべて
		for (var i = 0; i < g_all_types.length; i++)
			setCheck('check_type_' + g_all_types[i], true);
	}
	else
	{
		//指定の要素のみ選択
		for (var i = 0; i < g_types.length; i++)
			setCheck('check_type_' + g_types[i], true);
	}

	//チェックボックスにクリックハンドラを追加
	for (var i = 0; i < g_all_types.length; i++)
	{
		var id  = g_all_types[i];

		el('check_type_' + id).onclick
			= (function(obj) {
				return function() {onClickTypeCheckbox(obj.id);};
		      })({id:id});
	}
}
	
/**
 * 地図を閉じる/地図を開くボタン.
 */
function onClickToggleMapVisibility()
{
	//地図表示エリアの表示/非表示切り替え
	var div = document.getElementById('map_box');

	setMapVisibility(div.style.display == 'none');
}

/**
 * 「再検索」ボタン.
 */
function onClickSearchButton()
{
	//料理の種類を選択していないと検索できない
	if (getTypeString() == "")
	{
		alert("料理の種別を選択してください。");
		return;
	}
	
	//地図表示中であれば、中心座標を使う
	if (netmap && netmap.isAvailable())
	{
		var center = netmap.getCenter();
		
		g_lat = center.lat;
		g_lon = center.lon;
	}
	
	//検索実行
	execSearchShopList(g_lat, g_lon);

	//住所検索実行
	searchAddress(g_lon, g_lat);
}

/**
 * 店舗種別チェックボックスクリックハンドラ.
 *
 *	@param	id	all or 01～13
 */
function onClickTypeCheckbox(id)
{
	if (id == 'all')
	{
		//「すべてを選択」に他のチェックが連動
		var checked = getCheck('check_type_all');
		
		for (var i = 1; i < g_all_types.length; i++)
		{
			setCheck('check_type_' + g_all_types[i], checked);
		}
	}
	else
	{
		//すべてにチェックがつけば、「すべてを選択」をチェック
		var count = 0;
		for (var i = 1; i < g_all_types.length; i++)
		{
			if (getCheck('check_type_' + g_all_types[i]))
				count++;
		}
		
		setCheck('check_type_all', count == g_all_types.length-1);
	}
}

/**
 * NETMAP 初期化完了通知.
 */
function onNetmapInitialized()
{
	//アイコンレイヤー準備
	buildIconLayer();
	
	//初期化直後は、CANVAS_EXTENTS_CHANGEDは発生しないので自分でコール
	//→検索範囲外の店舗アイコンが更新される
	onNetmapCanvasExtentsChanged(
		Netmap.CANVAS_EXTENTS_CHANGED, netmap.getCanvasExtents());	
}

/**
 * NETMAP スクロール通知.
 */
function onNetmapExtentsChanged()
{
	//スクロールを行うと店舗情報のバルーンを消去
	clearTooltip();
	clearBaloon();

	updateShopIcon();
}

/**
 * NETMAP 縮尺変更通知.
 */
function onNetmapScaleChanged()
{
	//縮尺の変更を行うと店舗情報のバルーンを消去
	clearTooltip();
	clearBaloon();
	
	processScaleChanged();
}

/**
 * NETMAP キャンバス矩形更新通知.
 */
function onNetmapCanvasExtentsChanged(id, e)
{
	//※地図表示矩形より若干大きめのキャンバス矩形の更新タイミングで、
	//  検索範囲外店舗アイコンを更新する
	
	//検索範囲外店舗アイコン情報検索
	if (isIconVisible() && netmap)
	{
		var url = '/cgi-bin/bv/search_shop_list.cgi?mode=icon';
		url += "&minx="  + e.minx;
		url += "&miny="  + e.miny;
		url += "&maxx="  + e.maxx;
		url += "&maxy="  + e.maxy;
		url += "&scale=" + netmap.getScale();

		calljs(url, null, searchShopIconListCallback);
	}
}

/**
 * NETMAP 地図領域クリックハンドラ.
 */
function onNetmapClicked()
{
	//ツールチップ、バルーン消去
	clearTooltip();
	clearBaloon();
}

/**
 * タイマーハンドラ.
 */
function onTimer()
{
	//地図の中心座標を監視し、スクロール開始をキャプチャ
	if (netmap)
	{
		var pos = netmap.getCenter();
		if (g_lastMapCenter.lon != pos.lon || g_lastMapCenter.lat != pos.lat)
		{
			//スクロールを行うと店舗情報のバルーンを消去
			clearTooltip();
			clearBaloon();
		}
		
		g_lastMapCenter.lon = pos.lon;
		g_lastMapCenter.lat = pos.lat;
	}
	
	setTimeout(onTimer, 100);
}

/**
 * 地図表示状態切り替え.
 *
 *	@param	visible	表示状態
 */
function setMapVisibility(visible)
{
	var div = document.getElementById('map_box');
	var img = document.getElementById('btn_open_close_map');

	if (visible)
	{
		div.style.display = 'block';
		img.src   = '/bv/images/btn_close_map.gif';
		img.alt   = '地図を閉じる';
		img.title = '地図を閉じる';

		//地図を閉じてページを開いた場合、初回表示のタイミングで初期化
		if (!netmap)
		{
			initNetmap();

			//アイコン初期化
			updateShopIcon();
		}
	}
	else
	{
		div.style.display = 'none';
		img.src   = '/bv/images/btn_open_map.gif';
		img.alt   = '地図を表示';
		img.title = '地図を表示';
	}
}

/**
 * ページ切り替え.
 *
 *	@param	no	ページ番号(1～)
 */
function changePage(no)
{
	//ページを切り替えて一覧、アイコン更新を更新
	g_page = no - 1;
	
	updateShopList();
	updateShopIcon();
}

/**
 * ページ先頭切り替え.
 *
 *	@param	no	ページ先頭番号(1～)
 */
function changePageTop(no)
{
	//ページ先頭を切り替えて、そのページへ切り替え
	g_pageTop = no - 1;
	
	changePage(g_pageTop + 1);
}

/**
 * 検索範囲切り替え.
 *
 *	@param	range	検索範囲(200/500/1000)
 */
function changeRange(range)
{
	g_range = range;
	
	updateRangeButton();
	
	//再検索実行
	execSearchShopList(g_lat, g_lon);
}

/**
 * 一覧表示件数切り替え.
 *
 *	@paarm	count	一覧表示件数(20/30/40)
 */
function changeLine(count)
{
	//ボタン表示状態を更新
	g_line = count;

	updateLineButton();

	//ページグループ位置も正規化
	var pages      = Math.ceil(g_innerShops.length / g_line);
	var maxPageTop = Math.ceil(pages / g_maxPages) - 1;
	g_pageTop = Math.max(0, Math.min(g_pageTop, maxPageTop));
	g_pageTop = Math.floor(g_pageTop / g_maxPages) * g_maxPages;
								//ページ先頭は常に最大表示個数の倍数

	//一覧、アイコン更新
	updateShopList();
	updateShopIcon();
}

/**
 * 検索範囲ボタン更新.
 */
function updateRangeButton()
{
	var html = '';
	for (var i = 0; i < g_rangeButton.length; i++)
	{
		var r    = g_rangeButton[i];
		var href = "javascript:changeRange(" + r.range + ");";
		
		if (r.range != g_range)
			html += "<a href=" + SQ(href) + " title=" + SQ(r.title) + ">"
					+ "<img src=" + SQ(r.off);
		else
			html += "<img src=" + SQ(r.on);
			
		html += " alt="    + SQ(r.title);
		html += " title="  + SQ(r.title);
		html += " width="  + SQ(r.width);
		html += " height=" + SQ(r.height);
		html += " border=" + SQ(r.border);
		html += " />";
			
		if (r.range != g_range)
			html += "</a>";
			
		html += "\r";
	}

	el('rangebuttons').innerHTML = html;
}

/**
 * 一覧表示件数ボタン更新.
 */
function updateLineButton()
{
	var html = '';
	for (var i = 0; i < g_lineButton.length; i++)
	{
		var r    = g_lineButton[i];
		var href = "javascript:changeLine(" + r.count + ");";
		
		if (r.count != g_line)
			html += "<a href=" + SQ(href) + " title=" + SQ(r.title) + ">"
					+ "<img src=" + SQ(r.off);
		else
			html += "<img src=" + SQ(r.on);
			
		html += " alt="    + SQ(r.title);
		html += " title="  + SQ(r.title);
		html += " width="  + SQ(r.width);
		html += " height=" + SQ(r.height);
		html += " border=" + SQ(r.border);
		html += " />";
			
		if (r.count != g_line)
			html += "</a>";
			
		html += "\r";
	}

	el('linebuttons').innerHTML = html;
}

/**
 * 地図スクロール
 */
function jumpto(lat, lon)
{
	if (netmap)
	{
		netmap.zoomTo({lat:lat, lon:lon});
	}

	//地図表示位置へスクロール
	window.location.hash = 'map_box';
}

/**
 * 加盟店一覧更新.
 */
function updateShopList()
{
	//ページを範囲内へ
	var pages   = Math.ceil(g_innerShops.length / g_line);
	var minPage = g_pageTop;
	var maxPage = Math.min(pages - 1, g_pageTop + g_maxPages - 1);

	g_page = Math.max(minPage, Math.min(g_page, maxPage));
	
	//店舗情報をグループ化(同一緯度経度)
	groupingShopList(g_innerShops, g_line);
	
	//検索件数
	el('shop_count').innerHTML = g_innerShops.length;

	//ページ表示範囲、ページ切り替えリンク更新	
	el('pagerange0').innerHTML
	 = el('pagerange1').innerHTML = buildCurrentPageRange();
	el('pagelinks0').innerHTML
	 = el('pagelinks1').innerHTML = buildCurrentPageLinks();

	//一覧更新
	el('search_list_box').innerHTML
		= g_slTable + g_slThead + buildCurrentShopList() + "</table>";
}

/**
 * 店舗情報バルーン消去.
 */
function clearBaloon()
{
	if (g_baloon)
	{
		g_baloon.remove();
		g_baloon = null;
	}
}

/**
 * 店舗情報のツールチップ消去.
 */
function clearTooltip()
{
	if (g_tooltip)
	{
		g_tooltip.remove();
		g_tooltip = null;
	}
}

/**
 * 店舗情報リスト検索実行.
 */
function execSearchShopList(lat, lon)
{
	//検索実行	
	var url = '/cgi-bin/bv/search_shop_list.cgi?mode=shop';
	url += "&lat="  + lat;
	url += "&lon="  + lon;
	url += "&type=" + getTypeString();
	url += "&r="    + g_range;
	
	//検索中は店舗リストを空にしておく
	g_innerShops = [];
	g_page       = 0;
	g_pageTop    = 0;

	updateShopList();
	updateShopIcon();

	calljs(url, null, searchShopListCallback);
}

/**
 * 住所検索実行、テキスト更新.
 */
function searchAddress(lon, lat)
{
	if (g_addressSearch)
	{
		el('address_text').innerHTML = '';

		g_addressSearch.searchByPoint(
			{lon:lon,lat:lat}, addressSearchCallback);
	}
}

/**
 * 店舗リスト検索cgi応答ハンドラ.
 *
 *	@param	result		店舗情報リスト
 *	@param	noPageReset	trueでページのリセットを行わない(ページ初期化用)
 */
function searchShopListCallback(result, noPageReset)
{
	//配列を更新し、ページを先頭へ移動し、店舗リスト更新
	g_innerShops = result;

	if (!noPageReset)
	{
		g_page    = 0;
		g_pageTop = 0;
	}
	
	//店舗情報に連番(no)を付与
	for (var i = 0; i < g_innerShops.length; i++)
		g_innerShops[i].no = i;

	//加盟店一覧、アイコン更新
	updateShopList();
	updateShopIcon();
}

/**
 * 検索範囲外店舗情報cgi応答ハンドラ.
 *
 *	@param	result	[[lat,lon,[names]],...]
 */
function searchShopIconListCallback(result)
{
	g_outerShops = [];
	
	//緯度経度をキーとするハッシュへ格納し、地図アイコンを更新
	for (var i = 0; i < result.length; i++)
	{
		var icon = result[i];
		
		//ツールチップに表示する店舗数に上限を設けている
		if (MAX_TT_SHOP_COUNT < icon[2].length)
		{
			var hidden = icon[2].length - MAX_TT_SHOP_COUNT;
			icon[2].splice(MAX_TT_SHOP_COUNT, hidden,
							'...' + hidden + '件のお店');
		}

		icon.onMouseOver = function(enter)
		{
			//ツールチップ表示処理
			ShopObj.processMouseOver(
				enter, this[1], this[0], this[2].join('<br />'));
		};

		//dom要素のマウスハンドラ用
		icon.onmouseover = (function(obj) {return function() {obj.onMouseOver(true);};})(icon);
		icon.onmouseout  = (function(obj) {return function() {obj.onMouseOver(false);};})(icon);
		icon.onmousedown = ShopObj.processMouseDown;
		icon.onmouseup   = ShopObj.processMouseUp;
		
		g_outerShops[makeLatLonID(icon[0], icon[1])] = icon;
	}

	//検索範囲外アイコンはデータが更新されたときだけ更新	
	updateShopIcon(OUTER);
	
	//検索範囲内の店舗情報のツールチップにマージ
	for (var i = 0; i < g_innerShops.length; i++)
	{
		var s = g_innerShops[i].shopObj;

		if (s)
		{
			//店舗の緯度経度に一致する店舗名リストがあれば
			//それでツールチップを更新する
			var id = s.getLatLonID();

			if (g_outerShops[id])
				s.updateTooltipShopNames(g_outerShops[id][2]);			
		}
	}
}

/**
 * 住所検索エンジン結果ハンドラ.
 */
function addressSearchCallback(json)
{
	if (!json.erros)
	{
		var e = json[0];
		var address = ""+ NVL(e.prefName)
						+ NVL(e.cityName)
						+ NVL(e.areaName)
						+ NVL(e.koazaChomeName) + '&nbsp;'
						+ NVL(e.banchiGo)
						+ NVL(e.buildingName)
						+ NVL(e.buildingNunmber);
		el('address_text').innerHTML = address;
	}
}

/**
 * 加盟店一覧 ページ件数HTML(1-10).
 */
function buildCurrentPageRange()
{
	//結果0なら0表示
	var range = currentShopRange();
	
	return range.count == 0
			? '0'
			: ((range.start + 1) + '-' + (range.end));
}

/**
 * 加盟店一覧 ページ切り替えHTML.
 */
function buildCurrentPageLinks()
{
	var pages = Math.ceil(g_innerShops.length / g_line);
	var html  = '';

	//n個を超えてページ切り替えリンクが必要な場合は左右にグループ切り替え
	//リンクを用意します
	var left  = false;
	var right = false;

	if (g_maxPages < pages)
	{
		//先頭部分表示なら左への移動は不要
		left = g_pageTop != 0;
		
		//右へ移動の必要ありか?
		right = g_pageTop + g_maxPages < pages;

		pages = Math.min(pages - g_pageTop, g_maxPages);
	}

	//左へ移動リンク	
	if (left)
	{
		var href = "javascript:changePageTop(" + (g_pageTop-g_maxPages+1) + ");";
		html += "<li><a href=" + SQ(href) + ">" + "&lt;&lt;" + "</a></li>";
	}

	//ページ切り替えリンク	
	for (var i = g_pageTop; i < g_pageTop + pages; i++)
	{
		var no   = i + 1;
		var href = "javascript:changePage(" + (i+1) + ");";
		
		html += i == g_page
			? ("<li class='here'>" + no + "</li>")
			: ("<li><a href='" + href + "'>" + no + "</a></li>");
	}

	//右へ移動リンク	
	if (right)
	{
		var href = "javascript:changePageTop(" + (g_pageTop+g_maxPages+1) + ");";
		html += "<li><a href=" + SQ(href) + ">" + "&gt;&gt;" + "</a></li>";
	}
	
	return html;
}

/**
 * 加盟店一覧 一覧tbody HTML.
 */
function buildCurrentShopList()
{
	var html = '<tbody>';
	var range = currentShopRange();
	
	for (var i = range.start; i < range.end; i++)
	{
		var no = g_innerShops[i].groupNo
					- g_innerShops[range.start].groupNo;
		
		html += buildShopListElement(
					no + 1, g_innerShops[i].groupCount, g_innerShops[i]);
	}
	
	return html + '</tbody>';
}

/**
 * 加盟店一覧 店舗情報HTML.
 *
 *	@param	no			番号(1～)
 *	@param	groupCount	グループ数(
 *	@param	shop		店舗情報
 */
function buildShopListElement(no, groupCount, shop)
{
	var isNew = shop.newFlag;
	var tmp   = [];
	
	var href = "javascript:jumpto(" + shop.lat + "," + shop.lon + ");";
	
	tmp.push("<tr>");
		if (groupCount != null)
		{
			var attr = " rowspan=" + SQ(groupCount);
			tmp.push(td(isNew ? 'no_new' : 'no', null, attr));
				tmp.push("<a HREF='" + href + "' TITLE='店舗の位置に地図移動'>");
				tmp.push(no);
				tmp.push("</a>");
			tmp.push("</td>");
		}
		tmp.push(td(isNew ? 'type_new'     : 'type',     g_typeCode[shop.type]));
		tmp.push(td(isNew ? 'new_new'      : 'new',      isNew ? g_newImgTag : ''));
		tmp.push(td(isNew ? 'name_new'     : 'name',     shop.name));
		tmp.push(td(isNew ? 'address_new'  : 'address',  shop.address));
		tmp.push(td(isNew ? 'tel_new'      : 'tel',      shop.tel));
		tmp.push(td(isNew ? 'distance_new' : 'distance', shop.dist + 'm'));
	tmp.push("</tr>");
	
	return tmp.join('');
}

/**
 * 現在表示中の店舗範囲.
 */
function currentShopRange()
{
	var count = g_innerShops.length;
	var start = g_page * g_line;
	var end   = start + Math.min(count-start, g_line);
	
	return {start:start, end:end, count:count};
}

/**
 * 現在選択中の店種コードを連結して取得.
 */
function getTypeString()
{
	if (getCheck('check_type_all')) return "00";
	else
	{
		var type = "";
		for (var i = 1; i < g_all_types.length; i++)
		{
			if (getCheck('check_type_' + g_all_types[i]))
				type += g_all_types[i];
		}
		
		return type;
	}
}

/**
 * 店舗アイコン情報(URL、サイズ等)取得.
 *
 *	@param	shop	店舗情報
 *	@return	{url,w,h,ox,oy}
 */
function getShopIconInfo(shop)
{
	var range = currentShopRange();

	if (shop == null)
		return g_shopInnerIcon;

	//ページ範囲内は番号付		
	var hasGroup = shop.groupCount != null && 2 <= shop.groupCount;

	if (range.start <= shop.no && shop.no < range.end)
	{
		var no   = 1 + shop.groupNo - g_innerShops[range.start].groupNo;
		var icon = hasGroup ? g_shopInnerNoIconB : g_shopInnerNoIcon;

		return {
				url:icon.url.replace('%d', no),
				w:icon.w,
				h:icon.h,
				ox:icon.ox,
				oy:icon.oy};
	}
	//それ以外は番号無し
	else
	{
		return hasGroup ? g_shopInnerIconB : g_shopInnerIcon;
	}
}

