window.MasterPopupsCountdown = (function ($, window, document, undefined) {
  var app = {
    callbacks: [],
    dateParser: /(\s|:|\-|\/|T)/gi,
    units: {}
  };

  //Document ready
  $(function () {
    app.units = {
      seconds: MppCountdown.SECONDS,
      minutes: MppCountdown.MINUTES,
      hours: MppCountdown.HOURS,
      days: MppCountdown.DAYS,
      weeks: MppCountdown.WEEKS,
      months: MppCountdown.MONTHS,
      years: MppCountdown.YEARS,
    };

    // MasterPopupsCountdown.on('finish', function (countdownInstance, endDate) {
    //
    // });

  });

  function CountDown(element, options) {
    var _ = this;
    _.$el = $(element);
    _.timer = null;
    _.timerEnd = false;

    _.defaults = {
      id: 0,
      fillZeros: true,
      labels: ['months', 'weeks', 'days', 'hours', 'minutes', 'seconds'],
      date: new Date().setMonth(new Date().getMonth() + 1),//next month
      dateObj: {
        year: '0000',
        month: '00',
        day: '00',
        hour: '00',
        minute: '00',
        second: '00',
      },
      currDate: {},
      nextDate: {},
      newDate: {},
    }
    _.metadata = _.$el.data('options') || {};
    if( typeof _.metadata === 'string' ){
      try {
        _.metadata = JSON.parse(_.metadata);
      } catch (e) {
        _.metadata = {};
      }
    }
    _.options = $.extend(false, {}, _.defaults, _.metadata, options);
    //console.log('_.options', _.options);

    if( _.options.labels.length > 0 ){
      this.init();
      this.build();
      this.runTimer();
    }

    return this;
  }

  CountDown.prototype = {
    init: function () {
      var _ = this;
      //Initial Dates
      _.options.currDate = _.initialDate(_.options.labels);
      _.options.nextDate = _.initialDate(_.options.labels);
      _.options.newDate = _.initialDate(_.options.labels);
      this.sortLabels();
    },

    sortLabels: function () {
      var _ = this;
      _.options.labels.sort(function(a, b){
        return app.units[b] - app.units[a];
      });
    },

    build: function () {
      var _ = this;
      _.$el.html('');
      _.options.labels.forEach(function (label, index) {
        var curr = _.options.currDate[label];
        var next = _.options.currDate[label];
        _.$el.append('<div class="mpp-time mpp-time-' + label + '">');
        _.$el.find('.mpp-time').last().append('<div class="mpp-count-digit">');
        _.$el.find('.mpp-time').last().append('<span class="mpp-count-label">' + label + '</span>');
        _.$el.find('.mpp-time').last().find('.mpp-count-digit').append('<span class="mpp-count mpp-curr mpp-top">' + curr + '</span>');
        _.$el.find('.mpp-time').last().find('.mpp-count-digit').append('<span class="mpp-count mpp-next mpp-top">' + next + '</span>');
        _.$el.find('.mpp-time').last().find('.mpp-count-digit').append('<span class="mpp-count mpp-next mpp-bottom">' + next + '</span>');
        _.$el.find('.mpp-time').last().find('.mpp-count-digit').append('<span class="mpp-count mpp-curr mpp-bottom">' + curr + '</span>');
      });
    },

    initialDate: function () {
      var _ = this;
      var obj = {};
      _.options.labels.forEach(function (label, index) {
        obj[label] = '';
      });
      return obj;
    },

    extractDate: function (timeObj) {
      var _ = this;
      var obj = {};
      _.options.labels.forEach(function (label, index) {
        obj[label] = timeObj[label];
      });
      return obj;
    },

    diff: function (obj1, obj2) {
      var _ = this;
      var diff = [];
      _.options.labels.forEach(function (key) {
        if (obj1[key] !== obj2[key]) {
          diff.push(key);
        }
      });
      return diff;
    },

    getUnits: function () {
      var _ = this;
      var units = ~MppCountdown.ALL;
      _.options.labels.forEach(function (label, index) {
        units |= +(app.units[label]);
      });
      return units;
    },

    runTimer: function () {
      var _ = this;
      clearInterval(_.timer);
      _.timer = setInterval(function () {
        var start = Date.now();
        var end = _.options.date instanceof Date ? _.options.date : new Date(_.options.date);
        var timerObj = MppCountdown(start, end, _.getUnits());
        _.options.newDate = _.extractDate(timerObj);
        if (JSON.stringify(_.options.newDate) !== JSON.stringify(_.options.nextDate)) {
          _.options.currDate = _.options.nextDate;
          _.options.nextDate = _.options.newDate;

          _.diff(_.options.currDate, _.options.nextDate).forEach(function (label) {
            var $node = _.$el.find('.mpp-time-' + label + ' .mpp-count-digit');
            $node.removeClass('mpp-flip');
            $node.find('.mpp-curr').text(_.parseDigit(_.options.currDate[label]));
            $node.find('.mpp-next').text(_.parseDigit(_.options.nextDate[label]));
            // Esperar un repintado para luego voltear
            setTimeout(function () {
              $node.addClass('mpp-flip');
            }, 50);
          });
        }
        //Timer end!
        if (timerObj.value < 0) {
          clearInterval(_.timer);
          _.onEndCountdown(timerObj.end);
        }
      }, 100);
    },

    parseDigit: function (digit) {
      var _ = this;
      if( _.options.fillZeros && digit < 10 ){
        return '0' + digit.toString();
      }
      return digit;
    },

    onEndCountdown: function (endDate) {
      var _ = this;
      if( _.timerEnd ){
        return;
      }
      _.timerEnd = true;
      _.$el.find('.mpp-count').text(_.options.fillZeros ? '00': '0');
      app.callEvents('finish', this, endDate);
    },

    callFunction: function (event, callback, timerObj) {
      var _ = this;
      if ($.isFunction(callback)) {
        callback.call(_, timerObj.end);
      }
      app.callEvents(event, _, timerObj.end);
    },
  }

  app.on = function (event_name, callback) {
    app.callbacks.push({
      name: event_name,
      callback: callback,
    });
  }

  app.callEvents = function (event_name, countdownInstance, endDate) {
    app.callbacks.map(function (obj) {
      if (obj.name === event_name && typeof obj.callback === 'function') {
        obj.callback.call(this, countdownInstance, endDate);
      }
    });
  }

  $.fn.MasterPopupsCountdown = function (options) {
    return this.each(function () {
      $(this).data('MasterPopupsCountdown', new CountDown(this, options));
    });
  };

  return app;

})(jQuery, window, document);












