// 定数
var MAX_LINE_POINTS = 256;	// ひとつの線での最大点数
var TIMER_INTERVAL = 100;	//タイマ間隔[msec]

// グローバル変数
var objMap = null;	// マップオブジェクト
var objMarker = null;	//マーカオブジェクト
var objSlider = null;	//スライダオブジェクト
var objGraph = null;	//グラフ表示領域オブジェクト

var aryTracks = null;	//Track一覧データ配列
var aryPoint = null;	//Point位置データ配列
var hashTime = null;	//時刻連想配列
var aryTime = null;	//スライダー用時刻配列

var intTrackIndex = null;	//設定TrackIndex
var intPointValue = null;	//最終位置時刻位置index
var intDrawedIndex = null;	//最終描画index
var intTimerId = null;	//タイマID


var iconCycleR = null;	// 自転車アイコン右向き
var iconCycleL = null;	// 自転車アイコン左向き

// onloadイベント設定
window.onload = fncInitMap;
// onunloadイベント設定
window.onunload = GUnload;
// リサイズイベント設定
window.onresize = fncResizeMap;
	///他のイベントは、onloadイベントで設定。


// GMapにメソッド追加

// 必要な範囲から最適な縮尺中心を設定
GMap2.prototype.centerAndZoomOnBounds = function(boundsLatLon)
{
	//boundsLatLonの中心を取得
	var center = new GLatLng(
		(boundsLatLon.getNorthEast().lat() + boundsLatLon.getSouthWest().lat())/2
		,(boundsLatLon.getNorthEast().lng() + boundsLatLon.getSouthWest().lng())/2
		);

	//boundsLatLonが収まるズームのサイズを取得
	var zoom = this.getBoundsZoomLevel(boundsLatLon);
		///端に余裕を持たせるため、boundsLatLonを少し拡張してもよいかもしれない

	//中心とサイズを変更
	this.setCenter(center, zoom);

	return;
}

// 地図初期化
function fncInitMap()
{
	// map領域divを設定
	objDivMap = $("id_map");
	objDivList = $("id_list");

	// 地図領域のサイズを最適化?
	fncResizeMap();

	// 地図設定
	fncMakeMap();

	//グラフ表示領域設定
	objGraph = new Canvas($("id_graph"));

	// 自転車アイコン作成
	iconCycleR = new GIcon();
	iconCycleR.image = "icon/cycle_r.png";
	iconCycleR.transparent = "icon/cycle_r.png";
	iconCycleR.iconSize = new GSize(24, 15);
	iconCycleR.iconAnchor = new GPoint(19, 14);

	iconCycleR.shadow = "icon/cycle_rs.png";
	iconCycleR.shadowSize = new GSize(37, 15);
	iconCycleR.infoShadowAnchor = new GPoint(19, 14);

	iconCycleR.infoWindowAnchor = new GPoint(19, 0);


	iconCycleL = new GIcon();
	iconCycleL.image = "icon/cycle_l.png";
	iconCycleL.transparent = "icon/cycle_l.png";
	iconCycleL.iconSize = new GSize(24, 15);
	iconCycleL.iconAnchor = new GPoint(4, 14);

	iconCycleL.shadow = "icon/cycle_ls.png";
	iconCycleL.shadowSize = new GSize(37, 15);
	iconCycleL.infoShadowAnchor = new GPoint(4, 14);

	iconCycleL.infoWindowAnchor = new GPoint(4, 0);


	// track一覧データ取得開始
	var ojbAjax = new Ajax.Request(
		"./php/tracks.php"
		,{method: "get"
//			, onComplete: function(){alert("onComplete");}
			, onSuccess: fncOnRecvTracks
			, onFailure: function(){alert("一覧データ受信に失敗しました。");}
			}
		);

	return;
}

// GMap作成
function fncMakeMap()
{
	objMap = new GMap2(objDivMap);
	objDivMap.style.zIndex = "0";	//GOverviewMapControlより、後ろにするため…

	//ズームコントロール大
	objMap.addControl(new GLargeMapControl(), new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 30)));

	//Overview地図コントロール
	objMap.addControl(new GOverviewMapControl(new GSize(140,100)), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(0, 0)));

	//ドラッグした範囲を拡大するコントロール
	objMap.addControl(new GZoomControl(), new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 310)));


	//地図タイプ選択コントロール
//	objMap.addControl(new GMapTypeControl(), new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 5)));
	addMapTypeControl(objMap);

	//ストリートビューチェックボックス
	objChkStView = new CheckboxStreetviewControl();
	objMap.addControl(objChkStView);


	//日本全体を通常の地図で表示
	objMap.setCenter(new GLatLng(35.045519825, 135.074992775), 5, G_HYBRID_MAP);

	//左ダブルクリックでズームイン、右ダブルクリックでズームアウト
	objMap.enableDoubleClickZoom();
	//スムーズにズーム
	objMap.enableContinuousZoom();
	//ホイールでズーム
	objMap.enableScrollWheelZoom();

	//ストリートビュー可能な道を青く
//	objMap.addOverlay(new GStreetviewOverlay());


	// スライダー初期化
//	$("id_graph").style.width  = (fncGetClientWidth() -30) + "px";
	$("id_slider").style.width = ($("id_graph").offsetWidth + $("id_handle").offsetWidth) + "px";
}

//地図タイプいろいろコントロール
function addMapTypeControl(objMap)
{
	//地形+地名を定義
	var G_HYBRID_PHYSICAL_MAP = new GMapType(
		[G_PHYSICAL_MAP.getTileLayers() [0], G_HYBRID_MAP.getTileLayers() [1]]
		, G_NORMAL_MAP.getProjection()
		, "Hybrid Physical"
		);

	//地図タイプに地形を追加
	objMap.addMapType(G_PHYSICAL_MAP);
	//地図タイプに地形+地名を追加
	objMap.addMapType(G_HYBRID_PHYSICAL_MAP);


	//プルダウンのコントロール部品を追加
	var objCtrl = new GHierarchicalMapTypeControl();
	objCtrl.clearRelationships();

	///衛星の下に、地名付き衛星を
	objCtrl.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP,"地名を表示", false);	//衛星に地名表示のプルダウンを
	///地形の下に、地名付き地形を
	objCtrl.addRelationship(G_PHYSICAL_MAP, G_HYBRID_PHYSICAL_MAP, "地名を表示", false);	//地形に地名表示のプルダウンを

	///プルダウン付きを追加
	objMap.addControl(objCtrl); 
}

// 地図をリサイズ
function fncResizeMap()
{
	// 幅は勝手に変わるので、高さだけ変更。
	// 初期サイズの倍より大きくなるあたりで、描画が更新されないけど気にしない。
	var intHeight = fncGetClientHeight();
	var intWidth = fncGetClientWidth();

	intHeight -= $("id_footer").offsetHeight + 20;
	if(intHeight >= 0)
	{
		objDivMap.style.height = intHeight + "px";
		objDivList.style.height = (intHeight-20) + "px";
	}

	intWidth -= $("id_list").offsetWidth + 20;
	if(intWidth <= 300) intWidth = 300;
	objDivMap.style.width = intWidth + "px";

	return;
}

function fncGetClientHeight()
{
	if(window.self && self.innerHeight)
		// ねすけ用
		return self.innerHeight;
	else if(document.documentElement && document.documentElement.clientHeight)
		// IE用
		return document.documentElement.clientHeight;
}
function fncGetClientWidth()
{
	if(window.self && self.innerWidth)
		// ねすけ用
		return self.innerWidth;
	else if(document.documentElement && document.documentElement.clientWidth)
		// IE用
		return document.documentElement.clientWidth;
}


//innerHtml設定
function fncSetInnerHtml(objElement, strInnerHtml)
{
	objElement.innerHTML = strInnerHtml;
		// fncSetInnerTextと違い、意味が無い…
}

// track一覧データ受信イベント
function fncOnRecvTracks(objReq)
{
	//配列なjson受信データを配列に戻す
	aryTracks = JSON.parse(objReq.responseText);

	var strList = "";
	var date;
	for(var i=0; i<aryTracks.length; i++)
	{
		//開始時刻を取得
		date = new Date(aryTracks[i][1]*1000);
		var strDate = date.getFullYear().toString() + "/" + (date.getMonth()+1) + "/" + date.getDate();
//		var strDate = date.toLocaleString();

		strList += "<a href='javascript:fncSetTrack(" + i + ");'>"
			+ strDate + " " + aryTracks[i][3]
			+ "</a><br>";
	}

	// リスト設定
	fncSetInnerHtml(objDivList, strList);
}

// track選択
function fncSetTrack(intIndex)
{
	if(intTrackIndex == intIndex)
		// 選択済みなので、無視
		return;
	intTrackIndex = intIndex;

	// 地図クリア
	fncClearMap();

	// trackデータ取得開始
	var ojbAjax = new Ajax.Request(
		"./php/track_points.php"
		,{method: "get"
			, parameters: ("track=" + aryTracks[intTrackIndex][0])
//			, onComplete: function(){alert("onComplete");}
			, onSuccess: fncOnRecvPoints
			, onFailure: function(){alert("ルートデータ受信に失敗しました。");}
			}
		);

	return;
}

// pointsデータ受信イベント
function fncOnRecvPoints(objReq)
{
	aryTime = new Array();	//スライダ用時刻配列
	hashTime = new Array();	//時刻連想配列
	intDrawedIndex = 0;	//最終描画index


	//配列なjson受信データを配列に戻す
	aryPoint = JSON.parse(objReq.responseText);

	// アイコン初期値設定
	fncSetPointField(0);

	//範囲
	var bounds = new GLatLngBounds();
	///一番南西
	bounds.extend(new GLatLng(aryTracks[intTrackIndex][8], aryTracks[intTrackIndex][10]));
	///一番東北
	bounds.extend(new GLatLng(aryTracks[intTrackIndex][9], aryTracks[intTrackIndex][11]));
	/// すべてのpointが入る、位置と縮尺指定
	objMap.centerAndZoomOnBounds(bounds);
	/// ルート全体を示すを保存
	objMap.savePosition();


	//グラフ初期化&時間メモリ、最小値、最大値設定
	objGraph.clear();
	objGraph.setTimeScale(aryTracks[intTrackIndex][1], aryTracks[intTrackIndex][2]);
	objGraph.setMinValue(aryTracks[intTrackIndex][12]);
	objGraph.setMaxValue(aryTracks[intTrackIndex][13]);

	if(objSlider != null)
	{	//スライダ無効に
		objSlider.setDisabled();
	}

	//タイマ設定
	intTimerId = setTimeout("fncOnTimerDraw()", TIMER_INTERVAL);

	return;
}

//タイマ起動 描画処理
function fncOnTimerDraw()
{
	var strEncodedPoints = "";		//GPolyline.fromEncodedの引数points
	var strEncodedLevels = "";		//GPolyline.fromEncodedの引数levels


	//タイマをクリア
	clearTimeout(intTimerId);

	// グラフの線 開始
	objGraph.beginLine("rgba(0,255,0,1)");

	fncInitEncodedPoint();

	if(intDrawedIndex > 0)
	{	// 2回目以降なので、前回の点を設定して繋げる
		var aryFld = aryPoint[intDrawedIndex -1];

		// 前回の続きから
		objGraph.setLinePos(aryFld[0], aryFld[3], true);

		//GPolyline.fromEncoded引数データ作成
		strEncodedPoints += fncGetEncodedPoint(aryFld[1], aryFld[2]);
		strEncodedLevels += encodeNumber(0);
	}


	//最後まで、もしくは今回MAX_LINE_POINTSまでまわす
	for(i=0; intDrawedIndex < aryPoint.length && i < MAX_LINE_POINTS; intDrawedIndex++,i++)
	{
		// 配列indexから、取得
		var aryFld = aryPoint[intDrawedIndex];

		//グラフ描画
		objGraph.setLinePos(aryFld[0], aryFld[3], (intDrawedIndex==0 ? true : false));

		//GPolyline.fromEncoded引数データ作成
		strEncodedPoints += fncGetEncodedPoint(aryFld[1], aryFld[2]);
		strEncodedLevels += encodeNumber(0);

		//時刻連想配列に追加
		hashTime[aryFld[0].toString()] = intDrawedIndex;

		//スライダー用時刻配列に追加
		aryTime.push(aryFld[0]);
	}

	// グラフに線を描く
	objGraph.endLine();

	// 線を地図に貼る
	objMap.addOverlay(new GPolyline.fromEncoded({
		color:"#ff0000"
		,weight:2
		,opacity:1
		,points:strEncodedPoints
		,zoomFactor:32
		,levels:strEncodedLevels
		,numLevels:1
		}));

	//タイマ設定
	if(intDrawedIndex < aryPoint.length)
	{	//まだ続きあり
		intTimerId = setTimeout("fncOnTimerDraw()", TIMER_INTERVAL);
	}
	else
	{	//最後までいった
		intTimerId = setTimeout("fncOnTimerSlider()", TIMER_INTERVAL);
	}

	return;
}

//スライダ設定
function fncOnTimerSlider()
{
	//タイマをクリア
	clearTimeout(intTimerId);
	intTimerId = null;

	// スライダー初期化
//	$("id_graph").style.width = (fncGetClientWidth() -30) + "px";
	$("id_slider").style.width = ($("id_graph").offsetWidth + $("id_handle").offsetWidth) + "px";

	objSlider = new Control.Slider("id_handle", "id_slider"
		,{	values: aryTime
			,range: $R(aryTime[0], aryTime[aryTime.length-1])
			,sliderValue: aryTime[0]
			,onSlide: fncOnChangeSlider
			,onChange: fncOnChangeSlider
//			,onChange: function(v){$("id_slid_debug").innerHTML="changed! " + (new Date(v*1000)).toLocaleString();}
		});
	objSlider.setEnabled();

	intPointValue = -1;
}

//スライダー変更イベント
function fncOnChangeSlider(intValue)
{
	//前回と同じなら、処理しない
	if(intPointValue == intValue)
		return;
	intPointValue = intValue;

	//指定位置の連想配列キーから、配列インデックスを取得
	var intIndex = hashTime[intValue.toString()];

	//位置設定
	var objLatLng = fncSetPointField(intIndex);

	//中心を移動
	objMap.panTo(objLatLng);
}

//地図などクリア
function fncClearMap()
{
	$("id_slid_debug").innerHTML = "";
	objMap.clearOverlays();
	objMarker = null;

	if(objSlider != null)
	{	//スライダを無効に
		objSlider.setDisabled();
	}

	//グラフ初期化
	objGraph.clear();

	// ストリートビュー、人形アイコンが設定されていれば、
	if(objStViewOl)
		objMap.addOverlay(objStViewOl);
	if(objMarkerStv)
		objMap.addOverlay(objMarkerStv);
}

//位置設定
function fncSetPointField(intIndex)
{
	var aryFld = aryPoint[intIndex];

	//時刻、標高表示
	$("id_slid_debug").innerHTML = (new Date(aryFld[0]*1000)).toLocaleString() + " 標高:" + aryFld[3] + "m";

	//位置
	var objLatLng = new GLatLng(aryFld[1], aryFld[2]);

	//前後の位置
	var aryBefor = aryPoint[intIndex>0 ? intIndex-1 : intIndex];
	var aryNext = aryPoint[intIndex==aryPoint.length-1 ?  intIndex : intIndex+1];

	//前のマーカ消去
	if(objMarker != null)
		objMap.removeOverlay(objMarker);

	//新マーカ設定
	if(aryBefor[2] <= aryNext[2])
		//東にすすんでいるので、右向き
		objMarker = new GMarker(objLatLng, iconCycleR, true);
	else
		objMarker = new GMarker(objLatLng, iconCycleL, true);

	objMap.addOverlay(objMarker);

	//GLatLngを返す
	return objLatLng;
}



//キャンバス処理クラス コンストラクタ
function Canvas(element)
{
	this.divCanvas = element;

	this.oCtx = null;
	if(this.divCanvas.getContext)
	{
		// 2Dコンテキストを返す
		this.oCtx = this.divCanvas.getContext('2d');
	}

	// コンストラクタ処理の終了
	return this;
}

//canvasクリア
Canvas.prototype.clear = function()
{
	if(this.oCtx==null)	return;

	this.oCtx.clearRect(0, 0, this.divCanvas.offsetWidth, this.divCanvas.offsetHeight );
}


//時刻目盛り設定
Canvas.prototype.intStart = null;	//開始時刻
Canvas.prototype.intEnd = null;		//終了時刻
Canvas.prototype.setTimeScale = function(intStart, intEnd)
{
	if(this.oCtx==null)	return;

	//開始&終了時刻設定
	this.intStart = intStart;
	this.intEnd = intEnd;

	//キャンバスの幅・高さを取得
	///parseIntで末尾のpxも削除
	var intWidth = this.divCanvas.clientWidth;
	var intHeight = this.divCanvas.clientHeight;
//alert("intWidth:" + intWidth);
//alert("intHeight:" + intHeight);

	//開始時刻のDateオブジェクト
	var dtStart = new Date(intStart*1000);
	//最初の時間?(0分)
	var intFirstHour = (new Date(dtStart.getFullYear(), dtStart.getMonth(), dtStart.getDate()
		, dtStart.getHours(), 0, 0)).getTime() / 1000 + 3600;

	// 線の設定
	this.oCtx.strokeStyle = "rgba(0,0,0,1)";
	this.oCtx.lineWidth = 1;

	//1時間の3600秒間隔で、最終時刻を越えるまで回す
	for(var intHour=intFirstHour; intHour<intEnd; intHour+=3600)
	{
 		//x軸の位置を算出
		var intX = intWidth * (intHour - intStart) / (intEnd - intStart);
//alert(intHour + ':' + intX);
		//縦線を引く
		this.oCtx.beginPath();
		this.oCtx.moveTo(intX, 0);
		this.oCtx.lineTo(intX, intHeight);
//		this.oCtx.closePath();	// closePathすると、終点と始点をつなげるので行わない
		this.oCtx.stroke();
	}
}

//最小値設定
Canvas.prototype.intMinValue = null;
Canvas.prototype.setMinValue = function(intMinValue)
{
	this.intMinValue = intMinValue;
}
//最大値設定
Canvas.prototype.intMaxValue = null;
Canvas.prototype.setMaxValue = function(intMaxValue)
{
	this.intMaxValue = intMaxValue;
}

// 線開始
Canvas.prototype.beginLine = function(style)
{
	if(this.oCtx==null)	return;

	this.oCtx.strokeStyle = style;
	this.oCtx.lineWidth = 1;
	this.oCtx.beginPath();
}


//線の値を設定
Canvas.prototype.setLinePos = function(intTime, intValue, blnFirst)
{
	if(this.oCtx==null)	return;

	//キャンバスの位置を設定
	var intX = this.divCanvas.clientWidth *  (intTime - this.intStart) / (this.intEnd - this.intStart);
	var intY = this.divCanvas.clientHeight * (this.intMaxValue - intValue) / (this.intMaxValue - this.intMinValue);

	if(blnFirst)
	{	// 最初なので移動
		this.oCtx.moveTo(intX, intY);
	}
	else
	{	//最初でないので、前回から今回に線を引く
		this.oCtx.lineTo(intX, intY);
	}
}

// 線終了
Canvas.prototype.endLine = function()
{
	if(this.oCtx==null)	return;

//	this.oCtx.closePath();	// closePathすると、終点と始点をつなげるので行わない
	this.oCtx.stroke();
}

