var five = require('johnny-five')
var twilio = require('twilio')

var board
var init = false
var trips = 0
var isArmed = false

var armButton
var resetButton
var statusLight

var ultraSensor
var ultraBaseline
var ultraReadings = [ ]
var ultraThreshold = 24
var ultraTriggered = false

var magnetSensor
var magnetTriggered = false

var photoSensor
var photoReading = 0
var photoThreshold = 100
var photoTriggered = false

var accountSid = 'AC4a15b85283a3d7f79395276ffc805970'
var authToken = 'f5cb23e4cfdf522277b510541ee30468'
var client = twilio(accountSid, authToken)
var lastSMS = 0
var ratelimit = 5000

board = new five.Board()
board.on('ready', function ready() {
	
	armButton = new five.Button({

		isPullup : true
		, pin : 8
	})
	armButton.on('up', armDisarm)

	resetButton = new five.Button({

		isPullup : true
		, pin : 10
	})
	resetButton.on('up', ultraReset)

	statusLight = new five.Led.RGB({
		pins : {
			red : 6
			, green : 5
			, blue : 3
		}
	})

	ultraSensor = new five.Ping(11)
	ultraSensor.on('change', ultraChange)
	ultraSensor.on('data', ultraData)

	magnetSensor = new five.Button({		

		isPullup : true
		, pin : 12
	})
	magnetSensor.on('up', function() {

		trigger('magnet')
	})

	photoSensor = new five.Sensor({

		pin : "A0"
		, freq : 250
	})
	photoSensor.on('data', photoData)

})

/**
 * Funkcja wywoływana gdy czujnik wykryje, że odległość
 * zmieniła się od ostatniego pomiaru. Alarm jest zgłaszany
 * jeżeli został juz zainicjowany, a zmiana jest większa
 * niż wartość progowa.
 */
function ultraChange() {
	
	if(!init) { return }	
	var data = this.inches

	if(Math.abs(data - ultraBaseline) > ultraThreshold) {

		// Jeżeli jeszcze nie został zgłoszony alarm, zrób to teraz!
		if(!ultraTriggered) { 

			trigger('ultrasonic') 
			return ultraTriggered = true
		}
	}
	ultraTriggered = false
}

/**
 * Funkcja wywoływana gdy czujnik ultradźwiękowy wyśle dane,
 * co ma miejsce w regularnych odstępach czasu. Funkcja jest
 * wywoływana nawet wtedy, gdy nie zostanie wykryta zmiana
 * w danych.
 */
function ultraData() {

	var inches = this.inches
	if(ultraReadings.length >= 10) { 

		ultraReadings.shift()
		if(!init) {

			ultraBaseline = ultraReadings.sort()[4]
			console.log("Wyliczona wartość odniesienia: %s", ultraBaseline)
			armDisarm(true)
		}
		init = true
	}
	else {

		statusLight.color('#0000FF')
	}
	ultraReadings.push(inches)
}

/**
 * Resetowanie wartości odniesienia dla czujnika ultradźwiekowego.
 * Funkcja wywoływana po nacisnięciu przycisku reset.
 */
 function ultraReset() {

 	console.log("* Resetowanie...")
	ultraReadings = [ ] 
 	init = false
}

/**
 * Funkcja wywoływana gdy fotodetektor wyśle dane, co również
 * ma miejsce w regularnych odstępach czasu. Funkcja jest
 * wywoływana nawet wtedy, gdy nie zostanie wykryta zmiana
 * w danych.
 */
function photoData() {

	var data = this.value
	if(Math.abs(data - photoReading) > photoThreshold) {

		if(!photoTriggered) { 
			
			trigger('laser') 
		}
		return photoTriggered = true
	}
	photoTriggered = false
	photoReading = data
}

/**
 * Funkcja wywoływana po naciśnięciu przycisku uzbrojenia/
 * rozbrojenia alarmu. Zmieniany jest kolor diody LED
 * i blokowane jest wysyłanie wiadomości SMS.
 */
function armDisarm(override) {

	if(typeof override == 'boolean') { 

		isArmed = override 
	}
	else { isArmed = !isArmed }

	if(isArmed) {

 		console.log("* Uzbrajanie")
		statusLight.color('#FF0000')
	}
	else {

		console.log("* Rozbrajanie")
		statusLight.color('#00FF00')
	}
}

/**
 * Funkcja wywoływana gdy czyjnik wykryje zdarzenie.
 * Wysyła SMS za pomocą usługi Twilio i zapisuje
 * nazwę czujnika, który wywołała alarm.
 */
function trigger(sensor) {

	if(!isArmed) { return }
	var now = (new Date()).valueOf()

	console.log("* Zgłoszony alarm (%s) [%s]"
		, sensor
		, trips
	)
	if(now - ratelimit < lastSMS) {

		return console.log("> Ograniczenie wysyłanych wiadomości.")
	}
	
	++trips
	lastSMS = now
	client.messages.create({

		body : "Alarm zgłoszony przez " + sensor
		, to : "NUMER TELEFONU ADRESATA"
		, from : "TWÓJ NUMER TELEFONU"
	}, function smsResults(err, msg) {

		if(err) { 

			console.log("*** BŁĄD ***\n")
			return console.log(err) 
		}
		if(!msg.errorCode) {

			return console.log("> Udało się!")
		}
		console.log("> Problem: %s", msg.errorCode)
	})
	console.log("> Wysyłanie SMS.")
}