/* Giac evaluate, called in platform.js via ipc. */
ipc = require('electron').ipcMain;
nodegiac = {}
try{
	nodegiac = require('bindings')('giac');
}catch(e){
	nodegiac.evaluate = function(){return "?"};
}
ipc.on('giac', function (event, command) {
	command = command.replace(/;+$/, ''); // right trim ; characters
	if (!command.startsWith("caseval(")) command = "caseval(" + command + ")";
	var ret = nodegiac.evaluate(command);
	event.returnValue = ret;
	console.log("Giac: " + command + " -> " + ret);
}
);
ipc.on('log', function(event, message) {
	event.returnValue = true;
	console.log("GeoGebra: " + message);
}
);

ipc.on('clipboard', function(event, data) {
	event.returnValue = true;
	const nativeImage = require('electron').nativeImage
	img = nativeImage.createFromDataURL(data)

	const {clipboard} = require('electron')
	clipboard.write({image: img})
}
);

const {app, BrowserWindow, Menu} = require('electron');
const Config = require('electron-config')
const path = require('path')
const ggbConfig = require('./ggb-config.js')
// For some reason, when using Ermine to create an all-in-one bundle,
// this line results in a "SyntaxError: Unexpected token export", so
// we load 'windows-shortcuts' later only, when explicitly needed.
// const ws = require('windows-shortcuts');

// 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

function createWindow (appArgs) {
	
	// Create the browser window.
	var pref = {show:false, width: 1024, height: 768, title:"GeoGebra",webPreferences:{nodeIntegration:false, preload: __dirname + '/preload.js'}};
	const config = new Config();
	Object.assign(pref, config.get('winBounds'))
	
	// and load the index.html of the app.
	var startUrl = `file://html/index.html?`;	
	var perspective = appArgs && appArgs['perspective'] ? appArgs['perspective'] : ggbConfig.appName;
	console.log(perspective);
	if(perspective && perspective.match(/^graphing|geometry$/)){
		startUrl = "file://html/"+perspective+".html?";
		pref.icon = __dirname + "/html/" + perspective + ".ico";
	} else if(perspective){
		startUrl += "?perspective="+appArgs['perspective'];
	}
	if(appArgs && appArgs['prerelease']){
		startUrl += "&prerelease="+appArgs['prerelease'];
	}
	if(appArgs && appArgs['debug']){
		startUrl += "&debug="+appArgs['debug'];
	}

	win = new BrowserWindow(pref);
	win.setMenuBarVisibility(false);
	win.setAutoHideMenuBar(true);
	win.loadURL(startUrl);

	// Open the DevTools.
	// win.webContents.openDevTools()
	win.webContents.on('did-finish-load', () => {
		pref.show = true;
		win.show();
	});
	// Emitted when the window is closed.
	win.on('closed', () => {		
		console.log("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
	})
	win.unsaved = null;
	win.on('close', (e) => {
		if(!win.unsaved || !win.unsaved[0]){
				config.set('winBounds', win.getBounds());
				return;
		}		
		e.preventDefault();
		console.log("close killed");
			// 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.
		const {dialog} = require('electron');
		
		dialog.showMessageBox(win,{message:win.unsaved[0],buttons:win.unsaved.slice(1)},function(e){
			if(e==0){
					win.loadURL("javascript:ggbApplet.checkSaved()");
			}
			if(e==1){
				win.unsaved = false;
				setTimeout(function(){	win.close();},100);
				}
			});
			
	});
	
}
function trySpawn(execRelative, params, callback){
	var exec = process.execPath+"/../"+execRelative;
	callback = callback || function(){};
	var spawn2 = require("child_process");
	const fs = require('fs');
	fs.access(exec, (err)=>	{err ? console.log(err) : callback(spawn2.spawn(exec, params)) });
}

function getWinLocaleSync() {
	try {
		const crossSpawn = require('child_process');
		const lcid = require('lcid');
		const stdout = crossSpawn.spawnSync('wmic', ['os', 'get', 'locale'],{"encoding":"utf-8"}).stdout;
		const lcidCode = parseInt(stdout.replace('Locale', ''), 16);
		return lcid.from(lcidCode);
	}catch(e){
		console.log(e);
	}
	return "en_US";
}

function createShortcuts(locations){
	var exe = process.execPath.split("\\").reverse()[0];
	for(var k in locations){
		var basePath = false;
		if(locations[k] == "Desktop"){
			basePath = p`${'userDesktop'}`;
		}
		if(locations[k] == "StartMenu"){
			basePath = p`${'appData'}/Microsoft/Windows/Start Menu/Programs/GeoGebra`;
		}
		if(basePath){
			var loc = getWinLocaleSync();
			var dict = ggbConfig.localization.appName;
			var localizedName = dict[loc] || dict[loc.substr(0,2)] || dict["none"];
			var lnkPath = basePath + "/" + localizedName +".lnk";

			const ws = require('windows-shortcuts');
			ws.create( lnkPath, {target: process.execPath+"/../../Update.exe",
				icon: process.execPath, 
				args: "--processStart="+exe}, 
				() => {process.exit(0)});
			
		}
	}
}

const environmentVariableAliases = {
	'HOME': 'home',
	'USERPROFILE': 'home',
	'APPDATA': 'appData',
	'TEMP': 'temp',
	'TMPDIR': 'temp'
};

function getPath(key) {
 
	let aliasKey = null;
	if (environmentVariableAliases[key]) {
		aliasKey = environmentVariableAliases[key];
	}

	let result = null;

	if (app) {
		try {
			result = app.getPath(aliasKey || key);
		} catch (e) {
			// NB: We'd like to log this but this method gets called too early
			//logger.debug(`Failed to get path for key, this may be expected: ${aliasKey || key}`);
		}
	}

	result = result || process.env[key];
	if (!result) {
		// NB: Try to fix up the most commonly fucked environment variables
		if (key.toLowerCase() === 'appdata' && process.env.USERPROFILE) {
			result = path.join(process.env.USERPROFILE, 'AppData', 'Roaming');
		}

		if (key.toLowerCase() === 'localappdata' && process.env.USERPROFILE) {
			result = path.join(process.env.USERPROFILE, 'AppData', 'Local');
		}
	}

	return result;
}

function p(strings, ...values) {
	let newVals = values.map((x) => getPath(x) || x);
	let newPath = String.raw(strings, ...newVals);
	let parts = newPath.split(/[\\\/]/).map((x) => x || '/');

	// Handle Windows edge case: If the execution host is cmd.exe, path.resolve() will not understand
	// what `C:` is (it needs to be `C:\`)
	if (process.platform === 'win32' && /:$/.test(parts[0])) parts[0] += '\\';

	try {
		return path.resolve(...parts);
	} catch (e) {
		return path.join(...parts);
	}
}

function updateShortcuts(){
	let locations = [];
	console.log("Shortcuts update started.");
	const fs = require('fs');
	var dirs = [p`${'appData'}/Microsoft/Windows/Start Menu/Programs/Startup`,
        p`${'appData'}/Microsoft/Windows/Start Menu/Programs/GeoGebra`,
        p`${'appData'}/Microsoft/Windows/Start Menu/Programs/GeoGebraFake`,
        p`${'userDesktop'}`];
	
    function updateIcon(filename, description, callback){
        var currentFolder = process.execPath.replace(/\\[^\\]*$/,"");        
        var appFolder = process.execPath.replace(/\\[^\\]*\\[^\\]*$/,"");
        var exe = process.execPath.split("\\").reverse()[0];
        var target = description.expanded.target;
        var updater = appFolder + "\\Update.exe";
        if(target === process.execPath || target === updater){
            console.log(filename);
            console.log(description);
            const ws = require('windows-shortcuts');
            ws.edit(filename, {"target": updater, "workingDir": currentFolder, "icon": process.execPath, 
                "args": "--processStart=" + process.execPath}, callback);
        } else { 
            callback();
        }
    }
	function checkdir(i){
        if(!dirs[i]){
            process.exit(0);
        }
        fs.readdir(dirs[i],function(err,files){
            function checkFile(j) {
                f = files && files[j];
                if(f && f.match(/.lnk$/)){
                    const ws = require('windows-shortcuts');
                    ws.query(dirs[i]+"/"+f, (errF, description)=>{
                        updateIcon(dirs[i]+"/"+f, description, ()=>checkFile(j+1));
                        
                    });
                }else if(files && files[j+1]){
                    checkFile(j+1);
                } else{
                    checkdir(i+1);
                }
                return true;
            }
            checkFile(0);
        });
    }
    checkdir(0);
					
	
}


function onReady(){
	var nogui = false;
	var appArgs = {};
	process.argv.forEach(function (val, index, array) {
		console.log(val);
		if(val.match(/^--debug/)){
			appArgs['debug'] = true;
		}
		if(val.match(/^--app=/)){
			appArgs['perspective']= val.match(/^--app=(.*)/)[1];
			if(appArgs['perspective'] === "whiteboard"){
				appArgs['prerelease'] = true;
			}
		}
			if(val.match(/^--squirrel/) && !val.match(/^--squirrel-firstrun/)){
				nogui = true;
				if(val.match(/^--squirrel-install/)){
					 createShortcuts(["Desktop","StartMenu"]);
					 console.log("Icon creation");
					
				}
				else if(val.match(/^--squirrel-update/)){
					 updateShortcuts();
					
				} else {
					// --squirrel-obsolete, ...
					process.exit(0);
				}
				
				return;
			}
		});
	if(nogui){
		console.log("No GUI, exiting");
		return;
	}

	if (process.platform === 'darwin') {
    // Create our menu entries so that we can use MAC shortcuts
    Menu.setApplicationMenu(Menu.buildFromTemplate([
      {
        label: 'Edit',
        submenu: [
          { role: 'cut' },
          { role: 'copy' },
          { role: 'paste' },
        ]
      }
    ]));
  }
	app.setAppUserModelId("com.squirrel.geogebra.GeoGebra");
	let {protocol} = require('electron')
			 //protocol.registerStandardSchemes(['ggb'])
	protocol.unregisterProtocol('file', () => {})
	function localProtocol(request, callback) {
		const url = request.url.substr(5, request.url.length-5);
		if(url.match(/GGB_EXAM_ON/i)){
			trySpawn("disablekeys.exe",[],(proc)=>{global.disablekeys = proc});
			win.setKiosk(true); //disables all system shortcuts on Mac and ESC on Windows 
			return;
		}
		if(url.match(/GGB_EXAM_OFF/i)){
			win.setKiosk(false);

			if(global.disablekeys){
				global.disablekeys.kill();
			}
		}
		if(url.match(/SETUNSAVED/i) ){
			var messagesJSON = decodeURIComponent(url.substring(url.indexOf("=")+1));
			win.unsaved= JSON.parse(messagesJSON);
			return;
		}

		const bits = url.split("?");
		const urlPath = bits[0];
		const normalized = path.normalize(`${__dirname}/${urlPath}`);
		callback({path: normalized });
		console.log({path: normalized});
	}

	function localError(error){
		if (error){
			 console.error('Failed to register protocol')
		}
		else {
			console.log('Registered protocol succesfully');
		}
	};

	protocol.registerFileProtocol('file', localProtocol, localError);	
	protocol.registerFileProtocol('app', localProtocol, localError);
	createWindow(appArgs);
	if(/^win/.test(process.platform)){
		const subfolder = !ggbConfig.appName || (ggbConfig.appName == "classic") ? "" : (ggbConfig.appName + "/");
		trySpawn("../Update.exe", ["--update", "https://download.geogebra.org/installers/6.0/" + subfolder]);
	}else{
		console.log("No autoupdate for "+process.platform);
	}

}

// 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', onReady)

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

app.on('activate', () => {
	console.log("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) {
		createWindow({})
	}
})

