/**
 * A DataItem is a container for {@link Ext.dataview.DataView} with useComponents: true. It ties together
 * {@link Ext.data.Model records} to its contained Components via a {@link #dataMap dataMap} configuration.
 *
 * For example, lets say you have a `text` configuration which, when applied, gets turned into an instance of an
 * Ext.Component. We want to update the {@link #html} of a sub-component when the 'text' field of the record gets
 * changed.
 *
 * As you can see below, it is simply a matter of setting the key of the object to be the getter of the config
 * (getText), and then give that property a value of an object, which then has 'setHtml' (the html setter) as the key,
 * and 'text' (the field name) as the value. You can continue this for a as many sub-components as you wish.
 *
 *     dataMap: {
 *         // When the record is updated, get the text configuration, and
 *         // call {@link #setHtml} with the 'text' field of the record.
 *         getText: {
 *             setHtml: 'text'
 *         },
 *
 *         // When the record is updated, get the userName configuration, and
 *         // call {@link #setHtml} with the 'from_user' field of the record.
 *         getUserName: {
 *             setHtml: 'from_user'
 *         },
 *
 *         // When the record is updated, get the avatar configuration, and
 *         // call `setSrc` with the 'profile_image_url' field of the record.
 *         getAvatar: {
 *             setSrc: 'profile_image_url'
 *         }
 *     }
 */

Ext.define('Ext.dataview.component.DataItem', {
    extend: 'Ext.Container',
    xtype : 'dataitem',

    config: {
        baseCls: Ext.baseCSSPrefix + 'data-item',

        defaultType: 'component',

        /**
         * @cfg {Ext.data.Model} record The model instance of this DataItem. It is controlled by the Component DataView.
         * @accessor
         */
        record: null,

        /**
         * @cfg {String} itemCls
         * An additional CSS class to apply to items within the DataView.
         * @accessor
         */
        itemCls: null,

        /**
         * @cfg dataMap
         * The dataMap allows you to map {@link #record} fields to specific configurations in this component.
         *
         * For example, lets say you have a `text` configuration which, when applied, gets turned into an instance of an Ext.Component.
         * We want to update the {@link #html} of this component when the 'text' field of the record gets changed.
         * For example:
         *
         *      dataMap: {
         *          getText: {
         *              setHtml: 'text'
         *          }
         *      }
         *
         * In this example, it is simply a matter of setting the key of the object to be the getter of the config (`getText`), and then give that
         * property a value of an object, which then has `setHtml` (the html setter) as the key, and `text` (the field name) as the value.
         */
        dataMap: {},

        /*
         * @private dataview
         */
        dataview: null,

        width: '100%',

        items: [{
            xtype: 'component'
        }]
    },

    updateBaseCls: function(newBaseCls, oldBaseCls) {
        var me = this;

        me.callParent(arguments);
    },

    updateItemCls: function(newCls, oldCls) {
        if (oldCls) {
            this.removeCls(oldCls);
        }
        if (newCls) {
            this.addCls(newCls);
        }
    },

    doMapData: function(dataMap, data, item) {
        var componentName, component, setterMap, setterName;

        for (componentName in dataMap) {
            setterMap = dataMap[componentName];
            component = this[componentName]();
            if (component) {
                for (setterName in setterMap) {
                    if (data && component[setterName] && data[setterMap[setterName]] !== undefined && data[setterMap[setterName]] !== null) {
                        component[setterName](data[setterMap[setterName]]);
                    }
                }
            }
        }

        if (item) {
            // Bypassing setter because sometimes we pass the same object (different properties)
            item.updateData(data);
        }
    },

    /**
     * Updates this container's child items, passing through the `dataMap`.
     * @param newRecord
     * @private
     */
    updateRecord: function(newRecord) {
        if (!newRecord) {
            return;
        }
        this._record = newRecord;

        var me = this,
            dataview = me.dataview || this.getDataview(),
            data = dataview.prepareData(newRecord.getData(true), dataview.getStore().indexOf(newRecord), newRecord),
            items = me.getItems(),
            item = items.first(),
            dataMap = me.getDataMap();

        if (!item) {
            return;
        }
        if (dataMap) {
            this.doMapData(dataMap, data, item);
        }

        /**
         * @event updatedata
         * Fires whenever the data of the DataItem is updated.
         * @param {Ext.dataview.component.DataItem} this The DataItem instance.
         * @param {Object} newData The new data.
         */
        me.fireEvent('updatedata', me, data);
    }
});
