const	{app, dialog, protocol, BrowserWindow} = require("electron"),
		node_fs = require("fs"), 
		node_ini = require("ini"), 
		node_request = require("request"), 
		node_uuid = require("uuid"), 
		node_async = require("async"),
		node_extend = require("extend"),
		node_electron_is_dev = require('electron-is-dev'),
		node_mkdirp = require("mkdirp"),
		node_path = require("path"),
		node_inarray = require("in-array"),
		electron_shell = require("electron").shell,
		
		c_sVersionFileRelPath = "VERSION",
		c_sMainFileRelPath = "Main.js",
		c_sPackageFileRelPath = "package.json",
		c_sReadmeFileRelPath = "README",
		c_sIconFileRelPath = "icon.png",
		c_sLocalConfigFilePath = "config.ini",
		
		c_sCoreUiWrapperIndexFileRelPath = "core_ui/wrapper/index.html",
		c_sCoreUiWrapperLayoutFileRelPath = "core_ui/wrapper/layout.js",
		c_sCoreUiWrapperStyleFileRelPath = "core_ui/wrapper/style.css",
		c_sCoreUiChatLayoutFileRelPath = "core_ui/chat/layout.js",
		c_sCoreUiChatStyleFileRelPath = "core_ui/chat/style.css",
		c_sCoreUiSiteLayoutFileRelPath = "core_ui/site/layout.js",
		c_sCoreUiSiteStyleFileRelPath = "core_ui/site/style.css",
		
		c_sDefaultSkinWrapperLayoutFileRelPath = "skins/default/wrapper/layout.js",
		c_sDefaultSkinWrapperStyleFileRelPath = "skins/default/wrapper/style.css",
		c_sDefaultSkinChatLayoutFileRelPath = "skins/default/chat/layout.js",
		c_sDefaultSkinChatStyleFileRelPath = "skins/default/chat/style.css",
		c_sDefaultSkinSiteLayoutFileRelPath = "skins/default/site/layout.js",
		c_sDefaultSkinSiteStyleFileRelPath = "skins/default/site/style.css",
		c_sDefaultSkinParamsFileRelPath = "skins/default/params.ini",
		
		c_sExampleSkinWrapperLayoutFileRelPath = "skins/my_awesome_skin/wrapper/layout.js",
		c_sExampleSkinWrapperStyleFileRelPath = "skins/my_awesome_skin/wrapper/style.css",
		c_sExampleSkinChatLayoutFileRelPath = "skins/my_awesome_skin/chat/layout.js",
		c_sExampleSkinChatStyleFileRelPath = "skins/my_awesome_skin/chat/style.css",
		c_sExampleSkinChatBackgroundFileRelPath = "skins/my_awesome_skin/chat/images/background.jpg",
		c_sExampleSkinSiteLayoutFileRelPath = "skins/my_awesome_skin/site/layout.js",
		c_sExampleSkinSiteStyleFileRelPath = "skins/my_awesome_skin/site/style.css",
		c_sExampleSkinParamsFileRelPath = "skins/my_awesome_skin/params.ini",
		
		c_sDefaultSkin = "default",
		c_sRemoteAppDirUrl = "http://"+(node_electron_is_dev?"dev.":"")+"gamebanana.com/js/GbDesktop",
		c_aRequiredFiles = [
			c_sPackageFileRelPath,
			c_sVersionFileRelPath,
			c_sMainFileRelPath,
			c_sReadmeFileRelPath,
			c_sIconFileRelPath,
			
			c_sCoreUiWrapperIndexFileRelPath,
			c_sCoreUiWrapperLayoutFileRelPath,
			c_sCoreUiWrapperStyleFileRelPath,
			c_sCoreUiChatLayoutFileRelPath,
			c_sCoreUiChatStyleFileRelPath,
			c_sCoreUiSiteLayoutFileRelPath,
			c_sCoreUiSiteStyleFileRelPath,
			
			c_sDefaultSkinWrapperLayoutFileRelPath,
			c_sDefaultSkinWrapperStyleFileRelPath,
			c_sDefaultSkinChatLayoutFileRelPath,
			c_sDefaultSkinChatStyleFileRelPath,
			c_sDefaultSkinSiteLayoutFileRelPath,
			c_sDefaultSkinSiteStyleFileRelPath,
			c_sDefaultSkinParamsFileRelPath,

			c_sExampleSkinWrapperLayoutFileRelPath,
			c_sExampleSkinWrapperStyleFileRelPath,
			c_sExampleSkinChatLayoutFileRelPath,
			c_sExampleSkinChatStyleFileRelPath,
			c_sExampleSkinChatBackgroundFileRelPath,
			c_sExampleSkinSiteLayoutFileRelPath,
			c_sExampleSkinSiteStyleFileRelPath,
			c_sExampleSkinParamsFileRelPath
		],
		c_aBinaryFiles = [
			c_sIconFileRelPath,
			c_sExampleSkinChatBackgroundFileRelPath
		],
		c_oDefaultSkinParams = {
			"DisableCoreUi": false
		},
		c_bIsDevelopmentMode = (node_electron_is_dev?true:false),
		c_bEnableDebugConsole = false,
		c_oDefaultConfig = {
			"ShowDevTools": false,
			"ShowChatViewDevTools": false,
			"ShowSiteViewDevTools": false,
			"ClearCacheOnLaunch": false,
			"ShowWindowFrame": false,
			"InitialWindowWidth": 800,
			"InitialWindowHeight": 600,
			"Skin": "default"
		};
		
var	g_oConfig,
	g_oSkinParams,
	g_oDebugConsole,
	g_bForceUpdate = false,
	g_sLayoutFileRelPath,
	g_sStyleFileRelPath,
	g_sParamsFileRelPath;

global.sharedObj = {
	_sChatViewLandingPageUrl: "http://"+(node_electron_is_dev?"dev.":"")+"gamebanana.com/members/account/login"
		+"?redir=http%3A%2F%2F"+(node_electron_is_dev?"dev.":"")+"gamebanana.com%2Fchat",
	_sMainViewLandingPageUrl: "http://"+(node_electron_is_dev?"dev.":"")+"gamebanana.com",
	c_sCoreUiChatLayoutFileRelPath: c_sCoreUiChatLayoutFileRelPath,
	c_sCoreUiChatStyleFileRelPath: c_sCoreUiChatStyleFileRelPath,
	c_sCoreUiSiteLayoutFileRelPath: c_sCoreUiSiteLayoutFileRelPath,
	c_sCoreUiSiteStyleFileRelPath: c_sCoreUiSiteStyleFileRelPath
};

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;

g_oDebugConsole = {
	vLogMessage: (p_sMessage) => {
		console.info(p_sMessage);
	},
	vLogFunction: (p_sMessage) => {
		console.log("Executing "+p_sMessage+"()");
	},
	vLogError: (p_sMessage) => {
		console.error("ERROR: "+p_sMessage);
	}
};

function vInit() {
	console.log("Running in "+(c_bIsDevelopmentMode?"development":"production")+" mode");
	
	node_async.waterfall([
		vRegisterAssetProtocol,
		vDoRepairs,
		vCheckForUpdatesToSelf,
		vSetConfig,
		vSetSkinFilePaths,
		vSetSkinParams
	],(p_xError,p_sResult) => {
		vCreateWindow();
	});
}

function vRegisterAssetProtocol(callback) {
	protocol.registerFileProtocol("asset",(request,callback) => {
		var p_sUrl = request.url.substr(7);
		callback({
			path: node_path.normalize(__dirname+"/"+p_sUrl)
		});
	},(p_oError) => {
		if (p_oError) throw p_oError;
		callback(null);
	});
}

function vDoRepairs(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
	node_async.each(c_aRequiredFiles,(p_sPath,iterator_callback) => {
		node_mkdirp.sync(__dirname+"/"+node_path.dirname(p_sPath));

		node_fs.stat(__dirname+"/"+p_sPath,(p_oError,p_oStats) => {
			if (p_oError || !p_oStats.isFile()) {
				g_bForceUpdate = true;
				node_fs.writeFileSync(__dirname+"/"+p_sPath,"");
			}
			iterator_callback();
		});
	}, (p_xError) => {
		callback(null);
	});
}

function vCheckForUpdatesToSelf(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
	node_async.waterfall([
		vCheckVersion,
		vUpdateFiles
	],(p_xError,p_sResult) => {
		callback(null);
	});
	function vCheckVersion(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		node_request(c_sRemoteAppDirUrl+"/"+c_sVersionFileRelPath+"?"+node_uuid.v4(),(p_oError,response,p_nRemoteVersion) => {
			if (p_oError) throw p_oError;
			var _nLocalVersion = node_fs.readFileSync(__dirname+"/"+c_sVersionFileRelPath,"utf8");
			if (p_nRemoteVersion.toString() !== _nLocalVersion.toString()) {
				g_oDebugConsole.vLogMessage("Updating from version '"+_nLocalVersion+"' to version '"+p_nRemoteVersion+"'");
				callback(null);
			}
			else if (g_bForceUpdate) {
				g_oDebugConsole.vLogMessage("Forcing update due to missing required file(s)");
				callback(null);
			}
			else {
				g_oDebugConsole.vLogMessage("Version up-to-date");
				callback(1);
			}
		});
	}
	function vUpdateFiles(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		node_async.each(c_aRequiredFiles,(p_sFilePath,iterator_callback) => {
			node_request({
				url: c_sRemoteAppDirUrl+"/"+p_sFilePath+"?"+node_uuid.v4(),
				encoding: (node_inarray(c_aBinaryFiles,p_sFilePath)?null:"utf8")
			},(p_oError,response,p_sFileContents) => {
				if (p_oError) throw p_oError;
				node_fs.writeFileSync(__dirname+"/"+p_sFilePath,p_sFileContents,(node_inarray(c_aBinaryFiles,p_sFilePath)?"binary":"utf8"));
				iterator_callback();
			});
		}, (p_xError) => {
			callback(null,"Update complete");
		});
	}
}

function vSetConfig(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
	node_async.waterfall([
		vCheckForConfig,
		vReadConfig,
		vParseConfig
	],(p_xError,p_sResult) => {
		callback(null);
	});
	function vCheckForConfig(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		node_fs.stat(__dirname+"/"+c_sLocalConfigFilePath,(p_oError,p_oStats) => {
			if (p_oError || !p_oStats.isFile()) {
				node_fs.writeFile(__dirname+"/"+c_sLocalConfigFilePath,node_ini.stringify(c_oDefaultConfig),(p_oError) => {
					if (p_oError) throw p_oError;
					callback(null);
				});
			}
			else {
				callback(null);
			}
		});
	}
	function vReadConfig(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		node_fs.readFile(__dirname+"/"+c_sLocalConfigFilePath,"utf8",(p_oError,p_sData) => {
			if (p_oError) throw p_oError;
			callback(null,p_sData);
		});
	}
	function vParseConfig(p_sData,callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		var _oIniConfig = node_ini.parse(p_sData);
		g_oConfig = node_extend(c_oDefaultConfig,_oIniConfig);
		global.sharedObj.g_oConfig = g_oConfig;
		g_oDebugConsole.vLogMessage(JSON.stringify(g_oConfig));
		callback(null,g_oConfig);
	}
}

function vSetSkinFilePaths(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
	node_async.each([
		c_sDefaultSkinWrapperLayoutFileRelPath,
		c_sDefaultSkinWrapperStyleFileRelPath,
		c_sDefaultSkinSiteLayoutFileRelPath,
		c_sDefaultSkinSiteStyleFileRelPath,
		c_sDefaultSkinChatLayoutFileRelPath,
		c_sDefaultSkinChatStyleFileRelPath,
		c_sDefaultSkinParamsFileRelPath
	],(p_sDefaultSkinFileRelPath,iterator_callback) => {
		var _sCustomSkinFileRelPath = p_sDefaultSkinFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
		
		node_fs.stat(__dirname+"/"+_sCustomSkinFileRelPath,(p_oError,p_oStats) => {
			if (p_oError || !p_oStats.isFile()) {
				g_oDebugConsole.vLogError('Required custom skin file "'+_sCustomSkinFileRelPath+'" missing');
				iterator_callback(1);
			}
			else {
				iterator_callback();
			}
		});
	}, (p_xError) => {
		if (p_xError) {
			g_oDebugConsole.vLogError('Reverting to "default" skin');
			
			g_sSkinWrapperLayoutFileRelPath = c_sDefaultSkinWrapperLayoutFileRelPath;
			g_sSkinWrapperStyleFileRelPath = c_sDefaultSkinWrapperStyleFileRelPath;
			g_sSkinParamsFileRelPath = c_sDefaultSkinParamsFileRelPath;
			
			global.sharedObj.g_sSkinSiteLayoutFileRelPath = c_sDefaultSkinSiteLayoutFileRelPath;
			global.sharedObj.g_sSkinSiteStyleFileRelPath = c_sDefaultSkinSiteStyleFileRelPath;
			global.sharedObj.g_sSkinChatLayoutFileRelPath = c_sDefaultSkinChatLayoutFileRelPath;
			global.sharedObj.g_sSkinChatStyleFileRelPath = c_sDefaultSkinChatStyleFileRelPath;
		}
		else {
			g_oDebugConsole.vLogMessage('Loading skin "'+g_oConfig["Skin"]+'"');
			
			g_sSkinWrapperLayoutFileRelPath = c_sDefaultSkinWrapperLayoutFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
			g_sSkinWrapperStyleFileRelPath = c_sDefaultSkinWrapperStyleFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
			g_sSkinParamsFileRelPath = c_sDefaultSkinParamsFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
			
			global.sharedObj.g_sSkinSiteLayoutFileRelPath = c_sDefaultSkinSiteLayoutFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
			global.sharedObj.g_sSkinSiteStyleFileRelPath = c_sDefaultSkinSiteStyleFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
			global.sharedObj.g_sSkinChatLayoutFileRelPath = c_sDefaultSkinChatLayoutFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
			global.sharedObj.g_sSkinChatStyleFileRelPath = c_sDefaultSkinChatStyleFileRelPath.replace(c_sDefaultSkin,g_oConfig["Skin"]);
		}
		callback(null);
	});
}

function vSetSkinParams(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
	node_async.waterfall([
		vCheckForParams,
		vParseParams
	],(p_xError,p_sResult) => {
		callback(null,"done");
	});
	function vCheckForParams(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		node_fs.stat(__dirname+"/"+g_sSkinParamsFileRelPath,(p_oError,p_oStats) => {
			if (p_oError || !p_oStats.isFile()) {
				node_fs.writeFile(__dirname+"/"+g_sSkinParamsFileRelPath,node_ini.stringify(c_oDefaultSkinParams),(p_oError) => {
					if (p_oError) throw p_oError;
					callback(null);
				});
			}
			else {
				callback(null);
			}
		});
	}
	function vParseParams(callback) { g_oDebugConsole.vLogFunction(arguments.callee.name);
		var _sData = node_fs.readFileSync(__dirname+"/"+g_sSkinParamsFileRelPath,"utf8");
		var _oIniConfig = node_ini.parse(_sData);
		g_oSkinParams = node_extend(c_oDefaultSkinParams,_oIniConfig);
		global.sharedObj.g_oSkinParams = g_oSkinParams;
		g_oDebugConsole.vLogMessage(JSON.stringify(g_oSkinParams));
		callback(null);
	}
}

function vCreateWindow () { g_oDebugConsole.vLogFunction(arguments.callee.name);
	win = new BrowserWindow({
		width: g_oConfig["InitialWindowWidth"],
		height: g_oConfig["InitialWindowHeight"],
		frame: g_oConfig["ShowWindowFrame"],
		title: "GameBanana Desktop",
		icon: __dirname+"/icon.png"
	});
	
	win.loadURL("file://"+__dirname+"/"+c_sCoreUiWrapperIndexFileRelPath);
	
	if (g_oConfig["ShowDevTools"]) {
		win.webContents.openDevTools();
	}
	
	if (g_oConfig["ClearCacheOnLaunch"]) {
		win.webContents.session.clearCache(() => {});
		win.webContents.session.clearStorageData(() => {});
	}
	
	win.webContents.on("dom-ready",() => {
		if (!g_oSkinParams["DisableCoreUi"]) {
			win.webContents.executeJavaScript(node_fs.readFileSync(__dirname+"/"+c_sCoreUiWrapperLayoutFileRelPath,"utf8"));
			win.webContents.executeJavaScript('$("head").append(\'<link rel="stylesheet" type="text/css" href= "asset://'+c_sCoreUiWrapperStyleFileRelPath+'">\')');
		}
		
		win.webContents.executeJavaScript(node_fs.readFileSync(__dirname+"/"+g_sSkinWrapperLayoutFileRelPath,"utf8"));
		win.webContents.executeJavaScript('$("head").append(\'<link rel="stylesheet" type="text/css" href= "asset://'+g_sSkinWrapperStyleFileRelPath+'">\')');
	});
	
	//win.webContents.on("page-title-updated",(e,url) => {
	//	e.preventDefault();
	//});

	// Emitted when the window is closed.
	win.on("closed",() => {
		// Dereference the window object, usually you would store windows
		// in an array if your app supports multi windows, this is the time
		// when you should delete the corresponding element.
		win = null
	});
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready",vInit);

// Quit when all windows are closed.
app.on("window-all-closed", () => {
	// On macOS it is common for applications and their menu bar
	// to stay active until the user quits explicitly with Cmd + Q
	if (process.platform !== 'darwin') {
		app.quit();
	}
});

app.on("activate", () => {
	// On macOS it's common to re-create a window in the app when the
	// dock icon is clicked and there are no other windows open.
	if (win === null) {
		vInit();
	}
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.