'use strict';

(function() {

// Taken from http://stackoverflow.com/a/1830844/483271
function isNumeric(value) {
  return !isNaN(parseFloat(value)) && isFinite(value);
}

// Normalise expression values, such as the string equivelants of months/days
function normaliseExpressionValue(value) {
  var mappings = {
    'jan': '1',
    'feb': '2',
    'mar': '3',
    'apr': '4',
    'may': '5',
    'jun': '6',
    'jul': '7',
    'aug': '8',
    'sep': '9',
    'oct': '10',
    'nov': '11',
    'dec': '12',
    'sun': '0',
    'mon': '1',
    'tue': '2',
    'wed': '3',
    'thu': '4',
    'fri': '5',
    'sat': '6'
  };

  // If it was found in the mappings object return it
  if (typeof mappings[value.toLowerCase()] !== 'undefined') {
    return mappings[value.toLowerCase()];
  }

  return value;
}

// Used to parse the schedule on view load and update the GUI with those values
function parseSchedule(schedule) {
  // Split the schedule into its 5 parts based on whitespace
  var expression = schedule.split(' ');

  // Loop every value in the expression
  for (var i = 0; i < expression.length; i++) {
    // If the value is '*' we don't need to do anything
    if (expression[i] === '*') {
      continue;
    }

    // Select the panel for this expression
    var panel = Ember.$('#schedule-editor').find('.panel').eq(i);

    // If it's a */n expression
    if (expression[i].substr(0, 2) === '*/' && isNumeric(expression[i].substr(2))) {
      // Show the correct tab
      panel.find('.nav li:eq(1) a').tab('show');

      // Set the value of the expression in the input box
      panel.find('.tab-content .active input[type="number"]').val(expression[i].substr(2));
    }

    // If it's an each selected expression
    // TODO: support range expression e.g 10-15
    else if (isNumeric(expression[i]) || expression[i].split(',').length > 1 || expression[i].split('-').length > 1) {
      var value,
          range,
          selected = [],
          split_by_comma = expression[i].split(',');

      // Show the correct tab
      panel.find('.nav li').last().find('a').tab('show');

      // If it's just a plain number add it to selected array and we're done
      if (isNumeric(expression[i])) {
        selected.push(expression[i]);
      }

      // If it's a group of values then we need to split them up and handle them
      else if (split_by_comma.length > 0) {
        for (var j = 0; j < split_by_comma.length; j++) {
          // If it was a range expresssion convert it to a csv format
          if (split_by_comma[j].split('-').length > 1) {
            range = split_by_comma[j].split('-');

            // Loop every value in the range and add it to the selected array
            for (var pos = parseInt(range[0]); pos <= parseInt(range[1]); pos++) {
              selected.push(pos.toString());
            }
          // If it was just a normal csv expression
          } else {
            selected.push(normaliseExpressionValue(split_by_comma[j]));
          }
        }
      }

      // Loop every value in the selected array and 'check' it
      panel.find('.tab-content .active input[type="checkbox"]').each(function(k, v) {
        // Get the 'value' of the checkbox
        var $this = Ember.$(this);
        value = $this.data('value');

        // Should it be checked?
        if (selected.indexOf(value.toString()) >= 0) {
          $this[0].checked = true;
          $this.closest('label').addClass('active');
        }
      });
    }
  }

  // Finally set the schedule in the schedule input textbox
  updateScheduleInput(schedule);
}

// Helper to set the value of the schedule input textbox when it has been updated
function updateScheduleInput(value) {
  Ember.$('#schedule-input').find('input').val(value);
}

// Called when updates made to the cron GUI, this will update the schedule record
function handleUpdate(self, $this) {
  // Get the schedule
  var schedule = self.get('schedule');

  // The 'id' of the event which we use to defer the type
  // it's either the href with the # stripped off if it's a
  // tab click or the actual id attribute of the element
  var id;

  // If the href exists we can assume it's a tab
  if (typeof $this.attr('href') !== 'undefined') {
    id = $this.attr('href').substr(1);
  } else {
    id = $this.attr('id');

    // If it's a checkbox set the id to it's parents parent
    if ($this.attr('type') === 'checkbox') {
      id = $this.closest('.tab-pane').attr('id');
    }

    // If it's a every-n-value then strip off the -value
    else if (id.substr(-6) === '-value') {
      id = id.substr(0, id.length - 6);
    }
  }

  // Define the types of schedules we are searching for
  var every_n = ['every-minute', 'every-hour', 'every-day-of-the-month', 'every-month', 'every-day-of-the-week'];
  var every_n_type = ['every-n-minutes', 'every-n-hours'];

  // Define the key/value vars used when the change to the schedule is set
  var key, value = '';

  // Is it an 'every n' i.e *
  if (every_n.indexOf(id) >= 0) {
    // Transform the id into a key for the schedule, replace - with _
    key = id.substr(6).split('-').join('_');
    value = '*';
  }

  // Is it any 'every n type' i.e */n
  else if (every_n_type.indexOf(id) >= 0) {
    // Transform the id into a key for the schedule, replace - with _ and strip the trailing s
    key = id.substr(8, (id.length - 1) - 8).split('-').join('_');

    // Set the value using the value of the input
    value = '*/' + Ember.$('#' + id + '-value').val();
  }

  // Otherwise we can assume it's a each selected type
  else {
    // Transform the id into a key for the schedule, removing the every-selected-
    // and replace- with _
    key = id.substr(14).split('-').join('_');

    // Loop every checkbox
    Ember.$('#' + id).find('input[type="checkbox"]').each(function(k, v) {
      // If the checkbox is checked add the value
      if (v.checked === true) {
        value += Ember.$(this).data('value') + ',';
      }
    });

    // If no value has been set i.e no checkboxes are ticked, default to *
    if (value.length === 0) {
      value = '*';
    // Otherwise we need to remove the trailing ,
    } else {
      if (value.substr(-1) === ',') {
        value = value.substr(0, value.length - 1);
      }
    }
  }

  // Update the schedule
  console.log('setting', key, value);
  schedule.set(key, value);

  // Update the schedule input text box
  updateScheduleInput(schedule.get('formatted'));
}

Minicron.ScheduleEditorComponent = Ember.Component.extend({
  didInsertElement: function() {
    this.store = this.get('targetObject.store');
    var self = this;

    // Do we already have the schedule id? i.e we are editing a schedule
    if (this.get('schedule_id')) {
      // Look up the schedule
      this.store.find('schedule', this.get('schedule_id')).then(function(schedule) {
        self.set('schedule', schedule);

        // Parse the schedule and display it in the GUI
        parseSchedule(self.get('schedule.formatted'));
      });
    // If not we must be adding a new schedule
    } else {
      // Create a default schedule record
      this.set('schedule', this.store.createRecord('schedule', {
        minute: '*',
        hour: '*',
        day_of_the_month: '*',
        month: '*',
        day_of_the_week: '*'
      }));

      // Parse the schedule and display it in the GUI
      parseSchedule(this.get('schedule.formatted'));
    }

    // Update our reference to 'this' so we can pass it to the update handlers
    self = this;

    // Handle when one of the tabs or labels (checkboxes) is clicked in readonly mode
    Ember.$('#schedule-editor').find('a[data-toggle="tab"], .btn-group > label').on('click', function(e) {
      var $this = Ember.$(this);

      if (self.get('read_only')) {
        e.preventDefault();

        // Is it a label (checkbox)? Then we want to stop the click event bubbling
        // up the DOM so the label doesn't get highlighted
        if ($this[0].nodeName === 'LABEL') {
          return false;
        }
      } else {
        // Only handle the update if it isn't a label (checkbox)
        if ($this[0].nodeName !== 'LABEL') {
          handleUpdate(self, $this);
        }
      }
    });

    // Handle when one of the 'every n x' is inputs is changed
    Ember.$('#schedule-editor').find('input[type="number"], input[type="checkbox"]').on('change', function(e) {
      if (self.get('read_only')) {
        e.preventDefault();
        return false;
      } else {
        handleUpdate(self, Ember.$(this));
      }
    });
  },
  actions: {
    save: function() {
      this.sendAction('save', {
        job_id: this.get('job_id'),
        schedule: this.get('schedule')
      });
    },
    cancel: function(schedule) {
      this.sendAction('cancel', this.get('job_id'));
    }
  }
});

})();