var BUILD_OFFLINE_RESOURCES = function() {
	Event.observe(window, "load", function() {
		var gs = new GearsSuite();
		gs.prepareGears("GoGears");
	});

	if(!hotdog || !coolcat) return;
	window["ATTACH"] = new Object;
	window.ATTACH["store"] = new TamakoStore("attachment_store", "rstore");
	if(tom_and_jerry) ATTACH.store.on();
	else ATTACH.store.off();
	window.ATTACH["db"] = new TamakoDB(
		["attachments"],
		{"attachments":
			{
				"id": "Integer()",
				"file_name": "Varchar()",
				"file_size": "Integer()",
				"page_id": "Integer()",
				"page_title": "Varchar()",
				"workspace_id": "Integer()",
				"wiki_id": "Integer()",
				"created_at": "Timestamp()",
				"updated_at": "Timestamp()"
			}
		},
		"attachment_db"
	);

	if (tom_and_jerry) {
		window["Tamako"] = new LocalBuilder(Synki_LocalDB_Schema)
	}
}

var FETCH_ATTACHMENT = function() {

	Event.observe(window, "load", function() {
		if(!hotdog || !coolcat) return;
		var _ub = new URLBuilder();
		// temporary attachment fetcher.
		for(var i=0; i<__attachments.length; i++) {
			var exist = ATTACH.db.attachments.find_one({file_name: __attachments[i].file_name, page_id: String(__page.id)});
			if(exist) {
				if(exist.created_at == __attachments[i].created_at) continue;
				else {
					ATTACH.store.on();
					ATTACH.db.attachments.remove("file_name='" + __attachments[i].file_name + "'");
					ATTACH.store.remove(location.protocol + "//" + location.hostname + _ub.attachment_path(__attachments[i]));
				}
			}

			ATTACH.db.attachments.save(__attachments[i]);
			ATTACH.store.capture(location.protocol + "//" + location.hostname + _ub.attachment_path(__attachments[i]));
			ATTACH.store.off();
		}
	});
};

var GearsSuite = function() {
	this.updownMethod = (tom_and_jerry) ? "go_online" : "go_offline";

	if(!hotdog) {
		Imple(this, new InstallGears());
	} else if(!coolcat) {
		Imple(this, new AllowSite());
	} else {
		Imple(this, new ActionGears());
		this.success = true;
	}
};

GearsSuite.prototype.prepareGears = function(button_container) {
	var container = document.getElementById(button_container);
	if(!container) return false; // there's no on/off gears button

	container.style.cursor = "pointer";
	var button = this.spawnImage(container);
	this.bindEventTo(button);
};


GearsSuite.prototype.spawnImage = function(container) {
	var button_image = document.createElement("img");
	button_image.src = "/images/"+ this.updownMethod +".gif";
	button_image.alt = this.updownMethod;

	container.appendChild(button_image);

	return button_image;
};

//////////////////////////////////////////////////////////////
// Guide to allow site
var AllowSite = function() {
};

AllowSite.prototype.bindEventTo = function(button) {
	button.onclick = CallBack(this, function() {this.guideToAllow()})
};

AllowSite.prototype.guideToAllow = function() {
	document.body.appendChild(this._allowing());
};

AllowSite.prototype._allowing = function() {
	var container = document.createElement("div")
	container.id = "div_allow_site";
	container.style.position = "absolute";
	container.style.top = "0px";
	container.style.backgroundColor = "white";
	container.style.width = "100%";
	container.style.height = "100%";
	container.innerHTML = this._allowing_html();

	var buttons = this._allowing_buttons();
	container.appendChild(buttons);

	return container;
};

AllowSite.prototype._allowing_html = function() {
	var html = "";
	html += "<center><div style='padding-top:50px'>";
	html += "<img src='/images/allow.png'>";
	html += '<p style="font-weight:bold">#1: Check "I trust this site. Allow it to use Google Gears."</p>';
	html += '<p style="font-weight:bold">#2: Click Allow button</p></center>';
	
	html += "</div>";

	return html;
};

AllowSite.prototype._allowing_buttons = function() {
	var buttons_container = document.createElement("div");
	buttons_container.className = "Pop_Input";
	buttons_container.style.textAlign = "center";
	buttons_container.style.margin = "20px";

	var allow_button = document.createElement("input");
	allow_button.type = "button";
	allow_button.value = "Ok";
	allow_button.onclick = CallBack(this, function() { this.do_allow() });

	var cancel_button = document.createElement("input");
	cancel_button.type = "button";
	cancel_button.value = MSG[59];
	cancel_button.onclick = CallBack(this, function() { this.cancel_allowing() });

	buttons_container.appendChild(allow_button);
	buttons_container.appendChild(cancel_button);

	return buttons_container;
};

AllowSite.prototype.do_allow = function() {
	location.reload();
};

AllowSite.prototype.cancel_allowing = function() {
	container = document.getElementById("div_allow_site");
	document.body.removeChild(container);
};

//////////////////////////////////////////////////////////////
// Guide to gears install
var InstallGears = function() {
};

// bare method
InstallGears.prototype.bindEventTo = function(button) {
	button.onclick = CallBack(this, function() {this.guideToInstall()})
};

InstallGears.prototype.guideToInstall = function() {
	document.body.appendChild(this._installation());
}

// generate html
InstallGears.prototype._installation = function() {

	var container = document.createElement("div")
	container.id = "div_gears_install";
	container.style.position = "absolute";
	container.style.top = "0px";
	container.style.backgroundColor = "white";
	container.style.width = "100%";
	container.style.height = "100%";
	container.innerHTML = this._installation_html();

	var buttons = this._installation_buttons();
	container.appendChild(buttons);

	return container;
};

InstallGears.prototype._installation_html = function() {
	var html = "";
	//html += "<div id='fog_gears_install' style='background-color:black;width:100%;height:100%;position:absolute;z-index:1;line-height:100%'></div>";
	html += "<div class='gears_install_div' style='padding:50px'>";
	html += MSG[166]
	html += "</div>";

	return html;
};

InstallGears.prototype._installation_buttons = function() {
	var buttons_container = document.createElement("div");
	buttons_container.className = "Pop_Input";
	buttons_container.style.textAlign = "center";
	buttons_container.style.margin = "20px";

	var install_button = document.createElement("input");
	install_button.type = "button";
	install_button.value = MSG[550];
	install_button.onclick = CallBack(this, function() { this.redirect_to_gears_installation() });

	var cancel_button = document.createElement("input");
	cancel_button.type = "button";
	cancel_button.value = MSG[59];
	cancel_button.onclick = CallBack(this, function() { this.cancel_installation() });

	buttons_container.appendChild(install_button);
	buttons_container.appendChild(cancel_button);

	return buttons_container;
};

InstallGears.prototype.redirect_to_gears_installation = function() {
	var url = 'http://gears.google.com/?action=install&message=You%20can%20enable%20offline%20mode%20for%20Google%20Reader%20by%20installing%20Google%20Gears';

	this.cancel_installation();
	window.open(url, 'google_gears');
};

InstallGears.prototype.cancel_installation = function() {
	container = document.getElementById("div_gears_install");
	document.body.removeChild(container);
};




//////////////////////////////////////////////////////////////
// Go On/Off Action Module
var ActionGears = function() {
};

ActionGears.prototype.bindEventTo = function(button) {
	button.onclick = CallBack(this, function() { this[button.alt](button) });
};

ActionGears.prototype.clearEventFrom = function(button) {
	button.onclick = "return false";
};

// Go Offline
ActionGears.prototype.go_offline = function(button) {
	this.clearEventFrom(button)

	var progress = new SynkiProgress("go_offline")
	var cbo = new ProgressInterface(progress.rolling);
	new Downloader(ExtractIdFromUrl("workspace"), Synki_LocalDB_Schema, cbo);
};

// Go Online
ActionGears.prototype.go_online = function(button) {
	this.clearEventFrom(button)

	var progress = new SynkiProgress("go_online")
	var cbo = new ProgressInterface(progress.rolling);
	new Uploader(ExtractIdFromUrl("workspace"), Synki_LocalDB_Schema, cbo);
};



//////////////////////////////////////////////////////////////
// progress gate
var ProgressInterface = function(_cbo) {
	this.cbo = _cbo;
	this.temporaryTask = new Object();
	this.section_rate = this.calc_section_rate();
};

// ToDo: bad name. not a watcher. may listener? waiter? servant?
ProgressInterface.prototype.watcher = function(section, task, jobs) {
	
	if(this.autoRollId) clearInterval(this.autoRollId);
	var result = this.calc_percent(section, task, jobs);

	if(this.is_autoType[section] && !result.section_complete) {
		var _max = Number(this.section_rate[section]) + Number(this.fix_rate[section]);
		this.autoRollId = setInterval(CallBack(this, function() { this.rolling(result, _max)} ), 2500);
	} else {
		this.cbo(result.percent, result.message, result.section_complete);
	}

	return result;
};

ProgressInterface.prototype.rolling = function(result, _max) {
	
	if(result.percent < _max) {
		result.percent = result.percent + 1;
		this.cbo(result.percent, result.message);
	}
};

// when we can get number of pages by self,
// jobs count of DATA section can get static value.
ProgressInterface.prototype.setJobsCount = function(section, jobs) {
	if(jobs == 0) this.sendCompleteSignal();
	try {
		this.jobs[section] = jobs;
		this.temporaryTask[section] = 0;
	} catch(e) {
		return e.message;
	}

	return true;
};

ProgressInterface.prototype.sendCompleteSignal = function() {
	this.cbo(100, MSG[555]);
};

ProgressInterface.prototype.calc_percent = function(section, _task, jobs) {

	var task = this.controlTask(section, _task);
	
	// get total
	var task_total = this.jobs[section] || jobs;

	// set count of jobs first by setJobsCount(number)
	if(!task_total) return [0, "Error: Set Count of task By setJobsCount(number)"];
	var done = Number(task) / Number(task_total);
	var percent = Math.ceil(this.section_rate[section] * done);
	percent = percent + this.fix_rate[section];

	var message = (section == "DATA" || section == "UPLOAD") ? this.messages[section] : this.messages[section][task];
	var section_complete = (done == 1) ? section : null;
	return {"percent": percent, "message": message, "section_complete": section_complete};
};

ProgressInterface.prototype.messages = {
	"SHAKE": {
		1: MSG[56],
		2: MSG[552]
	},

	"APP": {
		1: MSG[57],
		2: MSG[551]
	},

	"DATA": MSG[54],

	"FINALIZE": MSG[55],

	"UPLOAD": MSG[554]
};

ProgressInterface.prototype.calc_section_rate = function() {
	var shake = 5;
	var app = 55;
	var data = 35;
	var finalize =  5;
	var upload = 100;

	return {"SHAKE": shake, "APP": app, "DATA": data, "FINALIZE": finalize, "UPLOAD": upload};
};

ProgressInterface.prototype.is_autoType = { 
	"APP": true 
};

ProgressInterface.prototype.controlTask = function(section, _task) {
	var task = 0;
	if(!_task) task = this.incrementTask(section);
	else {
		task = this._set_temporary_task_if_exists(section, _task)
	}

	return task;
};

ProgressInterface.prototype.incrementTask = function(section) {
	if(!this.temporaryTask[section]) this.temporaryTask[section] = 0;

	return ++this.temporaryTask[section];
};

ProgressInterface.prototype._set_temporary_task_if_exists = function(section, task) {
	this.temporaryTask[section] = Number(task);

	return Number(task);
};

ProgressInterface.prototype.fix_rate = {
	"SHAKE": 0,
	"APP": 5,
	"DATA": 60,
	"FINALIZE": 95,
	"UPLOAD": 0
};

ProgressInterface.prototype.jobs = {
	SHAKE: 2,
	APP: 2,
	DATA: null,
	FINALIZE: 1,
	UPLOAD: null
};


/////////////////////////////////////////////
// progress module
var SynkiProgress = function(_mode) {
	this.showProgress(_mode);
};

SynkiProgress.prototype.rolling = function(percent, message, section_complete) {
	var _pgs_title = document.getElementById('progress_title');
	var _pgs_percent = document.getElementById('progress_percent');
	var _pgs_bg = document.getElementById('progress_bg');
	if(section_complete) {
		var _pgs_job = document.getElementById(section_complete);
		if(_pgs_job) _pgs_job.style.backgroundImage = "url('/images/loading-check.gif')";
	}

	_pgs_title.innerHTML = message;
	_pgs_bg.style.width = percent + '%';
	_pgs_percent.innerHTML = percent + '%';


	if(percent == 100) {

		var button = document.getElementById("gears_cancel");
		if(button) button.style.display = "none";

		_pgs_title.innerHTML = MSG[555];

		//setTimeout('location.reload()', 2400);
		setTimeout(function() {
			var ub = new URLBuilder;
			var _ws = { id: ExtractIdFromUrl("workspace") };
			var _url = ub.workspace_path(_ws);
			location.replace(_url);
		}, 2400);
	}
}

SynkiProgress.prototype.showProgress = function(_mode) {
	document.body.appendChild(this._progress(_mode));

	this.generate_and_bind_cancel_button(_mode);
};

SynkiProgress.prototype._progress = function(_mode) {

	var container = document.createElement("div")
	container.id = "div_gears_progress";
	container.innerHTML = this._progress_html(_mode);

	return container;
};

SynkiProgress.prototype._progress_html = function(_mode) {
	var fog_height = Math.max(document.documentElement.clientWidth, document.body.clientWidth);

	var shadow_height = (_mode == "go_offline") ? "284" : "214";
	var progress_height = (_mode == "go_offline") ? "255" : "180";
	var html = "";
	html += "<div id='FogGearsProgress' style='background-color:white;width:100%;height:" + fog_height + "px;position:absolute;z-index:100;left:0;top:0;'></div>";
	html += "<div id='progress_shadow' style='border-right:2px solid #d4d4d4;border-bottom:2px solid #d4d4d4;position:absolute;width:470px;height:" + shadow_height + "px;top:50%;left:50%;margin-left:-235px;margin-top:-62px;z-index:101'>";
	html += "<div id='progress_border' style='background-color:white;border:2px solid #0eb81e;text-align:center;height:" + progress_height + "px;padding:15px 13px'>";

	html += " <div style='float:left;background:url(\"/images/gears_loading-logo.gif\") no-repeat 0% 50%;padding:0px;padding:10px 0px 0px 46px'>";
	html += " <div style='float:left;color:#00800c;font-weight:bold;font-size:14px;' id='progress_title'>" + MSG[585] + "</div>";
	html += " <div style='float:right;color:#00800c;font-weight:bold;font-size:20px;' id='progress_percent'>0%</div>";
	html += " </div>";

	html += "<div style='clear:both'></div>";
	html += "<div style='margin-top:10px;width:100%;height:33px;background:url(\"/images/gearsbg_gray.gif\") repeat-x;text-align:left'>";
	html += "<img id='progress_bg' src='/images/gearsbg_green.gif' style='float:left;width:0;height:33px' alt='' />";
	html += "</div>";

	if(_mode == "go_offline") {
		html += "<div style='clear:both'></div>";
		html += "<div id='SHAKE' style='text-align:left;background:url(\"/images/gears-loaders.gif\") no-repeat left 26%;margin:12px 0px 4px 8px;padding:6px 0px 0px 34px;color:#00800c;font-size:13px;height: 22px;'>";
		html += "<span id='SHAKE_title'>" + MSG[56];
		html += "</div>";

		html += "<div style='clear:both'></div>";
		html += "<div id='APP' style='text-align:left;background:url(\"/images/gears-loaders.gif\") no-repeat left 26%;margin:12px 0px 4px 8px;padding:6px 0px 0px 34px;color:#00800c;font-size:13px;height: 22px;'>";
		html += "<span id='APP_title'>" + MSG[57]; // ToDo: print out ( current / total )
		html += "</div>";

		html += "<div style='clear:both'></div>";
		html += "<div id='DATA' style='text-align:left;background:url(\"/images/gears-loaders.gif\") no-repeat left 26%;margin:12px 0px 4px 8px;padding:6px 0px 0px 34px;color:#00800c;font-size:13px;height: 22px;'>";
		html += "<span id='DATA_title'>" + MSG[551];
		html += "</div>";
	} else if(_mode == "go_online") {
		html += "<div style='clear:both'></div>";
		html += "<div id='UPLOAD' style='text-align:left;background:url(\"/images/gears-loaders.gif\") no-repeat left 26%;margin:12px 0px 4px 8px;padding:6px 0px 0px 34px;color:#00800c;font-size:13px;height: 22px;'>";
		html += "<span id='UPLOAD_title'>" + MSG[554];
		html += "</div>";
	}

	html += "<div style='clear:both;border-width:0 0 1px 0;border-color:black;border-style:solid;margin:0 0 12px 0'>&nbsp;</div>";
	html += "<div style='text-align:center;' id='cancel_container'></div>";

	html += "</div>";
	html += "</div>";

	return html;
};

SynkiProgress.prototype.generate_and_bind_cancel_button = function(_mode) {
	var buttons_container = document.getElementById("cancel_container");

	var cancel_button = document.createElement("input");
	cancel_button.id = "gears_cancel";
	cancel_button.type = "button";
	cancel_button.value = MSG[59];
	cancel_button.onclick = CallBack(this, function() { this["cancel_" + _mode]() });

	buttons_container.appendChild(cancel_button);
};

SynkiProgress.prototype.disable_cancel_button = function() {
	var button = document.getElementById("gears_cancel");
	if(!button) return;

	button.style.display = "none";
};

SynkiProgress.prototype.cancel_go_offline = function() {
	try {
		destroy_stores();
		var container = document.getElementById("div_gears_progress");
		if(container) document.body.removeChild(container);
		location.reload();
	} catch(e) {
		// /dev/null
	}
};

SynkiProgress.prototype.cancel_go_online = function() {
	container = document.getElementById("div_gears_progress");
	document.body.removeChild(container);
	location.reload();
};

////////////////////////////////////////////////////////
// GLOBAL!!!!!!!!!!!!!!!!!
CreateLocalPage = function(ws_id, title_dom) {
  var title = "";
  var dom = document.getElementById(title_dom);
  if(dom) title = dom.value;
  else return false;

	// blank
	if(/^\s*$/.test(title)) {
		new Shout().error({msg: MSG[529]})
		return false;
	}

	// over 128
	if(title.length > 128) {
		new Shout().error({msg: MSG[532]})
		return false;
	}

	// any tag
	if(false == /^[^\s><]+[^><]+$/.test(title)) {
		new Shout().error({msg: MSG[308]})
		return false;
	}


	// current date (without GMT)
	var _current = new Date().toUTCString()
	var df = new SynkiDateFormatter(0, "ko");
	var current_date = df.formattingDate(_current);

  // bind urls
  var user = Tamako.tables.users.find_one();
  var page = Tamako.tables.pages.find_one("workspace_id=" + ws_id, {"select": "max(id) as max_id"});
  var max_id = Number(page.max_id) + 1;
  
  var new_page = new Object();
  var new_revision = new Object();
	var new_permission = new Object();
  
  new_page["id"] = new_revision["page_id"] = new_permission["resource_id"] = max_id;
  new_page["last_user_id"] = new_page["owner_id"] = new_revision["user_id"] = user.id;
  new_page["last_user_login"] = new_page["owner_login"] = new_revision["user_login"] = user.login;
	new_page["created_at"] = new_page["updated_at"] = new_page["last_updated_at"] = current_date;
  new_page["local_created"] = "true";
  new_page["revisions_count"] = new_revision["version"] = 1;
  new_page["title"] = title; 
  new_page["workspace_id"] = ws_id;

	new_revision["id"] = new_page["id"] + "_" + new_page["revisions_count"];
	new_revision["local_only"] = "true";
	new_revision["content"] = "";

	new_permission["type"] = "page";
	new_permission["permission"] = "111";
    
	// ToDo: store require full url 
	// temporory front
	var wiki = location.protocol + "//" + location.hostname;
  var ub = new URLBuilder;
  var page_url = wiki + ub.page_path(new_page, false);
  var revision_url = page_url + "/revisions";
  var revision_show_url = revision_url + "/" + new_revision.version;
  var print_url = page_url + "/print";
 
  var page_template = wiki + ub.tardis_path({}, true, "tp_page/" + ws_id);
  var revision_template = wiki + ub.tardis_path({}, true, "tp_revision/" + ws_id);
  var revision_show_template = wiki + ub.tardis_path({}, true, "tp_revision_show/" + ws_id);
  var print_template = wiki + ub.tardis_path({}, true, "tp_page_print/" + ws_id);

  if(Tamako.stores[Tamako.rts].copy(page_template, page_url) &&
    Tamako.stores[Tamako.rts].copy(revision_template, revision_url) &&
		Tamako.stores[Tamako.rts].copy(revision_show_template, revision_show_url) &&
    Tamako.stores[Tamako.rts].copy(print_template, print_url)) {
    // complete copy url
    
		// save data
    Tamako.tables.pages.save(new_page);
    Tamako.tables.revisions.save(new_revision);
		Tamako.tables.permissions.save(new_permission);
    
    location.href = page_url;
  } else {
    // fail to copy url
    return false;
  }
};

////////////////////////////////////////////////////////
// GLOBAL!!!!!!!!!!!!!!!!!
toPostQueryString = function(name, obj) {
	var _hash = $H(obj);

	return _hash.map(CallBackWithArguments(this, function(pair) {

		function toQueryPair(key, value) {
			if (Object.isUndefined(value)) return key;
			return key + '=' + encodeURIComponent(String.interpret(value));
		}

		var key = name + "[" + encodeURIComponent(pair.key) + "]", values = pair.value;

		if (values && typeof values == 'object') {
			if (Object.isArray(values))
				return values.map(toQueryPair.curry(key)).join('&');
		}
		return toQueryPair(key, values);
	}, name)).join('&');
};

PermissionFromResultSet = function(permission_result_set) {
	return {
		"read"		: (permission_result_set.permission.charAt(0) == "1"),
		"write"		: (permission_result_set.permission.charAt(1) == "1"),
		"delete"	: (permission_result_set.permission.charAt(2) == "1")
	}
};

ExtractIdFromUrl = function(_name) {
	var name = _name + "s";
	var patt = new RegExp(name + "/([0-9]+)")

	var _match = patt.exec(location.href);

	if(_match.length >= 2) return _match[1];
	else return false;
};

ExtractIdFromQuery = function(_name) {
  var query = location.search;
  var switch_key_patt = new RegExp(_name + "=");
  if(switch_key_patt.test(query)) {
    var patt = new RegExp(_name + "=([^&]+)");
  } else {
    var patt = new RegExp(_name + "_id=([^&]+)");
  }

  var _match = patt.exec(query);

	if(_match && _match.length >= 2) return _match[1];
	else return false;
};

ExtractBaseDomainFromUrl = function() {
	var pieces = location.hostname.split(".");
	var domain = new Array;
	if(pieces.length == 2) return pieces.join(".");
	else {
		domain.push(pieces[pieces.length -2]);
		domain.push(pieces[pieces.length -1]);

		return domain.join(".");
	}
};

var Imple = function(_source, _target) {
	for(var idx in _target) {
		_source[idx] = _target[idx];
	}
};


