'use strict';

var winston = require('winston');
var Presence = require('../models/presence.js');
var Device = require('../models/device.js');
var deviceController = require('../controllers/device.js');
var config = require('../config/config.js');
var alertController = require('../controllers/alert.js');
var timeoutIDs = {};

exports.getPresenceMessage = function(req, res, next) {
    winston.info('Receiving ifttt presence message. Hostname: ' + req.hostname + ' Zone: ' + req.query.zone + ' Action: ' + req.query.action);

    var who = req.query.who,
        zone = req.query.zone,
        action = req.query.action,
        tolerance = req.query.tolerance,
        createdPresence = {};

    // Check last presence
    var query = Presence.findOne();
    if (who) {
        query = query.where('who').equals(who);
    }
    query = query.where('zone').equals(zone);
    query = query.sort('-timeIn');

    query.exec(function(err, lastPresence) {
        if (err) return err;

        // Complete last presence
        if (lastPresence && !lastPresence.timeOut) {
            // Overwrite last uncompleted presence
            if (action == 'entered') {
                lastPresence.timeIn = new Date();
                lastPresence.save();
            } else if (action == 'exited') {
                lastPresence.timeOut = new Date();
                var diff = lastPresence.timeOut - lastPresence.timeIn;
                lastPresence.minutes = diff / (60 * 1000);

                // If only passing by an not really staying in the gym for example
                if (tolerance && (tolerance > lastPresence.minutes)) {
                    lastPresence.remove();
                } else {
                    lastPresence.save();
                }
            }
            // Or create new
        } else if (action == 'entered') {
            var presence = {};
            presence.who = who;
            presence.zone = zone;
            presence.timeIn = new Date();
            Presence.create(presence, function(err, newPresence) {
                if (err) return err;

                createdPresence = newPresence;
            });
        }
    });

    res.json({
        type: true,
        data: createdPresence
    });
};

exports.IRSensorChange = function(data, alarm) {
    var time = new Date(),
        newPresence = { who: 'unknown', zone: data.area, timeIn: time };

    winston.info('IRSensorChange: ' + JSON.stringify(data));

    // Check last presence
    var query = Presence.findOne();
    query = query.where('zone').equals(newPresence.zone);
    query = query.sort('-timeIn');

    query.exec(function(err, lastPresence) {
        if (err) return err;

        winston.info('lastPresence: ' + JSON.stringify(lastPresence));

        // If entered
        if (data.valueNumber == 1) {
            winston.info('ENTERED');
            // If not the first time
            if (lastPresence) {
                // If last presence ended
                if (lastPresence.timeOut) {
                    var diff = (time - lastPresence.timeOut) / 1000;
                    winston.info('CHECKING diff: ' + diff);
                    // Check tolerance, if only a few seconds since last exit, join with previous presence
                    if (diff < config.IRsensorTolerance) {
                        winston.info('UPDATE last presence: ' + diff);
                        newPresence = null;
                        lastPresence.timeOut = null;
                        lastPresence.minutes = null;
                        lastPresence.save();
                    } else if (alarm && diff > config.IRAlarmTolerance) {
                        winston.info('ALARM: ' + diff);
                        alertController.alarm(data.area, lastPresence.timeOut);
                    }
                // Delete inconsistent data
                } else {
                    winston.info('REMOVE LAST PRESENCE');
                    lastPresence.remove();
                }
            }
            // If exited
        } else {
            winston.info('EXITED');
            newPresence = null;
            if (lastPresence) {
                lastPresence.timeOut = time;
                lastPresence.minutes = (lastPresence.timeOut - lastPresence.timeIn) / (60 * 1000);
                lastPresence.save();
            }
        }

        if (newPresence) {
            winston.info('CREATE newPresence: ' + JSON.stringify(newPresence));

            Presence.create(newPresence, function(err, createdPresence) {
                if (err) return err;
            });
        }
    });


    // Check associated lights and switches
    if (data.valueNumber == 1) {
        Device.find({ 'localSetup.schedules.irSensor': data.area }, function(err, devices) {
            // For each device associated with the IR Sensor
            for (var i = 0; i < devices.length; i++) {
                // Check mode
                if (devices[i].localSetup.auto === false) {
                    continue;
                }

                // Check Schedules
                var inSchedule = false;
                for (var j = 0; j < devices[i].localSetup.schedules.length; j++) {
                    var sched = devices[i].localSetup.schedules[j];
                    if (sched.irSensor == data.area) {
                        var time = new Date(),
                            timePlus1Day = new Date();
                            
                        timePlus1Day.setDate(timePlus1Day.getDate() + 1);

                        // Check weekdays
                        var inDay = false;
                        var day = time.getDay();
                        if (day === 0) {
                        	day = 7;
                        }
                        	
                        for (var k = 0; k < sched.weekDays.length; k++) {
                            if (sched.weekDays[k].dayNumber == day) {
                                inDay = true;
                                break;
                            }
                        }

                        if (inDay === false) {
                            continue;
                        }

                        // Check hour
                        var from = new Date(),
                              to = new Date();
                        var timeON  = new Date(sched.timeON),
                            timeOFF = new Date(sched.timeOFF);

                        from.setMinutes(timeON.getMinutes());
                        from.setHours(timeON.getHours());
                        from.setSeconds(0);

                        to.setMinutes(timeOFF.getMinutes());
                        to.setHours(timeOFF.getHours());
                        to.setSeconds(0);

                        if (to < from) {
                            to.setDate(to.getDate() + 1);
                        }

                        if ((time > from && time < to) || (timePlus1Day > from && timePlus1Day < to)) {
                            inSchedule = true;
                            break;
                        }
                    }
                }

                if (inSchedule === false) {
                    continue;
                }

                // Check previous timeout and cancel if neccessary
                var timerDeviceStatus;
                if (typeof timeoutIDs[devices[i]._id] !== 'undefined' && timeoutIDs[devices[i]._id] !== null) {
                    winston.info('IRSensorChange timer already exists (cancelling): ' + devices[i]._id);
                    clearTimeout(timeoutIDs[devices[i]._id]);
                    timeoutIDs[devices[i]._id] = null;
                    timerDeviceStatus = !devices[i].localSetup.on;
                } else {
                    // Turn on device
                    timerDeviceStatus = devices[i].localSetup.on;
                    deviceController.updateDeviceModeAux(devices[i]._id, !devices[i].localSetup.on, true);
                }

                // Launch timer
                timeoutIDs[devices[i]._id] = setTimeout(function(deviceID, currentStatus) {
                    deviceController.updateDeviceModeAux(deviceID, currentStatus, true);
                    // Clear timer register when executed
                    timeoutIDs[deviceID] = null;
                }, config.IRsensorTimer, devices[i]._id, timerDeviceStatus);
            }
        });
    }
};

exports.getPresence = function(req, res, next) {

    // Obtenemos los parametros de la consulta
    var period = req.query.period,
        date = new Date(req.query.date),
        zone = req.query.zone,
        who = req.query.who,
        from, to;

    // Construimos la consulta
    var query = Presence.find();
    if (period !== undefined && period !== '') {

        if (period == 'year') {
            from = new Date(date.getFullYear(), 0, 1);
            to = new Date(date.getFullYear() + 1, 0, 1);
        } else if (period == 'month') {
            from = new Date(date.getFullYear(), date.getMonth(), 1);
            to = new Date(date.getFullYear(), date.getMonth() + 1, 1);
        } else if (period == 'week') {
            if (date.getDay() === 0) {
                from = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 6);
            } else {
                from = new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + 1);
            }
            to = new Date(from.getFullYear(), from.getMonth(), from.getDate() + 7);
        } else if (period == 'day') {
            from = new Date(date.getFullYear(), date.getMonth(), date.getDate());
            to = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
        } 

        query = query.where('timeIn').gte(from).lt(to);
    }

    if (zone !== undefined && zone !== '') {
        query = query.where('zone').equals(zone);
    }
    if (who !== undefined && who !== '') {
        query = query.where('who').equals(who);
    }

    query = query.sort('timeIn');

    query.exec(function(err, presences) {
        if (err) return next(err);

        if (presences) {
            res.json({
                type: true,
                data: presences
            });
        } else {
            res.json({
                type: false,
                data: 'No data found'
            });
        }
    });
};
