var field
var tour
var overlay
var _timestamp
var headerHeight = 150
var footerHeight = 60
if (!window.console) {
	window.console = {
		log: function() {
		}
	}
}

function timestamp() {
	if (!_timestamp) _timestamp = new Date()
	return (new Date() - _timestamp) / 1000
}

// == つながりビューアの設定

Event.observe(window, 'load', function(e) {
	splash.create(5, {duration: 1});
	TourViewer.Coodicates.resizeMainView();
	buildField()
});

// == スプラッシュ

var splash = {
	element: $('splash'),
	alive: false,
	create: function(lifetime, option) {
		splash.alive = true;
		$('mainField').setStyle({visibility: 'hidden'});
		splash.adjust();
		splash.element.show();
		setTimeout(function(){splash.destroy(option);}, lifetime * 1000);
	},
	destroy: function(option) {
		splash.alive = false;
		$('mainField').setStyle({visibility: 'visible'});
		new Effect.Fade(splash.element, option);
	},
	adjust: function() {
		if (splash.alive) {
			var size = $('mainField').getDimensions();
			var zIndex = $('mainField').getStyle('zIndex') + 1000;
			splash.element.setStyle({
				zIndex: zIndex,
				width: size.width + 'px',
				height: size.height  + 'px'
			});
		}
	}
};

function buildField() {
	var blur = layout.blur - 0
	var scaleX = layout.scaleX - 0
	var scaleY = layout.scaleY - 0
	var usePolarCood = layout.usePolarCood
	
	field = Kanshin.graph.createField('mainField')
	
	var ctx = { keywords: $H(keywords).keys(), connections: $H(connections).keys() }
	
	// スクリプトのタイムアウトをさけるために、処理を分割して実行。
	// 0.001秒ごとに繰り返されるので、ほぼ連続して実行するのと変わりない速度。
	new PeriodicalExecuter(function(pe) {
		var count = 60
		
		if (ctx.keywords.length > 0) {
			var list = ctx.keywords.slice(0, count)
			ctx.keywords = ctx.keywords.slice(count) 
			
			list.each(function(key) {
				var info = keywords[key]
				var elm = $(key)
				
				var x = info.x - 0
				var y = info.y - 0
				
				if (usePolarCood) {
					if (x == 0) {
						y = 0
					} else {
						var t = y * Math.PI / 180
						var l = Math.abs(x)
						
						x = l * Math.cos(t)
						y = l * Math.sin(t)
					}
				}
				
				x = (x + blur * Math.random() - blur/2) * scaleX
				y = (y + blur * Math.random() - blur/2) * scaleY
				
				info.node = field.createNode(elm, { x: x, y: y})
			})
		} else if (ctx.connections.length > 0) {
			var list = ctx.connections.slice(0, count)
			ctx.connections = ctx.connections.slice(count) 
			
			list.each(function(key) {
				var info = connections[key]
				var elm = $(key)
				
				var kw1 = keywords['kw' + info.id1]
				var kw2 = keywords['kw' + info.id2]
				
				if (kw1 && kw2) {
					field.connectNodes(kw1.node, kw2.node, { label: elm })
				} else {
					console.log('invalid connection', info)
				}
			})
		} else {
			TourViewer.Coodicates.resizeMainView()
			Event.observe('mainField', 'mousedown', mainFieldDragStart, false)
			
			if (backgroundImage) {
				field.placeBackground(backgroundImage, { x: -backgroundX, y: -backgroundY });
			}
			
			if (foregroundImage) {
				field.placeImage(foregroundImage, { x: foregroundX, y: -foregroundY });
			}
			pe.stop()
		}
	}, 0.001)
};

// == つながりビューアのドラッグ

var dragStart
var dragStartOrogin
function mainFieldDragStart(ev) {
	var x = Event.pointerX(ev)
	var y = Event.pointerY(ev)
	dragStart = new Kanshin.graph.Point(x, y)
	dragStartOrogin = field.getOrigin()
	
	var elm = ('mainField')
	Event.observe(elm, 'mousemove', mainFieldDragMove, false)
	Event.observe(elm, 'mouseup', mainFieldDragEnd, false)
}

function mainFieldDragMove(ev) {
	var x = Event.pointerX(ev)
	var y = Event.pointerY(ev)
	
	var origin = new Kanshin.graph.Point(x - dragStart.x + dragStartOrogin.x, y - dragStart.y + dragStartOrogin.y)
	field.setOrigin(origin)
}

function mainFieldDragEnd(ev) {
	var elm = ('mainField')
	Event.stopObserving(elm, 'mousemove', mainFieldDragMove, false)
	Event.stopObserving(elm, 'mouseup', mainFieldDragEnd, false)
}

// == ツアービューの設定

function keywordInfo(elm, extra) {
	var info = keywords[elm.id];
	if (!info) return null;
	
	var obj = {title: '', body: '', image:''};
	obj.title = elm.down('.title') ? elm.down('.title').innerHTML : '';
	obj.image = elm.down('.image').innerHTML.strip() ? elm.down('.image').innerHTML.strip() : '';
	obj.body = elm.down('.comment') ? elm.down('.comment').innerHTML : '';
	
	Object.extend(info, obj);
	info.page_href = 'href="/keyword/' + info.id + '"';
	
	if (extra) Object.extend(info, extra)
	return info;
}

function nextElm(elm) {
	var i = keyword_order.indexOf(elm.id);
	if (i == keyword_order.length - 1) i = -1;
	return $(keyword_order[i + 1]);
}

function previousElm(elm) {
	var i = keyword_order.indexOf(elm.id);
	if (i == 0) i = keyword_order.length;
	return $(keyword_order[i - 1]);
}

function linkElms(elm) {
	var info = keywords[elm.id];
	var index = 1
	var list = [];
	$H(connections).each(function(pair){
		var info2 = pair.value;
		var conn = $(pair.key);
		if (info2.id1 == info.id || info2.id2 == info.id) {
			var info3 = keywordInfo($('kw' + (info2.id1 == info.id ? info2.id2 : info2.id1)));
			info3.reason = conn.innerHTML.strip();
			info3.index = index++
			list.push(info3);
		}
	});
	
	return list;
}

function tourContents(elm) {
	var src = $('tourViewTemplate').innerHTML
	var template = new Template(src, /(^|.|\r|\n)([$]\{(.*?)\})/)
	var info = keywordInfo(elm)
	
	var right1 = nextElm(elm);
	var right2 = nextElm(right1);
	var left1 = previousElm(elm);
	var left2 = previousElm(left1);
	info.right1 = evalTemplate('side1Template', keywordInfo(right1, {side:'right'}))
	info.right2 = evalTemplate('side2Template', keywordInfo(right2, {side:'right'}))
	info.left1 = evalTemplate('side1Template', keywordInfo(left1, {side:'left'}))
	info.left2 = evalTemplate('side2Template', keywordInfo(left2, {side:'left'}))
	
	linkElms(elm).sortBy(Math.random).each(function(info2, index) {
		info['tsunagari' + (index + 1)] = evalTemplate('tsunagariTemplate', info2)
	})
	
	return evalTemplate('tourViewTemplate', info)
}

function evalTemplate(src, info) {
	var src = $(src).innerHTML
	var template = new Template(src, /(^|.|\r|\n)(\{(.*?)\})/)
	return template.evaluate(info)
}

TourViewer = Class.create()
TourViewer.prototype = {
	initialize: function(elm){
		this.target=$(elm)
		this.closable = false
		setTimeout(this.allowClose.bind(this), 500)
		
		options = Object.extend({
			width: 847,
			height: 416,
			type: 'window',
			closeTitle: '&nbsp;&nbsp;&nbsp;',
			overlay: true,
			opacity: 1,
			left: false,
			top: false
		}, arguments[1] || {})
		this.setup(options)
		this.tracker('/tour/open/' + elm.id)
	},
	setup: function(options){
		this.getWindow(options)
		this.buildContent(this.target)
		this.display(options)
	},
	
	buildContent: function(target) {
		this.d3.update(tourContents(target))
	},
	
	show: function(cliker, targetId, label) {
		this.d3.update(tourContents($(targetId)))
		if (!label) label = 'click'
		this.tracker('/tour/' + label + '/' + targetId)
	},
	
	tracker: function(path) {
		if (campaign) {
			urchinTracker('/tracking/campaign/' + campaign + path)
		}
	},
	
	elm: function(tn) {
		if (!tn) tn = 'div'
		return $(document.createElement(tn))
	},
	getWindow: function(options){
		var remover = this.remove.bind(this)
		if(options.overlay == true){
			var d=this.elm()
			overlay = this.elm()
			document.body.appendChild(overlay)
			overlay.addClassName('LB_overlay')
			Event.observe(overlay, 'click', remover)
			
			overlay.style.height = TourViewer.Coodicates.yScroll() + "px"
			overlay.show()
		}
		this.d2 = this.elm()
		document.body.appendChild(this.d2)
		this.d2.className = 'LB_window'
		this.d2.style.height = parseInt(options.height) + 'px'
		this.d2.style.width = parseInt(options.width) + 'px'
		
		this.d3 = this.elm()
		this.d2.appendChild(this.d3)
		
		var d = this.elm()
		this.d2.appendChild(d)
		d.className='LB_closeWindow'
		d.options = options
		var close = this.elm('a')
		d.appendChild(close)
		Event.observe(close, 'click', remover)
		close.href='#'
		close.update(options.closeTitle)
	},
	display: function(options){
		Element.setOpacity(this.d2, 0)
		TourViewer.Coodicates.place(this.d2, options)
		new Effect.Opacity(this.d2, {from:0,to:options.opacity,duration:.2})
	},
	remove: function(ev){
		Event.stop(ev)
		if (!this.closable) return
		new Effect.Opacity(tour.d2, {from:1,to:0,duration:.2})
		if (overlay) {
			new Effect.Opacity(overlay, {from:.6,to:0,duration:.2})
			Element.remove(overlay)
		}
		Element.remove(tour.d2)
	},
	allowClose: function() {
		this.closable = true
	}
}

TourViewer.Coodicates = {
	place: function(elm, options) {
		var pageSize = TourViewer.Coodicates.getPageSize()
		var pw = pageSize[0]
		var ph = pageSize[1]
		
		elm.style.width = options.width + 'px'
		elm.style.display = 'block'
		
		var left = options.left
		if(!left || left < 0){
			left = ((pw - options.width) / 2)
		}else{
			left = parseInt(left)
		}
		elm.style.left = left + 'px'
		
		var top = options.top
		if(!top || top < 0){
			var pageScroll = TourViewer.Coodicates.getPageScrollTop()
			top = (pageScroll + ((ph-elm.offsetHeight)/2))
		} else {
			top = parseInt(top)
		}
		elm.style.top = top + 'px'
	},
	yScroll: function() {
		if (window.innerHeight && window.scrollMaxY) {	
			yScroll = window.innerHeight + window.scrollMaxY
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			yScroll = document.body.scrollHeight
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			yScroll = document.body.offsetHeight
		}
		return yScroll
	},
	getPageScrollTop: function(){
		var yScrolltop
		if (self.pageYOffset) {
			yScrolltop = self.pageYOffset
		} else if (document.documentElement && document.documentElement.scrollTop){    // Explorer 6 Strict
			yScrolltop = document.documentElement.scrollTop
		} else if (document.body) {// all other Explorers
			yScrolltop = document.body.scrollTop
		}
		return yScrolltop
	},
	getPageSize: function(){
		var de = document.documentElement
		var w = self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth
		var h = self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight
		
		return new Array(w,h) 
	},
	
	resizeMainView: function() {
		var size = TourViewer.Coodicates.getPageSize()
		var w = size[0]
		var h = size[1] - headerHeight - footerHeight
		
		
		$('mainField').setStyle({width: w + 'px', height: h + 'px'})
		if (field) field.resized()
		
		splash.adjust();
	}
}

Event.observe(window, 'resize',  TourViewer.Coodicates.resizeMainView)

