/// class PD.Web.UI.Controls.ListBox
// using PD.Web.UI.Controls.Control

PD.Web.UI.Controls.ListBox =
PD.Web.UI.Controls.Control.extend({

    //===================================
    // FIELDS
    //===================================

    CSS_PD_STATE_SELECTED: "-pd-state-selected",
    CSS_LIST_VIEW_ITEM: "-pd-listbox-item",

    //===================================
    // FIELDS
    //===================================

    _items: null,
    
    //===================================
    // PROPERTIES
    //===================================

    //===================================
    // EVENT HANDLERS
    //===================================

    onInit: function (e) {
        this._items = new PD.Web.UI.Controls.ListBoxItemCollection();
    },

    onActivate: function () {
        var that = this;
        PD.Web.UI.Controls.ControlMessage.mixin({
            target: this,
            node: this.get_node()
        });
        this._items.addRange(this.get_options()["data"]);
        this._renderItems();
    },

    onComplete: function (e) {
        this.get_node().on("click", "." + this.CSS_LIST_VIEW_ITEM, $.proxy(this._item_onClick, this));
        this.selectFirst();
    },

    //===================================
    // PUBLIC METHODS
    //===================================

    select: function (id) {

        var $item = null;

        if (id === undefined) {
            $item = this._getSelectedItemNode();
            return {
                data: this.dataItem($item),
                item: $item
            }
        }
        else {
            $item = this._getItemNode(id);
            $item.addClass(this.CSS_PD_STATE_SELECTED);
        }

    },

    selectFirst: function () {

        var $item = this.get_node().find("." + this.CSS_LIST_VIEW_ITEM + ":first");

        $item.addClass(this.CSS_PD_STATE_SELECTED);

        this._fireChangeEvent({
            selection: this.dataItem($item)
        });

    },

    dataItem: function ($item) {

        var id = $item.data("id"),
            result = null;

        this._items.each(function (index, item) {
            if (item.id === id) {
                result = item;
                return false;
            }
        });

        return result;

    },

    refresh: function (options) {

        var $scrollTo = null,
            previous = this.select().data;

        options = options || {};

        this._renderItems();

        if (options.clear) {
            this._clearSelections();
        }

        if (options.selection) {
            this._clearSelections();
            this.select(options.selection);
        }

        if (!this._hasSelection() && previous != null) {
            this.select(previous.id);
        }

        if (!this._hasSelection()) {
            this.selectFirst();
        }

        this._attemptFireChangeEvent(previous);

        this._scrollIntoView();

    },

    load: function (options) {

        var selectedDataItem = null,
            selection = null;

        if (!options.clear) {
            selectedDataItem = this.select().data;
            selection = selectedDataItem.id;
        }
        else {
            selection = options.selection;
        }
        
        this._items.clear();
        this._items.addRange(options.data);

        this.refresh({
            clear: options.clear,
            selection: selection
        });

    },

    scrollIntoView: function (id) {
        var $item = this._getItemNode(id);
        this._scrollIntoView($item);
    },

    //===================================
    // PROTECTED METHODS
    //===================================

    template: function () {
        return "<div class='-pd-listbox'></div>";
    },

    templateForListItem: function (data) {
        return [
            "<div class='" + this.CSS_LIST_VIEW_ITEM + "' data-id='" + data.id + "'>",
                data.icon ? "<div class='-pd-item-icon' style='background-image:url(" + PD.Path.resolve("~/application/icons/16x16/" + data.icon) + ");'></div>" : "",
                "<div class='-pd-item-label'>" + data.name + "</div>",
            "</div>"].join("");
    },

    //===================================
    // PRIVATE METHODS
    //===================================

    _addEmptyMessage: function () {

        var message = this.get_options()["emptyMessage"];

        if (message != null) {
            this.addMessage(message.text, message.callback);
        }

    },

    _item_onClick: function (e) {

        var $item = $(e.currentTarget),
            cssSelectedClass = this.CSS_PD_STATE_SELECTED;

        if (!$item.hasClass(cssSelectedClass)) {

            this._clearSelections();
            $item.addClass(cssSelectedClass);

            this._fireChangeEvent({
                selection: this.dataItem($item)
            })

        }

    },

    _clearSelections: function () {
        
        var $list = this.get_node()
            cssSelectedClass = this.CSS_PD_STATE_SELECTED;

        $list.find("." + cssSelectedClass)
                .removeClass(cssSelectedClass);

    },

    _hasSelection: function () {
        var $list = this.get_node();
        return $list.find("." + this.CSS_PD_STATE_SELECTED).length > 0;
    },

    _getItemNode: function (id) {
        return this.get_node().find("." + this.CSS_LIST_VIEW_ITEM + "[data-id=" + id + "]");
    },

    _getSelectedItemNode: function () {
        return this.get_node().find("." + this.CSS_LIST_VIEW_ITEM + "." + this.CSS_PD_STATE_SELECTED);
    },

    _renderItems: function () {

        var that = this,
            $list = this.get_node();

        $list.empty();

        this._items.sortAlpha();

        this._items.each(function (index, data) {
            var template = that.templateForListItem(data);
            if (template != null) {
                $list.append(template);
            }
        });

        if (this._items.count() === 0) {
            this._addEmptyMessage();
        }

    },

    _scrollIntoView: function ($item) {
        
        var list = this.get_node()[0];

        if ($item === undefined) {
            $item = this.select();
        }

        if ($item.length > 0) {
            list.scrollTop = $item[0].offsetTop;
        }

    },

    _fireChangeEvent: function (args) {

        var changeFn = this.get_options()["change"];

        if (PD.Type.isFunction(changeFn)) {
            changeFn(args);
        }

    },

    _attemptFireChangeEvent: function (previous) {

        var current = this.select().data,
            hasChanged = false;

        if (current === null && previous === null) {
            return;
        }

        hasChanged = (previous !== null && current === null)
            || (previous === null && current !== null)
            || (previous.id != current.id);

        if (hasChanged) {
            this._fireChangeEvent({
                selection: current
            })
        }

    },

    _itemExists: function (id) {
        return this._getItemNode(id).length > 0;
    }

});