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 blocks=[];
      var now = new Date();
      var day = now.getDate();
      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 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;
            }

      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 = '<em>' + workBlock.timeStart + '</em> - ';
      workBlock.long = '<em>' + workBlock.dtstart.format('{Weekday}') +', ' + workBlock.timeStart + '</em> - ';
    }
    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.
   */
};