
function RouteDelta(map)
{
	this.map = map;

	this.deltaHtml      = "";
	this.deltaText      = "";
	this.encoded_points = "";
	this.pathDistance   = 0;
	this.linearDistance = 0;

	this.baseIcon   = null;
	this.pathAry    = [];
	this.pathPoly   = null;
	this.zoom       = 16;
	this.maptype    = 0;
	this.resolution = 100000;
	this.panIndex   = 0;
	this.panIndex2  = 0;
	this.B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.';

	this.l = 0;	// RouteDelta_bb64()用：文字数
	this.s = '';	// RouteDelta_bb64()用：文字列(BASE64もどき)

	this.baseIcon = new GIcon();
	this.baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
	this.baseIcon.iconSize = new GSize(20, 34);
	this.baseIcon.shadowSize = new GSize(37, 34);
	this.baseIcon.iconAnchor = new GPoint(9, 34);
	this.baseIcon.infoWindowAnchor = new GPoint(9, 2);
	this.baseIcon.infoShadowAnchor = new GPoint(18, 25);
}

function RouteDelta_addLatLng(latlng)
{
	var lat = latlng.lat();
	var lng = latlng.lng();
	// 誤差蓄積回避のため、丸めておく
	lat = lat.toFixed(5);
	lng = lng.toFixed(5);
	this.pathAry.push(new GLatLng(lat,lng));	// パスを追加する
	this.panIndex = this.pathAry.length;	// スクロール抑制

	this.pathRedraw();
}
RouteDelta.prototype.addLatLng = RouteDelta_addLatLng;

// 最後の点を削除
function RouteDelta_delete_last1()
{
	this.pathAry.pop();
	this.pathRedraw();
}
RouteDelta.prototype.delete_last1 = RouteDelta_delete_last1;

// 線を全て削除
function RouteDelta_delete_all_lines()
{
	this.pathAry = [];
	this.pathRedraw();
}
RouteDelta.prototype.delete_all_lines = RouteDelta_delete_all_lines;


// パスの再描画・距離再計算
function RouteDelta_pathRedraw()
{
	this.pathDistance = 0;
	this.linearDistance = 0;

	this.map.clearOverlays();	// とりあえず全部消す！
	if ( this.pathAry.length >= 1 ) {  // 1個以上じゃないとPolylineでエラーが出るので。
		// 前回の線を消して、書く
		this.pathPoly = new GPolyline(this.pathAry, "#ff0000");
		this.map.addOverlay(this.pathPoly);
		// 距離計算
		for ( i=1; i<this.pathAry.length; i++ ) {
			this.pathDistance += (this.pathAry[i-1]).distanceFrom(this.pathAry[i]);
		}
		this.linearDistance = this.pathAry[0].distanceFrom(this.pathAry[this.pathAry.length-1]);

		// スタートマーカー描画
		var icon = new GIcon(this.baseIcon);
		icon.image = "http://www.google.com/mapfiles/markerS.png";
		var marker = new GMarker(this.pathAry[0], icon);
		this.map.addOverlay(marker);
	}

	this.createEncodings();
}
RouteDelta.prototype.pathRedraw = RouteDelta_pathRedraw;


// GPolyline.fromEncoded 形式の経路情報を読む
function RouteDelta_gpfe2pathAry(gpfe)
{
	var encodedPolyline = new GPolyline.fromEncoded({
		color: "#FF0000",
		weight: 10,
		points: gpfe,
		levels: "",
		zoomLevel: 32,
		numLevels: 4
	});			// gpfe以外のパラメータは、関係無いっす。GPolylineのインスタンスは後で作り直しちゃうんで。
	
	// 上で読んだ GPolyline を pathAry にぶち込む。
	this.pathAry = [];
	var len = encodedPolyline.getVertexCount();
	for ( i=0; i<len; i++ ) {
		this.pathAry.push(encodedPolyline.getVertex(i));
	}
	this.panIndex = this.pathAry.length;	// スクロール抑制
}
RouteDelta.prototype.gpfe2pathAry = RouteDelta_gpfe2pathAry;


// BASE64もどきpathから、this.pathAry を再生成
// ※※※旧バージョン用の盲腸関数※※※
function RouteDelta_pathparam2pathAry(path)
{
	n_lat =  36;
	n_lng = 138;

	var version = this.B64.indexOf(path.charAt(0));
	if ( version <=0 ||  3 <= version) {
		alert('パラメータのバージョンが不正です。非対応と思われます。'+this.B64.indexOf(path.charAt(0)));
		return;
	}
	var scale = 1;
	if ( version == 1 ) {
		// バージョン１では精度がコンマ6桁だったんですよ。
		scale = 10;
	}

	var param2 = this.B64.indexOf(path.charAt(1));
	if ( param2 & 32 ) {
		// 上のビットが立っていたら、航空写真
		this.maptype = G_SATELLITE_MAP;
	}
	else {
		// 上のビットが立っていたら、地図
		this.maptype = G_NORMAL_MAP;
	}
	// 下5ビットはズーム値
	this.zoom = param2 & 31;

	i=2;
	while (i<path.length) {
		// 1文字目処理
		pre = this.B64.indexOf(path.charAt(i));
		l_lat = (pre&24)/8 +1;
		l_lng = (pre&3)    +1;
		if ( pre&32 ) {
			s_lat = +1;
		}
		else {
			s_lat = -1;
		}
		if ( pre&4 ) {
			s_lng = +1;
		}
		else {
			s_lng = -1;
		}
		i++;

		// lat処理
		d_lat = 0;
		for ( l=0;l<l_lat;l++ ) {
			if ( path.length <= i ) {
				alert("パラメータがが不正です。");
				this.pathAry = [];
				return;
			}
			d_lat *= 64;
			d_lat += this.B64.indexOf(path.charAt(i));
			i++;
		}
		d_lat *= s_lat;
		// lng処理
		d_lng = 0;
		for ( l=0;l<l_lng;l++ ) {
			if ( path.length <= i ) {
				alert("パラメータがが不正です。");
				this.pathAry = [];
				return;
			}
			d_lng *= 64;
			d_lng += this.B64.indexOf(path.charAt(i));
			i++;
		}
		d_lng *= s_lng;

		// 古いバージョン用の盲腸処理
		d_lat = d_lat/scale;
		d_lng = d_lng/scale;

		// 座標追加
		n_lat+=d_lat/this.resolution;
		n_lng+=d_lng/this.resolution;
		this.pathAry.push(new GLatLng(n_lat,n_lng));
	}

	this.panIndex = this.pathAry.length;	// スクロール抑制
}
RouteDelta.prototype.pathparam2pathAry = RouteDelta_pathparam2pathAry;

function RouteDelta_bb64(d)
{
	var sign = 1;	// 符号(1:正 0:負)
	if ( d<0 ) {
		d = -d;   // 反転
		sign=0; // 符号は負ですよ
	}

	// 64進数作成
	this.s = '';
	this.l = 0; // 長さ 1-4
	while ( d > 0 ) {
		c = d % 64;
		d -= c;
		d /= 64;
		this.s = this.B64.charAt(c) + this.s;
		this.l++;
	}
	if ( sign == 0 ) {
		this.l = -this.l;
	}
	if ( this.l==0 ) {
		this.l = 1;
		this.s = this.B64.charAt(0);
	}
}
RouteDelta.prototype.bb64 = RouteDelta_bb64;

function RouteDelta_startScroll()
{
	this.map.setCenter(new GLatLng(this.pathAry[0].lat(), this.pathAry[0].lng()));
	this.panIndex=1;
	this.panIndex2=0;
	this.map_moveend();
}
RouteDelta.prototype.startScroll = RouteDelta_startScroll;

function RouteDelta_endScroll()
{
	this.panIndex = this.pathAry.length;
}
RouteDelta.prototype.endScroll = RouteDelta_endScroll;

function RouteDelta_map_moveend()
{
	if ( this.panIndex < this.pathAry.length ) {
		var projection = this.map.getCurrentMapType().getProjection();
		var p1 = projection.fromLatLngToPixel(this.map.getCenter(),        this.map.getZoom());
		var p2 = projection.fromLatLngToPixel(this.pathAry[this.panIndex], this.map.getZoom());
		this.map.panBy(new GSize(p1.x-p2.x, p1.y-p2.y));
		this.panIndex++;
/* memo
panTo を使うと、遠い点に移動するときにスクロールしてくれないのと、
moveend イベントが発生しないと言う致命的な弱点がある。
なので、panBy を使用した。

p1 は　getCenter じゃなくて panIndex-1 を使えばよさそうな気がするが、
誤差が蓄積しそうな予感なので getCenterを使用した。
*/

	}
}
RouteDelta.prototype.map_moveend = RouteDelta_map_moveend;



/*
  deltaフォーマット
    1文字目  バージョン
    2文字目  スケール (第5bitが 地図/衛星)
    それ以降 ⊿

⊿詳細
1文字目(pre)
543210
+      Lat符号(1:正 0:負)
 ++    Lat文字数(0-3)
   +   Lng符号(1:正 0:負)
    ++ Lng文字数(0-3)
2文字目以降 Lat Lng
*/



// Encode a signed number in the encode format.
function RouteDelta_encodeSignedNumber(num) {
  var sgn_num = num << 1;

  if (num < 0) {
    sgn_num = ~(sgn_num);
  }

  return(this.encodeNumber(sgn_num));
}
RouteDelta.prototype.encodeSignedNumber = RouteDelta_encodeSignedNumber;

// Encode an unsigned number in the encode format.
function RouteDelta_encodeNumber(num) {
  var encodeString = "";

  while (num >= 0x20) {
    encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
    num >>= 5;
  }

  encodeString += (String.fromCharCode(num + 63));
  return encodeString;
}
RouteDelta.prototype.encodeNumber = RouteDelta_encodeNumber;

// Create the encoded polyline and level strings.
function RouteDelta_createEncodings() {
	var i = 0;

	var plat = 0;
	var plng = 0;

	this.encoded_points = "";

	for(i = 0; i < this.pathAry.length; ++i) {
		var late5 = Math.floor(this.pathAry[i].lat() * 1e5);
		var lnge5 = Math.floor(this.pathAry[i].lng() * 1e5);
		this.encoded_points += this.encodeSignedNumber(late5 - plat) + this.encodeSignedNumber(lnge5 - plng);
		plat = late5;
		plng = lnge5;
	}
	this.zoom = this.map.getZoom();
	this.maptype = (this.map.getCurrentMapType()==G_SATELLITE_MAP) ? 1 : 0;
}
RouteDelta.prototype.createEncodings = RouteDelta_createEncodings;



// Google様のフォーマットがあるのに、独自フォーマットを作っちまったよ。
// 死亡。死蔵。使うな。
function RouteDelta_recalcDelta()
{
	// delta文字列を作る。このプログラムのキモ。
	this.deltaHtml = '';
	this.deltaText = '';

	// バージョン
	this.deltaHtml += '<font color="#666666">'+this.B64.charAt(2)+'</font>';
	this.deltaText += this.B64.charAt(2);

	// 現在のマップタイプとスケール
	var param2 = this.map.getZoom();
	if ( this.map.getCurrentMapType()==G_SATELLITE_MAP　) {
		// マップタイプが航空写真なら、上位ビットを立てる。
		param2 |= 32;
	}
	this.deltaHtml += '<font color="#666666">'+this.B64.charAt(param2)+'</font>';
	this.deltaText += this.B64.charAt(param2);

	for ( i=0; i<this.pathAry.length; i++ ) {
		// 前回との差分（最初の点の場合は(36,138)からの差分）
		d_lat = Math.round( (this.pathAry[i].lat() - (i ? this.pathAry[i-1].lat() :  36) )*this.resolution);
		d_lng = Math.round( (this.pathAry[i].lng() - (i ? this.pathAry[i-1].lng() : 138) )*this.resolution);
		//                0 1                22   2                      33      2 1        0

		g_RouteDelta.bb64(d_lat);
		var l_lat = this.l;
		var s_lat = this.s;

		g_RouteDelta.bb64(d_lng);
		l_lng = this.l;
		s_lng = this.s;

		// ⊿の1文字目を決定
		var pre=0;
		if ( l_lat > 0 ) {
			// 正
			pre += 32;	// 符号
			pre += (l_lat-1)*8;	// 文字数
		}
		else {
			// 符号はもともと0
			pre -= (l_lat+1)*8;	// 文字数
		}
		if ( l_lng > 0 ) {
			pre += 4	// 符号
			pre += l_lng-1;	// 文字数
		}
		else {
			// 符号はもともと0
			pre -= l_lng+1;	// 文字数
		}

		this.deltaHtml += '<font color="#0000cc">'+this.B64.charAt(pre)+'</font>' + '<font color="#00cc00">'+s_lat+'</font>' + '<font color="#cc0000">'+s_lng+'</font>';
		this.deltaText += this.B64.charAt(pre)+s_lat+s_lng;
	}//for
}
RouteDelta.prototype.recalcDelta = RouteDelta_recalcDelta;


