'use strict';
var calendar = require('./calendarInterface');
var mqttClient = require('../mqtt/mqttClient');
var cron = require('node-cron');
var log4js = require('log4js');
var logger = log4js.getLogger();
var events = require('events');
var eventBus ;
var util = require('util');

var apn = require('apn');

var jsonfile = require('jsonfile');
var file = 'data/iostokens.json';

var apnService = new apn.connection({ key: 'conf/key.pem',
  cert: 'conf/cert.pem', production: false });

apnService.on('connected', function() {
    logger.debug('APN Connected');
  });

apnService.on('transmitted', function(notification, device) {
    logger.debug('APN Notification transmitted to:' + device.token.toString('hex'));
  });

apnService.on('transmissionError', function(errCode, notification, device) {
    logger.error('APNNotification caused error: ' + errCode + ' for device ', device, notification);
    if (errCode === 8) {
      logger.error('A error code of 8 indicates that the device token is invalid. This could be for a number of reasons - are you using the correct environment? i.e. Production vs. Sandbox');
    }
  });

apnService.on('timeout', function() {
    logger.debug('Connection Timeout');
  });

apnService.on('disconnected', function() {
    logger.debug('Disconnected from APNS');
  });

apnService.on('socketError', logger.error);





var officeController = function(neweventbus) {
  this.iosTokens = [];


  logger.debug((typeof neweventbus));
  if ((typeof neweventbus !== 'undefined') && (neweventbus !== null)) {
    logger.warn('Using passed eventBus');
    eventBus = neweventbus;
  } else {
    logger.warn('Using internal eventBus');
    eventBus = new events();
  }

  console.log('~~~ officeController');
  this.cloneObject = function(from, to) {
      if (Object.keys(from).length !== 0) {
        for (var key in from) {
          if (from.hasOwnProperty(key)) {
            if (key !== 'cronJOBS') {
              to[key] = from[key];
            }
          }
        }
      }
    };

  jsonfile.readFile(file, function (err, obj) {
    if (err){
      logger.error(err);
    }
    this.iosTokens = obj;

  }.bind(this));
  this.saveTimer = 0;
  var self = this;
  this.schedule = {};
  this.todaysList = {};

  this.calendarControl = new calendar.calendarInterface();
  this.calendarControl.getRoomStatusV2((todaysList) => {

      this.todaysList = todaysList;
      /*This.todaysList = {};
      this.cloneObject(todaysList, this.todaysList);
  logger.debug(this.todaysList);*/
      this.setupNextMeeting(todaysList);
    });


  this.mqtt = new mqttClient.mqttClient();

  //This.timer;

  //  this.meetings = {cronjobs:{start:null.stop:null}};
  this.task = cron.schedule('* * * * *', function() {
      var n = new Date();
      logger.debug('tick: ' + n);
      logger.info('looped Schedule count: ' + Object.keys(this.schedule).length);

      var curMeeting = {};
      this.cloneObject(this.todaysList.current, curMeeting);
      curMeeting.cronJobs = {};

      eventBus.emit('sendSocket', {id: 'calendar',current: curMeeting});
    }.bind(this));

  this.task = cron.schedule('*/5 * * * *', function() {
      this.calendarControl.getRoomStatusV2((todaysList) => {
          this.todaysList = todaysList;
          this.setupNextMeeting(todaysList);
          var data = todaysList;
          data.id = 'calendarData';
          eventBus.emit('sendSocket', data);
        });
    }.bind(this));

  eventBus.on('setupNextMeeting', this.setupNextMeeting.bind(this, this.todaysList));

  logger.debug('Todayslist', this.todaysList);

  eventBus.on('cleanUp', (id) => {
      logger.debug('+ => cleanUp');
      this.cleanUpMeeting(id);
    });

  eventBus.on('announce', (meeting) => {
    logger.debug('+ => announce');
    this.announceMeetingEnd(meeting);

  });

  var timmy = setTimeout(function() {
    var now = new Date();
    logger.error('Test timer, going to send msg');

    this.announceMeetingEnd({uid: 'bob', summary: 'Test message - ' + now.toISOString()});
  }.bind(this),60000);
};

officeController.prototype.saveData = function() {
    jsonfile.writeFile(file, this.iosTokens, function(err, obj) {
      if(err) {
        logger.error(err);
      }
    });
};


officeController.prototype.sendiOSAPN = function(packet) {
  logger.info('Sending the same notification each of the devices with one call to pushNotification.');
  var note = new apn.notification();
  var now = new Date();
  note.setAlertText(packet.msg);
  note.setAlertTitle('Smart Office');
  note.setBadge(1);
  note.setSound('dong.aiff');
  note.badge = 1;

  apnService.pushNotification(note, this.iosTokens);
};


officeController.prototype.announceMeetingEnd = function(meeting) {
  logger.debug('announceMeetingEnd',meeting);
  var msg = ['The meeting "', meeting.summary, '" is due to end in five minutes. Would you like to extend it by another five minutes?'].join('');

  var packet = {id: 'announce', msg: msg, uid: meeting.uid};

  eventBus.emit('sendSocket', packet);

  /*var message = new gcm.Message({
      collapse_key: 'test',
      data: {
          key1: 'value1'
        },
      delay_while_idle: true,
      time_to_live: 34,
      dry_run: false
    });*/

  this.sendiOSAPN(packet);

  /*sender.sendMessage(message.toJSON(), '', true, function(err, data) {
      if (!err) {
        logger.info('Message sent');
        logger.debug(data);
        // Do something
      } else {
        logger.error('Message failed');
        logger.error(err);
        // Handle error
      }
    });


*/
};


officeController.prototype.cleanUpMeeting = function(id) {
    logger.debug('deleting scheduled item: ' + id);
    logger.info('Pre delete Schedule count: ' + Object.keys(this.schedule).length);
    delete this.schedule[id];
    logger.info('post delete Schedule count: ' + Object.keys(this.schedule).length);

  };

officeController.prototype.createMeeting = function(obj,delayStart) {
  // Logger.debug(util.inspect(this));

  var newMeeting = obj, _delayStart = delayStart || false, cronStartStr;
  logger.debug('obj', obj);
  logger.debug('Delay start?', delayStart);
  var now = new Date.create();
  var self = this;
  //  Logger.debug(newMeeting);
  newMeeting.cronJOBS = {start: null, stop: null};
  if (_delayStart) {

    cronStartStr = now.addSeconds(5).format('{s} {m} {H} * * *');
  } else {
    cronStartStr = newMeeting.cronStart;
  }



  newMeeting.cronJOBS.start = cron.schedule(cronStartStr, function() {
      var n = new Date();
      logger.debug('MEETING STARTED!!!!' , n);
      var key = Object.keys(self.schedule)[0];

      var curMeeting = {};
      self.cloneObject(self.schedule[key], curMeeting);
      curMeeting.cronJOBS = null;

      // We want to kick of the pre -end timer here.

      // Lets turn on some lights!
      eventBus.emit('lightingOn','o');
      eventBus.emit('lightingOn','n');

      eventBus.emit('sendSocket', {id: 'calendar',current: curMeeting});



    }, true);


  newMeeting.cronJOBS.alert = cron.schedule(newMeeting.cronAlert, function() {
        var n = new Date();
        logger.error('MEETING ends in 5 minutes');
        logger.debug(this);

        // Announce there are five minutes remaining..

        eventBus.emit('announce', newMeeting);

      }.bind(this), true);


  newMeeting.cronJOBS.stop = cron.schedule(newMeeting.cronStop, function() {
      var n = new Date();
      logger.debug('MEETING ENDED' + n);
      newMeeting.cronJOBS.start = null;
      newMeeting.cronJOBS.stop = null;

      eventBus.emit('lightingOn','f');
      eventBus.emit('lightingOn','g');

      logger.debug(newMeeting.cronJOBS);
      eventBus.emit('cleanUp',newMeeting.uid);

    }.bind(this), true);

  this.schedule[newMeeting.uid] = newMeeting;

};

officeController.prototype.setupNextMeeting = function(calData) {
    logger.debug('Setup next meeting...');

    var self = this;

    var now = new Date.create();
    if (Object.keys(calData.current).length > 0) {

      if (this.schedule.hasOwnProperty(calData.current.uid)) {
        logger.debug('Current Meeting exists in schedule');
      } else {
        logger.debug('Current Meeting does NOT exist in schedule');
        this.createMeeting(calData.current, true);
      }
    }

    if (calData.upcoming.length > 0) {

      for (var uCount = 0; uCount < calData.upcoming.length; uCount++) {
        var uEntry = calData.upcoming[uCount];
        if (this.schedule.hasOwnProperty(uEntry.uid)) {

          logger.debug('Upcoming Meeting exists in schedule');
          // Lets check to see if it's changed in anyway..

          var origEntry, origStart, origEnd, newStart, newEnd;

          origEntry = this.schedule[uEntry.uid];
          origStart = Date.create(origEntry.dtstart);
          origEnd = Date.create(origEntry.dtend);

          newStart = Date.create(uEntry.dtstart);
          newEnd = Date.create(uEntry.dtend);

          if ((origStart.getTime() != newStart.getTime()) || (origEnd.getTime() != newEnd.getTime())) {
            logger.error('WE HAVE A CHANGED ENTRY!!');

            origEntry.cronJOBS.start.destroy();
            origEntry.cronJOBS.stop.destroy();

            origEntry = uEntry;
            this.createMeeting(origEntry);
          }

        } else {
          logger.debug('Upcoming meeting does NOT exist in schedule');
          var newMeeting = uEntry;
          this.createMeeting(newMeeting);
        }

      }

    }

    //  Logger.info(this.schedule);
  };


officeController.prototype.startController = function(eventBus) {
    console.log('Starting.');
    getRoomStatus();
    this.timer = setInterval(function() { getRoomStatus() }, 300000);
  };

officeController.prototype.stopController = function() {
    console.log('Stopping.');
    clearInterval(this.timer);
  };

officeController.prototype.returnCalendar = function() {
  var exportList;

  exportList = this.calendarControl.getCachedStatus();
  logger.debug(exportList);
  return exportList;

};


officeController.prototype.registeriOSToken = function(id) {
  if (this.iosTokens.indexOf(id) === -1) {
    this.iosTokens.push(id);
    logger.info('C - IOS Device registered.');
    clearTimeout(this.saveTimer);
    this.saveTimer = setTimeout(function(){this.saveData();}.bind(this), 10000);
  }
};


//OfficeController.prototype.getRoomStatus = function () {
//    this.calendarControl.getRoomStatus();
//    console.log('Checking Calendar.');
//};

var meetingStates = {
    STARTING: 0,
    INPROGRESS: 1,
    NONE: 2,
    FINISHED: 3
  };

function getRoomStatus() {
  return;
  // Var calendarControl = new calendar.calendarInterface();
  //  var status = calendarControl.getRoomStatusV2();
  var status = officeController.calendarControl.getRoomStatusV2();
  if (status == meetingStates.STARTING) {
    console.log('Meeting about to start - turning on.');
    this.mqtt.projectorOn();
    this.mqtt.lightsOn();
  }
  if (status == meetingStates.INPROGRESS) {
    console.log('Meeting in progress - do nothing.');
  }
  if (status == meetingStates.NONE) {
    console.log('No meeting - do nothing.');
  }
  if (status == meetingStates.FINISHED) {
    console.log('No meeting - do nothing.');
    this.mqtt.projectorOff();
    this.mqtt.lightsOff();
  }


}



module.exports.officeController = officeController;