/***
 * Contains basic SlickGrid editors.
 * @module Editors
 * @namespace Slick
 */

var $ = require("jquery");


// register namespace
$.extend(true, window, {
  "Slick": {
    "Editors": {
      "Text": TextEditor,
      "Integer": IntegerEditor,
      "Date": DateEditor,
      "YesNoSelect": YesNoSelectEditor,
      "Checkbox": CheckboxEditor,
      "PercentComplete": PercentCompleteEditor,
      "LongText": LongTextEditor
    }
  }
});

function TextEditor(args) {
  var $input;
  var defaultValue;
  var scope = this;

  this.init = function () {
    $input = $("<INPUT type=text class='editor-text' />")
        .appendTo(args.container)
        .bind("keydown.nav", function (e) {
          if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
            e.stopImmediatePropagation();
          }
        })
        .focus()
        .select();
  };

  this.destroy = function () {
    $input.remove();
  };

  this.focus = function () {
    $input.focus();
  };

  this.getValue = function () {
    return $input.val();
  };

  this.setValue = function (val) {
    $input.val(val);
  };

  this.loadValue = function (item) {
    defaultValue = item[args.column.field] || "";
    $input.val(defaultValue);
    $input[0].defaultValue = defaultValue;
    $input.select();
  };

  this.serializeValue = function () {
    return $input.val();
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
  };

  this.validate = function () {
    if (args.column.validator) {
      var validationResults = args.column.validator($input.val());
      if (!validationResults.valid) {
        return validationResults;
      }
    }

    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}

function IntegerEditor(args) {
  var $input;
  var defaultValue;
  var scope = this;

  this.init = function () {
    $input = $("<INPUT type=text class='editor-text' />");

    $input.bind("keydown.nav", function (e) {
      if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
        e.stopImmediatePropagation();
      }
    });

    $input.appendTo(args.container);
    $input.focus().select();
  };

  this.destroy = function () {
    $input.remove();
  };

  this.focus = function () {
    $input.focus();
  };

  this.loadValue = function (item) {
    defaultValue = item[args.column.field];
    $input.val(defaultValue);
    $input[0].defaultValue = defaultValue;
    $input.select();
  };

  this.serializeValue = function () {
    return parseInt($input.val(), 10) || 0;
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
  };

  this.validate = function () {
    if (isNaN($input.val())) {
      return {
        valid: false,
        msg: "Please enter a valid integer"
      };
    }

    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}

function DateEditor(args) {
  var $input;
  var defaultValue;
  var scope = this;
  var calendarOpen = false;

  this.init = function () {
    $input = $("<INPUT type=text class='editor-text' />");
    $input.appendTo(args.container);
    $input.focus().select();
    $input.datepicker({
      showOn: "button",
      buttonImageOnly: true,
      buttonImage: "../images/calendar.gif",
      beforeShow: function () {
        calendarOpen = true
      },
      onClose: function () {
        calendarOpen = false
      }
    });
    $input.width($input.width() - 18);
  };

  this.destroy = function () {
    $.datepicker.dpDiv.stop(true, true);
    $input.datepicker("hide");
    $input.datepicker("destroy");
    $input.remove();
  };

  this.show = function () {
    if (calendarOpen) {
      $.datepicker.dpDiv.stop(true, true).show();
    }
  };

  this.hide = function () {
    if (calendarOpen) {
      $.datepicker.dpDiv.stop(true, true).hide();
    }
  };

  this.position = function (position) {
    if (!calendarOpen) {
      return;
    }
    $.datepicker.dpDiv
        .css("top", position.top + 30)
        .css("left", position.left);
  };

  this.focus = function () {
    $input.focus();
  };

  this.loadValue = function (item) {
    defaultValue = item[args.column.field];
    $input.val(defaultValue);
    $input[0].defaultValue = defaultValue;
    $input.select();
  };

  this.serializeValue = function () {
    return $input.val();
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
  };

  this.validate = function () {
    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}

function YesNoSelectEditor(args) {
  var $select;
  var defaultValue;
  var scope = this;

  this.init = function () {
    $select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='yes'>Yes</OPTION><OPTION value='no'>No</OPTION></SELECT>");
    $select.appendTo(args.container);
    $select.focus();
  };

  this.destroy = function () {
    $select.remove();
  };

  this.focus = function () {
    $select.focus();
  };

  this.loadValue = function (item) {
    $select.val((defaultValue = item[args.column.field]) ? "yes" : "no");
    $select.select();
  };

  this.serializeValue = function () {
    return ($select.val() == "yes");
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return ($select.val() != defaultValue);
  };

  this.validate = function () {
    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}

function CheckboxEditor(args) {
  var $select;
  var defaultValue;
  var scope = this;

  this.init = function () {
    $select = $("<INPUT type=checkbox value='true' class='editor-checkbox' hideFocus>");
    $select.appendTo(args.container);
    $select.focus();
  };

  this.destroy = function () {
    $select.remove();
  };

  this.focus = function () {
    $select.focus();
  };

  this.loadValue = function (item) {
    defaultValue = !!item[args.column.field];
    if (defaultValue) {
      $select.prop('checked', true);
    } else {
      $select.prop('checked', false);
    }
  };

  this.serializeValue = function () {
    return $select.prop('checked');
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return (this.serializeValue() !== defaultValue);
  };

  this.validate = function () {
    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}

function PercentCompleteEditor(args) {
  var $input, $picker;
  var defaultValue;
  var scope = this;

  this.init = function () {
    $input = $("<INPUT type=text class='editor-percentcomplete' />");
    $input.width($(args.container).innerWidth() - 25);
    $input.appendTo(args.container);

    $picker = $("<div class='editor-percentcomplete-picker' />").appendTo(args.container);
    $picker.append("<div class='editor-percentcomplete-helper'><div class='editor-percentcomplete-wrapper'><div class='editor-percentcomplete-slider' /><div class='editor-percentcomplete-buttons' /></div></div>");

    $picker.find(".editor-percentcomplete-buttons").append("<button val=0>Not started</button><br/><button val=50>In Progress</button><br/><button val=100>Complete</button>");

    $input.focus().select();

    $picker.find(".editor-percentcomplete-slider").slider({
      orientation: "vertical",
      range: "min",
      value: defaultValue,
      slide: function (event, ui) {
        $input.val(ui.value)
      }
    });

    $picker.find(".editor-percentcomplete-buttons button").bind("click", function (e) {
      $input.val($(this).attr("val"));
      $picker.find(".editor-percentcomplete-slider").slider("value", $(this).attr("val"));
    })
  };

  this.destroy = function () {
    $input.remove();
    $picker.remove();
  };

  this.focus = function () {
    $input.focus();
  };

  this.loadValue = function (item) {
    $input.val(defaultValue = item[args.column.field]);
    $input.select();
  };

  this.serializeValue = function () {
    return parseInt($input.val(), 10) || 0;
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return (!($input.val() == "" && defaultValue == null)) && ((parseInt($input.val(), 10) || 0) != defaultValue);
  };

  this.validate = function () {
    if (isNaN(parseInt($input.val(), 10))) {
      return {
        valid: false,
        msg: "Please enter a valid positive number"
      };
    }

    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}

/*
 * An example of a "detached" editor.
 * The UI is added onto document BODY and .position(), .show() and .hide() are implemented.
 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
 */
function LongTextEditor(args) {
  var $input, $wrapper;
  var defaultValue;
  var scope = this;

  this.init = function () {
    var $container = $("body");

    $wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
        .appendTo($container);

    $input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
        .appendTo($wrapper);

    $("<DIV style='text-align:right'><BUTTON>Save</BUTTON><BUTTON>Cancel</BUTTON></DIV>")
        .appendTo($wrapper);

    $wrapper.find("button:first").bind("click", this.save);
    $wrapper.find("button:last").bind("click", this.cancel);
    $input.bind("keydown", this.handleKeyDown);

    scope.position(args.position);
    $input.focus().select();
  };

  this.handleKeyDown = function (e) {
    if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
      scope.save();
    } else if (e.which == $.ui.keyCode.ESCAPE) {
      e.preventDefault();
      scope.cancel();
    } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
      e.preventDefault();
      args.grid.navigatePrev();
    } else if (e.which == $.ui.keyCode.TAB) {
      e.preventDefault();
      args.grid.navigateNext();
    }
  };

  this.save = function () {
    args.commitChanges();
  };

  this.cancel = function () {
    $input.val(defaultValue);
    args.cancelChanges();
  };

  this.hide = function () {
    $wrapper.hide();
  };

  this.show = function () {
    $wrapper.show();
  };

  this.position = function (position) {
    $wrapper
        .css("top", position.top - 5)
        .css("left", position.left - 5)
  };

  this.destroy = function () {
    $wrapper.remove();
  };

  this.focus = function () {
    $input.focus();
  };

  this.loadValue = function (item) {
    $input.val(defaultValue = item[args.column.field]);
    $input.select();
  };

  this.serializeValue = function () {
    return $input.val();
  };

  this.applyValue = function (item, state) {
    item[args.column.field] = state;
  };

  this.isValueChanged = function () {
    return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
  };

  this.validate = function () {
    return {
      valid: true,
      msg: null
    };
  };

  this.init();
}
