/**
 * IndexBar is a component used to display a list of data (primarily an alphabet) which can then be used to quickly
 * navigate through a list (see {@link Ext.List}) of data. When a user taps on an item in the {@link Ext.IndexBar},
 * it will fire the {@link #index} event.
 *
 * Here is an example of the usage in a {@link Ext.List}:
 *
 *     @example phone portrait preview
 *     Ext.define('Contact', {
 *         extend: 'Ext.data.Model',
 *         config: {
 *             fields: ['firstName', 'lastName']
 *         }
 *     });
 *
 *     var store = new Ext.data.JsonStore({
 *        model: 'Contact',
 *        sorters: 'lastName',
 *
 *        grouper: {
 *            groupFn: function(record) {
 *                return record.get('lastName')[0];
 *            }
 *        },
 *
 *        data: [
 *            {firstName: 'Screech', lastName: 'Powers'},
 *            {firstName: 'Kelly',   lastName: 'Kapowski'},
 *            {firstName: 'Zach',    lastName: 'Morris'},
 *            {firstName: 'Jessie',  lastName: 'Spano'},
 *            {firstName: 'Lisa',    lastName: 'Turtle'},
 *            {firstName: 'A.C.',    lastName: 'Slater'},
 *            {firstName: 'Richard', lastName: 'Belding'}
 *        ]
 *     });
 *
 *     var list = new Ext.List({
 *        fullscreen: true,
 *        itemTpl: '<div class="contact">{firstName} <strong>{lastName}</strong></div>',
 *
 *        grouped     : true,
 *        indexBar    : true,
 *        store: store,
 *        hideOnMaskTap: false
 *     });
 *
 */
Ext.define('Ext.dataview.IndexBar', {
    extend: 'Ext.Component',
    alternateClassName: 'Ext.IndexBar',
    xtype: 'indexbar',
 
    /**
     * @event index
     * Fires when an item in the index bar display has been tapped.
     * @param {Ext.dataview.IndexBar} this The IndexBar instance
     * @param {String} html The HTML inside the tapped node.
     * @param {Ext.dom.Element} target The node on the indexbar that has been tapped.
     */
 
    config: {
        /**
         * @cfg {Array} letters
         * The letters to show on the index bar.
         * @accessor
         */
        letters: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
 
        /**
         * @cfg {String} listPrefix
         * The prefix string to be used at the beginning of the list.
         * E.g: useful to add a "#" prefix before numbers.
         * @accessor
         */
        listPrefix: null
    },
 
 
    cachedConfig: {
        /**
         * @private
         * The parent list that created this index bar
         */
        parentList: null // this is a cachedConfig so that it is available from updateUi
    },
 
    classCls: Ext.baseCSSPrefix + 'indexbar',
    verticalCls: Ext.baseCSSPrefix + 'vertical',
    horizontalCls: Ext.baseCSSPrefix + 'horizontal',
    indexedCls: Ext.baseCSSPrefix + 'indexed',
    pressedCls: Ext.baseCSSPrefix + 'pressed',
    indexedVerticalCls: Ext.baseCSSPrefix + 'indexed-vertical',
    indexedHorizontalCls: Ext.baseCSSPrefix + 'indexed-horizontal',
 
    eventedConfig: {
        /**
         * @cfg {String} direction
         * Layout direction, can be either 'vertical' or 'horizontal'
         * @accessor
         */
        direction: 'vertical'
    },
 
    updateDirection: function(direction) {
        var me = this,
            verticalCls = me.verticalCls,
            horizontalCls = me.horizontalCls,
            indexedVerticalCls = me.indexedVerticalCls,
            indexedHorizontalCls = me.indexedHorizontalCls,
            oldCls, newCls, oldIndexedCls, newIndexedCls;
 
        if (direction === 'vertical') {
            oldCls = horizontalCls;
            newCls = verticalCls;
            oldIndexedCls = indexedHorizontalCls;
            newIndexedCls = indexedVerticalCls
        } else {
            oldCls = verticalCls;
            newCls = horizontalCls;
            oldIndexedCls = indexedVerticalCls;
            newIndexedCls = indexedHorizontalCls;
        }
 
        me.element.replaceCls(oldCls, newCls);
        me.wrapper.replaceCls(oldCls, newCls);
        me.getParentList().element.replaceCls(oldIndexedCls, newIndexedCls);
    },
 
    getElementConfig: function() {
        return {
            reference: 'wrapper',
            classList: ['x-center', 'x-indexbar-wrapper'],
            children: [this.callParent()]
        };
    },
 
    updateLetters: function(letters) {
        this.innerElement.setHtml('');
 
        if (letters) {
            var ln = letters.length,
                i;
 
            for (= 0; i < ln; i++) {
                this.innerElement.createChild({
                    cls: 'x-indexbar-item',
                    html: letters[i]
                });
            }
        }
    },
 
    updateListPrefix: function(listPrefix) {
        if (listPrefix && listPrefix.length) {
            this.innerElement.createChild({
                html: listPrefix
            }, 0);
        }
    },
 
    updateUi: function(ui, oldUi) {
        var me = this,
            list = me.getParentList(),
            listElement = list.element,
            indexedCls = me.indexedCls;
 
        // list element needs the x-indexed-[indexBarUi] class added so that it can pad
        // its items to account for the presence of the index bar
        if (oldUi) {
            listElement.removeCls(oldUi, indexedCls);
        }
 
        if (ui) {
            listElement.addCls(ui, indexedCls);
        }
 
        me.callParent([ui, oldUi]);
    },
 
    updateParentList: function(parentList) {
        if (parentList) {
            parentList.element.addCls(this.indexedCls);
        }
    },
 
    /**
     * @private
     */
    initialize: function() {
        var me = this;
 
        me.callParent();
 
        me.innerElement.on({
            touchstart: 'onTouchStart',
            drag: 'onDrag',
            dragEnd: 'onDragEnd',
            scope: me
        });
 
        me.innerElement.addClsOnClick(this.pressedCls);
    },
 
    isVertical: function() {
        return this.getDirection() === 'vertical';
    },
 
    onTouchStart: function(e) {
        var me = this;
 
        me.pageBox = me.innerElement.getBox();
        me.onDrag(e);
    },
 
    onDragEnd: Ext.emptyFn,
 
    /**
     * @private
     */
    onDrag: function(e) {
        var me = this,
            el = me.element,
            point = Ext.util.Point.fromEvent(e),
            target, isValidTarget,
            pageBox = me.pageBox;
 
        if (!pageBox) {
            pageBox = me.pageBox = me.el.getBox();
        }
 
 
        if (me.getDirection() === 'vertical') {
            if (point.y > pageBox.bottom || point.y < pageBox.top) {
                return;
            }
            target = Ext.Element.fromPoint(pageBox.left + (pageBox.width / 2), point.y);
            isValidTarget = target && target.getParent() === el;
 
            me.onVerticalDrag(point, target, isValidTarget);
        } else {
            if (point.x > pageBox.right || point.x < pageBox.left) {
                return;
            }
            target = Ext.Element.fromPoint(point.x, pageBox.top + (pageBox.height / 2));
            isValidTarget = target && target.getParent() === el;
        }
 
        if (target && isValidTarget) {
            me.fireEvent('index', me, target.dom.innerHTML, target);
        }
    },
 
    privates: {
        onVerticalDrag: Ext.privateFn
    }
});