/**
@fileOverview
Part of the QlikView WorkBench Javascript Library <br /><br />
Copyright (c) 2009 QlikTech International AB (http://www.qliktech.com)<br /><br />
All Rights Reserved. Email support@qliktech.com for licensing and support information.<br /><br />
@author <a href="mailto:support@qlikview.com">QlikView</a>
*/

Qww.ListBox = {};

/** 
Creates a new Qww.ListBox.Results instance.
@constructor
@class Represents the results contained in a listbox.<br />
@returns {Qww.ListBox.Results} Qww.ListBox.Results
*/
Qww.ListBox.Results = function() {

    /**
    Array of all the items contained in the current page of the ListBox
    @type Qww.ListBox.Item[]
    */
    this.All = [];

    this.cachedResults = [];
};

Qww.ListBox.Results.prototype.getArrayOfItemsWithState = function(state) {

    if (this.cachedResults[state] == null) {

        var res = [];

        var arrLength = this.All.length;

        for (var i = 0; i < arrLength; i++) {

            var item = this.All[i];

            if (item.State == state) res.push(item);
        }

        this.cachedResults[state] = res;

        return res;
    }
    else
        return this.cachedResults[state];
};


/**
Returns an array of the associated items 
in the current page of data.
@type Qww.ListBox.Item[]
*/
Qww.ListBox.Results.prototype.GetAssociated = function() {
    return this.getArrayOfItemsWithState(Qww.ListBox.Mgr.ItemState.Associated);
};

/**
Returns an array of the disabled items 
in the current page of data.
@type Qww.ListBox.Item[]
*/
Qww.ListBox.Results.prototype.GetDisabled = function() {
    return this.getArrayOfItemsWithState(Qww.ListBox.Mgr.ItemState.Disabled);
};

/**
Returns an array of the selected items 
in the current page of data.
@type Qww.ListBox.Item[]
*/
Qww.ListBox.Results.prototype.GetSelected = function() {
    return this.getArrayOfItemsWithState(Qww.ListBox.Mgr.ItemState.Selected);
};


/** 
Returns a summary string showing the number of selected, disabled 
and associated items in the current page of the listbox.
@type String
*/
Qww.ListBox.Results.prototype.GetSummary = function() {

    return "Selected = " + this.GetSelected().length +
    ", Disabled = " + this.GetDisabled().length +
    ", Associated = " + this.GetAssociated().length;
};

///**
//Returns whether the current set of results is equal to the set 
//passed as a parameter.
//@param {Qww.ListBox.Results} listBoxResults Qww.ListBox.Results instance to compare.
//@type Bool
//*/
//Qww.ListBox.Results.prototype.Equals = function(listBoxResults) {

//    if (listBoxResults.All.length != this.All.length)
//        return false;

//    for (i = 0; i < this.All.length; i++)
//        if (this.All[i] != listBoxResults.All[i])
//        return false;

//    return true;
//};

/** 
Constructs a new Qww.ListBox.Item instance.
@constructor
@class Represents an item in the listbox.<br />
@returns {Qww.ListBox.Item} Qww.ListBox.Item
*/
Qww.ListBox.Item = function() {

    /** 
    The state of the listbox item (associated, selected, disabled).        
    @type Qww.ListBox.Mgr.ItemState
    */
    this.State = null;

    /** 
    Whether the listitem has the selectedexcluded=true attribue. This is a deprecated 
    property and the .State == Qww.ListBox.Mgr.ItemState.SelectedExcluded should be used.
    @type Boolean
    */
    this.SelectedExcluded = false;

    /** 
    The underlying value of the listbox item. This should be used for selecting items by value.
    @see Qww.ListBox.Mgr#MakeSelection
    @see Qww.ListBox.Mgr#MakeSingleSelection
    @type Int
    */
    this.Value = -1;

    /** 
    The text value of the listbox item. This should be used for selecting items by text.
    @see Qww.ListBox.Mgr#MakeSelection
    @see Qww.ListBox.Mgr#MakeSingleSelection
    @type String
    */
    this.Text = "";

    /** 
    Whether the item has the locked attribute set to true.
    @type Boolean
    */
    this.Locked;

    /** 
    The frequency of the listbox item.
    @type Int
    */
    this.Frequency = -1;

    /** 
    The record number of the item. NOTE this is only currently populated when the object is created within 
    a Qww.Ctls.FlexiGrid.Mgr and passed to the OnRenderRecord method.
    @type Int
    */
    this.RecordNumber = -1;

    /** 
    ColleIf the .Text property represents a string of concatenated values (e.g. to mimic columns) then 
    this property will contain an array of cells representing these columns. NOTE that this will be empty
    UNLESS the .ParseCellsFromText method has first been called.
    @type String[]
    */
    this.Cells = [];
};

/** 
If the .Text property represents a string of concatenated values (e.g. to mimic columns) then 
this method will parse the text property and populate the .Cells property with the results.
@param {String} delimitter String to 'split' the .Text on in order to derive the .Cells collections of columns.
*/
Qww.ListBox.Item.prototype.ParseCellsFromText = function(delimitter) {

    var parts = this.Text.split(delimitter);

    this.Cells = [];

    var arrLength = parts.length;

    for (var x = 0; x < arrLength; x++) {
        this.Cells[x] = parts[x];
    }
};

/** 
Returns a summary string showing the main properites of the ListBoxItem.
@type String
*/
Qww.ListBox.Item.prototype.GetSummary = function() {

    return Qww.GetSummary(["State", "Value", "Text", "Frequency"], this);
};

/** 
Returns a text summary string for the item.
@type String
*/
Qww.ListBox.Item.prototype.GetSummary = function() {
    return "Text=" + this.Text + ", Value=" + this.Value + ",State=" + Qww.ListBox.Mgr.ItemState.GetStateAsString(this.State);
}

/**
Constructs a new Qww.ListBox.Mgr instance.
@constructor
@class JavaScript class to manage communication with a QlikView ListBox.<br />
@param {Object} cfg JSON object to configure ListBoxMgr.
@param {String} cfg.ObjectID Id of the ListBox in the QlikView document.
@param {String} [cfg.ApplicationID=null] Id/Name of the QlikView document. Note this is <strong>only</strong> necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null.
@param {Int} [cfg.PageSize=20] Number of rows to return in a single page of data.
@param {Bool} [cfg.DoNotInitialise=false] Set this to false if you do not want this particular object to initialise the 
underlying object with QlikView Server. Use this option for example if you are already using another object or control which 
will have already initialised this. In this mode this object will simply parse the existing data for this object as it comese from 
QlikView Server.
@param {Function} [cfg.OnUpdate] Function to call whenever the data is updated.
@returns {Qww.ListBox.Mgr} Qww.ListBox.Mgr
@example
var lbMgr = new Qww.ListBox.Mgr(
{   
ObjectID: "LBLISTBOXID", 
OnUpdate: function(listBoxMgr)
{
var s = "";
    
var allResults = listBoxMgr.Results.All;
    
for(var i = 0; i < allResults.length; i++)
{
var item = allResults[i];

s += item.GetSummary() + ", ";
}
    
jQuery("#summary").html(listBoxMgr.Results.GetSummary() + " - " + s);
}
});
*/
Qww.ListBox.Mgr = function(cfg) {

    var applicationID = cfg.ApplicationID;
    var objectId = cfg.ObjectID;
    var pageSize = cfg.PageSize;

    var _Initialized = false;
    var me = this;

    var lastPageOffset;

    me.Results = new Qww.ListBox.Results();

    /**
    Reference to the configuration object which was used to create construct the object. This 
    allows certain properties to be updated after initial instantiation.
    @type Object
    */
    this.Cfg = cfg;

    var _hasPageSizeBeenSet = false;

    if (pageSize == null)
        pageSize = 20;

    // -------------------------------------------------
    // INTERFACE

    /**
    Clears all selections in the listbox.
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.ClearAll = function(isFinal) {

        if (isFinal == null)
            isFinal = true;

        qwwHub.DoAvqSet(applicationID, objectId, "clear", "", isFinal);
    };

    /**
    Makes a single selection in the listbox based on a text or underlying numerical value. 
    @param {String|Int} itemValueOrText Value or Text of listbox item.
    @param {Bool} [valueIsText=false] Set to true if value is text, otherwise use false. Note using values is more 
    reliable however you must know the <em>underlying</em> value of the listbox item. 
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.MakeSingleSelection = function(itemValueOrText, valueIsText, isFinal) {

        if (isFinal == null)
            isFinal = true;

        if (valueIsText == null)
            valueIsText = false;

        //Qww.ListBox.Mgr.MakeSingleSelection(objectId, itemValueOrText, valueIsText, isFinal);

        Qww.ListBox.Mgr.MakeSingleSelection(applicationID, objectId, itemValueOrText, valueIsText, lastPageOffset == null);
        //avqSet(objectId, "pageoffset", lastPageOffset, isFinal);

        if (lastPageOffset != null)
            qwwHub.DoAvqSet(applicationID, objectId, "pageoffset", lastPageOffset, isFinal);
    };

    /**
    Adds a selection or selections to the underlying listbox based on the array of text or underlying numerical values passed. 
    @param {String[]|Int[]} arrayOfItems Array of Value or Text items to add to selection.
    @param {Bool} [valueIsText=false] Set to true if value is text, otherwise use false. Note using values is more 
    reliable however you must know the <em>underlying</em> value of the listbox item. 
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.AddSelection = function(arrayOfItems, valueIsText, isFinal) {

        if (isFinal == null)
            isFinal = true;

        if (valueIsText == null)
            valueIsText = false;

        Qww.ListBox.Mgr.AddSelection(applicationID, objectId, arrayOfItems, valueIsText, isFinal);

    };

    /**
    Makes a single selection in the listbox based on a text or underlying numerical value. 
    @param {String[]|Int[]} arrayOfItems Array of Value or Text items to select.
    @param {Bool} [valueIsText=false] Set to true if value is text, otherwise use false. Note using values is more 
    reliable however you must know the <em>underlying</em> value of the listbox item. 
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.MakeSelection = function(arrayOfItems, valueIsText, isFinal) {

        if (isFinal == null)
            isFinal = true;

        if (valueIsText == null)
            valueIsText = false;

        //Qww.ListBox.Mgr.MakeSelection(applicationID, objectId, arrayOfItems, valueIsText, lastPageOffset == null);
        Qww.ListBox.Mgr.MakeSelection(applicationID, objectId, arrayOfItems, valueIsText, isFinal);

        //        if (lastPageOffset != null)
        //            qwwHub.DoAvqSet(applicationID, objectId, "pageoffset", lastPageOffset, isFinal);
    };

    /**
    Selects all items in the listbox which match the specified search string.
    @param {String} searchString Search string.
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.SearchAndClose = function(searchString, isFinal) {
        Qww.ListBox.Mgr.SearchAndClose(applicationID, objectId, searchString, isFinal);
    };

    /**
    Sends a search to the listbox.
    @param {String} searchString Search string.
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.Search = function(searchString, isFinal) {
        Qww.ListBox.Mgr.Search(applicationID, objectId, searchString, isFinal);
    };

    /**
    Closes a search operation on the listbox (e.g. selects matches).
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.CloseSearch = function(isFinal) {
        Qww.ListBox.Mgr.CloseSearch(applicationID, objectId, isFinal);
    };

    /**
    Aborts a search operation on the listbox.
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    */
    this.AbortSearch = function(isFinal) {
        Qww.ListBox.Mgr.AbortSearch(applicationID, objectId, isFinal);
    };

    //    this.OnAllAvqUpdateCompletesCalled = function() {

    //        if (me.Cfg.OnUpdate) {
    //            if (me.Results.HaveUpdated == true) {
    //                me.Cfg.OnUpdate(me, me.Cfg.OnUpdateData);
    //            }
    //        }
    //    };

    this.OnAvqUpdateComplete = function() {
        me.updateResults();
    };


    function a(s) {
        alert("ListBoxMgr:" + s);
    };

    /**
    @ignore
    Returns an array of Qww.QvsConnectorSet objects which represents the initiasation which 
    needs to be sent to QlikView server in order to initialise this object.
    @returns {Qww.QvsConnectorSet[]} Array of Qww.QvsConnectorSet objects which represents 
    the initiasation for this object.
    */
    this.GetInitialisationSets = function() {

        var sets = [];

        sets.push(new Qww.QvsConnectorSet(applicationID, objectId, "add", "mode;text;pageoffset;pagesize;totalsize;fixedrows", false));
        sets.push(new Qww.QvsConnectorSet(applicationID, objectId + ".Caption", "add", "mode;text", false));
        sets.push(new Qww.QvsConnectorSet(applicationID, objectId, "pagesize", pageSize, false));
        sets.push(new Qww.QvsConnectorSet(applicationID, objectId, "pageoffset", 0, true));

        _hasPageSizeBeenSet = true;

        return sets;
    };

    function initialize() {

        var box = qwwHub.DoAvqSelect(applicationID, objectId);

        //if (box == null) {
        if (box == null && !_hasPageSizeBeenSet) {

            qwwHub.DoAllSets(me.GetInitialisationSets());

            _hasPageSizeBeenSet = true;

            return false;

            //            //<set name="Document.LBDIRECTOR" add="mode;text;pageoffset;pagesize;totalsize;fixedrows"/>
            //            //<set name="Document.LBDIRECTOR.Caption" add="mode;text"/>
            //            //<set name="Document.LBDIRECTOR" pagesize="20"/>
            //            //<set name="Document.LBDIRECTOR" pageoffset="0"/>

            //            //alert("setting "+ qualifiedId);         
            //            //avqSet(ID, "add", "text;value;choice;pagesize", false);

            //            //qwwHub.DoAvqSet(applicationID, objectId, "add", "mode;choice;label;pageoffset;pagesize;totalsizel;label", false);
            //            qwwHub.DoAvqSet(applicationID, objectId, "add", "mode;text;pageoffset;pagesize;totalsize;fixedrows", false);
            //            qwwHub.DoAvqSet(applicationID, objectId + ".Caption", "add", "mode;text", false);

            //            qwwHub.DoAvqSet(applicationID, objectId, "pagesize", pageSize, false);
            //            _hasPageSizeBeenSet = true;
            //            qwwHub.DoAvqSet(applicationID, objectId, "pageoffset", 0, true);
            //            return false;
        }
        else {
            if (!_hasPageSizeBeenSet) {
                //
                // We would come into this branch if a listbox on the page
                // had already setup this object. Here though we would override the
                // page size which had been set by the list box.
                //
                qwwHub.DoAvqSet(applicationID, objectId, "pagesize", pageSize, true);
                _hasPageSizeBeenSet = true;
            }
        }

        _Initialized = true;

        return true; // handshake - there will not be a new update
    };

    /**
    Calls a standard action on the list box (e.g. clear all, lock selections).
    @param {Qww.ListBox.Mgr.StandardAction} action Action to call    
    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    be sent in one request.
    @example
    lbMgr.CallAction(Qww.ListBox.Mgr.StandardAction.ClearAll, true);
    */
    this.CallAction = function(action, isFinal) {

        if (!isFinal)
            isFinal = true;

        Qww.ListBox.Mgr.CallAction(applicationID, objectId, action, isFinal);
    };

    //    /*
    //    Sets the value of the input field. (Only applicable if listbox is setup to show input field value).
    //    @param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
    //    Set this to false if you intend to call some methods on other objects and would like all the commands to 
    //    be sent in one request.
    //    */
    //    this.SetInputField = function(columnIndex, rowIndex, value, isFinal) {

    //        if (isFinal == null)
    //            isFinal = true;

    //        qwwHub.DoAvqSet(applicationID, objectId, "inputvalue", columnIndex + ":" + rowIndex + ":" + value, isFinal);
    //    };


    /**
    The .SelectSingleRecord method of the Qww.Ctls.FlexiGrid.Mgr delegates to this method when 
    a ListBoxMgr is being used as a dataprovider for the flexi grid. This simply calls through to 
    the .SelectSingleRecord method.
    @ignore
    */
    this.SelectSingleRecord = function(val) {
        me.MakeSingleSelection(val, false, true);
    };

    /**
    Set of results for current page of data which the ListBoxMgr is showing.
    @type Qww.ListBox.Results
    */
    this.Results = new Qww.ListBox.Results();

    me.Results.HaveUpdated = true;

    /**
    Returns the current page number which the ListBoxMgr holds data for.
    @property
    @type Int
    */
    this.CurrentPage = 1;

    /** 
    Number of items per page of data received for the listbox.
    @type Int
    */
    this.PageSize = -1;

    /** 
    Number of results for current unclosed search. This will be -1 if a search 
    is not currently being performed.
    @type Int
    */
    this.NumberOfSearchMatches = -1;

    /** 
    The offset of the current page of data.
    @type Int
    */
    this.PageOffset = -1;

    /** 
    This value increments (seems by 2 each time?) every time the state of 
    the underlying listbox changes and will remain the same if you are simple 
    requesting different pages/pageoffsets for the ListBox in a given state.
    @type Int
    */
    this.Stamp = -1;

    /** 
    Total number of items in the listbox.
    @type Int
    */
    this.TotalSize = -1;

    /** 
    The state of the object. This can be dependent, for example, upon show and hide conditions set 
    for the object in QlikView.
    @type Qww.QlikViewObjectState
    */
    this.Mode = "";

    /** 
    Whether the listbox is enabled (visible) within the QlikView document. This can be dependent, 
    for example, upon show and hide conditions set for the object in QlikView.
    @deprecated You should now use Mode.
    @type Bool
    */
    this.Enabled = true;

    /** 
    The number of columns the listbox is configured with.
    @type Number
    */
    this.NumberOfColumns = 1;

    //    /** 
    //    Current Title/Caption of the listbox control.
    //    @type String
    //    */
    //    this.Title = "";

    /** 
    Number of pages of data for the listbox.
    @type Int
    */
    this.NoPages = me.TotalSize / me.PageSize;

    /** 
    Caption for text object.
    @type Qww.ObjectCaption
    */
    this.Caption = new Qww.ObjectCaption();

    /** 
    Moves to the next page of data in the listbox.
    @returns {Bool} Returns true if the page was changed (if the listbox 
    was already set to the last page then false will be returned).
    */
    this.PageDown = function() {

        if (me.CurrentPage > 1) {
            me.SetPage(me.CurrentPage - 1);
            return true;
        }
        else {
            return false;
        }
    };

    /** 
    Moves to the previous page of data in the listbox.
    @returns {Bool} Returns true if the page was changed (if the listbox 
    was already set to the first page then false will be returned).
    */
    this.PageUp = function() {

        if (me.CurrentPage < me.NoPages) {
            me.SetPage(me.CurrentPage + 1);
            return true;
        }
        else {
            return false;
        }
    };

    /** 
    Moves to the page number specified.
    @param {Int} pageNumber Page number to move to.
    */
    this.SetPage = function(pageNumber) {

        me.CurrentPage = pageNumber;
        
        newOffset = ((pageNumber * 1 - 1) * pageSize);
        //newOffset = ((pageNumber * 1) * pageSize);

        lastPageOffset = newOffset;

        qwwHub.DoAvqSet(applicationID, objectId, "pageoffset", newOffset, true);

        qwwHub.TrackAction(applicationID, "LBSetPage", objectId, pageNumber);
    };

    /** 
    Moves to the page offset specified.
    @param {Int} Page offset to move to.
    */
    this.SetPageOffset = function(pageOffset) {

        //        me.CurrentPage = pageNumber;

        //        newOffset = ((pageNumber * 1 - 1) * pageSize);

        lastPageOffset = pageOffset;

        qwwHub.DoAvqSet(applicationID, objectId, "pageoffset", pageOffset, true);
    };

    this.updateResults = function() {

        var previousResults = me.Results;

        me.Results.HaveUpdated = false;

        if (!cfg.DoNotInitialise || cfg.DoNotInitialise == false) {
            if (!_Initialized) {
                if (!initialize()) {
                    return;
                }
            }
        }

        var CH = qwwHub.DoAvqSelect(applicationID, objectId);

        if (CH == null) {
            // This might be called as the result of an OnAvqUpdateComplete
            // which might be for an unrelated table or lisbox, in which case
            // the XML wont contain that for XH
            return;
        }

        me.Results = new Qww.ListBox.Results();
        me.Results.HaveUpdated = true;

        this.Mode = CH.getAttribute("mode");
        this.Enabled = (this.Mode == "enabled");

        if (this.Enabled == true) {

            this.Caption.ParseFromXml(CH);

            me.PageSize = CH.getAttribute("pagesize") * 1;
            me.PageOffset = (CH.getAttribute("pageoffset") * 1); // +1;
            me.TotalSize = CH.getAttribute("totalsize") * 1;

            me.Stamp = (1 * CH.getAttribute("stamp"));

            var matches = CH.getAttribute("numberofmatches");

            if (matches == null) {
                me.NumberOfSearchMatches = -1;
            }
            else {
                me.NumberOfSearchMatches = matches * 1;
            }

            //me.CurrentPage = Math.floor((me.PageOffset - 1) / me.PageSize) + 1;
            me.CurrentPage = Math.floor((me.PageOffset) / me.PageSize) + 1;

            //me.Name = CH.getAttribute("name");        

            var searchable = CH.getAttribute("searchable") * 1;

            me.NoPages = me.TotalSize / me.PageSize;
            me.NoPages = Math.round(me.NoPages + 0.49);

            var all = me.Results.All;

            var obj = jQuery("choice", CH);

            var responseIsJson = false;

            if (obj.length > 0) {
                var vals = obj[0].childNodes;
                me.NumberOfColumns = 1;
            }
            else {
                var vals = jQuery("element", CH);

                if (vals.length == 0) {
                    vals = jQuery("json", CH);

                    if (vals.length > 0)
                        responseIsJson = true;
                }

                me.NumberOfColumns = 0;

                var cols = jQuery("value", CH);

                var arrLength = cols.length;

                for (var i = 0; i < arrLength; i++) {
                    if (cols[i].getAttribute("name") != 'Caption') {
                        me.NumberOfColumns++;
                    }
                }
            }

            var noDummyItems = 0; // if columns are used the last few items might be empty.

            var index = 0;

            if (responseIsJson) {
                vals = eval("([" + vals[0].text + "])")
            }

            var arrLength = vals.length;

            for (var i = 0; i < arrLength; i++) {

                var node = vals[i];

                var newItem = Qww.ListBox.Mgr.GetListItemFromNode(node, responseIsJson);

                if (newItem.Value == -1) {
                    noDummyItems++;
                    continue;
                }
                else {
                    all[index++] = newItem;
                }
            }

            me.TotalSize = (me.NumberOfColumns * me.TotalSize) - noDummyItems;
        }

        //        if (previousResults != null && previousResults.Equals)
        //            me.Results.HaveUpdated = !previousResults.Equals(me.Results);

        me.Results.HaveUpdated = true;

        if (me.Cfg.OnUpdate) {
            if (me.Results.HaveUpdated == true) {
                me.Cfg.OnUpdate(me, me.Cfg.OnUpdateData);
            }
        }
    };

    if (qwwHub)
        qwwHub.Register(this);
};

/**
Returns a html string summary of the main properties of the TableMgr.
*/
Qww.ListBox.Mgr.prototype.GetSummary = function() {

    return "Caption:" + this.Caption.Text + "," + Qww.GetSummary([/*"Text",*/"Enabled", "TotalSize", "PageOffset", "PageSize"
    /*"NoRows", "CurrentPage", "NoPages", "InitialTotalSize",
    "InitialNoPages", "HeaderRowPresent"*/], this);
};

/**
Makes a selection in the listbox based on the array of text or underlying numerical values passed. 
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {String[]|Int[]} arrayOfItems Array of Value or Text items to select.
@param {Bool} [optionalUseText=false] Set to true if value is text, otherwise use false. Note using values is more 
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.MakeSelection = function(applicationID, objectId, arrayOfItems, optionalUseText, isFinal) {

    if (isFinal == null)
        isFinal = true;

    var mode = "value";

    if (optionalUseText) {
        qwwHub.DoAvqSet(applicationID, objectId, "clear", "", true);
        mode = "text";
    }
    else
        qwwHub.DoAvqSet(applicationID, objectId, "clear", "", false);

    var arrLength = arrayOfItems.length;

    for (var i = 0; i < arrLength; i++) {
        var isActuallyFinal = (isFinal && (i == (arrLength - 1)));

        qwwHub.DoAvqSet(applicationID, objectId, mode, arrayOfItems[i], isActuallyFinal);
    }

    qwwHub.TrackAction(applicationID, "LBSelection", objectId);
}

/**
Adds a selection or selections to the underlying listbox based on the array of text or underlying numerical values passed. 
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {String[]|Int[]} arrayOfItems Array of Value or Text items to additionally select.
@param {Bool} [optionalUseText=false] Set to true if value is text, otherwise use false. Note using values is more 
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.AddSelection = function(applicationID, objectId, arrayOfItems, optionalUseText, isFinal) {

    if (isFinal == null)
        isFinal = true;

    var mode = "value";

    if (optionalUseText) {
        mode = "text";
    }

    var arrLength = arrayOfItems.length;

    for (var i = 0; i < arrLength; i++) {

        var isActuallyFinal = (isFinal && (i == (arrLength - 1)));

        qwwHub.DoAvqSet(applicationID, objectId, mode, arrayOfItems[i], isActuallyFinal);
    }

    qwwHub.TrackAction(applicationID, "LBSelection", objectId);
}

/**
Makes a single selection in the listbox based on a text or underlying numerical value. 
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {String|Int} itemValueOrText Value or Text of item to select.
@param {Bool} [optionalUseText=false] Set to true if value is text, otherwise use false. Note using values is more 
reliable however you must know the <em>underlying</em> value of the listbox item. 
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.MakeSingleSelection = function(applicationID, objectId, itemValueOrText, optionalUseText, isFinal) {
    if (isFinal == null)
        isFinal = true;

    if (itemValueOrText == null) {
        qwwHub.DoAvqSet(applicationID, objectId, "clear", "", isFinal);
    }
    else {
        if (optionalUseText) {
            qwwHub.DoAvqSet(applicationID, objectId, "clear", "", true); // in text mode seems we must send clear through separately.
            qwwHub.DoAvqSet(applicationID, objectId, "text", itemValueOrText, isFinal);
        }
        else {
            qwwHub.DoAvqSet(applicationID, objectId, "clear", "", false);
            qwwHub.DoAvqSet(applicationID, objectId, "value", itemValueOrText, isFinal);
        }
    }

    qwwHub.TrackAction(applicationID, "LBSelection", objectId);
};

/** 
@class Enumeration representing the state which each item in the listbox can be in.<br />
*/
Qww.ListBox.Mgr.ItemState = {

    /**
    Item is associated.
    @constant
    */
    Associated: 0,

    /**
    Item is disabled.
    @constant
    */
    Disabled: 1,

    /**
    Item is selected.
    @constant
    */
    Selected: 2,

    /**
    Item is selected excluded (this state happens for example 
    with check box style).
    @constant
    */
    SelectedExcluded: 3

};

/**
Returns a string representation of the state.
@param {Int|Qww.ListBox.Mgr.ItemState} state State value to get string represenation for.
@returns {String} String representation of the state.
*/
Qww.ListBox.Mgr.ItemState.GetStateAsString = function(state) {

    if (state == 0)
        return "Associated";

    if (state == 1)
        return "Disabled";

    if (state == 2)
        return "Selected";

    if (state == 3)
        return "SelectedExcluded";

    return "Unknown";
};

/**
Enumeration of standard actions which can be called on a listbox.
@class Enumeration of standard actions which can be called on a listbox.<br />
@see Qww.ListBox.Mgr#CallAction
@example
Qww.ListBox.Mgr.CallAction(null, 'LBID', Qww.ListBox.Mgr.StandardAction.ClearAll);
*/
Qww.ListBox.Mgr.StandardAction = {

    /** 
    @ignore
    @constant
    */
    Minimize: 'MI',

    /** 
    @ignore
    @constant
    */
    Restore: 'RE',

    /** 
    @ignore
    @constant
    */
    Print: 'PR',

    /** 
    @ignore
    @constant
    */
    SendToExcel: 'XL',

    /** 
    Clear all selections in the listbox.
    @constant
    */
    ClearAll: 'CA',

    /** 
    @ignore
    @constant
    */
    Compare: 'CO',

    /** 
    Select all items in the listbox.
    @constant
    */
    SelectAll: 'SA',

    /** 
    Select all currently excluded items (invert selection).
    @constant
    */
    SelectExcluded: 'SE',

    /** 
    Select all possible items.
    @constant
    */
    SelectPossible: 'SP',

    /** 
    Lock the current selections.
    @constant
    */
    LockSelection: 'LS',

    /** 
    UnLock the current selections.
    @constant
    */
    UnlockSelection: 'US'
};

/**
Calls a standard action on the list box (e.g. clear all, lock selections).
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {Qww.ListBox.Mgr.StandardAction} action Action to call    
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
@example
Qww.ListBox.Mgr.CallAction(null, 'LBID', Qww.ListBox.Mgr.StandardAction.ClearAll);
*/
Qww.ListBox.Mgr.CallAction = function(applicationID, listBoxId, action, isFinal) {

    if (isFinal == null)
        isFinal = true;

    if (Qww.Hub.StartMode == Qww.Hub.StartModes.Pre8_5)
        qwwHub.DoAvqSet(applicationID, listBoxId + ".Caption." + action, "action", "", isFinal);
    else
        qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + listBoxId + "." + action, "action", "", isFinal);

};

/**
Sends a search to the listbox.
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {String} searchString Search string.
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.Search = function(applicationID, objectId, searchString, isFinal) {

    if (isFinal == null)
        isFinal = true;

    searchString = searchString.toString().replace(/>/g, "&gt;");
    searchString = searchString.toString().replace(/</g, "&lt;");

    qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "pageoffset", "0", false);
    qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "search", searchString, isFinal);
    //qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "closesearch", "accept", isFinal);
};

/**
Selects all items in the listbox which match the specified search string.
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {String} searchString Search string.
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.SearchAndClose = function(applicationID, objectId, searchString, isFinal) {
    if (isFinal == null)
        isFinal = true;

    searchString = searchString.toString().replace(/>/g, "&gt;");
    searchString = searchString.toString().replace(/</g, "&lt;");

    qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "search", searchString, false);
    qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "closesearch", "accept", isFinal);
};

/**
Closes a search operation on the listbox (e.g. selects matches).
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.CloseSearch = function(applicationID, objectId, isFinal) {

    if (isFinal == null)
        isFinal = true;

    qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "closesearch", "accept", isFinal);
};

/**
Aborts a search operation on the listbox.
@param {String} applicationId Id/Name of the QlikView document <strong>(note this is only necessary when 
multiple QlikView documents are being used on the same web page and should otherwise be set to null)</strong>.
@param {String} objectID Id of the ListBox in the QlikView document.
@param {Bool} [isFinal=true] If this is the final command in this set to send to QlikView Server.
Set this to false if you intend to call some methods on other objects and would like all the commands to 
be sent in one request.
*/
Qww.ListBox.Mgr.AbortSearch = function(applicationID, objectId, isFinal) {

    if (isFinal == null)
        isFinal = true;

    qwwHub.DoAvqSet(applicationID, Qww.ListBox.Mgr.CommandPrefix + objectId + ".Caption", "closesearch", "abort", isFinal);
};


Qww.ListBox.Mgr.CommandPrefix = 'Document.';

Qww.ListBox.Mgr.GetListItemFromNode = function(node, responseIsJson) {

    var newItem = new Qww.ListBox.Item();

    if (responseIsJson == null || responseIsJson == false) {

        newItem.Value = node.getAttribute("value") * 1;

        if (newItem.Value > -1) {

            newItem.Text = node.getAttribute("text");
            newItem.Frequency = node.getAttribute("frequency");

            newItem.Locked = (node.getAttribute("locked") == "yes");

            if (node.getAttribute("selected") != null && node.getAttribute("selected") != "no") //selected
                newItem.State = Qww.ListBox.Mgr.ItemState.Selected;
            else if (node.getAttribute("mode") == "disabled") //excluded
                newItem.State = Qww.ListBox.Mgr.ItemState.Disabled;
            else //associated
                newItem.State = Qww.ListBox.Mgr.ItemState.Associated;

            if (node.getAttribute("selectedexcluded") != null && node.getAttribute("selectedexcluded") != "no") //selectedexcluded
            {
                newItem.SelectedExcluded = true;
                newItem.State = Qww.ListBox.Mgr.ItemState.SelectedExcluded;
            }
            else
                newItem.SelectedExcluded = false;

        }
    }
    else {
        //
        // Experimental code to deserialise a node from a known Json structure.
        //
        //
        // NOTE : The following was experimental code, testing to see if performance
        // could be improved by serialising the qvpx data to JSON and having JSON objects
        // delivered to the client. In initial tested this did not appear to improve performance 
        // notably and the following code can probably be deleted (it is incomplete anyway).
        newItem.Value = node[0];

        if (newItem.Value > -1) {

            newItem.Text = node[1];
            newItem.Frequency = node[2];

            if (node[3] != null && node[3] != "no") //selected
                newItem.State = Qww.ListBox.Mgr.ItemState.Selected;
            else if (node[4] == "disabled") //excluded
                newItem.State = Qww.ListBox.Mgr.ItemState.Disabled;
            else //associated
                newItem.State = Qww.ListBox.Mgr.ItemState.Associated;
        }
    }

    return newItem;
}