// Common JavaScript Document

Event.observe(window, 'load', initialize);
Event.observe(window, 'unload', finalize);

// GMapsクラスのオブジェクト（グローバル変数）
var gblGMaps = null;

/**
 * 初期化処理
 */
function initialize(e) {

	// [フロント側] 検索ページ（マップ表示・一覧表示）
	if ($('searchForm')) {
		
		// マップ表示
		if ($('resultsMap')) {
			
			// 初回ロード時
			gblGMaps = new GMaps();
			new Remote().searchRequest('searchForm', 'gblGMaps.load(\'resultsMap\', json);');
		
		// 一覧表示
		} else {
		
			// 初回ロード時
			new Remote().searchUpdate('searchForm', 'results');
			
//			// 検索・表示
//			Event.observe('searchForm', 'change', function(e) {
//																							new Remote().searchUpdate('searchForm', 'results');
//																						});
		}
	}
	
	// [フロント側] 詳細ページ
	if ($('displayMap')) {
																																																																																																																																
		// 初回ロード時
		gblGMaps = new GMaps();
		// 中心点マーカーがデフォルト位置で、詳細住所（地図検索用）が存在する場合、住所から座標を取得する
		if (!$('degree_latitude').value && !$('degree_latitude').value && $('assress_detail').value) {
			gblGMaps.searchCoord($('assress_detail').value, "gblGMaps.load('displayMap')");
			//setTimeout(function(){gblGMaps.load('displayMap');}, 1000);	// 非同期処理との同期をとるため
		} else {
			gblGMaps.load('displayMap');
		}
	}
	
	// [管理側] 物件情報登録・編集ページ
	if ($('coordMap')) {
		
		// 初回ロード時
		gblGMaps = new GMaps();
		
		// 業者情報の初回ロード
		if ($('id_trader').disabled == false && $('id_trader').value) {
			new Remote().simpleUpdate('/manager/trader/info?tid='+$('id_trader').value, 'traderInfo');
		}
	}
}

/**
 * 終了処理
 */
function finalize(e) {
	
	// 検索用マップ、表示用マップ、座標取得用マップ
	if ($('resultsMap') || $('displayMap') || $('coordMap')) {
		
		// Google Maps APIが確保したメモリー・リソースを解放する
		GUnload();
	}
}


var Common = Class.create({
													
	initialize: function() {
		this.name = 'Common';
	},
	
	getName: function() {
		return this.name;
	}
});


var Utility = Class.create(Common, {
	
	initialize: function() {
		this.name = 'Utility';
	},
	
	/**
	 * 指定されたフォームのアクション値を変更する
	 *（フォーム送信を行う場合、送信後にアクション値をデフォルトに戻す）
	 *
	 * @param string f フォームID
	 * @param string a 変更後のアクション値
	 * @param boolean s フォーム送信をするかどうか
	 * @return void
	 */
	changeFormAction: function(f, a, s) {
		
		var formElement;		// フォームエレメント
		var defaultAction;	// デフォルトアクション値
		
		// フォームエレメントの取得
		formElement = $(f);
		
		// デフォルトアクション値の取得
		defaultAction = formElement.action;
		
		// アクション値の変更
		formElement.action = a;
		
		if (s) {
			// フォーム送信
			formElement.submit();
			
			// アクション値を戻す
			formElement.action = defaultAction;
		}
	},
	
	/**
	 * 指定されたフォームの属性値を変更する
	 *（フォーム送信を行う場合、送信後に属性値をデフォルトに戻す）
	 *
	 * @param string formId フォームID
	 * @param string attribs 変更対象のフォーム属性名と値の連想配列
	 * @param boolean s フォーム送信をするかどうか
	 * @return void
	 */
	changeFormAttribs: function(formId, attribs, s) {
		
		var formElem;												// フォームエレメント
		var defaultAttribs = new Object();	// デフォルトのフォーム属性値オブジェクト
		
		// フォームエレメントの取得
		formElem = $(formId);
		
		for (var property in attribs) {
			
			// デフォルトの取得
			defaultAttribs.property = formElem.property;
			
			// 属性値の変更
			formElem.property = attribs.property;
		}
		
		if (s) {
			// フォーム送信
			formElem.submit();
			
			for (var property in defaultAttribs) {
				
				// 属性値を戻す
				formElem.property = defaultAttribs.property;
			}
		}
	},
	
	/**
	 * IMGタグのsrc属性に指定した画像が存在しない場合、No Image画像を設定する
	 *
	 * @param object e エラー発生オブジェクト
	 * @return void
	 */
	setNoImage: function(e) {
				
		// No Image画像の設定
		e.src = 'http://www.housteer.co.jp/img/now_printing.gif';
	},
	
	/**
	 * 整数値を3桁ごとにカンマで区切って返す
	 *
	 * @param integer number 整数値
	 * @return void
	 */
	toComma: function (number) {
		
		var to = String(number);
		var tmp = "";
		while (to != (tmp = to.replace(/^([+-]?\d+)(\d\d\d)/,"$1,$2"))){
			to = tmp;
		}
		
		if (null != to.match(/\./)) {
			
			while (null != to.match(/0$/)) {
				//alert('here');
				to = to.replace(/0$/, "");
			}
			to = to.replace(/\.$/, "");
		}
		
		return to;
	},
	
	/**
	 * 対象エレメントの背景色を指定された色に変更する
	 *
	 * @param object element 対象エレメント
	 * @param string color 背景色
	 * @return void
	 */
	changeBgColor: function (element, color) {
		
		element.style.backgroundColor = color;
	},
	
	/**
	 * リターンキー入力によるキーボードイベントを無効化する
	 *
	 * @param object e イベントオブジェクト
	 * @return void
	 */
	disableReturnKey: function (e) {
		
		//if (!e) {
		//	// IEの場合
		//	var e = window.event;
		//}
		
		if (e.keyCode == Event.KEY_RETURN) {
			Event.stop(e);
		}
	}
});


var Remote = Class.create(Common, {
	
	initialize: function() {
		this.name = 'Remote';
	},
	
	/**
	 * Ajax接続により、検索条件に一致するデータを検索・取得し、
	 * 取得データにより指定エレメントの値を更新する
	 *
	 * @param string formId 検索フォームID
	 * @param string container 更新対象のエレメントID
	 * @return void
	 */
	searchUpdate: function(formId, container) {
		//alert('here!');
		var form = $(formId);
		
		new Ajax.Updater(
			container,
			form.action,
			{
				"method": form.method,
				"parameters": Form.serialize(form),
				onSuccess: function(xhrObject) {
				},
				onFailure: function(xhrObject) {
					alert('読み込みに失敗しました');
				}
			}
		);
	},
		
	/**
	 * 指定URLからの取得データにより指定エレメントの値を更新する
	 *
	 * @param string url URL
	 * @param string container 更新対象のエレメントID
	 * @return void
	 */
	simpleUpdate: function(url, container) {
		
		new Ajax.Updater(
			container,
			url,
			{
				"method": "get",
				"parameters": "",
				onSuccess: function(xhrObject) {
					// 成功時の処理を記述 
					// alert('成功しました'); 
					// jsonの値を処理する場合↓↓ 
					//  var json; 
					//  eval("json="+xhrObject.responseText); 
				},
				onFailure: function(xhrObject) {
					alert('読み込みに失敗しました');
				}
			}
		);
	},
	
	/**
	 * Ajax接続により、ページ処理を行う
	 *
	 * @param integer page 移動先ページ番号
	 * @return void
	 */
	paginate: function(page) {
		
		$('page').value = page;
		
		this.searchUpdate('searchForm', 'results');
		
		$('page').value = 1;
	},
	
	/**
	 * Ajax接続により、検索条件に一致するデータを検索・取得し、
	 * コールバック関数の指定があれば実行する
	 *
	 * @param string formId 検索フォームID
	 * @param string callback コールバック処理定義文字列
	 * @return void
	 */
	searchRequest: function(formId, callback) {
		
		var form = $(formId);
		
		new Ajax.Request(
			form.action,
			{
				"method": form.method,
				"parameters": Form.serialize(form),
				onSuccess: function(xhrObject) {
					
					var json;
					eval("json="+xhrObject.responseText);
					
					// コールバック関数が指定されている場合
					if (callback) {
						eval(callback);
					}
				},
				onFailure: function(xhrObject) {
					alert('読み込みに失敗しました');
				},
				onCreate: function() {
					$('resultsMap').innerHTML = '<div style="background:#FFFFFF url(img/loading.gif) no-repeat center center;width:480px;height:480px;border:0;"></div>';
				}
			}
		);
	},
	
	/**
	 * 指定URLを実行し、コールバック関数の指定があれば実行する
	 *
	 * @param string url URL
	 * @param object callback コールバック関数
	 * @return void
	 */
	simpleRequest: function(url, callback) {
		
		new Ajax.Request(
			url,
			{
				"method": "get",
				"parameters": "",
				onSuccess: function(xhrObject) {
					
					//var json;
					//eval("json="+xhrObject.responseText);
					
					// コールバック関数が指定されている場合
					if (callback) {
						callback();
					}
				},
				onFailure: function(xhrObject) {
					alert('読み込みに失敗しました');
				}
			}
		);
	},
	
	/**
	 * 公開側ログイン認証用メソッド
	 *
	 * @param string formId 検索フォームID
	 * @param string container 更新対象のエレメントID
	 * @return void
	 */
	login: function(formId, container) {
		
		var form = $(formId);
		
		new Ajax.Request(
			form.action,
			{
				"method": form.method,
				"parameters": Form.serialize(form),
				onSuccess: function(xhrObject) {
				
					// レスポンス文字列に 'logout' のフレーズが存在すれば、ログイン成功とみなす
					if (xhrObject.responseText.indexOf('logout') > -1) {
						// トップにリダイレクト
						location.href='/index.php';
					} else {
						Element.update('login', xhrObject.responseText);
					}
				},
				onFailure: function(xhrObject) {
					alert('読み込みに失敗しました');
				}
			}
		);
	}
});

var GMaps = Class.create(Common, {
	
	initialize: function() {
		this.name = 'GMaps';
		this.map = null;
		this.json = null;
		this.cPoint = null;
		this.cMarker = null;
		this.markers = [];
	},
	
	/**
	 * 中心点（緯度・経度）を指定して地図をロードする
	 *
	 * @param string mapId マップ要素ID
	 * @param ArrayObject json 検索結果データ
	 * @return void
	 */
	load: function(mapId, json) {
		
		// 中心点座標の取得
		var lat = ($('degree_latitude').value) ? parseFloat($('degree_latitude').value) : 34.666369;
		var lng = ($('degree_longitude').value) ? parseFloat($('degree_longitude').value) : 133.918588;
		
		if (GBrowserIsCompatible()) {
			
			// Google Map Apiにズームとズームアウト関数を追加
			GMap2.prototype.wheelZoom = function(event) {
				if (event.cancelable) event.preventDefault();
				if ((event.detail || -event.wheelDelta) < 0) {
					map.zoomIn();
				} else {
					map.zoomOut();
				}
				return false;
			}
			
			// マップオブジェクト生成
			var map = new GMap2($(mapId));
			
			// 全てのマーカーを消去
			map.clearOverlays();
			
			// 簡易コントロールボタンの設置
			map.addControl(new GSmallMapControl());
			
			// GOverviewMapControlを追加
			if (mapId == 'resultsMap') {
				try {
					map.addControl(new GOverviewMapControl());
				} catch(e) {
					// googleAPIから例外が返されて処理が止まるため、キャッチして処理を流す
					//console.debug(e.message);
				}
			}
			
			// マウスホイールイベントを追加
			GEvent.addDomListener($(mapId), "DOMMouseScroll", map.wheelZoom);
			GEvent.addDomListener($(mapId), "mousewheel", map.wheelZoom);
			
			// 中心点オブジェクト生成
			var cPoint = (this.cPoint) ? this.cPoint : new GLatLng(lat, lng);
			
			// 座標の設定
			map.setCenter(cPoint, 10);
						
			// 中心点マーカーのオプションオブジェクト生成
			var gmarkeroptions = new Object();
			
			if (mapId != 'displayMap') {
      	gmarkeroptions.draggable = true;
				// アイコン指定
				var gIcon = new GIcon();
				gIcon.iconSize = new GSize(31, 27);
				gIcon.shadowSize = new GSize(31, 27);
				gIcon.iconAnchor = new GPoint(15, 27);
				gIcon.infoWindowAnchor = new GPoint(0, 0);
				gIcon.image = 'http://www.housteer.co.jp/img/googlemap_marker/arrowSmall80.png';
				gIcon.shadow = 'http://www.housteer.co.jp/img/googlemap_marker/arrowshadowSmall80.png';
				gmarkeroptions.icon = gIcon;
				gmarkeroptions.title = '中心点';
			}
									
			// 中心点マーカーの生成
      var cMarker = new GMarker(cPoint, gmarkeroptions);
			
			// 中心点マーカーの設置
      map.addOverlay(cMarker);
			
			// GMapsクラスオブジェクトのプロパティに、各データオブジェクトへの参照を持たせる（メソッド間のデータ共有のため）
			this.map = map;
			this.json = json;
			this.cPoint = cPoint;
      this.cMarker = cMarker;
						
			// 中心点マーカーがドラッグ＆ドロップされた場合、緯度・経度を取得して中心点の座標とする
			GEvent.addListener(cMarker, 'dragend', function() {
				$('degree_latitude').value = cMarker.getLatLng().lat();
				$('degree_longitude').value = cMarker.getLatLng().lng();
			});
						
			// 画面毎の独自処理
			switch (mapId) {
				
				// [フロント側] マップ検索の場合
				case 'resultsMap':
					
					// 検索結果データがある場合
					if (json) {
									
						// 物件マーカーの生成・設置
						this.addMarker();
						
						// 中心点マーカーがドラッグ＆ドロップされた場合、物件マーカーの再描画を行う
						GEvent.addListener(cMarker, 'dragend', this.addMarker);
						
//						// ズーム＆スクロール時にマーカーを再度生成させる
//						GEvent.addListener(map, 'zoom', this.addMarker);
//						GEvent.addListener(map, 'moveend', this.addMarker);
					}
					break;
				
				// [管理側] 座標取得の場合
				case 'coordMap':
					
					// 座標の再設定（倍率を上げる）
					map.setCenter(cMarker.getLatLng(), 14);
					
//					// 中心点マーカーがドラッグ＆ドロップされた場合、緯度・経度から住所を取得する
//					GEvent.addListener(cMarker, 'dragend', function() {
//					
//						var geocoder = new GClientGeocoder();
//						
//						geocoder.getLocations(cMarker.getLatLng(), function(response) {
//							
//							if (!response) {
//								alert("緯度経度から住所を取得できませんでした。");
//							} else {
//								$('assress_detail').value = response.Placemark[0].address;
//							}
//						});
//					});
					break;
				
				// [フロント側] マップ表示の場合
				default:
					break;
			}
		}
	},
	
	/**
	 * 物件マーカーを生成・設置する（同時にテーブル部のレコード生成も行う）
	 *
	 * @return void
	 */
	addMarker: function() {
		
		// 表示範囲内物件マーカーの件数
		var count = 0;
		
		// 新規レコード挿入位置
		var index;
		
		// 中心点からの距離配列（近い順）
		var distanceArr = [];
				
		// テーブル部レコードの初期化
		while ($('targetTable').rows['length']) {
			$('targetTable').deleteRow(0);
			//alert('deleted!');
		}
		
//		if (!objGMaps || objGMaps.name != 'GMaps') {
//			objGMaps = this;
//		}
		
		var geocoder = new GClientGeocoder();
		
		gblGMaps.json.each(function(estateInfo) {
			
			if ((estateInfo['degree_latitude'] && estateInfo['degree_longitude']) || estateInfo['assress_detail']) {
								
				if (!estateInfo['degree_latitude'] || !estateInfo['degree_longitude']) {
					
					// 物件座標のデータがない場合、住所から座標を取得してマーカーを生成する
					geocoder.getLatLng(estateInfo['assress_detail'], function(point) {
																	 
						if (!point) {
							estateInfo['degree_latitude'] = '';
							estateInfo['degree_longitude'] = '';
						} else {
							estateInfo['degree_latitude'] = point.lat();
							estateInfo['degree_longitude'] = point.lng();
							exe(estateInfo);
						}
					});
				} else {
					exe(estateInfo);
				}		
			}
		});
		
		function exe(estateInfo) {
			
			var point = new GLatLng(estateInfo['degree_latitude'], estateInfo['degree_longitude']);
			if (point) {
			
//				// 表示範囲内のマーカーのみ生成
//				var area = gblGMaps.map.getBounds();
//				if (area.contains(point)) {
										
					// 物件マーカーのオプション設定
					var gmarkeroptions = new Object();
					var gIcon = new GIcon();
					gIcon.iconSize = new GSize(32, 32);
					gIcon.iconAnchor = new GPoint(16, 32);
					gIcon.infoWindowAnchor = new GPoint(0, 0);
					// 販売価格によるマーカーの色分け
					if (parseInt(estateInfo['sale_price']) <= 999) {
						gIcon.image = 'http://www.housteer.co.jp/img/googlemap_marker/yellow.png';
					} else if (parseInt(estateInfo['sale_price']) >= 1000 && parseInt(estateInfo['sale_price']) <= 1999) {
						gIcon.image = 'http://www.housteer.co.jp/img/googlemap_marker/green.png';
					} else if (parseInt(estateInfo['sale_price']) >= 2000 && parseInt(estateInfo['sale_price']) <= 2999) {
						gIcon.image = 'http://www.housteer.co.jp/img/googlemap_marker/orange.png';
					} else {
						gIcon.image = 'http://www.housteer.co.jp/img/googlemap_marker/red.png';
					}
					gmarkeroptions.icon = gIcon;
					gmarkeroptions.title = estateInfo['estate_name'];
					
					// 物件マーカーの生成
					var marker = new GMarker(point, gmarkeroptions);
					
					// 物件マーカーの設置
					gblGMaps.map.addOverlay(marker);
					
					// 詳細ページリンク先URL、物件種別の取得
					var url = '';
					var type = '';
					switch (estateInfo['estate_type']) {
						
						case 'H':
						
							url = 'house.php?eid=' + estateInfo['id_estate'];
							type = '中古戸建住宅';
							break;
						
						case 'L':
						
							url = 'land.php?eid=' + estateInfo['id_estate'];
							type = '土地';
							break;
						
						default:
						
							url = 'apartment.php?eid=' + estateInfo['id_estate'];
							type = '中古マンション';
					}
					
					var tmp = '';
					if (estateInfo['estate_type'] == 'A') {
						tmp = '■ 間取り / ' + estateInfo['layout'] + '<br />' +
									'■ 専有面積 / ' + estateInfo['monopolize_measure'] + 'm&#178;' + '<br />' +
									'■ 販売価格 / ' + new Utility().toComma(estateInfo['sale_price']) + '万円<br />';
					} else if (estateInfo['estate_type'] == 'H') {
						tmp = '■ 延床面積 / ' + estateInfo['floor_measure'] + 'm&#178;' + '<br />' +
									'■ 敷地面積 / ' + estateInfo['land_measure_square'] + 'm&#178;' + '<br />' +
									'■ 販売価格 / ' + new Utility().toComma(estateInfo['sale_price']) + '万円<br />';
					} else {
						tmp = '■ 敷地面積 / ' + estateInfo['land_measure_tsubo'] + '坪' + '<br />' +
									'■ 建築条件 / ' + estateInfo['built_condition'] + '<br />' +
									'■ 小学校区 / ' + estateInfo['area_elementary_school']+ '<br />';
					}
					
					// マーカークリック時に情報ウィンドウを表示させる
					GEvent.addListener(marker, 'click', function() {
						marker.openInfoWindowHtml('<table style="border:0;width:300px;text-align:left;">' +
																				'<tr style="border:0;">' +
																					'<td style="border:0;vertical-align:top;">' +
																						'<img src="image/estate/thumbnail/' + estateInfo['image_estate1'] +
																						'" onError="new Utility().setNoImage(this)" />' +
																					'</td>' +
																					'<td style="border:0;line-height:16px;vertical-align:top;">' +
																						'<b>' +	estateInfo['estate_name'] +	'</b>' + '<br />' +
																						tmp +
																						'<a target="_blank" href="' + url + '">物件詳細ページ</a>' +
																					'</td>' +
																				'</tr>' +
																			'</table>'
						);
					});
					
					// 新規レコード挿入位置の取得（テーブル部デフォルトの並び順は中心点に近い順にする）
					if (count > 0 && $('order').value == 'id_estate') {
						
						distanceArr.sort(function(a,b){return a - b;});
						
						for (index=0; index<count; index++) {
							
							if ((Math.round((point.distanceFrom(gblGMaps.cMarker.getLatLng()) / 1000) * 1000) / 1000) < distanceArr[index]) {
								break;
							}
						}
					} else {
						index = count;
					}

					// テーブル部レコードの生成
					var rowObj = $('targetTable').insertRow(index);
					rowObj.className = 'targetRow';
					rowObj.style.backgroundColor = 'transparent';
					rowObj.onmouseover = function(){new Utility().changeBgColor(this, '#EEEEEE');};
					rowObj.onmouseout = function(){new Utility().changeBgColor(this, 'transparent');};
					rowObj.onclick= Function('x', 'gblGMaps.panAndShowMarker(' + count + ');');
					
					var innerHtml = '<td class="map_type">' + type + '</td>' +
													'<td class="map_property">' + estateInfo['estate_name'] + '</td>' +
													'<td class="map_price">' + new Utility().toComma(estateInfo['sale_price']) + '万円</td>' +
													'<td class="map_school">' +
													((estateInfo['estate_type'] == 'L') ? estateInfo['area_elementary_school'] : estateInfo['layout']) +
													'</td>' +
													'<td class="map_range">' + Math.round((point.distanceFrom(gblGMaps.cMarker.getLatLng()) / 1000) * 1000) / 1000 + 'km</td>';
					
					Element.update(rowObj, innerHtml);
					
					// 物件マーカーを物件マーカーリストに格納
					gblGMaps.markers[count] = marker;
					
					// 中心点からの距離配列にデータを追加する
					distanceArr[count] = Math.round((point.distanceFrom(gblGMaps.cMarker.getLatLng()) / 1000) * 1000) / 1000;
					
					// 物件マーカー件数のカウントアップ
					count += 1;
//				}
			}
		}
		
	},
	
	/**
	 * 指定されたマーカーに移動し、情報ウィンドウを表示させる
	 *
	 * @param integer index 物件マーカーリストのインデックス
	 * @return void
	 */
	panAndShowMarker: function(index) {
		
		var marker = gblGMaps.markers[index];
		
		gblGMaps.map.panTo(marker.getPoint());
		GEvent.trigger(marker, 'click');
	},
	
	/**
	 * 入力された住所から地図上の座標（緯度・経度）を取得する
	 *
	 * @param string address 住所
	 * @param string callback コールバック関数 (optional)
	 * @param arrayObject estateInfo 物件情報配列 (optional)
	 * @return void
	 */
	searchCoord: function(address, callback, estateInfo) {
		
		var geocoder = new GClientGeocoder();
		
		geocoder.getLatLng(address, function(point) {
														 
			if (!point) {
				
				if (estateInfo == undefined) {
					$('degree_latitude').value = '';
					$('degree_longitude').value = '';
					//alert("住所から緯度経度を取得できませんでした。");
				} else {
					estateInfo['degree_latitude'] = '';
					estateInfo['degree_longitude'] = '';
				}
			} else {
				
				if (estateInfo == undefined) {
					$('degree_latitude').value = point.lat();
					$('degree_longitude').value = point.lng();
				} else {
					estateInfo['degree_latitude'] = point.lat();
					estateInfo['degree_longitude'] = point.lng();
				}
				
				// コールバック関数があれば実行
				if (callback) {
					eval(callback);
				}
			}
		});
		
//		// 戻り値要求フラグがあれば、取得した座標オブジェクトを返す（取得できていなければnullが返る）
//		if (flg) {
//			return rtnPoint;
//		}
	}
});
