js.branch_limit = 0;
js.time_limit = 0;
load("json-client.js");
load("event-timer.js");

var root = argv[0];
log("SyncWall service loaded");
var jsonClient, users, systems, state, timer, month, dbName, historyPath, httpPath;
var dummy = [ { 'x' : 1, 'y' : 1, 'c' : "CLEAR", 'a' : 0, 'u' : 0, 's' : 0 } ];

var checkConnection = function() {
	if(jsonClient.connected)
		return;
	log(LOG_INFO, "SyncWall service: attempting to reconnect ...");
	jsonClient.connect();
}

var newMonth = function() {

	var thisMonth = strftime("%m%Y");
	if(thisMonth == month)
		return;

	log(LOG_INFO, "SyncWall service: performing monthly maintenance.");

	var oldMonth = {
		'MONTH' : month,
		'USERS' : users,
		'SYSTEMS' : systems,
		'SEQUENCE' : [],
		'STATE' : state
	};

	var len = jsonClient.read(dbName, "SEQUENCE.length", 1);
	for(var i = 0; i < len; i++)
		oldMonth.SEQUENCE.push(jsonClient.shift(dbName, "SEQUENCE", 2));

	state = {};
	jsonClient.write(dbName, "STATE", state, 2);
	jsonClient.write(dbName, "SEQUENCE", dummy,	2);
	jsonClient.write(dbName, "LATEST", dummy, 2);
	jsonClient.write(dbName, "MONTH", thisMonth, 2);

	if(!file_exists(historyPath) || !file_isdir(historyPath))
		mkdir(historyPath);

	var f = new File(historyPath + "/" + month + ".json");
	f.open("w");
	f.write(JSON.stringify(oldMonth));
	f.close();

	jsonClient.push(dbName, "MONTHS", httpPath + "/" + month + ".json", 2);

	month = thisMonth;

}

var processUpdate = function(update) {

	if(typeof update.location == "undefined" || update.oper != "WRITE")
		return;

	data = update.data;

	if(update.location == "USERS" && users.indexOf(data) < 0) {
		users.push(data);
		return;
	}

	if(update.location == "SYSTEMS" && systems.indexOf(data) < 0) {
		systems.push(data);
		return;
	}

	if(	update.location == "LATEST"
		&&
		data.u < users.length && data.u >= 0
		&&
		data.s < systems.length && data.s >= 0
	) {
		if(data.c == "CLEAR") {
			state = {};
			jsonClient.write(dbName, "STATE", state, 2);
		} else {
			if(typeof state[data.y] == "undefined")
				state[data.y] = {};
			state[data.y][data.x] = { 'c' : data.c, 'a' : data.a };
			jsonClient.write(
				dbName,
				"STATE." + data.y + "." + data.x,
				state[data.y][data.x],
				2
			);
		}
		jsonClient.push(dbName, "SEQUENCE", data, 2);
		return;
	}

}

var init = function() {

	while(system.lastuser < 1)
		mswait(15000);

	timer = new Timer();

	var f = new File(root + "service.ini");
	f.open("r");
	var serviceIni = f.iniGetObject();
	f.close();
	dbName = serviceIni.dbName;
	historyPath = serviceIni.historyPath;
	httpPath = serviceIni.httpPath;

	var usr = new User(1);
	jsonClient = new JSONClient("localhost", 10088);
	jsonClient.ident("ADMIN", usr.alias, usr.security.password);
	jsonClient.callback = processUpdate;

	month = jsonClient.read(dbName, "MONTH", 1);
	if(!month) {
		month = strftime("%m%Y");
		jsonClient.write(dbName, "MONTH", month, 2);
	}

	var historyFiles = directory(historyPath + "/*.json");
	for(var h = 0; h < historyFiles.length; h++)
		historyFiles[h] = httpPath + "/" + file_getname(historyFiles[h]);
	var months = jsonClient.read(dbName, "MONTHS", 1);
	if(!months) {
		months = historyFiles;
		jsonClient.write(dbName, "MONTHS", months, 2);
	}
	for(var h = 0; h < historyFiles.length; h++) {
		if(months.indexOf(historyFiles[h]) < 0)
			jsonClient.push(dbName, "MONTHS", historyFiles[h], 2);
	}

	users = jsonClient.read(dbName, "USERS", 1);
	if(!users) {
		users = [ usr.alias ];
		jsonClient.write(dbName, "USERS", users, 2);
	}
	jsonClient.subscribe(dbName, "USERS");

	systems = jsonClient.read(dbName, "SYSTEMS", 1);
	if(!systems) {
		systems = [ system.name ];
		jsonClient.write(dbName, "SYSTEMS", systems, 2);
	}
	jsonClient.subscribe(dbName, "SYSTEMS");

	if(!jsonClient.read(dbName, "SEQUENCE.length", 1))
		jsonClient.write(dbName, "SEQUENCE", dummy,	2);

	state = jsonClient.read(dbName, "STATE", 1);
	if(!state)
		state = {};

	jsonClient.subscribe(dbName, "LATEST");

	// Monthly maintenance will happen on startup, or between midnight and
	// one o'clock AM, depending on start time.
	timer.addEvent(3600000, true, newMonth);
	timer.addEvent(60000, true, checkConnection);
	newMonth();
}

var main = function() {
	while(!js.terminated) {
		timer.cycle();
		jsonClient.cycle();
		mswait(5);
	}
}

var cleanUp = function() {
	jsonClient.disconnect();
}

try {
	init();
	main();
	cleanUp();
	exit();
} catch(err) {
	log("SyncWall service error: " + err);
}
