if (!console) var console = { log: function () {} };
var p = function () { console.log.apply(console, arguments) };

if (!nioibu) var nioibu = {
	path_func : [],
	map_targets : [],
	map_onload_func : [],
	maps : []
};

nioibu.dispatcher = function (path, func) {
	if (func) {
		nioibu.path_func.push([path, func]);
		return;
	};
	$.each(nioibu.path_func, function () {
		var match = path.match(this[0]);
		if (match) return this[1].apply(nioibu, match);
	});
};

/* 念のためmethod chain */
$.each(nioibu, function (key, val) {
	if (!$.isFunction(nioibu[key])) return;
	nioibu[key] = function () {
		var result = val.apply(nioibu, arguments);
		return (result === undefined) ? nioibu : result;
	};
});

/* 呼び出しURLの指定（URLの正規化含む） */
$(function () {
	nioibu.dispatcher('/' + $.grep(location.pathname.replace(/\.\w+$/, '').split(/\//), function (v) { return !!v }).join('/'));
});

/* 全画面で使用 */
nioibu.dispatcher('.', function () { var self = this;

	/* 検索フォーム */
	new function () {
		var form = $('#search form:first');
		if (!form.length) return;
		var selected = '<ul class="selectbox"></ul>';
		var map = function () {
			return $('<li><span class="key none">'+this.value+'</span><span class="value">'+$(this).html()+'</span></li>').get();
		};
		form.find(':image').click(function (e) { e.preventDefault();
			$(this).parents('form:first').submit();
		});
		form.find('select').hide().each(function () {
			var $_ = $(this).after(selected), select = $_;
			var li = $_.parent().find('.selectbox').append(
				$_.find('option').map(map)
			).prepend($_.find('option:selected').map(map)).find('li');
			var over = false;
			var first = li.filter(':first');
			var notfirst = li.not(':first');
			li.hover(function() {
				over = true;
				li.show();
			}, function() {
				over = false;
				setTimeout(function () {
					if (over) return;
					notfirst.hide();
				}, 200);
			});
			notfirst.click(function () {
				var $_ = $(this);
				notfirst.hide();
				select.val($_.find('.key:first').text());
				first.show();
				first.find('.key').text($_.find('.key').text());
				first.find('.value').text($_.find('.value').text());
			});
			first.addClass('selected').click(function () {
				over = true;
				li.show();
			});
		});
		var hidden = form.find('input[type="hidden"]');
		form.find(':text').each(function (num) {
			var $_ = $(this);
			var color = '#999999', black = '#000000';
			var title = $_.attr('title');
			($_.val() != '' && $_.val() != title)
				? $_.css('color', black)
				: $_.css('color', color).val(title)
			;
			var hide = hidden.eq(num);
			$_
				.focus(function () {
					$_.css('color', black);
					if ($_.val() != title) return;
					$_.val('');
					hide.val($_.val());
				})
				.blur(function () {
					hide.val($_.val() == title ? '' : $_.val());
					if (!$_.val() || $_.val() == title) return $_.css('color', color).val(title);
					$_.css('color', black);
				})
			;
		}).end().submit(function () {
			form.find(':text').blur();
		});
	};

	/* ニュース表示 */
	new function () {
		var ul = $('#smellList ul:first');
		if (!ul.length) return;
		JSTweener.frameRate = 20;
		var li = ul.find('li:first');
		var max = li.length;
		var left = li.eq(0).width();
		var style = ul.get(0).style;
		var exec_tween = function (delay) {
			JSTweener.addTween(style, {
				delay: delay,
				time: 1,
				transition: 'easeOutExpo',
				suffix: {left: 'px'},
				left: 0
			});
		};
		exec_tween(0.7);
		setInterval(function () {
			ul.css({'left' : left});
			ul.append(ul.find('li:first').remove().clone());
			exec_tween(0);
		}, 5000);
	};

	/* DropDown menuの制御 */
	new function () {
		var li = $('#globalNavi ul ul').removeClass('none').hide().parent();
		if (!li.length) return;
		li.hover(function () {
			$(this).children('ul').slideDown(200);
		}, function () {
			$(this).children('ul').slideUp(200);
		});
	};

	/* ajax uploadの実施 */
	new function () {
		var form = $('form[enctype="multipart/form-data"]');
		if (!form.length) return;
		(new Image).src = '/js/loading.gif';
		form.find(':file').each(function () { var $_ = $(this), data = $.data(this);
			$_.change(function () { var $_ = $(this);
				var all_remove;
				var iframe = $_
					.after('<iframe name="uploader'+data+'" src=""></iframe>')
					.next('iframe')
					.addClass('autouploader')
					.css({'width':0, 'height':0, 'border':'none'})
					.load(function () {
						if (!all_remove) return;
						try { load() }
						finally { all_remove() }
					})
				;
				function load () {
					var text = iframe.contents().find('body').text();
					if (!text) return;
					var json = eval('('+text+')');
					if (json.result != 'success') return;
					if (!json.datas.path) return;
					var div = my_load_func(json.datas.path);
					div.find('button').click(function () {
						$_.val('');
						setTimeout(function () {
							div.remove();
						});
					});
				};
				var inform = $_
					.wrap('<form target="uploader'+data+'" action="/api.php/image/set" method="post" enctype="multipart/form-data"></form>')
					.parent('form')
					.addClass('autouploader')
				;
				inform.append('<img style="position:absolute" src="/js/loading.gif" height="24" width="24">');
				form.bind('submit.autouploader', function (e) {
					e.preventDefault();
				});
				setTimeout(function () {
					var name = $_.attr('name');
					$_.attr('name', 'image_src');
					inform.submit();
					$_.attr('name', name);
					all_remove = function () {
						setTimeout(function () {
							iframe.remove();
							inform.replaceWith($_);
							form.unbind('submit.autouploader');
							all_remove = function () {};
						}, 0);
					};
				}, 0);
				setTimeout(function () {
					all_remove();
				}, 5000);
			});
			function my_load_func (path) {
				var offset = $_.offset();
				var img_css = {
					'left' : offset.left + $_.width() + 20,
					'top' : offset.top - 20,
					'width' : 200
				};
				$('div.autouploader'+data).remove();
				var src = path + '?' + (new Date()).getTime();
				var div = $(document.body)
					.append('<div class="autouploader-wrap"><span class="preview-msg">プレビュー画像</span><button>削除</button><img src="'+src+'"></div>')
					.find('div.autouploader-wrap:last')
					.addClass('autouploader'+data)
					.css(img_css)
					.css({
						'position' : 'absolute',
						'border' : 'solid 1px',
						'background-color' : '#FFF',
						'cursor' : 'move'
					})
					.fadeTo(0, 0.75)
				;
				div.find('img').css(img_css);
				new Draggable(div.get(0));
				return div;
			}
		});
	};

	/* 生年月日用コンボボックス */
	new function () {
		var width_padding = $.browser.msie
			? 15
			: $.browser.mozilla
			? 15
			: $.browser.safari
			? 20
			: 15
		;
		var span_tag = '<span class="combobox" style="position:relative"></span>';
		$('select.combobox')
			.ime_external({'type' : 'ime_off'})
			.keydown(keydown)
		;
		function keydown (e) {
			var val = String.fromCharCode(e.keyCode);
			if (val.match(/\D/)) return;
			if ($.data(this, 'combobox_open')) return;
			$.data(this, 'combobox_open', true);
			e.preventDefault();
			var $_ = $(this), select = this;
			var next_elem = get_next_element($_);
			var max_length = get_select_maxlength($_);

			var span = $_.parent('span.combobox');
			if (!span.length) {
				span = $_.wrap(span_tag).parent('span');
			}

			var input = span
				.append('<input type="text">')
				.find('input:last')
				.addClass('combobox')
				.css({
					'position' : 'absolute',
					'width' : $_.width() - width_padding,
					'height' : $_.height(),
					'top' : 0,
					'left' : 0
				})
				.attr('maxlength', max_length)
			;

			setTimeout(function () {
				input
					.val(val)
					.blur(input_blur)
					.keypress(input_keypress)
					.ime_external({'type' : 'ime_off'})
				;
				set_selection_last(input.get(0));
			}, 0);

			function input_blur () {
				var $_ = $(this);
				var vold = $(select).val();
				var vnew = $_.val();
				var set = ($(select).val(vnew).val() != vnew);
				if (set) $(select).val(vold).change();
				$.data(select, 'combobox_open', false);
				$_.remove();
				setTimeout(function () {
					next_elem.focus()
				}, $.browser.msie ? 100 : 0);
			};

			function input_keypress () {
				var $_ = $(this);
				setTimeout(function () {
					$_.val($_.val().replace(/\D/g, ''));
				}, 0);
			};
		};

		function set_selection_last (row) {
			row.focus();
			var len = row.value.length;
			var sel = row.setSelectionRange;
			if (sel) return sel.apply(row, [len, len]);
			if (!row.createTextRange) return;
			var range = row.createTextRange();
			range.move('character', len);
			range.select();
		};

		function get_select_maxlength ($_) {
			var max = Math.max.apply(
				null,
				$.makeArray(
					$_
						.find('option')
						.map(function () {
							return $(this).text().length;
						})
					)
				)
			;
			return max;
		};

		function get_next_element ($_) {
			return (function (elems) {
				var next = false;
				var data = $.data($_.get(0));
				var hit = {};
				elems.each(function () {
					if (next) return !(hit = this);
					if ($.data(this) == data) next = true;
				});
				return hit;
			})($_.parents('form:first').find(':input:not(:hidden)'));
		};
	};

	/* 年齢をまとめてhiddenに追加 */
	new function () {
		var birth = $('#birth');
		if (!birth.length) return;
		var year = $('#birthYear').change(set);
		var month = $('#birthMonth').change(set);
		var day = $('#birthDay').change(set);
		birth.parents('form:first').submit(set);
		function set () {
			birth.val(year.val() + '-' + month.val() + '-' + day.val());
		};
	}
});

/* トップ地図表示 */
nioibu.dispatcher('^(/\\w*$|/smell/map|/smell/index)', function () { var self = this;
	new function () {
		var form = $('.searchForm:first');
		if (!form.length) return;
		var input = form.find(':text:first');
		if (!input.length) return;
		var title = input.attr('title');
		input.attr('value', title);
		input.focus(function () {
			if (input.attr('value') === title) input.attr('value', '');
		});
		input.blur(function () {
			if (input.attr('value') === '') input.attr('value', title);
		});
		form.submit(function (e) {
			if (input.attr('value') !== title) return;
			e.preventDefault();
			input.focus();
		});
	};

	/* 地図表示（window.onload後のcallback） */
	$.getJSON('http://www.nioibu.com/api.php/smell/map'+location.search, function (data) {
		self.map_onload(function () {
			nioibu.map_register(data, false);
		});
	});
});

/* 地図表示画面 */
nioibu.dispatcher('^(/smell/detail|/home/show|/smell/register/confirm|/smell/edit/confirm)', function () { var self = this;
	/* 地図表示（window.onload後のcallback） */
	self.map_onload(function () {
		nioibu.map_register_html('#newSmell dd, #map_icon ul', false);
	});
});

/* スメルリストトップ */
nioibu.dispatcher('^/home/show', function () { var self = this;
	var list = $('#map_icon div').not('.page1, .pager').hide().end();
	nioibu.pager(list, '.pager');
	self.map_onload(function () { $('div.showMap').hide(); });
	var links = $('#tabCollection a').click(function (e) { e.preventDefault();
		var $_ = $(this).addClass('current');
		$('.'+$_.parent('li').attr('class')).show();
		$('div.'+links.not(this).removeClass('current').parent('li').attr('class')).hide();
	});
});

/* においMAP */
nioibu.dispatcher('^/smell/map', function () { var self = this;
	if (!$('#memberInfo').length) {
		$('#commentSpotRegist img').attr({
			'alt' : 'においスポットを登録するには、ログインしてください。',
			'src' : '/img/dictionary/txt_comment_spot_regist_nologin.png',
			'width' : 230,
			'height' : 93
		}).css({
			'cursor': 'pointer'
		}).click(function () {
			location = '/login'
		});
	};

	$('.selectArea:first select').change(function () {
		$(this).parents('form:first').submit();
	});

	var marker;
	var map;

	/* markerを生成する（最初呼ばれたときに自己破壊） */
	var init_marker = function () {
		marker = create_marker();
		marker.setLatLng(map.getCenter());
		GEvent.addListener(map, 'move', function () {
			if (marker.isHidden()) return;
			marker.setLatLng(map.getCenter());
		});
		init_marker = function () {};
	};
	self.map_onload(function () {
		var mgr = self.get_mgr();
		map = self.get_map();
		$('#btnSpot')
			.find('.regist')
				.toggle(function () {
					init_marker();
					$('#commentSpotRegist').show();
					marker.setLatLng(map.getCenter());
					if ($('#memberInfo').length) marker.show();
				}, function () {
					$('#commentSpotRegist').hide();
					$('#boxSpotRegist').hide();
					marker.hide();
				})
				.end()
			.find('.search')
				.toggle(function () {
					init_marker();
					var $_ = $('#boxSpotSearch').css({
						'top' : 200,
						'left' : 500
					}).show();
					flash_search_result($_);
				}, function () {
					$('#boxSpotSearch').hide();
				})
		;
		$('.infoWindow .btnClose').click(function () {
			$(this).parent().hide();
		});
		$('.addNewSmell').click(function (e) { e.preventDefault();
			var latlng = marker.getLatLng();
			var href = $(this).attr('href');
			location.href = href + '?lon=' + latlng.lng() + '&lat=' + latlng.lat();
		});

		/* スポットを探すボタン制御 */
		var drag = new Draggable($('#boxSpotSearch').get(0));
		$('#boxSpotSearch').find('form')
			.hover(function () {
				drag.destroy();
			}, function () {
				var info = $(this).parents('.infoWindow:first');
				drag = new Draggable(info.get(0));
			})
			.bind('submit', {click:search_click}, search_submit)
		;
		function search_click (e) { e.preventDefault();
			var marker = $.data($(this).parent().get(0), 'marker');
			map.setZoom(10);
			map.panTo(marker.getLatLng());
			GEvent.trigger(marker, 'click');
		};

		/* スポット登録ボタン制御 */
		$('#boxSpotRegist').find('form')
			.bind('submit', {
				click: regist_click,
				marker: true,
				bind: true
			}, search_submit)
		;
		function regist_click (e) { e.preventDefault();
			var parent_marker = $.data($(this).parent().get(0), 'marker');
			var data = {};
			var item = parent_marker.my_item;
			var latlng = marker.getLatLng();
			data.id = item.id;
			data.lat = latlng.lat();
			data.lon = latlng.lng();
			$.get('/api.php/smell/addLocation', data, function () {
				var clone = new GMarker(latlng, {icon: parent_marker.getIcon(), title: item.smell_name, clickable: !!item.window});
				GEvent.addListener(clone, 'click', function () {
					map.openInfoWindowHtml(clone.getLatLng(), nioibu.get_window_html(item));
				});
				GEvent.trigger(clone, 'click');
				mgr.addMarkers([clone], 0);
				$('#btnSpot .regist').click();
				mgr.refresh();
			});
		};

	});

	var page_count = $('#page_count').text() - 0;

	/* におい検索結果表示 */
	function search_submit (e) { e.preventDefault();
		var mgr = self.get_mgr();
		var li_click = e.data.click;
		var bind = e.data.bind;
		var $_ = $(this);
		var target = $(this).parents('.infoWindow:first');
		target.find('.content').hide();
		var text = $_.find(':text');
		if (!text.val()) {
			var offset = text.offset();
			var span = $(document.body).append('<span>「におい」名を入れてください。</span>').find('span:last');
			span.css({
				position: 'absolute',
				top: offset.top,
				left: offset.left,
				'z-index': 110,
				color: '#999999'
			}).click(function () {
				text.focus();
			});
			setTimeout(function () {
				span.fadeOut(1500, function () { span.remove(); })
			}, 500);
			text.focus().keydown(function () {
				span.remove();
			});
			return;
		};
		var data = $_.find(':input').serialize();
		var action = $_.attr('action');
		$.getJSON(action, data, function (json) {
			if (json.result != 'success') return;
			target.find('.content').show();
			var li = target
				.find('.searchResultSpot')
				.html(get_json_to_tag(json))
				.children('li')
			;
			nioibu.light_pager(li, target.find('.pagerLight'), 8);
			nioibu.map_register_html(li, !!bind);
			if (e.data.marker) {
				marker = create_marker();
				marker.show();
			};
			if (li_click) li.find('a').click(li_click);
			var bg = target.css('background-image').replace(/_no_match(\.[\w\)\s]+)$/, '$1').replace(/(\.[\w\)\s]+)$/, '_no_match$1');
			json.datas.length
				? target.css('background-image', '').find('.content').show()
				: target.css('background-image', bg).find('.content').hide()
			;
		});
	};

	/* markerの作成 */
	function create_marker () {
		marker = new GMarker(map.getCenter());
		map.addOverlay(marker);
		marker.hide();
		GEvent.addListener(marker, 'click', function () {
			var $_ = $('#boxSpotRegist').toggle().css({
				'top' : 150,
				'left' : 500
			});
			flash_search_result($_);
		});
		return marker;
	};
	
	/* windowの内容クリア */
	function flash_search_result ($_) {
		$_
			.find('.pagerLight')
				.empty()
				.end()
			.find('.searchResultSpot')
				.empty()
				.end()
			.find('.content')
				.hide()
				.end()
			.find(':text:first')
				.val('')
				.focus()
				.end()
		;
	};

	/* jsonをhtml tag(string)に変換して返す */
	function get_json_to_tag (json) {
		return ($.map(json.datas, function (data, i) {
			var num = Math.ceil((i + 1) / page_count);
			var span = '';
			$.each(data, function (k, v) {
				span += '<span class="'+k+'">'+v+'</span>';
			});
			var style = num == 1 ? '' : ' style="display:none"';
			return '<li class="page'+num+'"'+style+'><a href="#">'+data.smell_name+'</a><span class="none">'+span+'</span></li>';

		})).join('');
	};
});

/* 詳細画面 */
nioibu.dispatcher('^/smell/detail', function () { var self = this;
	var tamp = function (e) { e.preventDefault(); return false; };

	/* わかる～追加 */
	$('#empathize .button a').click(function (e) { e.preventDefault();
		var $_ = $(this).unbind('click').click(function (e) { e.preventDefault(); });
		$.getJSON(this.href, function (json) {
			alert('わかる～に追加しました');
			var parent = $_.parents('.innerSubColumn:first');
			var member = parent
				.find('.total:first')
					.html(json.total)
					.end()
				.find('.member:first')
					.empty()
			;
			$.each(json.datas, function () {
				member.append(([
					'<li>',
						'<a href="/home/show?member_id='+this.member_id+'">'+this.member_name+'</a>',
						this.member_level,
					'</li>'
				]).join(''));
			});
			var img = $_.find('img');
			var src = img.attr('src').replace(/(_down)?\.\w+$/, '_down$&');
			$_.replaceWith(img.attr('src', src).clone());
		});
	});

	/* コレクションする画面 */
	var col = $('#collection .button a').bind('tosubmit', function (e, json, close, box) {
		setTimeout(function () {
			$.get('/smell/collectionAddComplete/', {l:'on'}, function () {
				close.click();
				open_lightbox.call(this, arguments[0], col);
				col.unbind('click').click(tamp);
				col.bind('toclose', function () {
					location.reload();
				});
			});
		}, 0);
	});

	var member_id = $('#status .member_id').text();
	$('#collection .id').each(function () {
		if ($(this).text() != member_id) return;
		var img = col.find('img');
		var src = img.attr('src').replace(/(_down)?\.\w+$/, '_down$&');
		col.replaceWith(img.attr('src', src).clone());
		return false;
	});

	/* 似てる似てないの投票 */
	$('#similar .post a').click(nioibu.vote_throw);
});

/* 詳細画面 */
nioibu.dispatcher('^(/similar/list|/smell/sympathy|/smell/collection|/similar/vslist|/similar/complete)', function () { var self = this;
	/* 似てる似てないの投票 */
	$('#dictionary .vote a').click(nioibu.vote_throw);
	$('#similar .post a').click(nioibu.vote_throw);
});

/* においINDEX */
nioibu.dispatcher('^/smell/category', function () { var self = this;
	var links = $('#tabRefine a');
	var tabs = links.filter('.tab');
	var btn_close = $('#popupRefine').children('.btnClose');
	tabs.click(function (e) { e.preventDefault();
		var $_ = $(this);
		var cname = $_.parent().attr('class');
		/* 自分を2回選択 */
		if ($_.filter('.current').length) {
			$_.removeClass('current');
			$('#popupRefine').hide().children().hide()
			$('#sort').show();
			btn_close.show();
			form_reset();
			return;
		};
		/* 他に選択しているタブがない */
		if (!links.filter('.current').length) {
			$_.addClass('current');
			$('#popupRefine').show().children()
				.hide().filter('.'+cname).show();
			$('#sort').hide();
			btn_close.show();
			return;
		};
		/* 他に選択しているタブがある */
		tabs.removeClass('current');
		$_.addClass('current');
		$('#popupRefine').show().children().hide().filter('.'+cname).show();
		btn_close.show();
		form_reset();
		$('#sort').hide();
	});
	links.filter(':not(.tab)').click(function (e) { e.preventDefault();
		var $_ = $(this);
		var k_v = $_.attr('href').replace('#', '').split('=');
		form_reset();
		$('#smell_category').append('<input type="hidden" name="'+k_v.shift()+'" value="'+k_v.shift()+'" />');
		$_.parents('form:first').submit();
	});
	$('#popupRefine .btnClose').click(function () {
		tabs.removeClass('current');
		$('#popupRefine').hide().children('ul').hide();
		$('#sort').show();
		form_reset();
	});
	$('#sort').change(function () {
		$(this).parents('form:first').submit();
	});
	function form_reset () {
		$('#smell_category')
			.find(':radio[value="0"]')
				.attr('checked', true)
				.end()
			.find(':checkbox')
				.attr('checked', false)
		;
	};
	new function () {
		var cname = tabs.filter('.current').parent().attr('class');
		if (!cname) return;
		$('#popupRefine').show().children().filter('.'+cname).show();
		$('#sort').hide();
	};
});

/* 場所追加画面 */
nioibu.dispatcher('^(/index.php)?/smell/placeadd', function () { var self = this;
	/* 地図表示（window.onload後のcallback） */
	self.map_onload(function () {
		var title = $('#area').text();
		if (!$('#lat').val() || !$('#lon').val()) return;
		var latlng = new GLatLng($('#lat').val(), $('#lon').val());
		var map = self.get_map();
		map.setZoom(10);
		map.panTo(latlng);
		var marker_opt = $('#map_fixed').length ? {
			clickable: false
		} : {
			dragCrossMove: true,
			draggable: true,
			bouncy: true
		};
		var marker = new GMarker(latlng, marker_opt );
		map.addOverlay(marker);
		if ($('#map_fixed').length) return map.setZoom(16);

		nioibu.search_addr_register(marker);

		/* マーカドラッグの追従 */
		nioibu.marker_dragger(map)(marker);

		GEvent.addListener(marker, 'dragend', function () {
			var latlng = marker.getLatLng();
			$('#lat').val(latlng.lat());
			$('#lon').val(latlng.lng());
		});

		/* 逆ジオコーディング用座標設定（nioibu.reverse_geocoderより先に呼ぶこと） */
		GEvent.addListener(map, 'mouseout', function () {
			var latlng = marker.getLatLng();
			$('#lat').val(latlng.lat());
			$('#lon').val(latlng.lng());
		});

		/* 逆ジオコーディング */
		nioibu.reverse_geocoder(map)(function (addr) {
			$('#area').text(addr.address ? addr.address+'付近' : '');
		});

		GEvent.trigger(map, 'mouseout');
	});

	/* 閉じるボタン */
	$('.btnClose').click(function () { window.close(); window.opener.location.reload(); });
});

/* 検索結果表示 */
nioibu.dispatcher('^(/index.php)?(/smell/category|/smell/list)', function () { var self = this;
	$('.indexForm:first')
		.find(':submit')
			.hide()
			.end()
		.find('select')
			.change(function () {
				$(this).parents('form:first').submit();
			})
			.end()
		.end()
	;
});

/* 検索結果表示 */
nioibu.dispatcher('^(/index.php)?/similar/input', function () { var self = this;
	/* lightbox open */
	$('.arrowLink:first a').bind('tosubmit', nioibu.light_search);
});

/* におい登録 */
nioibu.dispatcher('^/smell/register|^/smell/edit', function (hit) { var self = this;
	if (!$('.section').length) var hide_dragger = true;

	new function () {
		var hidden = $('#makeChart').nextAll('input[type="hidden"]');
		window.updata = function (before) {
			$.each(before.split(new RegExp('')), function (i) {
				hidden.eq(i).val(this);
			});
		};
	};

	$('.area:first')
		.find('.hiddens')
			.hide()
			.end()
		.end()
	;

	/* 地図表示（window.onload後のcallback） */
	self.map_onload(function () {
		setTimeout(function () {
			var area = $('.to_area_register');
			if (!$('#area_register').attr('checked')) area.hide();
			$('#area_register').click(function () {
				$(this).attr("checked") ? area.slideDown(200) : area.slideUp(500);
			});
		}, 0);

		if (hide_dragger) return;
		var map = self.get_map();

		map.setZoom(12);
		/* 東京選択時の座標 */
		var latlng = new GLatLng($('#lat').val() || '35.689568', $('#lon').val() || '139.691717');
		map.panTo(latlng);
		var marker = new GMarker(latlng, {dragCrossMove: true,
			draggable: true, bouncy: true } );
		map.addOverlay(marker);

		nioibu.search_addr_register(marker);

		/* マーカドラッグの追従 */
		nioibu.marker_dragger(map)(marker);

		/* 逆ジオコーディング用座標設定（nioibu.reverse_geocoderより先に呼ぶこと） */
		GEvent.addListener(map, 'mouseout', function () {
			var latlng = marker.getLatLng();
			$('#lat').val(latlng.lat());
			$('#lon').val(latlng.lng());
		});

		/* 逆ジオコーディング */
		nioibu.reverse_geocoder(map)(function (addr) {
			$.each(addr, function (k, v) {
				$('#'+k).val(v);
			});
			var latlng = marker.getLatLng();
			$('#lat').val(latlng.lat());
			$('#lon').val(latlng.lng());
		});
	});

	

	/* lightbox open */
	$('#similar_id').next().bind('tosubmit', nioibu.light_search);

	/* 読み仮名自動入力 */
//	$('#smell_name').autokana({target:'#smell_kana'});
});

/* 地図の住所検索登録 */
nioibu.search_addr_register = function (marker) { var self = this;
	var map = self.get_map();
	var loaded = false;

	/* 郵便番号入力の制御 */
	new function () {
		var post = $('.area:first .postCode:first').removeClass('none');
		var text = post.find(':text')
			.ime_external({'type' : 'ime_off'}).change(change);
		post.append('<button>住所検索</button>')
			.find('button:last')
				.click(function (e) { e.preventDefault();
					change.apply(text.get(0), arguments);
				})
		;
		/* 郵便番号入力から住所、座表検索 */
		var loaded = false;
		function change () {
			if (loaded) return;
			loaded = true;
			var $_ = $(this);
			setTimeout(function () {
				loaded = false;
				var post = $_.val().replace(/\D/g, '');
				if (post.length != 7) return;
				var data = {};
				data.q = post;
				get_location(data, function () {
					var span = nioibu.error_fadeout($_);
					$_.keydown(function () {
						span.remove();
					});
				});
			}, 500);
		};
	};

	/* 住所検索フォームの制御 */
	new function () {
		geocoder = new GClientGeocoder();
		var loading = false;
		var addr = $('#search_address').removeClass('none')
			.blur(function () {
				if (!addr.val()) return;
				if (loading) return;
				loading = true;
				setTimeout(function () {
					geocoder.getLatLng(addr.val(), success);
				}, 500);
			})
		;
		var button = addr.after('<button>住所検索</button>')
			.next('button:last')
			.click(function (e) { e.preventDefault(); })
		;
		function success () {
			map_move.apply(this, arguments) || missing();
			loading = false;
		};

		function missing () {
			var span = nioibu.error_fadeout(button);
			addr.keydown(function () {
				span.remove();
			});
		};
	};

	/* 都道府県選択 */
	$('#area_pref').removeClass('none').change(function () {
		var $_ = $(this);
		if (loaded) return;
		loaded = true;
		var data = {};
		data.area_code = $_.val();
		get_location(data, function () {});
		loaded = false;
	});

	/* JSONの展開と地図制御 */
	function get_location (indata, func) {
		$.getJSON('/api.php/geocode/get', indata, function (json) {
			var data = json.datas;
			if (json.result != 'success' || !data) return;
			if (!data.lat && !data.lon) return func();
			if (data.pref) $('#area_pref').val(data.pref);
			if (data.city) $('#area_middle').val(data.city);
			if (data.town) $('#area_narrow').val(data.town);
			if (data.lat) $('#lat').val(data.lat);
			if (data.lon) $('#lon').val(data.lon);
			map_move(new GLatLng(data.lat, data.lon));
		});
	};

	/* 座標から地図を移動させる */
	function map_move (latlng) {
		if (!latlng) return false;
		map.setZoom(14);
		map.panTo(latlng);
		marker.setLatLng(latlng);
		GEvent.trigger(map, 'mouseout');
		return true;
	};

};

/* 似てる似てないの投票 */
nioibu.vote_throw = function (e) { e.preventDefault();
	var tamp = function (e) { e.preventDefault(); return false; };

	var $_ = $(this).unbind('click').click(tamp);
	$.getJSON(this.href, function (json) {
		$_.parents('ul:first')
			.find('.positive')
				.text(json.datas.approve)
				.end()
			.find('.negative')
				.text(json.datas.no_approve)
				.end()
			.find('a')
				.unbind('click')
				.click(tamp)
				.end()
			.find('.link')
				.remove()
			.end()
		;
		alert('投票を受け付けました');
	});
};

/* エラーメッセージの浮かび上げ */
nioibu.error_fadeout = function (base) {
	var span = $(document.body).append('<span>見つかりませんでした</span>').find('span:last');
	span.css($.extend(
		{'position' : 'absolute'},
		base.offset()
	));
	span.css('top', parseInt(span.css('top')) - parseInt(base.css('height')));
	setTimeout(function () {
		span.fadeOut(1500, function () { span.remove(); });
	}, 500);
	return span;
};

/* ライトボックス検索画面の追加 */
nioibu.light_search = function (e, json, btn_close, box) {
	var form = box.find('form');
	if (json.result != 'success') return;
	if (!$('#page_count').length) box.append('<span id="page_count" class="none">10</span>')
	var list = '';
	form.find('.tblInput').find('.liner').remove();
	if (!json.datas.length) {
		form.find('.tblInput tr:first').parent().append('<tr class="liner"><td colspan="2" class="result">キーワードに一致するにおいはありませんでした。</td></tr>');
		box.trigger('fixpotision');
		return;
	};
	$.each(json.datas, function (i) {
		var t = this;
		var p = Math.ceil(++i / 10);
		list += '<li class="line page'+p+'"><a href="#'+t.id+'">'+t.smell_name+'</a></li>';
	});
	form.find('.tblInput tr:first').parent().append('<tr class="liner"><td colspan="2" class="result"><ul class="pagerLight"></ul><ul class="pointList">'+list+'</ul></td></tr>');
	form.find('.result a').click(function (e) { e.preventDefault();
		var v = $('#similar_id').val();
		if (v) v += ',';
		$('#similar_id').val(v + this.href.match(/\#(\d+)/)[1]);
		btn_close.click();
	});
	var li = form.find('.pointList .line');
	nioibu.light_pager(li, form.find('.pagerLight'), 10);
	li.filter(':not(.page1)').hide();
	box.trigger('fixpotision');
};

/* 地図の登録 */
new function () {
	var mgr;
	var map;
	var get_names = ['id', 'lat', 'lon', 'updated_at', 'smell_name', 'smell_source', 'member_id', 'member_name', 'icon'];
	/* 出力済みmarker id */
	var mapping_id = {};

	nioibu.map_register = function (json, bind) { var self = this;
		mgr = self.get_mgr();
		map = self.get_map();

		new function () {
		    if (!mgr) return;
			mgr.clearMarkers();
			map.clearOverlays();
			if (!json.datas.length) return mgr.refresh();
			var markers = [];
			var bounds = new GLatLngBounds();
			$.each(json.datas, function () {
				var marker = create_marker( create_marker_json(this) );
				if (!marker) return;
				if (!bind) bounds.extend(marker.getLatLng());
				markers.push(marker);
				mapping_id[marker.my_item.id] = true;
			});
			if (!markers.length) return mgr.refresh();
			if (!bind) {
				var zoom = map.getBoundsZoomLevel(bounds);
				if (16 < zoom) zoom = 16;
				map.setZoom(zoom);
				map.panTo(bounds.getCenter());
			};
			mgr.addMarkers(markers, 0);
			mgr.refresh();
			if ($('#no_nearest').length) return;

			var meter = get_pixel_to_meter(50, 50);
			$.each(markers, function () {
				var marker = this;
				setTimeout(function () {
					nearest_marker(marker, meter);
				}, 100);
			});
		};
	};

	/* 地図の登録 */
	nioibu.map_register_html = function (selector, bind) { var self = this;
		mgr = self.get_mgr();
		map = self.get_map();

		new function () {
			var ul = $(selector);
			mgr.clearMarkers();
			map.clearOverlays();
			if (!ul.length) return mgr.refresh();
			var markers = [];
			var bounds = new GLatLngBounds();
			ul.each(function () {
				var marker = create_marker( create_marker_elem($(this)) );
				if (!marker) return;
				if (!bind) bounds.extend(marker.getLatLng());
				markers.push(marker);
				mapping_id[marker.my_item.id] = true;
			});
			if (!markers.length) return mgr.refresh();
			if (!bind) {
				var zoom = map.getBoundsZoomLevel(bounds);
				if (16 < zoom) zoom = 16;
				map.setZoom(zoom);
				map.panTo(bounds.getCenter());
			};
			mgr.addMarkers(markers, 0);
			mgr.refresh();
			if ($('#no_nearest').length) return;

			var meter = get_pixel_to_meter(50, 50);
			$.each(markers, function () {
				var marker = this;
				setTimeout(function () {
					nearest_marker(marker, meter);
				}, 100);
			});
		};
	};

	/* マーカー周辺情報の取得 */
	function nearest_marker (marker, meter) {
		var data = {};
		var latlng = marker.getLatLng();
		data.lat = latlng.lat();
		data.lon = latlng.lng();
		data.max_meter = meter;
		data.count = 10;
		$.getJSON('/api.php/smell/nearest', data, function (json) {
			if (json.result != 'success') return;
			if (!json.datas.length) return;
			var markers = [];
			$.each(json.datas, function () {
				if (mapping_id[this.id]) return;
				var item = create_marker_json(this);
				markers.push( create_marker(item) );
			});
			if (markers.lenght) return;
			mgr.addMarkers(markers, 0);
			mgr.refresh();
		});
	};

	/* 表示上の領域(pixel)を地図上の領域(meter)に変換 */
	function get_pixel_to_meter (top, left) {
		var latlng_from = map.fromContainerPixelToLatLng(new GPoint(0, 0));
		var latlng_to = map.fromContainerPixelToLatLng(new GPoint(top, left));
		return latlng_from.distanceFrom(latlng_to);
	};

	/* html elementからのItemの作成 */
	function create_marker_elem ($_) {
		if (!$_.length) return;
		var item = {};
		item.window = true;
		$.each(get_names, function () {
			item[this] = $_.find('.'+this+':first').text();
			if (item.window && !item[this]) item.window = false;
		});
		item.$_ = $_;
		return item;
	};

	/* jsonからのItemの作成 */
	function create_marker_json (json) {
		var item = {};
		item.window = true;
		$.each(get_names, function () {
			item[this] = json[this];
			if (item.window && !item[this]) item.window = false;
		});
		return item;
	};

	/* マーカーの作成 */
	function create_marker (item) {
		if (!item.lat && !item.lon) return;
		var icon = new GIcon();
		var $_ = item.$_;
		delete(item.$_);
		icon.image = item.icon;
		icon.iconSize = new GSize(16, 30);
		icon.iconAnchor = new GPoint(8, 30);
		var marker = new GMarker(
			new GLatLng(item.lat, item.lon),
			{icon: icon, title: item.smell_name, clickable: !!item.window}
		);
		marker.my_item = item;
		if ($_) $.data($_.get(0), 'marker', marker);
		if (!item.window) return marker;
		GEvent.addListener(marker, 'click', function () {
			map.openInfoWindowHtml(marker.getLatLng(), nioibu.get_window_html(marker.my_item));
		});
		GEvent.addListener(marker, 'mouseover', function () {
			map.openInfoWindowHtml(marker.getLatLng(), nioibu.get_window_html(marker.my_item));
		});
		return marker;
	};
};

/* infoWindow用のhtml作成 */
nioibu.get_window_html = function (item) { var self = this;
		return ([
			'<h5>',
				'<img height="20" width="12" class="icn" title="" alt="" src="'+item.icon+'"/>',
				'<a href="/smell/detail?id='+item.id+'">',
					item.smell_name,
				'</a>',
			'</h5>',
			'<ul>',
				'<li>By  <a href="/home/show?member_id='+item.member_id+'" class="user">'+item.member_name+'</a></li>',
				'<li>'+item.smell_name+'</li>',
			'</ul>',
			'<p class="point">発生源：'+item.smell_source+'</p>',
		]).join('');
};

/* ページャ */
nioibu.pager = function (list, pager) { var self = this;
	if (!list.length) return;
	var page_count = $('#page_count').text() - 0;
	var pager_area;
	var all_count = list.length;
	/* ページジャンプリンク生成 */
	new function () {
		var page_max = Math.ceil(all_count / page_count);
		var page = [];
		while (page_max--) page.push('');
		$.each(page, function (i) {
			var n = i + 1;
			page[i] = '<a href="#" class="number num'+n+'">'+n+'</a>';
		});
		var all_page = page.length;
		page[0] = '<strong class="number num1">1</strong>';
		var next_link = (all_page == 1) ? ['<span>次の', '件</span>'] : ['<a href="#">次の', '件</a>'];
		page.unshift('<li class="page">');
		page.push('</li>');
		page.unshift('<li class="next">'+next_link.join(page_count)+'</li>');
		page.push('<li class="prev"><span>前の'+page_count+'件</span></li>');
		var end_page = (all_page == 1) ? all_count : page_count;
		var start_pace = end_page ? 1 : 0;
		page.unshift('<li class="pageNavi"><span class="start">'+start_pace+'</span>～<span class="end">'+end_page+'</span>件/'+all_count+'件中</li>');
		pager_area = $(pager).html(page.join(''));
		pager_area
			.find('.prev a').click(prev).end()
			.find('.next a').click(next).end()
			.find('a.number').click(click).end()
		;
	};

	/* ページジャンプ */
	function click (e) { e.preventDefault();
		var $_ = $(this);
		var this_page = pager_area.find('.num'+$_.text());
		var num = $_.text() - 0;
		var rep = pager_area.find('strong.number');
		var rep_num = rep.html() - 0;
		if (num == rep_num) return;
		rep.replaceWith('<a href="#" class="number num'+rep_num+'">'+rep_num+'</a>');
		this_page.replaceWith('<strong class="number num'+num+'">'+num+'</strong>');
		var start = (num * page_count) - 1;
		list.filter('.page'+rep_num).hide().end().filter('.page'+num).show();
		pager_area.find('.number').unbind('click').click(click);
	};

	/* ページナンバーバック */
	function prev (e) { e.preventDefault();
		var $_ = $(this);
		var pager = $_.parents('.pager');
		pager.find('.page strong').prev('a.number').click();
		check_last(pager);
	};

	/* ページナンバーネクスト */
	function next (e) { e.preventDefault();
		var $_ = $(this);
		var pager = $_.parents('.pager');
		pager.find('.page strong').next('a.number').click();
		check_last(pager);
	};

	/* ページナンバーネクスト */
	function check_last (pager) {
		manip('.prev', ':first', 'strong', prev);
		manip('.next', ':last', 'strong', next);
		function manip (find, filter1, filter2, func) {
			var $_ = pager.find(find);
			var $a = $_.find('a');
			var $span = $_.find('span');
			pager.find('.number').filter(filter1).filter(filter2).length
				? $a.replaceWith('<span>'+$a.text()+'</span>')
				: $span.replaceWith('<a href="#">'+$span.text()+'</a>')
			;
			$_.find('a').unbind('click').click(func);
		};
		var current = pager.find('strong.number').text() - 1;
		var end = page_count * (current + 1);
		if (end > all_count) end = all_count;
		$('.pageNavi')
			.find('.start').text((page_count * current) || 1).end()
			.find('.end').text(end).end()
		;
	};
};

/* lightboxページャ */
nioibu.light_pager = function (list, pager, scroll_number) { var self = this;
	if (!list.length) return;
	var page_count = $('#page_count').text() - 0;
	var pager_area;
	/* ページジャンプリンク生成 */
	new function () {
		var page_max = Math.ceil((list.length - 0) / page_count);
		var flow = (page_max > scroll_number);
		var page = [];
		while (page_max--) page.push('');
		$.each(page, function (i) {
			var n = i + 1;
			page[i] = '<li class="line"><a href="#" class="number num'+n+'">'+n+'</a></li>';
		});
		if (!page.length) return $(pager).html('1');
		page[0] = '<li class="line"><span class="number num1">1</span></li>';
		if (flow) {
			page.unshift('<li style="display:none;"><a href="#" class="prev">＜</a></li>');
			page.push('<li><a href="#" class="next">＞</a></li>');
		};
		pager_area = $(pager).html(page.join(''));
		pager_area
			.find('.prev').click(prev).end()
			.find('.next').click(next).end()
			.find('.number')
				.click(click)
				.slice(scroll_number)
					.parent()
					.hide()
		;
	};

	/* ページジャンプ */
	function click (e) { e.preventDefault();
		var $_ = $(this);
		var this_page = pager_area.find('.num'+$_.text());
		var num = $_.text() - 0;
		var rep = pager_area.find('span.number');
		var rep_num = rep.html() - 0;
		if (num == rep_num) return;
		rep.replaceWith('<a href="#" class="number num'+rep_num+'">'+rep_num+'</a>');
		this_page.replaceWith('<span class="number num'+num+'">'+num+'</span>');
		var start = (num * page_count) - 1;
		list.filter('.page'+rep_num).hide().end().filter('.page'+num).show();
		pager_area.find('.number').unbind('click').click(click);
	};

	/* ページナンバーバック */
	function prev (e) { e.preventDefault();
		manip('prev', 'next', function (child) {
			child.filter(':first').prev().show().end().end()
				.filter(':last').hide()
		});
	};

	/* ページナンバーネクスト */
	function next (e) { e.preventDefault();
		manip('next', 'prev', function (child) {
			child.filter(':first').hide().end()
				.filter(':last').next().show()
		});
	};

	/* ページナンバー操作 */
	function manip (name, not, func) {
		var cname = '.'+name;
		var current = pager_area.find('span.number');
		var next = current.parents('li:first')[name]('li.line');
		if (!next[name]('li.line').length) pager_area.find(cname).parents('li:first').hide();
		next.find('a').click();
		if (!next.filter(':hidden').length) return;
		pager_area.find('.'+not).parents('li:first').show();
		func(pager_area.children('li.line:not(:hidden)'));
	};
};

/* マーカの移動と地図移動を連動 */
nioibu.marker_dragger = function (map) { var self = this;
	return function (marker) {
		var dragging = false;
		GEvent.addListener(marker, 'drag', function () {
			if (dragging) return;
			dragging = true;
			setTimeout(function () {
				map.panTo(marker.getLatLng());
				dragging = false;
			}, 100);
		});
		GEvent.addListener(map, 'move', function () {
			if (dragging) return;
			marker.setLatLng(map.getCenter());
		});
	};
};

/* 逆ジオコーディング */
nioibu.reverse_geocoder = function (map) { var self = this;
	return function (func) {
		/* 住所名取得 */
		var geocoder = new GClientGeocoder();
		GEvent.addListener(map, 'mouseout', function () {
			var latlng = new GLatLng($('#lat').val(), $('#lon').val());
			geocoder.getLocations(latlng, function(addr) {
				if (addr.Status.code != 200) return;
				if (!addr.Placemark.length) return;
				func(get_detail(addr.Placemark));
			});
		});
	};
	function get_detail (placemark) {
		var detail = {};
		$.each(placemark, function () {
			if (!this.AddressDetails) return;
			var adc = this.AddressDetails.Country;
			if (!adc) return;
			detail.country_code = detail.country_code || adc.CountryNameCode;
			detail.country_name = detail.country_name || adc.CountryName;
			detail.area_postal_code = detail.area_postal_code || (adc.PostalCode && adc.PostalCode.PostalCodeNumber);

			var adcaa = adc.AdministrativeArea;
			if (!adcaa) return;
			detail.area_pref = detail.area_pref || adcaa.AdministrativeAreaName;

			var adcaal = adcaa.Locality;
			if (!adcaal) return;
			detail.area_middle = detail.area_middle || adcaal.LocalityName;

			var adcaaldl = adcaal.DependentLocality;
			if (!adcaaldl) return;
			detail.area_narrow = detail.area_narrow || adcaaldl.DependentLocalityName;

			detail.address = detail.address || this.address;
			return false;
		});
		return detail;
	};
};

/* 地図表示（window.onload後の遅延実行） */
nioibu.write_map = function () { var self = this;
	self.map_targets.push($('script:last').parents('.map:first').get(0));
};

$.each(['map', 'mgr'], function () {
	var name = this;
	nioibu['get_' + name] = function (num) { var self = this;
		if (!num) num = 0;
		if (self.maps.length < num) throw(num + ' is nioibu.maps.length over');
		if (self.maps[num] && self.maps[num][name]) return self.maps[num][name];
	};
});

nioibu.map_onload = function (func) { var self = this;
	if (func) return self.map_onload_func.push(func);
	if (self.get_mgr() && self.get_map()) $.each(self.map_onload_func, function () { this.apply(self) });
	self.map_onload = function (func) {
		func.apply(self);
	};
};

$(function () { var self = nioibu;
	/* 地図表示 */
	if (!GBrowserIsCompatible()) return;
	$(window).unload(GUnload);
	$.each(self.map_targets, function () {
		var map = new GMap2(this);
		map.setCenter(new GLatLng(36.527295, 136.40625), 5);
		map.addControl(
			($(this).height() >= 290)
				? new GLargeMapControl()
				: new GSmallMapControl()
		);
		map.addControl(new GMapTypeControl());
		map.enableScrollWheelZoom();
		map.infoWindowEnabled();
		var mgr = new MarkerManager(map);
		self.maps.push({map: map, mgr: mgr});
	});
	self.map_onload();
});

