function nicofetch(elem,id,parent,link_id){
	if(elem&&elem.__fetching)return;
	var frm=elem,fetcher;
	for(;parent--;)frm=frm.parentNode;
	if (!~id.indexOf('&')){
		fetcher=new nlMovieFetcher(id,elem,frm,(link_id || "watch/"+id));
	}else{
		var params=id.split('&');
		id=params[0];
		fetcher=new nlMovieFetcher(id,elem,frm,(link_id || "watch/"+id));
		fetcher.params=params;
	}
	fetcher.fetch();
}

(function(){
// nlMovieFetcherの登録
if (!window.nlMovieFetcher) {
	// 外部サムネやユーザースクリプトを考慮してPrototype.jsは使わずに実装
	window.nlMovieFetcher = function(){ this.initialize.apply(this, arguments) }
	window.nlMovieFetcher.prototype = {
		// 最低限、動画IDさえ渡せば動作OK
		initialize: function(id, elem, frame, anchor) {
			this.id     = id;						// 動画ID(必須)
			this.elem   = this.__getElem(elem); 	// ステータスを表示するElement
			this.frame  = this.__getElem(frame);	// 背景色を変更するElement
			this.anchor = this.__getElem(anchor);	// 動画を開くアンカーElement
			this.params = [ id ];					// APIに渡すパラメータ配列
			this.bgColor1 = '#FFFF99';				// 背景色(1段階目)
			this.bgColor2 = '#FFFF00';				// 背景色(2段階目)
			this.interval = 2000;					// ステータス取得間隔(ミリ秒)
		},
		fetch: function() {
			var fetch_text = "fetching...";
			if (this.elem) {
				if(this.elem.__fetching) return;
				this.elem.__fetching = true;
				this.__setText(fetch_text);
			}
			if (this.frame) {
				if (this.__marking()) {
					if (this.frame.className.indexOf("marked") < 0)
						this.frame.className += " marked";
				} else {
					this.bgImage0 = this.frame.style.backgroundImage;
					this.bgColor0 = this.frame.style.backgroundColor;
					this.frame.style.backgroundImage = 'none';
					this.frame.style.backgroundColor = this.bgColor1;
				}
			}
			var self = this;
			this.callAPI(this.params.join('&'), function(r) {
				var text = r.responseText;
				if (r.status == 200 && text.indexOf("OK") == 0) {
					if (text.indexOf("accepted") > 0) {
						self.__updateStatus();
					} else {
						self.__setText(text.substring(3));
						self.__finish(text.indexOf("cached") > 0);
					}
				} else {
					self.__setText(fetch_text+" FAILED!");
					self.__finish(false);
				}
				self.__modifyAnchor();
			});
		},
		callAPI: function(param, callback) {
			var FETCH_API_URL = "http://"+document.location.host+"/cache/fetch?";
			/*
			var xhr = null;
			if (window.XMLHttpRequest) {
				xhr = new XMLHttpRequest();
			} else if (window.ActiveXObject) {
				try {
					xhr = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (e) {
					try {
						xhr = new ActiveXObject("Microsoft.XMLHTTP");
					} catch (e) {}
				}
			}
			if (xhr == null) {
				this.__setText("AJAX ERROR!"); return;
			}
			*/
			var xhr = new XMLHttpRequest();
			xhr.open('GET', FETCH_API_URL + param, true);
			xhr.onreadystatechange = function() {
				if(xhr.readyState == 4 && callback) callback(xhr);
			}
			xhr.send(null);
		},
		__getElem: function(name) {
			return (typeof name == 'string') ?
				document.getElementById(name) : name;
		},
		__setText: function(text) {
			if(!this.elem) return;
			if (this.elem.textContent) {
				this.elem.textContent = text;
			} else if (this.elem.innerText) {
				this.elem.innerText = text;
			} else {
				this.elem.innerHTML = text;
			}
		},
		__updateStatus: function() {
			if(!this.elem) return;
			var self = this;
			var timer = setInterval(function() {
				self.callAPI("status="+self.id, function(r) {
					if (r.status != 200) return;
					var text = r.responseText;
					self.__setText(text);
					if (!/( wait|\d%)$/.test(text)) {
						clearInterval(timer);
						self.__finish(/ done\.$/.test(text));
					}
				});
			}, this.interval);
		},
		__modifyAnchor: function() {
			if(!this.anchor || this.anchor.__fetched) return;
			var self = this;
			var rmfunc = function() {
				self.callAPI("rm="+self.id);
				if (self.frame && self.frame != self.elem) {
					if (self.__marking()) {
						self.frame.className = self.frame.className.replace(/\s+marked/, "");
					} else {
						self.frame.style.backgroundImage = self.bgImage0;
						self.frame.style.backgroundColor = self.bgColor0;
					}
				}
			}
			if (this.anchor.addEventListener) {
				this.anchor.addEventListener('click', rmfunc, true);
			} else if (this.anchor.attachEvent) {
				this.anchor.attachEvent('onclick', rmfunc);
			}
			this.anchor.target = '_blank';
			this.anchor.__fetched = true;
		},
		__finish: function(cached) {
			if(!this.elem) return;
			if (cached) {
				if (this.frame && this.frame != this.elem) {
					if (!this.__marking()) {
						this.frame.style.backgroundColor = this.bgColor2;
					}
				}
				this.elem.removeAttribute('href');
				this.elem.removeAttribute('onclick');
				// totalRenameが存在する場合はキャッシュタイトルを再取得
				if (window.TR_cacheAPI && this.id.match(/[a-z]{2}\d+/))
					TR_cacheAPI("tr_helper/get", this.id, null, true);
			}
			this.elem.__fetching = false;
		},
		__marking: function() { // marking.js 対応
			return this.frame.className && this.frame.className.indexOf("marking") > -1;
		},
		__empty: function(){}
	}
}
// playlist.js用 似非DOM Storageの登録
// あらかじめfetchedというリストを追加しておき、更にfetchedに対する操作をフックする
/*
if (window.Prototype && !window.nlMovieFetcherStorage) {
	var Storage = Class.create();
	Storage.prototype = {
		initialize: function(constructor) {
			this.getItem    = function(key)      { return constructor.getItem(key)       }
			this.setItem    = function(key,value){ return constructor.setItem(key,value) }
			this.removeItem = function(key)      { return constructor.removeItem(key)    }
			this.clear      = function()         { return constructor.clear()            }
			this.key        = function(index)    { return constructor.key(index)         }
			this.__keys     = function()         { return constructor.__keys()           }
			this.__values   = function()         { return constructor.__values()         }
			this.__load     = function()         { return constructor.__load()           }
			this.__save     = function(force)    { return constructor.__save(force)      }
			this.length = 3;
			this["playlist.all"] = "default,fetched";
			this["current"] = "fetched";
			this["playlist_fetched"] = "fetched;"
		}
	};
	var StorageConstructor = Class.create();
	StorageConstructor.prototype = {
		initialize: function() {
			this.__construct();
			var self = this;
			Event.observe(window, 'unload', function(){ self.__save() });
		},
		__construct: function() {
			this.loaded = false;
			this.modified = false;
			this.storage = new Storage(this);
			window.nlMovieFetcherStorage = this.storage;
		},
		__validate: function(key) {
			var value = this.storage[key];
			if (typeof value == 'function' || key == "length")
				return false;
			return true;
		},
		getItem: function(key) {
			this.__load();
			if (!this.__validate(key) || this.storage[key] == undefined)
				return null;
			return this.storage[key];
		},
		setItem: function(key, value) {
			this.__load();
			if (!this.__validate(key) || this.storage[key] == value)
				return;
			if (!this.storage[key]) this.storage.length++;
			if (key == "playlist_fetched") {
				// fetchedに対しては削除操作のみ許可する
				var a = this.__SMIDs(this.storage[key]), b = this.__SMIDs(value);
				if (a.length > b.length) {
					new Ajax.Request("/cache/fetch", {
						method: 'GET',
						asynchronous: false,
						parameters: "rm=" + this.__diffSMID(a, b)
					});
				}
			} else {
				this.modified = true;
			}
			this.storage[key] = value;
		},
		__SMIDs: function(value) {
			value = value.substring(value.indexOf(";") + 1);
			return value.split(":").map(function(e){ return e.split("&")[0] });
		},
		__diffSMID: function(large, small) {
			return large.find(function(smid){ return small.indexOf(smid) == -1 });
		},
		removeItem: function(key) {
			this.__load();
			if (this.__validate(key) && this.storage[key]) {
				delete this.storage[key];
				this.storage.length--;
				this.modified = true;
			}
		},
		clear: function() {
			this.__construct();
			this.modified = true;
		},
		key: function(index) {
			return this.__keys()[index];
		},
		__keys: function() {
			this.__load();
			var keys = [];
			for (prop in this.storage) {
				if (!this.__validate(prop)) continue;
				keys.push(prop);
			}
			return keys;
		},
		__values: function() {
			this.__load();
			var values = [];
			for (prop in this.storage) {
				if (!this.__validate(prop)) continue;
				values.push(this.storage[prop]);
			}
			return values;
		},
		__load: function() {
			if (!this.storage || this.loaded)
				return;
			var json = this.__loadJSON("/cache/fetch?storage");
			if (typeof json == 'object') {
				json.length = Object.keys(json).length + 1; // playlist_fetched
				Object.extend(this.storage, json);
				if (this.storage["playlist.all"].indexOf("fetched") < 0)
					this.storage["playlist.all"] += ",fetched";
				this.storage["playlist_fetched"] = "fetched;"
				json = window.fetchedList || this.__loadJSON("/cache/fetch?json");
				if (typeof json == 'object') {
					var fetched = Object.keys(json).map(function(key) {
						var title = json[key]
						return key + "&" + escape(json[key]);
					}).join(":");
					this.storage["playlist_fetched"] += fetched;
				}
				this.loaded = true;
			}
		},
		__loadJSON: function(path) {
			var result = null;
			new Ajax.Request(path, {
				method: 'GET',
				asynchronous: false,
				onComplete: function(xhr, json) {
					result = (json) ? json : xhr.responseText.evalJSON();
				}
			});
			return result;
		},
		__save: function(force) {
			var saved = false;
			if (this.storage && (this.modified || force)) {
				var clone = Object.clone(this.storage);
				delete clone.length;
				delete clone.playlist_fetched;
				var self = this;
				new Ajax.Request("/cache/fetch?storage", {
					postBody: Object.toJSON(clone),
					asynchronous: false,
					onComplete: function(){ self.modified = false; saved = true; }
				});
			}
			return saved;
		}
	};
	new StorageConstructor();
}
*/
})();
