define([], function () {

    /**
     * Rule class
     * @class Rule
     * @constructor
     */
    var Rule = function (rule) {
        this.model = new Rule.Model(rule);

        this.view = new Rule.View();

        this.model.setView(this.view);
        this.view.setModel(this.model);
    };

    /**
     * @constructor
     * @property {Number} id - rule id
     * @property {String} label - rule label
     * @property {String} name - rule name
     * @property {String|Number} newValue - raw value
     * @property {String} newValueText - text representation of new value
     */
    Rule.Model = function (rule) {

        this.view = null;

        /**
         * Rule id
         * @private
         * @type {Number}
         */
        this.id = null;

        /**
         * Rule label
         * @private
         * @type {String}
         */
        this.label = null;

        /**
         * Rule name
         * @private
         * @type {String}
         */
        this.name = null;

        /**
         * Value to assign
         * @private
         * @type {Number|String|Array|Object}
         */
        this.newValue = null;

        /**
         * Text representation of new value
         * @private
         * @type {String}
         */
        this.newValueText = null;

        this.fieldSymName = null;

        this.init(rule);
    };

    Rule.Model.prototype = (function () {
        var setView = function (view) {
            this.view = view;
        };
        /**
         * Set object data
         * @private
         * @memberOf Rule
         * @returns Rule
         * @param data
         */
        var setData = function (data) {
            var self = this;
            setId.call(this, data.id);
            setLabel.call(this, data.label);
            setName.call(this, data.name);
            setNameValue.call(this, data.newValue);
            setNewValueText.call(this, data.newValueText);
            setFieldSymName.call(this, data.fieldSymName);
            return self;
        };
        /**
         * @private
         * @memberOf Rule
         */
        var deleteRule = function (event) {
            var rule = event.data.rule;
            var field = Instance.Fields.collection.getByFieldSymName(rule.model.fieldSymName);
            var ruleIndex = field.model.rules.collection.getIndexByRuleId(rule.model.id);
            field.model.rules.collection.rules.splice(ruleIndex, 1);
            Instance.Fields.view.render();
        };

        /**
         * @private
         * @memberOf Rule
         */
        var editRule = function (event) {
            var rule = event.data.rule;
            xajax_rule_edit(rule.model.id, rule.model.fieldSymName, window.projectId);
        };

        var setId = function (id) {
            this.id = parseInt(id, 10);
        };

        /**
         * Rule id
         * @private
         * @memberOf Rule
         */
        var getId = function () {
            if (_.isNumber(this.id)) {
                return parseInt(this.id, 10);
            } else {
                return NaN;
            }
        };

        var setLabel = function (label) {
            this.label = label;
        };

        /**
         * Rule label
         * @private
         * @memberOf Rule
         */
        var getLabel = function () {
            if (_.isString(this.label)) {
                return this.label;
            } else {
                return '';
            }
        };

        var setName = function (name) {
            this.name = name;
        };

        /**
         * Rule name
         * @private
         * @memberOf Rule
         */
        var getName = function () {
            if (_.isString(this.name)) {
                return this.name;
            } else {
                return '';
            }
        };

        var setNameValue = function (newValue) {
            this.newValue = newValue;
        };

        /**
         * Value to assign
         * @private
         * @memberOf Rule
         */
        var getNewValue = function () {
            return this.newValue;
        };

        var setNewValueText = function (setNewValueText) {
            this.setNewValueText = setNewValueText;
        };

        /**
         * Text representation of new value
         * @private
         * @memberOf Rule
         */
        var getNewValueText = function () {
            return this.newValueText;
        };

        var setFieldSymName = function (fieldSymName) {
            this.fieldSymName = fieldSymName;
        };

        var getFieldSymName = function () {
            return this.fieldSymName;
        };

        return {
            setView: setView,

            /**
             * @public
             * @memberOf Rule
             */
            init: setData,

            /**
             * Rule id
             * @public
             * @memberOf Rule
             */
            id: getId,

            /**
             * Rule label
             * @public
             * @memberOf Rule
             */
            label: getLabel,

            /**
             * Rule name
             * @public
             * @memberOf Rule
             */
            name: getName,

            /**
             * Value to assign
             * @public
             * @memberOf Rule
             */
            newValue: getNewValue,

            /**
             * Text representation of new value
             * @public
             * @memberOf Rule
             */
            newValueText: getNewValueText,

            fieldSymName: getFieldSymName,

            editRule: editRule,

            deleteRule: deleteRule
        };
    })();

    Rule.View = function () {
        this.model = null;
    };

    Rule.View.prototype = (function () {
        var setModel = function (model) {
            this.model = model;
        };
        /**
         * Render the rule
         * @private
         * @memberOf Rule
         * @param {Object} el - jQuery object div for the whole field
         * @returns Rule
         */
        var render = function (el) {
            el.prepend(_.template($('#rule-tmpl').html())(this.model));
            setElement.call(this, el);
            bindElements.call(this);
            return this;
        };

        /**
         * @private
         * @memberOf Rule
         */
        var setElement = function (el) {
            this.el = el.find('tr[data-rule-id=' + this.model.id + ']');
        };

        /**
         * @private
         * @memberOf Rule
         */
        var getElement = function () {
            return this.el;
        };

        /**
         * @private
         * @memberOf Rule
         */
        var bindElements = function () {
            this.el.find('a[name=edit_link]').on('click', {
                rule: this
            }, this.model.editRule);
            this.el.find('a[name=del_link]').on('click', {
                rule: this
            }, this.model.deleteRule);
        };

        return {
            setModel: setModel,
            /**
             * @public
             * @memberOf Rule
             */
            render: render,

            /**
             * @public
             * @memberOf Rule
             */
            el: getElement
        };
    })();

    return Rule;
});