// Alexa Loxone Skill
// Michael Steins 04.03.2017
// coplaning.lu
//

'use strict';

var AlexaSkill = require('./AlexaSkill');
var rp = require('request-promise');

var sessionLocale = '';
var APP_ID = undefined; //recommended to replace with 'amzn1.echo-sdk-ams.app.[your-unique-value-here]';
var loxoneHost = 'xx'; //required to replace with loxone host, if port is not 80, it has to be appended with colon (e.g. myloxone.dyndns.org:8080)
var loxoneUsername = 'xx'; //required to replace with loxone username, it is recommended to create a dedicated alexa user in loxone with fewer rights
var loxonePassword = 'xx'; //required to replace with password of loxone user

var AlexaLoxone = function() {
	AlexaSkill.call(this, APP_ID);
}

AlexaLoxone.prototype = Object.create(AlexaSkill.prototype);
AlexaLoxone.prototype.constructor = AlexaLoxone;

AlexaLoxone.prototype.eventHandlers.onLaunch = function(launchRequest, session, response) {
	console.log('AlexaLoxone Skill onLaunch requestId: ' + launchRequest.requestId + ', sessionId: ' + session.sessionId);

	var speechOutput = 'Willkommen zu Loxone. Was ist dein Wunsch?';

	response.ask(speechOutput, speechOutput);
}

AlexaLoxone.prototype.intentHandlers = {
	'ControlIntent': function(intent, session, response) {

		var query = intent.slots.control.value.toLowerCase();
		console.log ('Query: "'+query+'"');
		
		// Title for Alexa app card
		var cardTitle = (query);
			
		function speakResults (speechText, cardText) {
			var cardOutputText = (cardText == undefined) ? speechText : cardText;
				
			// Convert speechText into SSML
			var SSMLspeechText = {
				speech: '<speak>' + speechText + '</speak>',
				type: 'SSML'
			};

			response.tellWithCard (SSMLspeechText, cardTitle, cardOutputText);
		};
		
		/*
			sample utterances:
			
			schalte licht ein - OK
			schalte das licht ein - OK
			licht ein - OK
			fahre rollladen hoch - OK
			rollladen hochfahren - OK
			fahre rollladen auf 50 % - OK
			rollladen auf 50 % fahren - OK
			dimme wohnzimmerbeleuchtung auf 25 % - OK
		*/
		
		var arrActionKeywordsSet = ['fahre', 'fahren', 'schalte', 'schalten', 'stelle', 'stellen', 'dimme', 'dimmen', 'triggere', 'trigger'];
		var arrActionKeywordsGet = ['wieviele', 'wieviel', 'wie viele', 'wie viel', 'wie hoch', 'wie'];
		// define control values
		var arrValueKeywords = ['hoch', 'runter', 'rauf', 'stop', 'stopp', 'stoppen', 'ein', 'aus', 'an', 'ab', 'runterfahren', 'hochfahren', 'ausschalten', 'einschalten'];
		var arrUselessKeyWords = ['ist', 'bitte', 'jetzt', 'sofort', 'der', 'die', 'das', 'dem', 'den', 'meinen', 'meine', 'mein', 'unserem', 'unseren', 'unsere', 'unser', 'zustand', 'position', 'helligkeit', 'level', 'proz', 'prozent', 'grad', 'celsius', 'soll', 'es', 'sie', 'er', '%'];
		var arrOkayMessages = ['Okay','Mach ich','Kommt sofort','Läuft','Geht klar'];
		var intendedRoom = '';
		var intendedDevice = '';
		var intendedAction = '';
		var intendedValue = '';
		var translatedValue = '';
		var mode = 'Unknown';

		query = ' '+query+' ';

		//bug fixing
		query = query.replace (/ rolladen /g, ' rollladen ');

		//remove useless words
		query = query.replace (/ \\? /g, ' ');
		arrUselessKeyWords.forEach (function(keyword) {
			query = query.replace(new RegExp(' '+keyword+' ', 'g'), ' ');
		});

		query = query.replace(/ +(?= )/g,'');

		// detect action type and remove from query
		arrActionKeywordsSet.forEach(function(action) {
			action = ' '+action+' ';
		  if (query.indexOf(action) == 0) {
			mode = 'SET';
			intendedAction = action.trim();
			
			if (intendedAction == 'triggere' || intendedAction == 'trigger') {
				intendedValue = 'Pulse';
				translatedValue = 'Pulse';
			}

			query = query.replace (action, ' ');
		  }
		});

		// detect action type and remove from query
		arrActionKeywordsGet.forEach(function(action) {
			action = ' '+action+' ';
		  if (query.indexOf(action) == 0) {
			mode = 'GET';
			intendedAction = action.trim();
			query = query.replace (action, ' ');
		  }
		});

		if (intendedValue == '') {
			// detect value and translate to loxone api specific
			arrValueKeywords.forEach(function(action) {
			  action = ' ' + action + ' ';
			  if (query.indexOf(action) !== -1) {
				intendedValue = action.trim();
				query = query.replace (action, ' ');

				if (intendedValue === 'ein') translatedValue = 'On';
				else if (intendedValue === 'an') translatedValue = 'On';
				else if (intendedValue === 'einschalten') translatedValue = 'On';
				else if (intendedValue === 'aus') translatedValue = 'Off';
				else if (intendedValue === 'ausschalten') translatedValue = 'Off';
				else if (intendedValue === 'hoch') translatedValue = 'Up';
				else if (intendedValue === 'hochfahren') translatedValue = 'Up';
				else if (intendedValue === 'rauf') translatedValue = 'Up';
				else if (intendedValue === 'ab') translatedValue = 'Down';
				else if (intendedValue === 'runter') translatedValue = 'Down';
				else if (intendedValue === 'runterfahren') translatedValue = 'Down';
				else if (intendedValue === 'stop') translatedValue = 'Stop';
				else if (intendedValue === 'stopp') translatedValue = 'Stop';
				else if (intendedValue === 'stoppen') translatedValue = 'Stop';
			  }
			})
		}

		var z = /(?:(?:(?:im|in) )([A-Za-z0-9öäüÖÄÜ]{0,}))/i.exec (query);
		if (z != null)
		{
			query = query.replace (z[0], '');
			intendedRoom = z[1].trim().toLowerCase();
		}

		z = /(?:(?:(?:auf|um) )([A-Za-z0-9öäüÖÄÜ]{0,}))/i.exec (query);
		if (z != null)
		{
			query = query.replace (z[0], '');
			intendedValue = z[1].trim();
			translatedValue = intendedValue;
		}

		intendedDevice = query.trim();

		console.log ('Intent: '+mode);
		console.log ('Intended action: '+intendedAction);
		console.log ('Intended device: '+intendedDevice);
		console.log ('Intended room: '+intendedRoom);
		console.log ('Intended value: '+intendedValue+ ' (translated to: '+translatedValue+')');

		if ((mode == 'GET' && intendedDevice != '') || (mode == 'SET' && intendedDevice != '' && translatedValue != '')) {
			var login = new Buffer(loxoneUsername+':'+loxonePassword).toString('base64');

			var options = {
				uri: 'http://'+loxoneHost+'/data/loxApp3.json',
				json: true,
				headers: {
					'Authorization': 'Basic '+login
				}
			}

			// get loxApp3.json info to check if device exists and if so, get device ID.
			rp(options)
				.then(function(loxAppJSON) {
					var foundDevice = null;
					var foundDeviceID = '';
					
					var rooms = loxAppJSON.rooms;
					var controls = loxAppJSON.controls;

					for (var device in controls) {
						var deviceName = controls[device].name.trim().toLowerCase();
						
						if (deviceName == intendedDevice || deviceName == intendedDevice.replace (/ /g, '')) {
							if (intendedRoom == '' || rooms[controls[device].room].name.toLowerCase() == intendedRoom)
							{
								foundDevice = controls[device]; //controls[device].name;
								foundDeviceID = device;
								break;
							}
						}
					}

					if (foundDevice != null) {
						//http://miniserver/dev/sps/io/TasterLichtWohnzimmer/Ein
						var url;

						if (mode == 'SET')
							url = 'http://'+loxoneHost+'/dev/sps/io/'+foundDeviceID+'/'+translatedValue;
						else if (mode == 'GET')
							url = 'http://'+loxoneHost+'/dev/sps/io/'+foundDeviceID+'/all';
						
						console.log ('--> '+url);
						
						options = {
							uri: url,
							json: false,
							headers: {
								'Authorization': 'Basic '+login
							}
						}

						rp (options).then (function (result) {
							//response.ask('Läuft! Sonst noch was?', 'Sonst noch was?');
							//console.log ('Result: '+result); 
							//speakResults ('Läuft!', url);
							
							if (mode == 'SET')
								speakResults (arrOkayMessages [Math.floor(Math.random() * arrOkayMessages.length)]); 
							else if (mode == 'GET')
							{
								result = result.substring (result.indexOf('value'));
								
								var resValue = /(?:(?:value="))([0-9öäüÖÄÜA-Za-z.,%°'/ ]{0,})/i.exec (result);
								
								if (resValue != null && resValue.length == 2)
								{
									var intValue = Math.abs(resValue[1]);
									
									if (foundDevice.type == 'Alarm')
										speakResults ('Die Alarmanlage ist '+(['unscharf', 'scharf mit bewegungsmelder', 'scharf ohne bewegungsmelder'][intValue]));
									else if (foundDevice.type == 'InfoOnlyDigital')
										speakResults (foundDevice.name+ ' ist '+((intValue == 1) ? foundDevice.details.text.on : foundDevice.details.text.off));
									else if (foundDevice.type == 'Switch')
										speakResults (foundDevice.name+ ' ist '+((intValue == 1) ? 'ein':'aus'));
									else
										speakResults (resValue[1]);
								}
								else
									speakResults ('Keine Ahnung');
							}
						})
						.catch(function (err) {
							speakResults ('Es trat ein Fehler bei der Kommunkation mit dem MiniServer auf.');
						});
					} else {
						speakResults ('Sorry, ich kenne kein Gerät das '+intendedDevice+' heisst.');
					}
				})
				.catch (function (err) {
					speakResults ('Sorry, ich konnte keine Verbindung zum Miniserver aufbauen.');
				});
		} else {
			speakResults ('Sorry, diesen Loxone-Befehl habe ich nicht verstanden.');
		}
	},
	'AMAZON.StopIntent': function(intent, session, response) {
		response.tell('');
	}
}

exports.handler = function(event, context) {
	var AlexaLoxoneHelper = new AlexaLoxone();
	sessionLocale = event.request.locale;
	console.log('handler locale is: '+ sessionLocale);

	if (sessionLocale == 'de-DE') {
	console.log('Setting locale to de-DE');
	// ...
	}   

	AlexaLoxoneHelper.execute(event, context);
}