var ICON_MIN_SCALE = 2;			//アイコンを表示するスケールは2～ (2009.3.5 成川修正）

var g_iconsCount    = 200;	//作成済み店舗アイコン用HTML要素
var g_iconZTop      = 8000;	//店舗アイコンZ番号先頭
var g_outerIconZTop = 5000;	//店舗アイコンZ番号先頭

//検索中心,店舗アイコンスプライト
var g_centerIcon       = {url:"/bv/images/icon/star_blue.png",   w:16, h:16, ox:-8, oy:-8};
var g_shopInnerIcon    = {url:"/bv/images/icon/icon_shop.png",   w:12, h:14, ox:-6, oy:-14};
var g_shopInnerIconB   = {url:"/bv/images/icon/icon_shop_b.png", w:14, h:16, ox:-7, oy:-16};
var g_shopInnerNoIcon  = {url:"/bv/images/icon/icon_no%d.png",   w:18, h:20, ox:-9, oy:-20};
var g_shopInnerNoIconB = {url:"/bv/images/icon/icon_no%db.png",  w:18, h:20, ox:-9, oy:-20};
var g_iconsIcon        = {url:"/bv/images/icon/icons.png",       w:18, h:20, ox:-9, oy:-20};

var g_printing = false;	//印刷時はtrueにセット(店舗アイコンをimgで描画)
var g_usePrintingGLayer = true;	//印刷ページで印刷用のグラフレイヤーを使うか?

var INNER = 1;				//updateShopIcon 第1引数
var OUTER = 2;				//updateShopIcon 第1引数
var UNSELECTABLE = true;	//createElementWith 第4引数

var NETMAP_SHOP_ICONS_LAYER_ID   = '@bv_shop_icons_normal';
var NETMAP_SHOP_ICONS_P_LAYER_ID = '@bv_shop_icons_printing';

/**
 * アイコンレイヤー準備.
 */
function buildIconLayer()
{
	var kamap = netmap.myKaMap;
	var size  = netmap.getPixelSize();
	var layer = {};

	//仮想的に地図のタイル領域サイズの3倍の大きさでベースとなるdivを構築
	layer.width   = size.width  * 3;
	layer.height  = size.height * 3;
	layer.offsetX = -Math.floor((layer.width  - size.width) / 2);
	layer.offsetY = -Math.floor((layer.height - size.height) / 2);
	layer.parent = document.getElementById('theInsideLayer');
	layer.canvas = createElementWith(layer.parent, 'div', null, UNSELECTABLE);
	layer.canvas.style.position = 'absolute';
	layer.canvas.style.left     = 0 + 'px';	//updateShopIconで正しい位置へ
	layer.canvas.style.top      = 0 + 'px';
	layer.canvas.style.width    = 0 + 'px';	//※実際のサイズは0(3倍の大きさを与えると
	layer.canvas.style.height   = 0 + 'px';	//  IEでスクロール中フリーズする場合がある)→関係なかった
	layer.canvas.style.visibility = 'hidden';
	layer.canvas.style.zIndex   = 500;
	
	//検索中心アイコン
	layer.center = buildHiddenImg(layer.canvas, g_iconZTop+1);

	//検索範囲外店舗アイコン(ツールチップ表示非表示div)	
	layer.outerIcons = [];

	//最終更新座標等
	layer.lastPos = {};

	g_iconLayer = layer;

	//段階的にアイコンを追加し、再描画	
	layer.icons = [];

	progressiveAppendIcons();
	
	//ブラウザを識別し、印刷専用のグラフレイヤーを使うか判定
	//※IE、FF3.0以上、Safari以外は専用レイヤーを使う
	if (g_printing)
	{
		var bv = getBrowserVersions();
		g_usePrintingGLayer = !(bv.ie
								 || (bv.ff && 3.0 <= bv.ff_ver)
								 || bv.safari);
	}
	
	//検索範囲外の店舗アイコン用システムグラフレイヤーを可視状態へ
	processScaleChanged();
}

/**
 * アイコンレイヤーへ段階的にアイコン用imgを追加していく.
 */
function progressiveAppendIcons()
{
	var append = 100;
	var layer  = g_iconLayer;

	//規定数に至るまで繰り返し追加
	if (layer.icons.length < g_iconsCount)
	{
		var c = layer.icons.length;
		for (var i = c; i < c + append; i++)
			layer.icons[i] = buildHiddenImg(layer.canvas,
								g_iconZTop - layer.icons.length);

		updateShopIcon();
	}

	if (layer.icons.length < g_iconsCount)
		setTimeout(progressiveAppendIcons, 1);
}

/**
 * 地図上のアイコン更新.
 *
 *	@param	target	指定無し:検索範囲アイコンのみ更新
 *					OUTER:検索範囲外アイコンのみ更新
 *					
 */
function updateShopIcon(target)
{
	if (g_iconLayer == null)
		return;

	var kamap = netmap.myKaMap;
	var layer = g_iconLayer;

	//アイコンレイヤー位置調整
	var newPos = {
		x:kamap.nCurrentLeft - kamap.xOrigin + layer.offsetX,
		y:kamap.nCurrentTop  - kamap.yOrigin + layer.offsetY};

	layer.canvas.style.left = newPos.x + 'px';
	layer.canvas.style.top  = newPos.y + 'px';
	
	//いかなる指定でも、レイヤー位置が変更されていれば全更新する
	var bForce = false;
	if (layer.lastPos.x != newPos.x || layer.lastPos.y != newPos.y)
	{
		bForce = true;
	}

	//最終更新座標を保存	
	layer.lastPos.x = newPos.x;
	layer.lastPos.y = newPos.y;

	//検索範囲内アイコン表示状態更新
	if (target == null || bForce)
	{
		//検索範囲内は表示地図領域の縦横3倍の矩形
		var e = netmap.getExtents();
		var w = (e.maxx - e.minx) * 1.5;
		var h = (e.maxy - e.miny) * 1.5;
		e.minx -= w;
		e.miny -= h;
		e.maxx += w;
		e.maxy += h;

		var icons = layer.icons;
		icons.cUsed = 0;

		var addCount = 0;//追加するアイコンの数

		if (isIconVisible())
		{
			//表示中ページ(front) 非ページ(rear)と2回描画
			for (var l = 0; l < 2; l++)
				addCount += _updateShopIcon_inner(
								kamap, e, layer, icons, l == 0);
		}
		
		//未使用アイコンを非表示状態へ
		for (var i = icons.cUsed; i < icons.length; i++)
			showElement(icons[i]);
			
		//アイコンが不足していれば動的に追加していく
		if (0 < addCount)
		{
			g_iconsCount += addCount;
			
			progressiveAppendIcons();
		}
	}

	//検索範囲外アイコン更新
	if (target == OUTER || bForce)
		_updateShopIcon_outer(g_outerShops);

	//検索中心位置アイコン位置更新
	setImgPosition(kamap, layer, layer.center, {lon:g_lon, lat:g_lat}, 83);
}

/**
 * 地図上のアイコン更新(検索範囲内アイコン).
 *
 *	@param	kamap	kamap
 *	@param	e		表示範囲({minx,miny,maxx,maxy})
 *	@param	layer	g_iconLayer
 *	@param	icons	g_iconLayer.icons
 *	@param	front	true:表示ページ範囲を更新/false:非表示ページ範囲を更新
 */
function _updateShopIcon_inner(kamap, e, layer, icons, front)
{
	var addCount = 0;
	var range    = currentShopRange();

	for (var i = 0; i < g_innerShops.length;)
	{
		var shop  = g_innerShops[i];
		var index = 0;

		//表示中のページなら番号付,ページ外は番号無し
		var hasGroup = shop.groupCount != 1;
		if (range.start <= shop.no && shop.no < range.end)
		{
			if (!front) {i++;continue;}
			var no = shop.groupNo - g_innerShops[range.start].groupNo;
			index = hasGroup ? (0 + no) : (40 + no);
		}
		else
		{
			if (front) {i++;continue;}
			index = hasGroup ? 80 : 81;
		}
		
		//アイコンが残っていれば位置を調整して可視状態へ
		if (icons.cUsed+1 < icons.length)
		{
			if (e.minx <= shop.lon && shop.lon <= e.maxx
				&& e.miny <= shop.lat && shop.lat <= e.maxy)
			{
				var icon = icons[icons.cUsed++];

				setImgPosition(kamap, layer, icon, shop, index);

				//検索結果ページならばマウスオーバー時のカーソル設定						
				if (!g_printing)
				{
					icon.style.cursor = 'pointer';
				}
			
				if (typeof(ShopObj) != 'undefined')
				{
					shop.shopObj = new ShopObj(shop, icon);
				}
			}
		}
		else
		{
			addCount++;
		}
			
		i += g_innerShops[i].groupCount;
	}
	
	return addCount;
}

/**
 * 地図上のアイコン更新(検索範囲外アイコン).
 *
 *	@param	outerShops	検索範囲外店舗情報リスト(緯度経度をキーとしたハッシュ)
 *						{latlon, {0:lat, 1:lon, 2:[name,...],
 *						 onmouseover, onmouseout, onmousedown, onmouseup},...}
 *						※検索範囲外店舗は、表示地図矩形内のみの情報となる
 */
function _updateShopIcon_outer(outerShops)
{
	if (g_iconLayer == null || netmap == null)
		return;
		
	var layer = g_iconLayer;
	var kamap = netmap.myKaMap;
	var c     = 0;

	for (var latlon in outerShops)
	{
		var o = outerShops[latlon];

		//不足するなら逐次追加(表示なしのdivなので速度的な問題なし)
		if (!(c < layer.outerIcons.length))
		{
			//青アイコンのサイズでdiv作成
			var div = createElementWith(layer.canvas, 'div', null, UNSELECTABLE);

			div.style.position = 'absolute';
			div.style.width    = g_shopInnerIconB.w + 'px';
			div.style.height   = g_shopInnerIconB.h + 'px';
			div.style.zIndex   = g_outerIconZTop + c;

			//IEは背景無しだとonclickが反応しないので、
			//塗りつぶして不透明度を0にする
			div.style.opacity         = 0.0;
			div.style.MozOpacity      = 0.0;
			div.style.filter          = 'Alpha(opacity=0)';
			div.style.backgroundColor = '#ffffff';
			
			layer.outerIcons[c] = div;
		}

		//位置を調整し、マウスオーバーハンドラ設定
		var div = layer.outerIcons[c];
		var xy  = kamap.geoToPix(o[1], o[0]);
		var x   = xy[0] - kamap.nCurrentLeft - layer.offsetX;
		var y   = xy[1] - kamap.nCurrentTop  - layer.offsetY;
		div.style.left  = (x + g_shopInnerIconB.ox) + 'px';
		div.style.top   = (y + g_shopInnerIconB.oy) + 'px';
		div.onmouseover = o.onmouseover;
		div.onmouseout  = o.onmouseout;
		div.onmousedown = o.onmousedown;
		div.onmouseup   = o.onmouseup;
		
		showElement(layer.outerIcons[c], true);

		c++;
	}

	//未使用divを非表示	
	for (var i = c; i < layer.outerIcons.length; i++)
		showElement(layer.outerIcons[i], false);
}

/**
 * 縮尺変更時の処理.
 */
function processScaleChanged()
{
	//縮尺に応じて,検索範囲外の店舗アイコングラフレイヤーの
	//表示/非表示切り替え
	if (netmap)
	{
		var bVisible = isIconVisible();
		
		var layers = netmap.graph.getLayers();
		for (var i = 0; i < layers.length; i++)
		{
			var n = bVisible && (!g_printing || !g_usePrintingGLayer);
			var p = bVisible && !n;
			var layers = netmap.graph.getLayers();
			for (var i = 0; i < layers.length; i++)
			{
				//検索結果、印刷ページではレイヤーが異なる
				if (layers[i].getID() == NETMAP_SHOP_ICONS_LAYER_ID)
				{
					layers[i].setVisibility(n);
					layers[i].setOpacity(100);
				}
				else if (layers[i].getID() == NETMAP_SHOP_ICONS_P_LAYER_ID)
				{
					layers[i].setVisibility(p);
					layers[i].setOpacity(100);
				}
			}
		}
		
		//検索範囲外の店舗アイコン(ツールチップ表示用)も更新
		if (!bVisible)
			g_outerShops = [];	//非表示ならばアイコンクリア
			
		updateShopIcon(OUTER);
	}
}

/**
 * 現在のスケールではアイコン表示を行うか?
 */
function isIconVisible()
{
	return netmap && ICON_MIN_SCALE <= netmap.getScaleIndex()+1;
}

/**
 * アイコンレイヤー用の非表示アイコンをimgで構築.
 *
 *	@param	parent	imgの親要素
 *	@param	zIndex	Zオーダー番号
 */
function buildHiddenImg(parent, zIndex)
{
	var url  = g_iconsIcon.url;
	var type = g_printing ? 'img' : 'div';
	var img  = document.createElement(type);

	img.style.position = 'absolute';
	img.style.left     = 0 + 'px';
	img.style.top      = 0 + 'px';
	img.style.width    = g_iconsIcon.w + 'px';
	img.style.height   = g_iconsIcon.h + 'px';
	
	if (g_printing)
	{
		//印刷用はimgタグを使う(setImgPositionでURL,座標を指定)
	}
	else
	{
		//通常はdivでのCSSスプライト
		img.style.backgroundImage  = 'url(' + url + ')';
		img.style.backgroundRepeat = 'no-repeat';

		img.ox = g_iconsIcon.ox;
		img.oy = g_iconsIcon.oy;
	}
		
	if (zIndex != null)
		img.style.zIndex = zIndex;
		
	//選択の抑制
	setUnselectableAttribute(img)

	showElement(img, false);	//非表示状態で作成
	
	parent.appendChild(img);
	
	return img;
}

/**
 * アイコンレイヤーのimg要素の位置を指定の店舗情報で設定.
 *
 *	@param	kamap
 *	@param	layer	アイコンレイヤー
 *	@param	img		アイコンimg
 *	@param	shop	{lat,lon}
 *	@param	index	icons.pngを使う際のスプライトインデックス(0～82)
 */
function setImgPosition(kamap, layer, img, shop, index)
{
	var xy = kamap.geoToPix(shop.lon, shop.lat);
	var x  = xy[0] - kamap.nCurrentLeft - layer.offsetX;
	var y  = xy[1] - kamap.nCurrentTop  - layer.offsetY;
	
	if (index != null)
	{
		//  0～39:番号付グループ店舗
		// 40～79:番号付単一店舗
		// 80    :番号なしグループ店舗
		// 81    :番号なし単一店舗
		// 83    :検索中心
		var icon = g_shopInnerNoIconB;
		if (0 <= index && index < 40)		{icon = g_shopInnerNoIconB;}
		else if (40 <= index && index < 80)	{icon = g_shopInnerNoIcon;}
		else if (index == 80)				{icon = g_shopInnerIconB;}
		else if (index == 81)				{icon = g_shopInnerIcon;}
		else if (index == 83)				{icon = g_centerIcon;}

		if (g_printing)
		{
			//img
			var url = icon.url;
			if (0 <= index && index < 80)
				url = url.replace("%d", (index % 40) + 1); //番号付アイコン

			img.style.left   = (x + icon.ox) + 'px';
			img.style.top    = (y + icon.oy) + 'px';
			img.style.width  = (icon.w) + 'px';
			img.style.height = (icon.h) + 'px';
			img.src          = url;
		}
		else
		{
			//div
			var bpx = -18 * (index % 10);
			var bpy = -20 * Math.floor(index / 10)
			
			img.style.left   = (x + icon.ox) + 'px';
			img.style.top    = (y + icon.oy) + 'px';
			img.style.width  = icon.w + 'px';
			img.style.height = icon.h + 'px';
			img.style.backgroundPosition = bpx + 'px ' + bpy + 'px';
		}
	}

	showElement(img, true);
}

/**
 * 店舗情報をグループ化(同一緯度経度).
 *
 *	@shops	店舗情報配列({lon,lat})
 *	@line	ページ表示件数
 */
function groupingShopList(shops, line)
{
	//同一ページ内の要素において、連続する同一緯度経度をグループ化
	var groupNo = 0;

	for (var i = 0; i < shops.length;)
	{
		shops[i].groupNo = groupNo;

		var cGroup = 1;	//グループに含まれる店舗数

		for (var j = i + 1;
				j < shops.length
					&& Math.floor(i/line) == Math.floor(j/line);//同一ページ
				j++)
		{
			if (shops[i].lon == shops[j].lon
				&& shops[i].lat == shops[j].lat)
			{
				shops[j].groupNo = groupNo;
				cGroup++;
			}
			else
			{
				break;
			}
		}
		
		//ページまたがりが発生すれば、その情報を追加
		if (i + cGroup < shops.length
			&& shops[i].lon == shops[i + cGroup].lon
			&& shops[i].lat == shops[i + cGroup].lat)
		{
			shops[i].cross = true;
		}

		i += cGroup;	//次のグループ先頭へ

		groupNo++;		//グループ番号も更新
	}

	//グループの先頭店舗にグループに含まれる店舗数を格納
	for (var i = 0; i < shops.length;)
	{
		var top = shops[i];	//先頭店舗
		top.groupCount = 1;

		for (var j = i+1; j < shops.length; j++)
		{
			if (top.groupNo == shops[j].groupNo)
			{
				top.groupCount++;
				shops[j].groupCount = null;	//非先頭要素はnull
			}
			else
				break;
		}
		
		i += top.groupCount;
	}
}

/**
 * DOM要素構築(親要素、クラス指定可能).
 */
function createElementWith(parent, tag, _class, unselectable)
{
	var obj = document.createElement(tag);

	if (_class)
	{
		obj.setAttribute('className', _class);	//IE
		obj.setAttribute('class',     _class);	//other
	}
	
	if (unselectable)
		setUnselectableAttribute(obj);
	
	if (parent)
		parent.appendChild(obj);
	
	return obj;
}

/**
 * HTML要素取得.
 *
 *	@param	id	要素ID
 *	@return	要素オブジェクト
 */
function el(id)
{
	return document.getElementById(id);
}

/**
 * 要素のstyle.visibilityを書き換え.
 */
function showElement(obj, visible)
{
	//状態が変わったときのみ更新(IEのステータスバー更新表示抑制)
	var v = visible ? 'visible' : 'hidden';

	if (obj.style.visibility != v)
		obj.style.visibility = v;
}

/**
 * CHECKBOX チェック状態取得.
 */
function getCheck(id)
{
	var cb = el(id);

	return cb ? cb.checked : false;
}

/**
 * CHECKBOX チェック状態設定.
 */
function setCheck(id, checked)
{
	var cb = el(id);

	if (cb)
		cb.checked = checked;
}

/**
 * <td class=_class>inner</td>.
 */
function td(_class, inner, attr)
{
	return "<td class=" + SQ(_class) + NVL(attr) + ">"
				+ (inner != null ? inner + "</td>" : '');
}

/**
 * テキストをシングルクオート.
 */
function SQ(t)
{
	return "'" + (t == null ? '' : t) + "'";
}

function NVL(v)
{
	return v ? v : '';
}

/**
 * 配列に要素が含まれるか?.
 */
function contains(a, e)
{
	for (var i = 0; i < a.length; i++)
		if (a[i] == e) return true;

	return false;
}

function makeLatLonID(lat, lon)
{
	return "" + lat + "-" + lon;
}

/**
 * 選択の抑制.
 */
function setUnselectableAttribute(obj, unselectable)
{
	unselectable = unselectable == null ? true : unselectable;
	
	if (unselectable)
	{
		//kaMap.f_setUnselectable.
		obj.setAttribute('unselectable', 'on');	//for IE
		obj.style.MozUserSelect = 'none';		//for Firefox
		obj.style.KhtmlUserSelect = 'none';		//for Safari
		obj.onmousedown = function() {return false;};
		obj.onselectstart = function () {return false;};
	}
	else
	{
		obj.setAttribute('unselectable', 'off');	//for IE
		obj.style.MozUserSelect = "";				//for Firefox
		obj.style.KhtmlUserSelect = "";				//for Safari
		obj.onmousedown = function() {return true;};
		obj.onselectstart = function () {return true;};
	}
}

/**
 * ブラウザバージョン取得(IE/FF/Safariのみ対応)
 */
function getBrowserVersions()
{
	var r  = {};
	var ua = navigator.userAgent ? navigator.userAgent : '';
	var m  = null;
	
	r.ua = ua;
	
	m = ua.match(new RegExp("\\bMSIE ([0-9]+)\.([0-9]+)"));
	r.ie     = m != null;
	r.ie_ver = m ? parseFloat(RegExp.$1 + "." + RegExp.$2) : null;

	m = ua.match(new RegExp("\\bFirefox/([0-9]+)\.([0-9]+)"));
	r.ff     = m != null;
	r.ff_ver = m ? parseFloat(RegExp.$1 + "." + RegExp.$2) : null;

	m = ua.match(new RegExp("\\bSafari/([0-9]+)\.([0-9]+)"));
	r.safari     = m != null;
	r.safari_ver = m ? parseFloat(RegExp.$1 + "." + RegExp.$2) : null;

	return r;
}

