Source: src/main/javascript/oracle/oj/ojrowexpander/FlattenedNodeSet.js

Oracle® JavaScript Extension Toolkit (JET)
1.1.2

E65298-01

/**
 * Copyright (c) 2014, Oracle and/or its affiliates.
 * All rights reserved.
 */
 
/**
 * Flattens a hierarchical node set, which can happen in node set returned from
 * fetchDescendants call.
 * @param {Object} nodeSet the node set to flatten
 * @param {number=} actualStart in the fetch descendant case the result set would
 *        be a subset of the node set.  This param gives the exact start index in the
 *        wrapped node set where the result should start.
 * @constructor
 * @export
 */
oj.FlattenedNodeSet = function(nodeSet, actualStart)
{
    this.m_nodeSet = nodeSet;
    this.m_start = actualStart;
};

/**
 * Gets the parent
 * @return {Object} the key of the parent.
 * @export
 */
oj.FlattenedNodeSet.prototype.getParent = function()
{
    return this.m_nodeSet.getParent();
};

/**
 * Gets the start index of the result set.  
 * @return {number} the start index of the result set.  
 * @export
 */
oj.FlattenedNodeSet.prototype.getStart = function()
{
    // if explicit start index is specified, use it, otherwise
    // delegate to wrapped node set
    if (this.m_start != undefined)
    {
        return this.m_start;
    }
    else
    {
        return this.m_nodeSet.getStart();
    }
};

/**
 * Gets the actual count of the result set.  
 * @return {number} the actual count of the result set.  
 * @export
 */
oj.FlattenedNodeSet.prototype.getCount = function()
{
    // see if it's calculated already
    if (this.m_count === undefined)
    {
        this.m_count = this._getCount(this.m_nodeSet, 0);

        // if explicit start is specified (subset), need to take that into
        // account when calculating total count
        if (this.m_start != undefined)
        {
            this.m_count = this.m_count - this.m_start;
        }
    }

    return this.m_count;
};

/**
 * Recursive function to calculate the total number of nodes in the node set.
 * @param {Object} nodeSet the node set to calculate count
 * @param {number} total the total number of nodes so far 
 * @return {number} the total number of nodes
 * @private
 */
oj.FlattenedNodeSet.prototype._getCount = function(nodeSet, total)
{
    var start, count, i, child;

    start = nodeSet.getStart();
    count = nodeSet.getCount();
    total = total + count;

    // if there's child node set
    if (nodeSet.getChildNodeSet)
    {
        for (i=0; i<count; i++)
        {
            child = nodeSet.getChildNodeSet(i+start);
            if (child != null)
                total = this._getCount(child, total); 
        }
    }

    return total;
};

/**
 * Gets the data of the specified index.  An error is throw when 1) the range is not yet available and
 * 2) the index specified is out of bounds. 
 * @param {number} index the index of the node/row in which we want to retrieve the data from.  
 * @return {Object} the data for the specified index.
 * @export
 */
oj.FlattenedNodeSet.prototype.getData = function(index)
{
    return this._getDataOrMetadata(this.m_nodeSet, index, {'index': this.m_nodeSet.getStart()}, this._getData);
};

/**
 * Gets the metadata of the specified index.  An error is throw when 1) the range is not yet available and 
 * 2) the index specified is out of bounds. 
 * The metadata that the data source must return are:
 *  1) key - Object, the key of the node/row.
 *  2) state - state of the node, valid values are 'expanded', 'collapsed', 'leaf'. 
 *  3) depth - number, the depth of the node/row. 
 * @param {number} index the index of the node/row in which we want to retrieve the metadata from.  
 * @return {Object} the metadata object for the specific index.
 * @export
 */
oj.FlattenedNodeSet.prototype.getMetadata = function(index)
{
    return this._getDataOrMetadata(this.m_nodeSet, index, {'index': this.m_nodeSet.getStart()}, this._getMetadata);
};

/**
 * Callback function to retrieve metadata of specified index in node set
 * @param {Object} nodeSet the node set to retrieve metadata from
 * @param {number} index the index to retrieve metadata from
 * @return {Object} the metadata
 * @private
 */
oj.FlattenedNodeSet.prototype._getMetadata = function(nodeSet, index)
{
    return nodeSet.getMetadata(index);
};

/**
 * Callback function to retrieve data of specified index in node set
 * @param {Object} nodeSet the node set to retrieve data from
 * @param {number} index the index to retrieve data from
 * @return {Object} the data
 * @private
 */
oj.FlattenedNodeSet.prototype._getData = function(nodeSet, index)
{
    return nodeSet.getData(index);
};

/**
 * Retrieve data or metadata (depending on callback function) from the node set
 * @param {Object} nodeSet the node set to retrieve data from
 * @param {number} index the index to retrieve data from
 * @param {Object} current contains the current index keep track by the method
 * @param {function(Object, number)} func the callback function to retrieve data or metadata
 * @return {Object} the data or metadata
 * @private
 */
oj.FlattenedNodeSet.prototype._getDataOrMetadata = function(nodeSet, index, current, func)
{
    var start, count, i, currIndex, child, result;

    // walk the node set recursively until we found the index
    start = nodeSet.getStart();
    count = nodeSet.getCount();
    for (i=0; i<count; i++)
    {
        currIndex = current['index'];
        // found the index
        if (currIndex === index)
            return func.call(this, nodeSet, i+start);

        current['index'] = currIndex+1;
        // if there's child node set
        if (nodeSet.getChildNodeSet)
        {
            child = nodeSet.getChildNodeSet(i+start);
            if (child != null)
            {
                result = this._getDataOrMetadata(child, index, current, func); 
                if (result != null)
                    return result;
            }
        }
    }       

    return null;
};