/**
 * RSSを読み込み、右から左へ流れるようにするティッカー
 * 
 * このプログラムは、xml(RSS)の読み込みにJKL.ParseXMLを、
 * 文字コードの変換にecl.jsを使用しています。
 *
 * JKL.ParseXML
 * http://www.kawa.net/works/js/jkl/parsexml.html
 */
var Ticker = function() {};

Ticker.ReadRssOne = function(url, data) {
	this.data = data;
	this.rss_items = [];

	this.now_counter = 0;
}

Ticker.ReadRssOne.prototype = {
	parse: function() {
		for(var i in this.data['rdf:RDF'].item) {
			this.rss_items.push(this.data['rdf:RDF'].item[i]);
		}
		
		this.now_counter = this.rss_items.length;
	},
	now_content: function() {
		var now = this.rss_items.pop();

		if (now) {
			return { title: now['title'], date: now['dc:date'], description: now['description'], url: now['link'] };
		} else {
			return null;
		}
	}
}

Ticker.ReadRssTwo = function(url, data) {
	this.data = data;
	
	this.rss_items = [];
	this.now_counter = 0;
}

Ticker.ReadRssTwo.prototype = {
	parse: function() {
		for(var i in this.data.rss.channel.item) {
			this.rss_items.push(this.data.rss.channel.item[i]);
		}
		
		this.now_counter = this.rss_items.length;
	},
	now_content: function() {
		var now = this.rss_items.pop();
		
		if (now) {
			return { title: now['title'], date: now['pubDate'], description: now['description'], url: now['link'] };
		} else {
			return null;
		}
	}
}

Ticker.NotFound = function() {
	this.rss_error_put = 0;
}
Ticker.NotFound.prototype = {
	parse: function() {},
	now_content: function() {
		if (this.rss_error_put++ == 0) {
			return { title: 'RSS error', date: '0000-00-00', description: '', url: '' };
		} else {
			return null;
		}
	}
}

Ticker.ReadRssFactory = function(url) {
	var http = new JKL.ParseXML(url);
	http.setOutputArrayElements('item');

	var data = http.parse();

	if (!data || data.parsererror) {
		return new Ticker.NotFound();
	} else if (data.rss && data.rss.version == '2.0') {
		return new Ticker.ReadRssTwo(url, data);
	} else {
		return new Ticker.ReadRssOne(url, data);
	}
}

/**
 * 文字を右から左へ移動させる
 */
Ticker.RtoL = function(id_node, template, text) {
	if (arguments.length <= 0) {
		return;
	}
	
	this.id_node = document.getElementById(id_node);
	this.text = template.parse(text);
	
	this.reset();
	this.get_size();
	
	this.startx = this.x = Math.min(this.id_node.offsetWidth, this.id_node.parentNode.offsetWidth);
	
	this.id_node.style.overflow = 'hidden';
}

Ticker.RtoL.SpeedX = -4;
Ticker.RtoL.SpeedY = 0;

Ticker.RtoL.prototype = {
	get_size: function() {
		var child = document.createElement('div');
		
		while(this.id_node.firstChild) {
			child.appendChild(this.id_node.removeChild(this.id_node.firstChild));
		}
		
		this.id_node.appendChild(child);
		
		child.style.position = 'absolute';
		
		this.minw = child.offsetWidth;
		this.minh = child.offsetHeight;
		
		child.style.position = 'relative';
		
		this.id_node.appendChild(child);
	},
	move: function() {
		this.x += Ticker.RtoL.SpeedX;
		this.id_node.firstChild.style.left = this.x + 'px';
	},
	is_stop: function() {
		return this.x < -this.minw;
	},
	reset: function() {
		this.x = this.startx;
		this.y = this.starty;
		
		this.flush();
	},
	flush: function() { 
		this.id_node.innerHTML = this.text;
		this.id_node.firstChild.style.position = 'relative';
	}
}

/*
 * 文字を左から一文字ずつ右へ増やしていく
 */
Ticker.LtoRString = function(id_node, template, text) {
	this.id_node = document.getElementById(id_node);
	this.template = template;
	this.text = text;
	
	this.textNodes = [];
	
	var self = this;
	
	this.now_position = 0;
	
	// テンプレートを呼んで整形してきて、それをHTMLパーサーに挿入する。
	// HTMLのテキストを一文字ずつ抜き出すため。
	this.id_node.innerHTML = this.template.parse(this.text);
	
	this.searchText(this.id_node, function(elem) {
		self.textNodes.push(elem.data); // これがあるので、resetメソッドで処理できない
		elem.data = '';
	});
	
	this.flush();
	
	this.now_position = 0;
}
Ticker.LtoRString.prototype = new Ticker.RtoL();
Ticker.LtoRString.prototype.move = function() {
	this.now_position++;
	this.flush();
}
Ticker.LtoRString.prototype.is_stop = function() {
	var cat = "";
	this.searchText(this.id_node, function(elem) { cat += elem.nodeValue; });
	
	return this.now_position >= this.id_node.innerHTML.length;
}
Ticker.LtoRString.prototype.reset = function() {
	this.now_position = 0;
	this.id_node.innerHTML = this.template.parse(this.text);
	
	// これをいれないと、テキストが切り替わるときに縮んで伸びる場合があるため
	this.searchText(this.id_node, function(elem) { elem.nodeValue = '　'; });
	this.flush();
}
Ticker.LtoRString.prototype.flush = function() {
	this.parse();
}
Ticker.LtoRString.prototype.searchText = function(elem, func) {
	for(var i = 0;i < elem.childNodes.length;i++) {
		if (elem.childNodes[i].nodeType == 3) {
			func(elem.childNodes[i]);
		} else {
			this.searchText(elem.childNodes[i], func);
		}
	}
}
Ticker.LtoRString.prototype.parse = function() {
	var cat = "", key = 0, self = this, lists = this.textNodes;
	stringParse(this.id_node);

	function stringParse(html) {
		if (html.nodeType == 3) {
			var tmp = lists[key];
			var now = tmp ? tmp : "";
			
			cat += now;
			
			if (cat.length <= self.now_position) {
				html.data = now.split('').slice(0, -(cat.length - self.now_position)).join('');
			}
			key++;
		} else {
			for (var i = 0;i < html.childNodes.length;i++) {
				stringParse(html.childNodes[i]);
			}
		}
	}
}

/**
 * テンプレートを読み込んで、出力させる
 */
Ticker.Template = function(path, id_node, values) {
	this.path = path;
	
	if (typeof id_node == "string") {
		this.id_node = document.getElementById(id_node);
	} else {
		this.id_node = id_node;
	}
	
	this.template = "";
	
	this.obj = window.ActiveXObject ? new ActiveXObject('Msxml2.XMLHTTP') : new XMLHttpRequest();
}

Ticker.Template.prototype = {
	set_template: function(call_func) {
		var self = this;
		
		this.obj.onreadystatechange = function() {
			if(self.obj.readyState == 4 && self.obj.status == 200) {
				self.template = self.obj.responseText;
				call_func(self.template);
			}
		}
		
		this.obj.open('GET', this.path, true);
		this.obj.send(null);
	},
	parse: function(values, template) {
		var ret = template ? template : this.template;
		var ymd = this.jp_date(values['date']);
		
		values['year'] = ymd[0];
		values['month'] = ymd[1];
		values['day'] = ymd[2];
		
		for(var value_name in values) {
			ret = ret.replace(new RegExp('<\\?echo[ ]+'+value_name+'[ ]+\\?\\>'), values[value_name]);
		}
		
		return ret;
	},
	jp_date: function(date) {
		var three_fields = date.match(/^([0-9]{4})-(0?[0-9]|1[0-2])-([012]?[0-9]|3[01])$/);
		
		if (three_fields) {
			return three_fields.slice(1);
		} else {
			var dobj = new Date(date);
			return [dobj.getFullYear(), dobj.getMonth() + 1, dobj.getDate()];
		}
	}
}

/**
 * RSSを読み込んで、読み込んだタイトル、URLを右から左へ流す
 */
Ticker.Top = function(url, id_node) {
	this.id_node = id_node;
	
	this.rss = new Ticker.ReadRssFactory(url);
	this.rss.parse();

	this.template = new Ticker.Template('/__ticker_template.temp', id_node);

	this.now_contents = 0;
	this.rtol_list = [];

	var now = null;
	var self = this;
	
	var template_set_variable = function(xml) {
		while((now = self.rss.now_content())) {
//			self.rtol_list.push(new Ticker.RtoL(id_node, self.template, now));
			self.rtol_list.push(new Ticker.LtoRString(id_node, self.template, now));
		}
		self.rtol = self.rtol_list[self.now_contents++];
		self.goto_left();
	}
	
	this.template.set_template(template_set_variable);
}

Ticker.Top.prototype = {
	goto_left: function() {
		var self = this;
		var call_timer = function() {
			if(self.rtol.is_stop()) {
				self.rtol = self.rtol_list[self.now_contents++ % self.rtol_list.length];
				self.rtol.reset();
			}
			self.rtol.move();
		};
		
		Ticker.RtoL.move_timer_id = setInterval(call_timer, 100);
	}
}

Ticker.Start = function(url, id) {
	if (window.addEventListener) {
		window.addEventListener('load', function() {new Ticker.Top(url, id)}, false);
	} else if (window.attachEvent) {
		window.attachEvent('onload', function() { new Ticker.Top(url, id)} );
	}
}

Ticker.Start('/rss.php', 'article');
