Source: picasso.js

/* Picasso
 * A Framework to build dinamic forms using MVC
 * Build date: Sun, 11 Oct 2015 03:00:09 GMT
 * @author Rubens Pinheiro Gonçalves Cavalcante
 * @version 0.9.4
 * @license GPL-3.0
 */

/**
 * Main namespace
 * @namespace
 */
var Picasso = Picasso || {};

/**
 * @alias Picasso
 */
var P = P || Picasso;

// -- Namespace virtual comments -- //

/**
 * Declares the plain javascript object constructors
 * @namespace {Object} Picasso.pjo
 */

/**
 * All the system core objects
 * @namespace {Object} Picasso.core
 */

/**
 * All the system errors objects
 * @namespace {Object} Picasso.error
 */

/**
 * All the utils modules
 * @namespace {Object} Picasso.utils
 */

/**
 * Reunites functions to augment Picasso functionality
 * @namespace {Object} Picasso.extend
 */

/**
 * The dynamic form builder namespace
 * @namespace {Object} Picasso.form
 */

/**
 * All the field constructors are stores here
 * @namespace {Object} Picasso.form.field
 */

// -- End of load virtual comments -- //

/**
 * Shows the information about the framework
 * @type {{author: string, version: string, build: string, license: string}}
 */
Picasso.info = {
    author: "%author%",
    version: "%version%",
    build: "%buildDate%",
    license: "%license%"
};
/**
 * Declares or loads already declared module/namespace
 * @example
 * // Declaring
 * Picasso.load("utils.array");
 * // Using
 * var arrayUtils = Picasso.load("utils.array");
 *
 * @param {string} namespace The module complete namespace
 * @return {Object} The loaded module
 */
Picasso.load = function (namespace) {
    var parts = namespace.split('.');
    var currentObj = Picasso;

    // strip redundant leading global
    if (parts[0] === "Picasso") {
        parts = parts.slice(1);
    }

    for (var i = 0; i < parts.length; i++) {
        if (typeof currentObj[parts[i]] === "undefined") {
            currentObj[parts[i]] = {};
        }
        currentObj = currentObj[parts[i]];

    }
    return currentObj;
};


Picasso.load("loadField");
/**
 * Loads a field of the given type
 * @param {Picasso.pjo.Field} field
 * @returns {Picasso.form.field.PicassoField}
 */
Picasso.loadField = function (field) {
    var fieldFactory = new Picasso.form.FieldFactory();
    try {
        return fieldFactory.create(field);
    }
    catch (e) {
        var log = Picasso.load("utils.log");
        log.error(e.message);
        return null;
    }
};
Picasso.load("extend");

/**
 * Adds a extra field to the Picasso form
 * @param {string} fieldName The name to access this type of field
 * @param {function} Field Constructor of the field
 * @throws {Picasso.error.InvalidParameters}
 */
Picasso.extend.field = function (fieldName, Field) {
    var objUtil = Picasso.load("utils.object");
    var log = Picasso.load("utils.log");

    if (typeof Field == "function") {
        if (!objUtil.isEmpty(Field.prototype)) {
            log.warn("Overriding the field prototype from given constructor", Field);
        }

        Field.prototype = new Picasso.form.field.PicassoField;

        if (Picasso.form.FieldFactory.constructors.hasOwnProperty(fieldName)) {
            log.warn("Overriding a already registered Picasso field " + fieldName);
        }

        Picasso.form.FieldFactory.constructors[fieldName] = Field;
    }

    else {
        throw new Picasso.error.InvalidParameters("Picasso.extend.field", {Field: "Invalid constructor"}, this);
    }
};

/**
 * Adds a extra validator to the Picasso fields
 * @param {string} fieldName
 * @param {function} validator
 * @throws {Picasso.error.InvalidParameters}
 */
Picasso.extend.validator = function (fieldName, validator) {
    var objUtil = Picasso.load("utils.object");
    var log = Picasso.load("utils.log");

    if (typeof validator == "function") {
        if (Picasso.form.validators.hasOwnProperty(fieldName)) {
            log.warn("Overriding a already registered Picasso field validator " + fieldName);
        }

        Picasso.form.validators[fieldName] = validator;
    }

    else {
        throw new Picasso.error.InvalidParameters("Picasso.extend.validator", {validator: "Invalid function"}, this);
    }
};
Picasso.load("pjo.Event");

/**
 * The default event object
 * @param {string} name
 * @param {*} data
 * @param {Object} target
 * @constructor
 */
Picasso.pjo.Event = function PicassoEvent(name, data, target) {
    /** @type String */
    this.name = name || "any";

    /** @type * */
    this.data = data || null;

    /** @type Object */
    this.target = target || null;
};
Picasso.load("pjo.EventHandler");

/**
 * Default event handler
 * @param {string} eventName
 * @param {Function|String} callback
 * @param {Object} context
 * @constructor
 */
Picasso.pjo.EventHandler = function (eventName, callback, context) {
    /** @type String */
    this.eventName = eventName || "";

    /** @type Function */
    this.callback = callback || new Function();

    /** @type Object */
    this.context = context || null;
};
Picasso.load("pjo.Column");

/**
 * An form fieldset
 * @constructor
 */
Picasso.pjo.Column = function(){
    /** @type {string|number} */
    this.id = null;

    /** @type {number} */
    this.index = 0;

    /** @type {Picasso.pjo.Column.colSize} */
    this.colXSize = 3;

    /** @type {Picasso.pjo.Field[]} */
    this.fields = [];
};

/**
 * The size of the grid columns
 * @enum {string}
 * @readonly
 */
Picasso.pjo.Column.colSize = {
    SMALL: 2,
    MEDIUM: 3,
    LARGE: 4
};
Picasso.load("pjo.Field");

/**
 * A form field
 * @constructor
 */
Picasso.pjo.Field = function(){
    /** @type {string|number} */
    this.id = null;

    /** @type {string} */
    this.label = "";

    /** @type {Picasso.pjo.Field.type} */
    this.type = null;

    /** @type {boolean} */
    this.required = false;

    /** @type {boolean} */
    this.formIgnore = false;

    /** @type {*} */
    this.value = null;

    /**
     * The field attributes
     * @type {{name: string}}
     */
    this.attrs = {
        name: ""
    };
};

/**
 * Available default field types
 * @readonly
 * @enum {string}
 */
Picasso.pjo.Field.type = {
    TEXT: "text",
    TEXTAREA: "textarea",
    NUMBER: "number",
    EMAIL: "email",
    PASSWORD: "password",
    SUBMIT: "submit",
    CANCEL: "cancel"
};
Picasso.load("pjo.Form");

/**
 * A form object representation
 * @constructor
 */
Picasso.pjo.Form = function(){
     /** @type {string|number} */
    this.id = null;

    /**
     * The form attributes
     * @type {{action: string, method: string, name: string}}
     */
    this.attrs = {
        action: "",
        method: "",
        name: ""
    };

    /** @type {Picasso.pjo.Grid} */
    this.grid = null;
};
Picasso.load("pjo.Grid");

Picasso.pjo.Grid = function(){
    /** @type {string|number} */
    this.id = null;

    /** @type {string} */
    this.legend = null;

    /**
     * The element attributes
     * @type {{name: string}}
     */
    this.attrs = {};

    /** @type {Picasso.pjo.Column[]} */
    this.columns = [];
};
Picasso.load("pjo.Validation");

/**
 * A validation object
 * @constructor
 */
Picasso.pjo.Validation = function () {

    /** @type {Picasso.form.field.PicassoField} */
    this.field = null;

    /** @type {string[]} */
    this.errorMessages = [];

    /**0@type {boolean} */
    this.valid = false;

};
Picasso.load("error.InvalidFieldType");

/**
 * Invalid field type used
 * @param {string} fieldType
 * @constructor
 * @extends Error
 */
Picasso.error.InvalidFieldType = function(fieldType){
    this.name = "InvalidFieldType";
    this.message = "Can't find a constructor. Invalid field type " + String(fieldType);
};

Picasso.error.InvalidFieldType.prototype = Error.prototype;
Picasso.error.InvalidFieldType.constructor = Picasso.error.InvalidFieldType;
Picasso.load("error.InvalidParameters");

/**
 * Invalid parameters error
 * @param {string} funcName The name of the function that are throwing this error
 * @param {Object<string, String>} errorParameters A map of parameter/error message type
 * @param {Object} context The context that the error occurred
 * @extends {Error}
 * @constructor
 */
Picasso.error.InvalidParameters = function (funcName, errorParameters, context) {

    this.name = "InvalidParameters";

    this.message = "The function " + funcName + " has received invalid parameters\n";
    var template = "\tparameter %param%: %dependence%;\n";

    for(var i in errorParameters){
        if(errorParameters.hasOwnProperty(i)){
            this.message += template.replace("%param%", i).replace("%dependence%", errorParameters[i]);
        }
    }

    this.errorParameters = errorParameters || null;
    this.context = context || null;
};

Picasso.error.InvalidParameters.prototype = Error.prototype;
Picasso.error.InvalidParameters.constructor = Picasso.error.InvalidParameters;
Picasso.load("error.NotImplementedError");

/**
 * Invalid field type used
 * @param {string} constructor
 * @param {string} method
 * @constructor
 * @extends Error
 */
Picasso.error.NotImplementedError = function(constructor, method){
    this.name = "NotImplementedError";
    this.message = constructor + " object child must implement the " +  method + " method";
};

Picasso.error.NotImplementedError.prototype = Error.prototype;
Picasso.error.NotImplementedError.constructor = Picasso.error.NotImplementedError;

Picasso.load("utils.array");
Picasso.utils.array = (

    /**
     * A set of array utils
     * @exports utils/array
     */
    function () {
        /**
         * Finds a element into the array
         * @param {Array} arr A array to search into
         * @param {*} element The element to find
         * @return {boolean} If the element was found
         * @public
         */
        var find = function (arr, element) {
            /**
             * Object utils
             * @type module:utils/object
             * @private
             */
            var objUtil = Picasso.load("Picasso.utils.object");

            for (var i = 0; i < arr.length; i++) {
                if (typeof arr[i] == 'object' && typeof element == 'object') {
                    if (objUtil.equals(arr[i], element)) {
                        return true;
                    }
                }
                else {
                    if (arr[i] === element) {
                        return true;
                    }
                }
            }

            return false;
        };

        /**
         * Compares two arrays and verify if their are equals
         * @param {Array} arr1 First array
         * @param {Array} arr2 Second array
         * @return {boolean} If they are equals
         * @public
         */
        var equals = function (arr1, arr2) {
            if (arr1.length != arr2.length) return false;

            for (var i = 0; i < arr2.length; i++) {
                if (!find(arr1, arr2[i])) {
                    return false;
                }
            }

            return true;
        };

        /**
         * 'For each' callback
         * @callback module:utils/array.eachCallback
         * @param {*} element Current element of the iteration
         * @param {number} index The current index
         */

        /**
         * Iterates over a array, executing a callback
         * to each element
         * @param {Array} arr
         * @param {module:utils/array.eachCallback} call
         * @public
         */
        var each = function (arr, call) {
            if(typeof arr === "undefined"){
                return;
            }

            var i, l;

            l = arr.length;
            for (i = 0; i < l; i++) {
                call(arr[i], i);
            }
        };

        // Public API
        return {
            find: find,
            equals: equals,
            each: each
        }

    }()
);
Picasso.load("utils.html");
Picasso.utils.html = (

/**
 * HTML and DOM utils
 * @exports utils/html
 */
    function () {

        /**
         * Set the given elements to the HTML object
         * @param {HTMLElement} element
         * @param {Object} attrs
         * @public
         */
        var setAttributes = function (element, attrs) {
            for (var attr in attrs) {
                if (attrs.hasOwnProperty(attr)) {
                    element.setAttribute(attr, attrs[attr]);
                }
            }
        };

        /**
         * Add a class to a element
         * @param {HTMLElement} element An HTML element to add the classes
         * @param {string} _class One or more classes separated by space
         */
        var addClass = function (element, _class) {
            var classes = element.classList;
            var toAppend, i;

            if (_class.indexOf(' ') != -1) {
                toAppend = _class.split(' ');
            }
            else {
                toAppend = [_class]
            }

            for (i = 0; i < toAppend.length; i++) {
                if (!classes.contains(toAppend[i])) {
                    classes.add(toAppend[i]);
                }
            }
        };

        /**
         * Remove a class of a element
         * @param {HTMLElement} element
         * @param {string} _class
         */
        var removeClass = function (element, _class) {
            var classes = element.classList;
            var toRemove, i;

            if (_class.indexOf(' ') != -1) {
                toRemove = _class.split(' ');
            }
            else {
                toRemove = [_class]
            }

            for (i = 0; i < toRemove.length; i++) {
                if (!classes.contains(toRemove[i])) {
                    classes.remove(toRemove[i]);
                }
            }
        };

        // Public API
        return {
            setAttributes: setAttributes,
            addClass: addClass,
            removeClass: removeClass
        };
    }()
    );


Picasso.load("utils.log");

Picasso.utils.log = (
/**
 * Defines a set of functions to log messages
 * @exports utils/log
 */
    function () {
        /**
         * The log levels
         * @enum {string}
         */
        var lvs = {
            ERROR: "error",
            WARN: "warn",
            INFO: "info",
            DISABLED: "disabled"
        };

        var currentLevel = lvs.DISABLED;

        /**
         * Shows info in the console
         * @param {string} msg
         * @param {object} context
         */
        var info = function (msg, context) {
            if (currentLevel == lvs.INFO) {
                context = context || "(no context informed)";
                console.info(msg, context);
            }
        };

        /**
         * Warning in the console
         * @param {string} msg
         * @param {object} context
         */
        var warn = function (msg, context) {
            if (currentLevel == lvs.INFO || currentLevel == lvs.WARN) {
                context = context || "(no context informed)";
                console.warn(msg, context);
            }
        };

        /**
         * Error in the console
         * @param {string} msg
         * @param {object} context
         */
        var error = function (msg, context) {
            if (currentLevel == lvs.INFO || currentLevel == lvs.WARN || currentLevel == lvs.ERROR) {
                context = context || "(no context informed)";
                console.error(msg, context);
            }
        };

        /**
         * Sets the level of the logger
         * @param {lvs} level
         */
        var setLogLevel = function(level){
            currentLevel = level;
        };

        /**
         * Get the log level
         * @return {lvs}
         */
        var getLogLevel = function(){
            return currentLevel;
        };

        return {
            lvs: lvs,
            info: info,
            warn: warn,
            error: error,
            setLogLevel: setLogLevel,
            getLogLevel: getLogLevel
        };
    }());

Picasso.load("utils.object");
Picasso.utils.object = (
/**
 * A set of object utils
 * @exports utils/object
 */
    function () {

        /**
         * Transforms a string delimited by "-"
         * to a camel case notation
         * @param {string} property
         * @returns {string}
         * @private
         */
        var _toCamelCase = function (property) {
            return property.toLowerCase().replace(/-(.)/g, function (match, g1) {
                return g1.toUpperCase();
            });
        };

        /**
         * Extends a constructor
         * @param {Function} Class The object constructor
         * @param {Function} Parent The parent object constructor
         * @returns {Function} The Class constructor
         */
        var extend = function (Class, Parent) {
            //Rent a prototype
            var Rented = new Function();
            Rented.prototype = Parent.prototype;
            Class.prototype = new Rented();
            Class._super = Parent.prototype;
            Class.prototype.constructor = Class;

            return Class;
        };


        /**
         * 'For each' callback
         * @callback utils/object.eachCallback
         * @param {*} value
         * @param {string} property
         */

        /**
         * Iterates over a object properties
         * @param {Object} obj
         * @param {module:utils/object.eachCallback} call
         */
        var each = function (obj, call) {
            if (obj instanceof Object) {
                var property;
                for (property in obj) {
                    if (obj.hasOwnProperty(property)) {
                        call(obj[property], property);
                    }
                }
            }
        };

        /**
         * Compares two objects and
         * verify if they are equals
         * @param {Object} obj1
         * @param {Object} obj2
         * @return {Boolean}
         * @public
         */
        var equals = function (obj1, obj2) {
            var path;
            for (path in obj1) {
                if (typeof(obj2[path]) == 'undefined') {
                    return false;
                }
            }

            for (path in obj1) {
                if (obj1[path]) {
                    switch (typeof(obj1[path])) {
                        case 'object':
                            if (!obj1[path].equals(obj2[path])) {
                                return false;
                            }
                            break;
                        case 'function':
                            if (typeof(obj2[path]) == 'undefined' ||
                                (path != 'equals' && obj1[path].toString() != obj2[path].toString())
                                ) {
                                return false;
                            }
                            break;
                        default:
                            if (obj1[path] != obj2[path]) {
                                return false;
                            }
                    }
                }
                else {
                    if (obj2[path]) {
                        return false;
                    }
                }
            }

            for (path in obj2) {
                if (typeof(obj1[path]) == 'undefined') {
                    return false;
                }
            }

            return true;
        };

        /**
         * Converts the given object to the strict properties of
         * the plain object constructor
         * @param {Object} obj
         * @param {Object.constructor} plainObjectConstructor
         */
        var deserialize = function (obj, plainObjectConstructor) {
            var pjo = new plainObjectConstructor();
            var formattedObj = {};

            for (var i in obj) {
                if (obj.hasOwnProperty(i)) {
                    if (i.indexOf("-") != -1) {
                        formattedObj[_toCamelCase(i)] = obj[i];
                    }
                    else {
                        formattedObj[i] = obj[i];
                    }
                }
            }

            for (var property in pjo) {
                if (pjo.hasOwnProperty(property) && formattedObj.hasOwnProperty(property)) {
                    pjo[property] = formattedObj[property];
                }
            }

            return pjo;
        };

        /**
         * Tests if a object is empty
         * @param {Object} obj
         * @returns {boolean}
         */
        var isEmpty = function(obj){
            for(var key in obj){
                if(obj.hasOwnProperty(key)){
                    return false;
                }
            }

            return true;
        };

        // Public API
        return {
            extend: extend,
            equals: equals,
            each: each,
            deserialize: deserialize,
            isEmpty: isEmpty
        }
    }()
    );
Picasso.load("core.Sequence");
Picasso.core.Sequence = (function () {
    /**
     * Stores all the sequences
     * @type {Object<string, number>}
     * @private
     * @static
     */
    var _registeredEntities = {};

    /**
     * Validates and if necessary starts a new sequence
     * based on the given entity name
     * @param {string} entityName The entity name
     * @return {boolean}
     * @private
     * @static
     */
    var _validateAndStartSequence = function (entityName) {
        if (typeof entityName == "undefined" || typeof entityName != "string") {
            return false;
        }

        if (!_registeredEntities.hasOwnProperty(entityName)) {
            _registeredEntities[entityName] = null;
        }

        return true;
    };

    /**
     * Controls a sequence of the given entity. </br>
     * Take note that this is the real Sequence constructor.
     *
     * @param {string} entity The entity name
     * @constructor
     * @alias Picasso.core.Sequence
     * @example
     * var userSeq = new Picasso.core.Sequence("User");
     * var secUserSeq = new Picasso.core.Sequence("User");
     *
     * secUserSeq.currentVal(); // returns 0
     * userSeq.nextVal(); // returns 1
     * secUserSeq.currentVal(); // returns 1
     */
    var SeqConstructor = function (entity) {
        this._entity = entity;
    };


    /**
     * View the sequence current value
     * @return {?number} The current sequence value or null
     * to a invalid entity name
     * @public
     */
    SeqConstructor.prototype.currentVal = function () {
        if (_validateAndStartSequence(this._entity)) {
            return _registeredEntities[this._entity];
        }

        return null;
    };

    /**
     * Get the next val of a sequence and increments it
     * @return {number} The current sequence value
     * @public
     */
    SeqConstructor.prototype.nextVal = function () {
        if (_validateAndStartSequence(this._entity)) {
            if (_registeredEntities[this._entity] == null) {
                _registeredEntities[this._entity] = 0;
                return 0;
            }
            return ++_registeredEntities[this._entity];
        }

        return null;
    };

    return SeqConstructor

}());

Picasso.load("core.Subject");

/**
 * The subject constructor
 * See the observer design pattern
 * @constructor
 */
Picasso.core.Subject = function () {

    /**
     * All the event handlers (Observers) are stored here
     * @type {Object<string, Picasso.pjo.EventHandler[]>}
     */
    var handlers = {};

    /**
     * Visits all the associated handlers to the given event
     * and call it or remove it
     * @param {string} action
     * @param {function} callback
     * @param {Picasso.pjo.Event} event
     * @private
     */
    var _visit = function (action, event, callback) {

        var evListeners = handlers[event.name] || [];
        for (var i = 0; i < evListeners.length; i++) {
            if (action == "fire") {
                var cbk = evListeners[i].callback;
                if(typeof cbk == "string" && evListeners[i].context.hasOwnProperty(cbk)){
                    evListeners[i].context[cbk](event);
                }
                else{
                    evListeners[i].callback.call(evListeners.context, event);
                }
            }
            else if (evListeners[i].callback === callback && (event.context == null || evListeners.context === event.context)) {
                evListeners.splice(i, 1);
            }
        }

    };

    /**
     * Subscribes a new observer
     * @param {string} eventType
     * @param {Function} callback
     * @param {Object} context
     * @throws Picasso.error.InvalidParameters
     * @protected
     */
    this._subscribe = function (eventType, callback, context) {
        if (typeof  eventType == "undefined") {
            throw new Picasso.error.InvalidParameters("_subscribe", {eventType: "obrigatory"}, this._subscribe);
        }

        if (!handlers.hasOwnProperty(eventType)) {
            handlers[eventType] = [];
        }

        var handler = new Picasso.pjo.EventHandler(eventType, callback, context || this);
        handlers[eventType].push(handler);
    };

    /**
     * Removes a observer of a event.
     * If, only the eventType is given, removes all observers of
     * this event type. If callback is given, removes all observers
     * that calls this callback. And finnaly, if context is given too,
     * removes if match the eventType, callback and context.
     * @param {string} eventType
     * @param {Function} callback
     * @param {Object} context
     * @throws {Picasso.error.InvalidParameters}
     * @protected
     */
    this._unsubscribe = function (eventType, callback, context) {
        if (typeof  eventType == "undefined") {
            throw new Picasso.error.InvalidParameters("usubscribe", {eventType: "obrigatory"}, this._unsubscribe);
        }

        if (typeof callback == "undefined" && typeof context == "undefined") {
            delete handlers[eventType];
        }
        else {
            _visit("_unsubscribe", new Picasso.pjo.Event(eventType, [], context), callback);
        }
    };

    /**
     * Fires a event, calling all the observers
     * of this event
     * @param {string} eventType
     * @param {*} eventData
     * @param {Object} context
     * @throws {Picasso.error.InvalidParameters}
     */
    this.fire = function (eventType, eventData, context) {
        if (typeof  eventType == "undefined") {
            throw new Picasso.error.InvalidParameters("fire", {eventType: "String"}, this.fire);
        }

        _visit("fire", new Picasso.pjo.Event(eventType, eventData, context || this));
    }
};

Picasso.load("Collection");

Picasso.Collection = function (ModelConstructor) {
    var Collection = Picasso.utils.object.extend(Picasso.Collection.MetaConstructor, Array);
    var collection = new Collection();
    collection.setCollectionType(ModelConstructor);

    return collection;
};

/**
 * A model collection constructor
 * @extends {Array}
 * @constructor
 */
Picasso.Collection.MetaConstructor = function () {
    /**
     * Sets the type of the collection
     * @param {Picasso.Model} ModelConstructor
     */
    this.setCollectionType = function (ModelConstructor) {
        this.ModelConstructor = ModelConstructor;
    };

    /**
     * Clears the collection
     */
    this.clear = function () {
        for (var i = 0, l = this.length; i < l; i++) {
            this.pop();
        }
    };

    /**
     * Iterates over each element of the collection
     * @param {function} callback
     */
    this.each = function (callback) {
        for (var i = 0, l = this.length; i < l; i++) {
            callback(this[i], i);
        }
    };

    /**
     * Gets a element of the collection
     * @param {number} id
     * @returns {?Picasso.Model}
     */
    this.getElement = function (id) {
        for (var i = 0; i < this.length; i++) {
            if (this[i].id == id) {
                return this[i];
            }
        }
        return null;
    };

    /**
     * Adds a element to the collection
     * @param element
     */
    this.addElement = function (element) {
        var model = new this.ModelConstructor();
        model.update(element);
        this.push(model);
    };

    /**
     * Adds elements to the collection
     * @param elements
     */
    this.addElements = function (elements) {
        for (var i = 0; i < elements.length; i++) {
            this.addElement(elements[i]);
        }
    };

    /**
     * Removes a element from the collection
     * @param {number} id
     * @returns {Picasso.Model}
     */
    this.removeElement = function (id) {
        for (var i = 0; i < this.length; i++) {
            if (this[i].id == id) {
                return this.splice(i, 1);
            }
        }
    };

    /**
     * Update a element from collection
     * @param {Picasso.Model} element
     * @param {string} [property='id']
     */
    this.updateElement = function (element, property) {
        if (!element.hasOwnProperty(property) || typeof property === 'undefined') {
            property = 'id';
        }

        for (var i = 0; i < this.length; i++) {
            if (this[i].hasOwnProperty(property) && element.hasOwnProperty(property)
                && element[property] === this[i][property]) {

                this[i].update(element);
            }
        }
    };
};
Picasso.load("Controller");

/**
 * The picasso Controller entity.
 * To create an application controller use the extend static method
 * @example:
 *      var MyCustomController = Picasso.Controller.extend(function (model, view) {
 *          this.construct(model, view);
 *          // ...
 *      });
 *
 * @param {Picasso.Model} model A model to associate to this controller
 * @param {Picasso.View} view A view to associate to this controller
 * @constructor
 */
Picasso.Controller = function (model, view) {
    /**
     * All the UI action events are stored here
     * @type {Picasso.pjo.EventHandler[]}
     * @private
     */
    this._UIActions = [];

    /**
     * @type {Picasso.Model}
     * @protected
     */
    this._model = null;

    /**
     * @type {Object<string, Picasso.View>}
     * @protected
     */
    this._views = {};

    /**
     * Autowired form validator
     * @type {Picasso.form.Validator}
     * @public
     */
    this.validator = new Picasso.form.Validator();
};

/**
 * Listen all registered UIActions to a view
 * @param {Picasso.View} view
 * @private
 */
Picasso.Controller.prototype._registerUIAction = function (view) {
    var l = this._UIActions.length;
    for (var i = 0; i < l; i++) {
        var evHandler = this._UIActions[i];
        view._subscribe(evHandler.eventName, evHandler.callback);
    }
};

/**
 * The Default Controller constructor
 * @param {Picasso.Model} model
 * @param {...Picasso.View}
 */
Picasso.Controller.prototype.construct = function (model) {
    Picasso.Controller.apply(this, arguments);

    this._model = model;
    var l = arguments.length;
    if (l > 1) {
        for (var i = 1; i < l; i++) {
            if (arguments[i] instanceof Picasso.View) {
                this.registerView(arguments[i]);
                arguments[i].setModel(model);
            }
        }
    }
};

/**
 * Registers a view to this controller
 * @param {Picasso.View} view
 */
Picasso.Controller.prototype.registerView = function (view) {
    view.setModel(this._model);
    this._views[view._seq] = view;
    this._registerUIAction(view);
};

/**
 * Register a uiAction (event) to a controller callback
 * @param {string} uiActionName
 * @param {Function} callback
 */
Picasso.Controller.prototype.listen = function (uiActionName, callback) {
    var uiAcion = new Picasso.pjo.EventHandler(uiActionName, callback, this);
    this._UIActions.push(uiAcion);

    for (var i in this._views) {
        if (this._views.hasOwnProperty(i)) {
            this._views[i]._subscribe(uiActionName, callback);
        }
    }
};

/**
 * Gets the model associated with this controller
 * @return {Picasso.Model|Picasso.Collection}
 */
Picasso.Controller.prototype.getModel = function(){
    return this._model;
};

Picasso.Controller.prototype.setModel = function(model){
    for(var i in this._views){
        if(this._views.hasOwnProperty(i)){
            this._views[i].setModel(model);
        }
    }
};

/**
 * Extends from a Controller
 * @static
 * @param {Function} constructor The constructor to extend
 * @returns {Function} The updated constructor
 */
Picasso.Controller.extend = function (constructor) {
    return Picasso.utils.object.extend(constructor, Picasso.Controller);
};
Picasso.load("Model");

/**
 * The picasso Model entity
 * @constructor
 * @extends Picasso.core,Subject
 */
Picasso.Model = function () {};
Picasso.Model.prototype = new Picasso.core.Subject();

/**
 * Sets a property of the model
 * @param {string} property
 * @param {*} value
 */
Picasso.Model.prototype.set = function (property, value) {
    if (this.hasOwnProperty(property)) {
        if (this[property] instanceof Picasso.Model) {
            this[property].update(value);
        }
        else {
            this[property] = value;
            this.fire("propertyChange", {property: property, value: value});
        }
    }
};

/**
 * Gets a model property value
 * @param {string} property
 * @return {*}
 */
Picasso.Model.prototype.get = function (property) {
    if (this.hasOwnProperty(property)) {
        return this[property];
    }
};

/**
 * Updates the properties of the model
 * @param {Object} plainModel
 */
Picasso.Model.prototype.update = function (plainModel) {
    for (var i in plainModel) {
        if (plainModel.hasOwnProperty(i)) {
            this.set(i, plainModel[i]);
        }
    }
};

/**
 * Returns the plain object of this model with
 * all the values
 * @return {Object}
 */
Picasso.Model.prototype.toPlainObject = function () {
    var pjo = new this.constructor();
    for (var property in pjo) {
        if (pjo.hasOwnProperty(property) && typeof pjo[property] != "function") {
            pjo[property] = this[property];
        }
    }
    return pjo;
};

/**
 * Extends from a Model
 * @static
 * @param {Function} Constructor The constructor to extend
 * @returns {Function} The updated constructor
 */
Picasso.Model.extend = function (Constructor) {
    var metaData = [];
    var sampleModel = new Constructor();

    for (var attr in sampleModel) {
        if (sampleModel.hasOwnProperty(attr)) {
            metaData.push(attr);
        }
    }

    var Model = Picasso.utils.object.extend(Constructor, Picasso.Model);
    for (var i = 0; i < metaData.length; i++) {
        (function (attr) {

            var methodSuffix = attr.charAt(0).toUpperCase() + attr.slice(1);
            Model.prototype['set' + methodSuffix] = function (val) {
                this.set(attr, val);
            };

            Model.prototype['get' + methodSuffix] = function () {
                return this.get(attr);
            };
        }(metaData[i]));
    }

    return Model;
};

Picasso.load("View");

/**
 * The picasso View entity
 * @constructor
 * @extends Picasso.core.Subject
 */
Picasso.View = function () {
    var that = this;

    /**
     * @type {Picasso.Model}
     * @protected
     */
    this._model = null;

    /**
     * The view form
     * @type {Picasso.form.PicassoForm}
     * @private
     */
    this._form = null;

    /**
     * Stores the models events callbacks
     * @type {Object<string, Function>}
     * @protected
     */
    this._modelEvents = {};

    /**
     * The dynamic form builder
     * @type {Picasso.form.Builder}
     * @protected
     */
    this._formBuilder = new Picasso.form.Builder();

    /**
     * The main object of the view
     * @type {HTMLObjectElement}
     * @public
     */
    this.dom = null;

};
Picasso.View.prototype = new Picasso.core.Subject();

/**
 * Default constructor of a view
 * @param {HTMLObjectElement} dom
 */
Picasso.View.prototype.construct = function(dom){
    Picasso.View.apply(this, arguments);
    this.dom = dom || document;
};

/**
 * Set a model to this view
 * @param {Picasso.Model} model
 */
Picasso.View.prototype.setModel = function(model){
    this._model = model;
    for(var i in this._modelEvents){
        if(this._modelEvents.hasOwnProperty(i)){
            this._model._subscribe(i, this._modelEvents[i], this);
        }
    }
};

/**
 * Binds the model properties to the form
 * fields.
 */
Picasso.View.prototype.bindFormData = function(){
    var that = this;
    this._model._subscribe("propertyChange", function(ev) {
        var property = ev.data.property;
        var value = ev.data.value;

        if (that._form != null) {
            var field = that._form.getField(property);
            field.value(value);
        }
    });
};

/**
 * Builds a picasso form object from the given JSON
 * @param {Object} formJSON
 * @returns {Picasso.form.PicassoForm}
 */
Picasso.View.prototype.buildForm = function(formJSON){
    return this._formBuilder.buildForm(formJSON);
};

/**
 * Sets the view form
 * @param {Picasso.form.PicassoForm} pForm
 */
Picasso.View.prototype.setForm = function(pForm){
    this._form = pForm;
};

/**
 * Gets the view form
 * @return {Picasso.form.PicassoForm}
 */
Picasso.View.prototype.getForm = function(){
    return this._form;
};

/**
 * Registers a model event
 * @param {string} eventName
 * @param {Function} method
 */
Picasso.View.prototype.register = function(eventName, method){
    this._modelEvents[eventName] = method;
};

/**
 * Extends from a View
 * @static
 * @param {Function} constructor The constructor to extend
 * @returns {Function} The updated constructor
 */
Picasso.View.extend = function(constructor){
    return Picasso.utils.object.extend(constructor, Picasso.View);
};
Picasso.load("form.validators.text");

/**
 * Default validation for text fields
 * @param {Picasso.form.field.PicassoField} emailField
 * @returns {Picasso.pjo.Validation}
 */
Picasso.form.validators.email = function (emailField) {
    var validation = new Picasso.pjo.Validation();
    validation.field = emailField;

    validation.valid = typeof emailField.value() != "undefined";
    if (!validation.valid && emailField.isRequired()) {
        validation.errorMessages.push("Field value is undefined");
    }

    var emailRegex = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
    if (!emailRegex.test(emailField.value()) && emailField.isRequired()) {
        validation.valid = false;
        validation.errorMessages.push("Field contains a invalid email");
    }

    return validation;
};
Picasso.load("form.validators.hidden");

/**
 * Default validation for hidden fields
 * @param {Picasso.form.field.PicassoField} hiddenField
 * @returns {Picasso.pjo.Validation}
 */
Picasso.form.validators.hidden = function(hiddenField){
    var validation = new Picasso.pjo.Validation();
    validation.valid = true;

    return validation;
};
Picasso.load("form.validators.number");

/**
 * Default validation for number fields
 * @param {Picasso.form.field.PicassoField} numberField
 * @returns {Picasso.pjo.Validation}
 */
Picasso.form.validators.number = function (numberField) {
    var val = numberField.value();
    var validation = new Picasso.pjo.Validation();
    validation.field = numberField;

    validation.valid = !isNaN(Number(val));
    if (!validation.valid) {
        validation.errorMessages.push("Field value is not a number");
    }
};
Picasso.load("form.validators.password");

/**
 * Default validation for password fields
 * @param {Picasso.form.field.PicassoField} passwordField
 * @returns {Picasso.pjo.Validation}
 */
Picasso.form.validators.password = function(passwordField){
    var validation = new Picasso.pjo.Validation();
    validation.field = passwordField;
    validation.valid = typeof passwordField.value() != "undefined";
    if(!validation.valid){
        validation.errorMessages.push("Field value is undefined");
    }

    return validation;
};
Picasso.load("form.validators.text");

/**
 * Default validation for text fields
 * @param {Picasso.form.field.PicassoField} textField
 * @returns {Picasso.pjo.Validation}
 */
Picasso.form.validators.text = function(textField){
    var validation = new Picasso.pjo.Validation();
    validation.field = textField;

    validation.valid = typeof textField.value() != "undefined";
    if(!validation.valid){
        validation.errorMessages.push("Field value is undefined");
    }

    return validation;
};
Picasso.load("form.field.PicassoField");

/**
 * The default field implementation
 * @constructor
 */
Picasso.form.field.PicassoField = function (label, type, required, formIgnore) {
    /**
     * Sequence manager
     * @type {Picasso.core.Sequence}
     */
    var Sequence = Picasso.load("core.Sequence");

    /**
     * The html utils
     * @type {utils/html}
     */
    var htmlUtils = Picasso.load("utils.html");

    /**
     * The id of the field
     * @type {string|number}
     * @protected
     */
    this._id = null;

    /**
     * The html of the field
     * @type {HTMLElement}
     * @protected
     */
    this._element = null;

    /**
     * The field label
     * @type {string}
     * @protected
     */
    this._label = "";

    /**
     * If this field is ignored in
     * a form final value
     * @type {boolean}
     * @protected
     */
    this._formIgnore = false;

    /**
     * The flag to mark this field as required
     * @type {boolean}
     * @protected
     */
    this._required = false;

    /**
     * The type of this field
     * @type {string}
     * @protected
     */
    this._type = "";

    /**
     * Calls a 'post constructor' to this object
     * @param {string} label
     * @param {string} type
     * @param {boolean} required
     * @param {boolean} formIgnore
     * @private
     */
    this.__postConstructor__ = function(label, type, required, formIgnore){
        this._label = label;
        this._type = type;
        this._required = required;
        this._formIgnore = formIgnore;
    };

    /**
     * Builds the field
     * @param {Picasso.pjo.Field} field
     * @abstract
     * @throws {Picasso.error.NotImplementedError}
     */
    this.build = function (field) {
        throw new Picasso.error.NotImplementedError("PicassoField", "build");
    };

    /**
     * Verifies if the field is empty or not
     * @returns {boolean}
     * @abstract
     * @throws {Picasso.error.NotImplementedError}
     */
    this.isEmpty = function () {
        throw new Picasso.error.NotImplementedError("PicassoField", "isEmpty");
    };

    /**
     * Returns or sets the value of a field
     * @param {*} val
     * @abstract
     * @throws {Picasso.error.NotImplementedError}
     */
    this.value = function (val) {
        throw new Picasso.error.NotImplementedError("PicassoField", "value");
    };

    /**
     * Resets the field
     * @abstract
     * @throws {Picasso.error.NotImplementedError}
     */
    this.reset = function () {
        throw new Picasso.error.NotImplementedError("PicassoField", "reset");
    };

    /**
     * Get this field id
     * @returns {string|number}
     */
    this.getId = function () {
        return this._id;
    };

    /**
     * Get the field label
     * @return {string}
     */
    this.getLabel = function(){
        return this._label;
    };

    /**
     * Verify if the field is required
     * @return {boolean}
     */
    this.isRequired = function(){
        return this._required;
    };

    /**
     * Verify if the field is ignored in the form
     * @return {boolean}
     */
    this.isFormIgnored = function(){
        return this._formIgnore;
    };

    /**
     * Get the field type
     * @return {string}
     */
    this.getType = function(){
        return this._type;
    };

    /**
     * Sets this field id, if not is given
     * generates the id based on a sequence
     * @param {string|number} id
     */
    this.setId = function (id) {
        if (id == null || id == "") {
            var entity = this.type || "PicassoField";
            this._id = new Sequence(entity).nextVal();
        }
        else {
            if (this._element != null) {
                this._element.setAttribute("id", String(id));
            }

            this._id = id;
        }
    };

    /**
     * Add one or more classes (separated by space) to the field
     * @param {string} _class
     */
    this.addClass = function (_class) {
        htmlUtils.addClass(this._element, _class);
    };

    /**
     * Removes one or more classes (separated by space) to the field
     * @param {string} _class
     */
    this.removeClass = function (_class) {
        htmlUtils.removeClass(this._element, _class);
    };

    /**
     * Get the HTMLElement of this field
     * @return {HTMLElement}
     */
    this.getHTMLElement = function () {
        return this._element;
    };

    /**
     * Sets the HTMLElement of this field
     * @param {HTMLElement} element
     */
    this.setHTMLElement = function (element) {
        if (element instanceof HTMLElement) {
            this._element = element;
        }
    };

};
Picasso.load("form.field.ButtonField");

/**
 * Default buttons constructor
 * @constructor
 * @extends {Picasso.form.field.PicassoField}
 */
Picasso.form.field.ButtonField = function () {
    /** @type {utils/html} */
    var htmlUtils = Picasso.load("utils.html");

    /**
     * Verify if the button is empty
     * @returns {boolean}
     */
    this.isEmpty = function () {
        return false;
    };

    /**
     * Gets the value of the button
     * @returns {*}
     */
    this.value = function () {
        return this._element.value;
    };

    /**
     * Builds the button field
     * @param {Picasso.pjo.Field} field
     */
    this.build = function (field) {
        this.setId(field.id);

        var buttomElement = document.createElement("button");
        htmlUtils.setAttributes(buttomElement, {
            id: this.getId(),
            type: field.type || "button",
            class: "btn btn-default"
        });

        htmlUtils.setAttributes(buttomElement, field.attrs);
        buttomElement.innerHTML = field.value;
        this.formIgnore = true;

        this.setHTMLElement(buttomElement);
    };
};

Picasso.form.field.ButtonField.prototype = new Picasso.form.field.PicassoField();
Picasso.load("form.field.HiddenField");

/**
 * The default hidden input builder
 * @constructor
 * @extends {Picasso.form.field.PicassoField}
 */
Picasso.form.field.HiddenField = function () {
    /** @type {utils/html} */
    var htmlUtils = Picasso.load("utils.html");


    /**
     * Verify if the input is empty
     * @returns {boolean}
     */
    this.isEmpty = function () {
        return this.value() == "";
    };

    /**
     * Gets/Sets the value of t he input
     * @param {*} val
     * @returns {*}
     */
    this.value = function (val) {
        var el = this._element;
        if (typeof val != "undefined") {
            el.value = val;
        }
        else {
            var res = el.value;
            return res == ""? null : res;
        }
    };

    /**
     * The HTMLElement builder
     * @param {Picasso.pjo.Field} field
     * @return {HTMLElement}
     */
    this.build = function (field) {

        var fieldElement = document.createElement("input");
        htmlUtils.setAttributes(fieldElement, {
            name: field.id || "",
            type: "hidden"
        });

        htmlUtils.setAttributes(fieldElement, field.attrs);
        this.setHTMLElement(fieldElement);
    };
};

Picasso.form.field.HiddenField.prototype = new Picasso.form.field.PicassoField();
Picasso.load("form.field.InputField");

/**
 * The default 'input' builder
 * @constructor
 * @extends {Picasso.form.field.PicassoField}
 */
Picasso.form.field.InputField = function () {
    /** @type {utils/html} */
    var htmlUtils = Picasso.load("utils.html");


    /**
     * Verify if the input is empty
     * @returns {boolean}
     */
    this.isEmpty = function () {
        return this.value() == "";
    };

    /**
     * Gets/Sets the value of the input
     * @param {*} val
     * @returns {*}
     */
    this.value = function (val) {
        var el = this._element.getElementsByTagName("input")[0];
        if (typeof val != "undefined") {
            el.value = val;
        }
        else {
            return el.value;
        }
    };

    /**
     * The HTMLElement builder
     * @param {Picasso.pjo.Field} field
     * @return {HTMLElement}
     */
    this.build = function (field) {

        var formGroup = document.createElement("div");
        formGroup.setAttribute("class", "form-group");

        var fieldElement = document.createElement("input");
        htmlUtils.setAttributes(fieldElement, {
            name: field.id || "",
            type: field.type || "text"
        });

        htmlUtils.setAttributes(fieldElement, field.attrs);
        htmlUtils.addClass(fieldElement, "form-control");

        var labelElement = document.createElement("label");
        labelElement.setAttribute("class", "control-label");
        labelElement.innerHTML = field.label;

        formGroup.appendChild(labelElement);
        formGroup.appendChild(fieldElement);

        this.setHTMLElement(formGroup);
    };
};

Picasso.form.field.InputField.prototype = new Picasso.form.field.PicassoField();
Picasso.load("form.Builder");

/**
 * Translates and builds a form from
 * a object to HTML elements
 * @constructor
 */
Picasso.form.Builder = function () {
    //Load dependencies

    /** @type {utils/array} */
    this.arrayUtils = Picasso.load("utils.array");

    /** @type {utils/html} */
    this.htmlUtils = Picasso.load("utils.html");

    /** @type {utils/object} */
    this.objUtils = Picasso.load("utils.object");

    /**@type {Picasso.form.FieldFactory} */
    this.fieldFactory = new Picasso.form.FieldFactory();
};

/**
 * Translates a columns object into a set of HTML elements
 * @param {Picasso.pjo.Column} col
 * @param {Picasso.form.PicassoForm} pForm
 * @returns {HTMLDivElement}
 */
Picasso.form.Builder.prototype.buildColumn = function (col, pForm) {
    col = this.objUtils.deserialize(col, Picasso.pjo.Column);

    var column = document.createElement("div");
    this.htmlUtils.setAttributes(column, col.attrs);
    column.setAttribute("id", col.id);

    var colSizeClass = "col-xs-";
    colSizeClass += col.colXSize || Picasso.pjo.Column.colSize.MEDIUM;

    this.htmlUtils.addClass(column, "column " + colSizeClass);

    var that = this;
    this.arrayUtils.each(col.fields, function (field) {
        var picassoField = that.fieldFactory.create(field);
        pForm.addField(picassoField);

        column.appendChild(picassoField.getHTMLElement());
    });

    return column;
};

/**
 * Translates a serialized grid into a HTML div
 * @param {Picasso.pjo.Grid} grid
 * @param {Picasso.form.PicassoForm} pForm
 */
Picasso.form.Builder.prototype.buildGrid = function (grid, pForm) {
    grid = this.objUtils.deserialize(grid, Picasso.pjo.Grid);

    var that = this;
    var divElement = document.createElement("div");

    if (grid.legend != null || grid.legend != "") {
        var legend = document.createElement("p");
        legend.innerHTML = grid.legend;
        this.htmlUtils.addClass(legend, "bg-info");
        divElement.appendChild(legend);
    }

    this.htmlUtils.setAttributes(divElement, grid.attrs);
    divElement.setAttribute('id', grid.id);
    this.htmlUtils.addClass(divElement, "grid-block");

    this.arrayUtils.each(grid.columns, function (fieldSet) {
        divElement.appendChild(that.buildColumn(fieldSet, pForm));
    });

    return divElement;
};

/**
 * Translates a serialized form to a HTML form
 * @param {Picasso.pjo.Form} form
 * @returns {Picasso.form.PicassoForm}
 */
Picasso.form.Builder.prototype.buildForm = function (form) {
    form = this.objUtils.deserialize(form, Picasso.pjo.Form);
    var pForm = new Picasso.form.PicassoForm();

    var formElement = document.createElement("form");
    formElement.setAttribute("id", form.id);
    formElement.setAttribute("role", "form");
    formElement.setAttribute("novalidate", "novalidate");

    this.htmlUtils.setAttributes(formElement, form.attrs);

    var that = this;
    this.arrayUtils.each(form.grid, function (block) {
        formElement.appendChild(that.buildGrid(block, pForm));
    });

    pForm.setHTMLElement(formElement);
    return pForm;
};
Picasso.load("form.FieldFactory");

/**
 * A field factory
 * @constructor
 */
Picasso.form.FieldFactory = function () {};

/**
 * All the available field constructors
 * Can be a method name or the function itself
 * @type {Object<string, string|Picasso.form.field.PicassoField.constructor>}
 * @static
 */
Picasso.form.FieldFactory.constructors = (function(){
    return {
        hidden: Picasso.form.field.HiddenField,
        text: Picasso.form.field.InputField,
        textArea: Picasso.form.field.InputField,
        email: Picasso.form.field.InputField,
        password: Picasso.form.field.InputField,

        submit: Picasso.form.field.ButtonField,
        cancel: Picasso.form.field.ButtonField,
        button: Picasso.form.field.ButtonField
    }
})();

/**
 * Sets some picasso attributes to the html field element
 * @param {Picasso.form.field.PicassoField} pField
 * @private
 */
Picasso.form.FieldFactory.prototype._setPicassoAttributes = function (pField) {
    /** @type {utils/html} */
    var htmlUtils = Picasso.load("utils.html");

    if (pField.required) {
        htmlUtils.addClass(pField.getHTMLElement(), "prequired");
    }

    if (pField.formIgnore) {
        htmlUtils.addClass(pField.getHTMLElement(), "pform-ignore");
    }
};

/**
 * Strategy pattern to choose the right
 * field builder method
 * @param {string} fieldType
 * @returns {Picasso.form.field.PicassoField.constructor}
 * @throws {Picasso.error.InvalidFieldType}
 * @private
 */
Picasso.form.FieldFactory.prototype._getFieldConstructorByFieldType = function (fieldType) {
    var constructors = this.constructor.constructors;
    if (constructors.hasOwnProperty(fieldType)) {
        var fieldConstructor = constructors[fieldType];
        if (typeof fieldConstructor === 'string') {
            return this[fieldConstructor];
        }
        else {
            return fieldConstructor;
        }
    }

    throw new Picasso.error.InvalidFieldType(fieldType);
};

/**
 * Builds a field element
 * @param {Picasso.pjo.Field} field
 * @returns {Picasso.form.field.PicassoField} The picasso field object
 */
Picasso.form.FieldFactory.prototype.create = function (field) {
    var objUtils = Picasso.load("utils.object");
    field = objUtils.deserialize(field, Picasso.pjo.Field);

    var FieldConstructor = this._getFieldConstructorByFieldType(field.type);
    var picassoField = new FieldConstructor();
    picassoField.__postConstructor__(field.label, field.type, field.required, field.formIgnore);
    picassoField.build(field);

    if (field.hasOwnProperty("id")) {
        picassoField.setId(field.id);
    }

    if(field.value != null){
        picassoField.value(field.value);
    }

    this._setPicassoAttributes(picassoField);
    return picassoField;
};
Picasso.load("form.PicassoForm");

/**
 * The Picasso representation of a form
 * @constructor
 */
Picasso.form.PicassoForm = function () {

    /**
     * The form fields
     * @type {Object<string, Picasso.form.field.PicassoField>}
     * @private
     */
    var fields = {};

    /**
     * The HTML representation of this object
     * @type {HTMLFormElement}
     * @private
     */
    var element = null;

    /**
     * Describes the valid state of the form
     * @type {boolean}
     */
    this.valid = false;

    /**
     * Adds a field to the form
     * @param {Picasso.form.field.PicassoField} pField
     */
    this.addField = function (pField) {
        fields[pField.getId()] = pField;
    };

    /**
     * Gets the form fields
     * @returns {Picasso.form.field.PicassoField[]}
     */
    this.getFields = function () {
        var res = [];
        for (var i in fields) {
            if (fields.hasOwnProperty(i)) {
                res.push(fields[i]);
            }
        }
        return res;
    };

    /**
     * Gets a field by the Id
     * @param {string} fieldId
     * @return {Picasso.form.field.PicassoField}
     */
    this.getField = function (fieldId) {
        if (fields.hasOwnProperty(fieldId)) {
            return fields[fieldId];
        }
        return null;
    };

    /**
     * Sets the html element
     * @param {HTMLFormElement} htmlForm
     */
    this.setHTMLElement = function (htmlForm) {
        element = htmlForm;
    };

    /**
     * Gets the html element
     * @returns {HTMLFormElement}
     */
    this.getHTMLElement = function () {
        return element;
    };

    /**
     * Gets/Sets the form value
     * @param {Object<string, *>} data
     * returns {Object}
     */
    this.value = function (data) {
        var fields = this.getFields();
        if (typeof data == "undefined") {
            var val = {};

            for (var i = 0; i < fields.length; i++) {
                var id = fields[i].getId();
                if (typeof id != "undefined" && !fields[i].formIgnore) {
                    val[id] = fields[i].value();
                }
            }

            return val;
        } else {
            for (var key in data) {
                if (data.hasOwnProperty(key)) {
                    this.getField(key).value(data[key]);
                }
            }
        }
    };
};

/**
 * A alias to the Picasso Form object constructor
 * @alias {Picasso.form.PicassoForm}
 */
Picasso.Form = Picasso.form.PicassoForm;

Picasso.load("form.Renderer");

/**
 * Manage the render of a dynamic form
 * @param {HTMLElement} container
 * @constructor
 */
Picasso.form.Renderer = function (container) {
    this.container = container;
};

/**
 * Builds and renders the given form
 * @param {Picasso.pjo.Form} form
 */
Picasso.form.Renderer.prototype.render = function(form) {

};
Picasso.load("form.Validator");

/**
 * Validates fields
 * @param {Picasso.form.Form} _form
 * @constructor
 */
Picasso.form.Validator = function (_form) {

    var log = Picasso.load("utils.log");
    var form = _form;

    /**
     * Validates a field
     * @param {Picasso.form.field.PicassoField} pField
     * @returns {Picasso.pjo.Validation}
     */
    this.validate = function (pField) {
        var validation = new Picasso.pjo.Validation();
        validation.field = pField;
        validation.valid = false;

        if (!pField.isRequired() || !pField.isEmpty()) {
            if (Picasso.form.validators.hasOwnProperty(pField.getType())) {
                return Picasso.form.validators[pField.getType()](pField);
            }
            else {
                log.warn("No validator found to the field type " + pField.getType(), pField);
                validation.valid = null;
                return validation;
            }
        }

        validation.errorMessages.push("Field is required");
        return validation;
    };

    /**
     * Validates a entire form, returning the id
     * and the validation value
     * @param {Picasso.form.PicassoForm} pForm
     * @returns {{string: boolean}}
     */
    this.validateForm = function (pForm) {
        var fields = pForm.getFields();
        var validation = {};
        var formValid = true;

        for (var i = 0; i < fields.length; i++) {
            var f = fields[i];
            if (!f.isFormIgnored()) {
                validation[f.getId()] = this.validate(f);

                //If there's no validator registered, the valid property is always null
                if (validation[f.getId()].valid !== null) {
                    formValid = formValid && !!validation[f.getId()].valid;
                }
            }
        }

        pForm.valid = formValid;
        return validation;
    };
};