var request = require('request'); var log4js = require('log4js'); var logger = log4js.getLogger(); var STRING = require('string'); var util = require('util'); var Elapsed = require('elapsed'); require('sugar-date'); function processICAL(ical) { 'use strict'; logger.info('+ processICAL'); var workingBlock = []; var segments = { meetingStartID: 'DTSTART;TZID=Europe/London:', meetingStartAlt: 'DTSTART:', meetingStartAltOther: 'DTSTART;VALUE=DATE:', meetingEndID: 'DTEND;TZID=Europe/London:', meetingEndAlt: 'DTEND:', meetingEndAltOther: 'DTEND;VALUE=DATE:', meetingDescID: 'DESCRIPTION:', summaryID: 'SUMMARY:', begin: 'BEGIN:VEVENT', end: 'END:VEVENT', beginAlarm: 'BEGIN:VALARM', endAlarm: 'END:VALARM', recur: 'RRULE:' }; var rules = ['FREQ','WKST','UNTIL','BYMONTH','BYMONTHDAY','INTERVAL','BYDAY']; function nThDayOfMonth(monthsAhead, wantedDay) { var now = new Date(); for(var t=0; t < monthsAhead; t++) { } } function processRecurrence(workBlock) { var _workBlock = workBlock; // logger.debug('Processing recurrence...'); // logger.debug('Processing recurrence...'); var weekBits = {'SU':0,'MO':1,'TU':2,'WE':3,'TH':4,'FR':5,'SA':6}; var blocks=[]; var now = new Date(); var day = now.getDate(); var dayNum = now.getDay(); var month = now.getMonth(); var year = now.getFullYear(); var recurSettings = {freq:null, wkst:null, until:null, bymonth:null, bymonthday:null, interval:null, byday:null}; var firstSplit = _workBlock.recur.split(';'); for (var t=0; t< firstSplit.length;t++) { var ws = firstSplit[t].split('='); if (rules.indexOf(ws[0]) > -1) { recurSettings[ws[0].toLowerCase()] = ws[1]; } } // if all null discard.. if (recurSettings.freq === null && recurSettings.wkst === null && recurSettings.until === null && recurSettings.byday === null && recurSettings.bymonth === null && recurSettings.bymonthday === null && recurSettings.interval === null) { return null; } if (recurSettings.until !== null) { // have we expired? //var _until = Date.create(recurSettings.until).isPast(); return null; } if (recurSettings.freq !== null) { // logger.debug(_workBlock); var origStart, origEnd, distance, newStart, newEnd; origStart = Date.create(_workBlock.dtstart); origEnd = Date.create(_workBlock.dtend); var _d = origStart.getDate(); var _m = origStart.getMonth(); var _h = origStart.getHours(); var _min = origStart.getMinutes(); var _secs = origStart.getSeconds(); distance = origEnd - origStart; if (recurSettings.freq === 'YEARLY') { if (recurSettings.bymonth !== null && recurSettings.bymonthday !== null) { // ok, a day and month. newStart = Date.create().set({year:year, month: recurSettings.bymonth - 1 , day: recurSettings.bymonthday, hour:_h, minutes:_min, seconds:_secs}); newEnd = Date.create(newStart).addMilliseconds(distance); _workBlock.dtstart = newStart; _workBlock.dtend = newEnd; } else if (recurSettings.bymonth === null && recurSettings.bymonthday === null) { // extract month and year from dtstart newStart = Date.create().set({year:year, month: _m , day: _d, hour:_h, minutes:_min, seconds:_secs}); newEnd = Date.create(newStart).addMilliseconds(distance); _workBlock.dtstart = newStart; _workBlock.dtend = newEnd; } return _workBlock; } if (recurSettings.freq === 'MONTHLY') { if (recurSettings.bymonthday !== null) { // ok, a day and month. newStart = Date.create().set({year:year, month: month , day: recurSettings.bymonthday, hour:_h, minutes:_min, seconds:_secs}); newEnd = Date.create(newStart).addMilliseconds(distance); _workBlock.dtstart = newStart; _workBlock.dtend = newEnd; } } if (recurSettings.freq === 'WEEKLY' && recurSettings.interval === null) { var byDayBit = recurSettings.byday.split(',')[0]; var byDayNumber = weekBits[byDayBit]; if (byDayNumber >= dayNum) { var daysAdded = byDayNumber - dayNum; newStart = Date.create().set({year:year, month: month , day: day, hour:_h, minutes:_min, seconds:_secs}).addDays(daysAdded); newEnd = Date.create(newStart).addMilliseconds(distance); _workBlock.dtstart = newStart; _workBlock.dtend = newEnd; } } } // if we get here we've skipped everything just return the _workblock return _workBlock; } function processBlock(block) { var _wb; var workBlock = { summary: '', dtstart: null, dtend: null, description: '', timeStart: null, timeEnd: null, duration: 0, combined: '', recur: null }; var alarmFlag = false, ws, blockStep; for (var step = 0; step < block.length; step++) { blockStep = block[step]; if (blockStep.indexOf(segments.recur) >= 0) { workBlock.recur = STRING(block[step].split(segments.recur)[1]).collapseWhitespace().s; //logger.debug(workBlock.recur); } if (blockStep.indexOf(segments.summaryID) >= 0) { workBlock.summary = STRING(block[step].split(segments.summaryID)[1]).collapseWhitespace().s; } if (blockStep.indexOf(segments.meetingStartID) >= 0) { ws = STRING(block[step].split(segments.meetingStartID)[1]).collapseWhitespace().s; workBlock.dtstart = Date.create(ws); } if (blockStep.indexOf(segments.meetingEndID) >= 0) { ws = STRING(block[step].split(segments.meetingEndID)[1]).collapseWhitespace().s; workBlock.dtend = Date.create(ws); } if (blockStep.indexOf(segments.meetingStartAlt) >= 0) { ws = STRING(block[step].split(segments.meetingStartAlt)[1]).collapseWhitespace().s; workBlock.dtstart = Date.create(ws); } if (blockStep.indexOf(segments.meetingEndAlt) >= 0) { ws = STRING(block[step].split(segments.meetingEndAlt)[1]).collapseWhitespace().s; workBlock.dtend = Date.create(ws); } if (blockStep.indexOf(segments.meetingStartAltOther) >= 0) { ws = STRING(block[step].split(segments.meetingStartAltOther)[1]).collapseWhitespace().s; workBlock.dtstart = Date.create(ws); } if (blockStep.indexOf(segments.meetingEndAltOther) >= 0) { ws = STRING(block[step].split(segments.meetingEndAltOther)[1]).collapseWhitespace().s; workBlock.dtend = Date.create(ws); } if (blockStep.indexOf(segments.meetingDescID) >= 0) { if (!alarmFlag) { workBlock.description = STRING(block[step].split(segments.meetingDescID)[1]).collapseWhitespace().s; } } if (blockStep.indexOf(segments.beginAlarm) >= 0) { alarmFlag = true; } } // We have to check recuring stuff before the cron stuff is processed. if (workBlock.recur !== null) { _wb = processRecurrence(workBlock); // logger.warn('returning:', _wb); if (_wb !== null) { if (!Array.isArray(_wb)) { workBlock = _wb; } else { logger.error('We made an array'); } } } //logger.debug(workBlock); if (workBlock.dtstart !== null) { workBlock.timeStart = workBlock.dtstart.format('{24hr}:{mm}:{ss}'); workBlock.combined = '' + workBlock.timeStart + ' - '; workBlock.long = '' + workBlock.dtstart.format('{Weekday}') +', ' + workBlock.timeStart + ' - '; } workBlock.combined = workBlock.combined + workBlock.summary; workBlock.longcombined = workBlock.long + workBlock.summary; if (workBlock.dtend !== null) { workBlock.timeEnd = workBlock.dtend.format('{24hr}:{mm}:{ss}'); } if (workBlock.dtstart !== null && workBlock.dtend !== null) { var elapsedTime = new Elapsed(workBlock.dtstart, workBlock.dtend); workBlock.duration = elapsedTime.optimal; workBlock.combined = workBlock.combined + ', ' + elapsedTime.optimal; workBlock.longcombined = workBlock.longcombined + ', ' + elapsedTime.optimal; } return workBlock; } var lines = ical.split('\r\n'), l = lines.length, counter = 0; var alarmed = false; while (counter < l) { if (lines[counter].indexOf(segments.begin) < 0) { counter++; } else { var subcounter = 0, subBlock = []; alarmed = false; while (subcounter < 75) { if (lines[counter + subcounter].indexOf(segments.end) < 0) { if (lines[counter + subcounter].indexOf(segments.beginAlarm) > -1) { alarmed = true; } if (!alarmed) { subBlock.push(lines[counter + subcounter]); } if (lines[counter + subcounter].indexOf(segments.endAlarm) > -1) { alarmed = false; } subcounter++; } else { break; } } counter = counter + subcounter; var b = processBlock(subBlock); if (Array.isArray(b)) { logger.error('!returned an array...'); } else { if (b.dtstart !== null) { workingBlock.push(b); } } } } logger.info('- processICAL'); // If (workingBlock.dtstart == null) return {}; return workingBlock; } module.exports = { calendars: ['https://calendar.google.com/calendar/ical/martind2000%40gmail.com/private-40cfebc9f7dcfa7fde6b9bf2f0092c93/basic.ics', 'https://calendar.google.com/calendar/ical/mt5pgdhknvgoc8usfnrso9vkv0%40group.calendar.google.com/private-58876002af9f302a593acfa6fa792dcf/basic.ics', 'https://www.tripit.com/feed/ical/private/DB96E4BB-94A9BD8F9CC1CF51C6CC0D920840F4F5/tripit.ics', 'https://calendar.google.com/calendar/ical/en.uk%23holiday%40group.v.calendar.google.com/public/basic.ics', 'https://calendar.google.com/calendar/ical/i8dglj12p5nuv20sbjmun5s588%40group.calendar.google.com/private-c8adccb41e56d6a2f285078aaed313f5/basic.ics'], jsonBlock: [], getTodaysSimple: function() { 'use strict'; logger.info('+ getTodaysSimple'); var today = { entries: [] }; for (var t = 0; t < this.jsonBlock.length; t++) { if (this.jsonBlock[t].dtstart.isToday()) { today.entries.push(this.jsonBlock[t]); } } logger.info('- getTodaysSimple'); return today; }, getTomorrow: function() { 'use strict'; logger.info('+ getTomorrow'); var today = { entries: [] }; for (var t = 0; t < this.jsonBlock.length; t++) { if (this.jsonBlock[t].dtstart.isTomorrow()) { today.entries.push(this.jsonBlock[t]); } } logger.info('- getTomorrow'); return today; }, getWeek: function() { 'use strict'; logger.info('+ getWeek'); var today = { entries: [] }; var now, twoDays, sevenDays; now = Date.create('today'); // logger.debug(now); twoDays = Date.create(now).addDays(2).beginningOfDay(); // logger.debug(twoDays); sevenDays = Date.create(twoDays).addDays(5).beginningOfDay(); // logger.debug(now, twoDays, sevenDays); for (var t = 0; t < this.jsonBlock.length; t++) { if (this.jsonBlock[t].dtstart.isBetween(twoDays, sevenDays)) { today.entries.push(this.jsonBlock[t]); } } logger.info('- getWeek'); return today; }, getTodaysMeetings: function() { 'use strict'; logger.info('+ getTodaysMeetings'); var today = { previous: [], upcoming: [], current: {} }; var now = new Date(); for (var t = 0; t < this.jsonBlock.length; t++) { if (this.jsonBlock[t].dtstart.isToday()) { if (this.jsonBlock[t].dtstart.isAfter(now)) { today.upcoming.push(this.jsonBlock[t]); } else { today.previous.push(this.jsonBlock[t]); } if (now.isBetween(this.jsonBlock[t].dtstart, this.jsonBlock[t].dtend)) { today.current = this.jsonBlock[t]; } } } // logger.debug(today); logger.info('- getTodaysMeetings'); return today; }, getSimpleCalV2: function(url, cb) { 'use strict'; var self = this; // Var calJson = []; try { request(url, function(err, res, body) { if (err) { logger.error('Get remote Calendar Request failed'); // Callback.call(null, new Error('Request failed')); return; } self.jsonBlock = processICAL(body); // logger.debug(self.jsonBlock); var st = self.getTodaysSimple(); if (typeof cb === 'function') { cb(st); } }, function(error, response, body) { if (response.statusCode !== 200) { logger.error(response.statusCode); logger.error(body); } }); } catch (e) { console.log(e); } }, getSimpleCalV3: function(url) { 'use strict'; var self = this; return new Promise(function(resolve, reject) { try { request(url, function(err, res, body) { if (err) { // logger.error(err); return reject(err); // Throw err; } self.jsonBlock = processICAL(body); // logger.debug(self.jsonBlock); var st = self.getTodaysSimple(); return resolve(st); }, function(error, response, body) { if (response.statusCode !== 200) { logger.error(response.statusCode); logger.error(body); return reject(error); } }); } catch (e) { console.log(e); return reject(e); } }); // Var calJson = []; }, getAdvancedCalV3: function(url) { 'use strict'; var self = this; return new Promise(function(resolve, reject) { try { request(url, function(err, res, body) { if (err) { // logger.error(err); return reject(err); // Throw err; } self.jsonBlock = processICAL(body); // logger.debug(self.jsonBlock); var st = self.getTodaysSimple().entries; var tom = self.getTomorrow().entries; var week = self.getWeek().entries; var obj = {today:st, tomorrow:tom, week:week}; logger.debug(obj); return resolve(obj); }, function(error, response, body) { if (response.statusCode !== 200) { logger.error(response.statusCode); logger.error(body); return reject(error); } }); } catch (e) { console.log(e); return reject(e); } }); // Var calJson = []; } /** * Created by Martin on 16/02/2016. */ };