// Nov 13, 2015 Koji Ota
// May 01, 2017 Koji Ota

// load library
var FS = require("fs");
var PATH = require("path");
var URL =  require("url");

//
var site = {
	file: "etc/site.json",
	name: "ko2ib",
	version: "0.0.1",
	description: "Welcome to KO2IB test site.",
	copyright: "Copyright &copy; 2014-2017 Koji Ota All Rights Reserved.",
	session: {
		expire: 0,
	},
	users: [
		{ user: "admin", password: "admin0", role: "admin", permit: "" },
		{ user: "guest", password: "guest",  role: "guest", permit: "" },
		{ user: "ota",   password: "ota",    role: "admin", permit: "" }
	],
	debug: {
		warning: 1,
		trace: 1,
		verbose: 1
	}
};

//
function color_output(color, msg) {
	var cin;
	var cout = '\u001b[0m';
	switch(color) {
		case "black": cin = '\u001b[30m'; break;
		case "red": cin = '\u001b[31m'; break;
		case "green": cin = '\u001b[32m'; break;
		case "yellow": cin = '\u001b[33m'; break;
		case "blue": cin = '\u001b[34m'; break;
		case "magenta": cin = '\u001b[35m'; break;
		case "cyan": cin = '\u001b[36m'; break;
		case "white": cin = '\u001b[37m'; break;
	}
	console.log(cin+msg+cout);
}
function panic(msg) {
	color_output("red", msg);
}
function perror(msg) {
	color_output("magenta", msg);
}
function pwarning(msg) {
	if (site.debug.warning) {
		color_output("yellow", msg);
	}
}
function ptrace(msg) {
	if (site.debug.trace) {
		color_output("green", msg);
	}
}
function pverbose(msg) {
	if (site.debug.verbose) {
		color_output("cyan", msg);
	}
}
function print(msg) {
	console.log(msg);
}

//
var objutil = {
	replacer: function(key, val) {
		return typeof val == "function" ? val.toString() : val;
	},
	parser: function(key, val) {
		try {
			return (typeof val == "string" && val.match(/^function[\s\S]+?}$/)) ? eval('('+val+')') : val;
		} catch(e) {
			return val;
		}
	},
	obj2str: function(obj) {
		var str = JSON.stringify(obj, objutil.replacer);
		return str;
	},
	str2obj: function(str) {
		var body = JSON.parse(str, objutil.parser);
		return body;
	}
};

// User manager
function AccountManager()
{
	this.authentification = function(user, password) {
		for(var i=0; i<site.users.length; i++) {
			if ((user == site.users[i].user) && (password == site.users[i].password)) {
				return true;
			}
		}
		return false;
	};
	this.role = function(user) {
		for(var i=0; i<site.users.length; i++) {
			if (user == site.users[i].user) {
				return site.users[i].role;
			}
		}
		return "unknown";
	};
	this.names = function() {
		var u = [];
		for(var i=0; i<site.users.length; i++) {
			u.push(site.users[i].user);
		}
		return u;
	};
}
var account = new AccountManager();

// Session
function Session(req, res, next)
{
	this._req = req;
	this._res = res;
	this._next = next;

	this._param = {};
	//this._param.user = undefined;
	//this._param.role = undefined;
	this._param.box = ""; // cabinet box name
	this._param.cid = ""; // card id

	// url
	this._url = urlparser.parse(req.url);

	// cookies
	var cookies = {};
	req.headers.cookie && req.headers.cookie.split(';').forEach(function( cookie ) {
		var parts = cookie.split('=');
		cookies[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim();
	});
	for(var k in cookies) {
		this._param[k] = cookies[k];
	}

	// method=get
	for(var k in req.query) {
		this._param[k] = req.query[k];
		console.log(k+"="+this._param[k]);
	}

	// method=post
	for(var k in req.body) {
		this._param[k] = req.body[k];
		console.log(k+"="+this._param[k]);
	}

	if (typeof(this._param.user) != "undefined") {
		this._param.role = account.role(this._param.user);
	}

	this.dump = function() {
		for(var k in this._param) {
			pverbose("session.param["+k+"]=("+this._param[k]+")");
		}
	};

	this.cookie = function(name) {
		return this._param.cookies[name];
	};

	this.get = function(name) {
		return this._param[name];
	};

	this.exists = function(name) {
		if (typeof(this._param[name]) != "undefined") {
			return true;
		} else {
			return false;
		}
	};
}

// IO - inforamtion object
// io.scrpt.gui
function IO(name, proc)
{
	this._name = name;
	this.script = { gui: {} };
	this.initialize = function() {};
	this.put = function(session) {};
	this.get = function(session) {};
	this.post = function(session) {};
	this.delete = function(session) {};

	if (typeof(proc.gui) != "undefined") { this.script.gui = proc.gui; };

	var names = ["initialize", "put", "get", "post", "delete"];
	for(var i=0; i<names.length; i++) {
		var name = names[i];
		if (typeof(proc[name]) != "undefined") {
			this[name] = proc[name];
		}
	}
}

/*
http://qiita.com/shuhei/items/a61b4324fd5dbc1af79b
var black   = '\u001b[30m';
var red     = '\u001b[31m';
var green   = '\u001b[32m';
var yellow  = '\u001b[33m';
var blue    = '\u001b[34m';
var magenta = '\u001b[35m';
var cyan    = '\u001b[36m';
var white   = '\u001b[37m';
var reset   = '\u001b[0m';
console.log(red + 'This text is red. ' + green + 'Greeeeeeen!' + reset);
*/

var ko2ib = {
	// configuration
	config: {
		prog: {
			name: "ko2ib",
			version: "0.0.1",
			copyright: "Copyright &copy; 2017 Koji Ota All Rights Reserved.",
		},
		path: {
		},
		output: {
			warning: 1,
			trace: 1,
			verbose: 1
		}
	},
	// utility
	// debugging
	panic: function(msg) { panic(msg); },
	perror: function(msg) { perror(msg); },
	pwarning: function(msg) { pwarning(msg); },
	ptrace: function(msg) { ptrace(msg); },
	pverbose: function(msg) { pverbose(msg); },
	print: function(msg) { print(msg); },
	// IO
	_io: [],
	io: {
		add: function(io) {
			ko2ib._io.push(io);
		},
		get: function(name) {
			ko2ib.ptrace("ko2ib.io.get("+name+")");
			for(var i=0; i<ko2ib._io.length; i++) {
				ko2ib.ptrace(">"+ko2ib._io[i]._name);
				if (name == ko2ib._io[i]._name) {
					return ko2ib._io[i];
				}
			}
			return null;
		}
	},
	// authentification
	gatekeeper: function(req, res, next) {
		ko2ib.ptrace("gatekeeper:");
		var session = new Session(req, res);
		if (!session.exists("user")) { // ログイン検査
			ko2ib.perror("missing user."); // 未ログイン
			res.redirect("/login");
			return;
		}
		ko2ib.pverbose(session.get("user")+" logined.");

		if (site.session.expire != 0) { // 有効期限確認
			if (typeof(session.get("expire")) == "undefined") {
				ko2ib.perror("missing expire");
				res.redirect("/login");
				return false;
			}
			// expires?
			if (Date.now() > session.get("expire")) {
				ko2ib.perror("expire");
				res.redirect("/login");
				return;
			}
		}
		ko2ib.pverbose(session.get("user")+" within expiration date.");

		// 認証
		if (next != null) {
			ko2ib.ptrace("gatekeeper: go next.");
			next();
		} else {
			ko2ib.pverbose(session.get("user")+" no page. loading default page.");
		}
	},
	// dispatcher
	// interface
	login: function(req, res, next) {
		ko2ib.ptrace("ko2ib.login");
		var pc = {
			site_title: site.name,
			site_version: site.version,
			site_description: site.description,
			site_copyright: site.copyright,
			message: "",
			prog_name: ko2ib.config.prog.name,
			prog_version: ko2ib.config.prog.version,
			prog_copyright: ko2ib.config.prog.copyright
		};

		var session = new Session(req, res);
		if ((!session.exists("user")) || (!session.exists("password"))) {
			res.render("login", pc);
			return;
		}
		var u = session.get("user");
		var p = session.get("password");
		if (account.authentification(u, p)) {
			res.cookie('user', u);
			if (site.session.expire != 0) {
				res.cookie('expire', Date.now() + 900000);
			}
			res.redirect('/');
		} else {
			pc.message = "Incorrect user name or password. Try again!";
			res.render("login", pc);
		}
	},
	logout: function(req, res, next) {
		ko2ib.ptrace("ko2ib.logout");
		res.clearCookie("user");
		res.redirect("/login");
	},
	welcome: function(req, res, next) {
		ko2ib.ptrace("ko2ib.welcome");
		var session = new Session(req, res);
		var pc = {};
		pc.pname = ko2ib.config.prog.name;
		pc.pversion = ko2ib.config.prog.version;
		pc.user = session.get("user");
		res.render("home", pc);
	},
	get: function(req, res, next) {
		ko2ib.ptrace("ko2ib.get");
		var session = new Session(req, res);
		console.log("path=public"+req.url+"="+fs.existsSync("public"+req.url));
		if (fs.existsSync("public"+req.url)) {
			next();
		} else {
			var names = session._url.pathname.split("/");
			for(var i=0; i<names.length; i++) {
				ko2ib.pverbose("["+i+"]="+names[i]);
			}
			var io = ko2ib.io.get(names[1]);
			if (io == null) {
				ko2ib.perror("no object for "+names[1]);
				return;
			}
			io.get(session, names);
		}
	},
	post: function(req, res, next) {
		ko2ib.ptrace("ko2ib.post");
	},
	put: function(req, res, next) {
		ko2ib.ptrace("ko2ib.put");
	},
	delete: function(req, res, next) {
		ko2ib.ptrace("ko2ib.delete");
	},
	_socketio: null,
	_connections: {},
	socketio: function(io) {
		ko2ib._socketio = io;
		io.sockets.on("connection", function(socket) {
			socket.on("connected", function(name) {
				var msg = name + " が入室しました";
				ko2ib._connections[socket.id] = name;
				io.sockets.emit("publish", {value: msg});
			});
			socket.on("publish", function(data) {
				var msg = name + " in";
				ko2ib._connections[socket.id] = name;
				io.sockets.emit("publish", {value: data.value});
			});
			socket.on("disconnected", function() {
				if (userHash[socket.id]) {
			      var msg = userHash[socket.id] + "が退出しました";
			      delete userHash[socket.id];
			      io.sockets.emit("publish", {value: msg});
			    }
			});
		});
	},
	// main function
	main: function(app, io) {
		ko2ib.ptrace("ko2ib.main");
		app.get("/", ko2ib.gatekeeper, ko2ib.welcome);
		app.get("/login", ko2ib.login);
		app.get("/logout", ko2ib.logout);
		app.get("/*", ko2ib.gatekeeper, ko2ib.get);
		app.post("/*", ko2ib.gatekeeper, ko2ib.post);
		app.put("/*", ko2ib.gatekeeper, ko2ib.put);
		app.delete("/*", ko2ib.gatekeeper, ko2ib.delete);
		ko2ib.socketio(io);
	}
};

exports.main = ko2ib.main;

// admin
ko2ib.io.add(
	new IO("admin",
		{
			get: function(session, names) {
				switch(names[2]) {
					case "view":
					switch(names[3]) {
						case "menu":
							break;
					}
					break;
				}
			}
		}
	)
);

// home
ko2ib.io.add(
	new IO("home",
		{
			get: function(session, names) {
				ko2ib.ptrace("home.get:"+names[2]+","+names[3]);
				switch(names[2]) {
					case "view":
						switch(names[3]) {
							case "menu":
								var script = objutil.obj2str(
									{
										action: function(menu) {
											// http://qiita.com/takeharu/items/9935ce476a17d6258e27
											var self = this;
											menu.add_group("Home");
											menu.add("Home", "Front", function() {
												console.log("home>front");
												self.hello();
											});
											menu.add_group("Wiki");
											menu.add("Wiki", "Home", function() {
												console.log("wiki>home");
											});
											menu.add("Wiki", "Query", function() {
												console.log("wiki>query");
											});
										},
										hello: function() {
											console.log("hello");
										}
									}
								);
								session._res.send(script);
								break;
						}
						break;
				}
			}
		}
	)
);

// wiki
// /wiki/view			- get
// /wiki/card/<no>		- get(load), put(save)
// /wiki/card			- post(new)
// /wiki/history/<no>	- get
// /wiki/backward/<no>	- get
// /wiki/list			- card list
ko2ib.io.add(
	new IO("wiki",
		{
			get: function(session, names) {
				switch(names[2]) {
					case "view":
						break;
					case "card":
						break;
					case "history":
						break;
					case "backward":
						break;
					case "list":
						break;
				}
			},
			put: function(session, names) {

			},
			post: function(session, names) {

			},
			delete: function(session, names) {

			}
		}
	)
);

// task
// /task/view			- get
// /task/card/<no>		- get(load), put(save)
// /task/card			- post(new)
// /task/history/<no>	- get
// /task/backword/<no>	- get
// /task/list			- card list (parents)
// /task/list/<no>		- card list (children of <no>)
ko2ib.io.add(
	new IO("task",
		{
			get: function(session, names) {

			},
			put: function(session, names) {

			},
			post: function(session, names) {

			},
			delete: function(session, names) {

			}
		}
	)
);

ko2ib.panic(ko2ib.config.prog.name);
ko2ib.perror("version "+ko2ib.config.prog.version);
ko2ib.pwarning(ko2ib.config.prog.copyright);
ko2ib.ptrace("ptrace");
ko2ib.pverbose("pverbose");
ko2ib.print("start");

exports.main = function(app, io)
{

}
