Source: src/main/javascript/oracle/oj/ojcube/CubeAxisValue.js

Oracle® JavaScript Extension Toolkit (JET)
1.1.2

E65298-01

/**
 * Copyright (c) 2015, Oracle and/or its affiliates.
 * All rights reserved.
 */
/*jslint browser: true*/

/**
 * @class oj.CubeAxisValue 
 * @classdesc Represents one value within an axis header
 * @see oj.CubeAxis
 * @since 1.1.0
 */

/**
 * Represents one value within an axis header
 * @constructor
 * @export
 * @private
 */
oj.CubeAxisValue = function(value, label, level, parent) {
    this.Init();
    this._children = [];
    this._parent = parent;
    this._cubeLevel = level;
    this._data = {};    
    this._data.value = value;
    this._data.label = label;
};
 
// Subclass from oj.Object 
oj.Object.createSubclass(oj.CubeAxisValue, oj.Object, "oj.CubeAxisValue");

/**
 * Initializes instance with the set options
 * @private
 */
oj.CubeAxisValue.prototype.Init = function() 
{
  oj.CubeAxisValue.superclass.Init.call(this);
}; 

/**
 * Get the {@link oj.CubeLevel} of which this value is a member
 * @return {oj.CubeLevel} the level to which this header value belongs
 * @export
 */
oj.CubeAxisValue.prototype.getLevel = function() {
    return this._cubeLevel;
};
 
/**
 * Get the number of levels this header value spans
 * @return {number} the number of levels this header value spans.  Typically one, but in the future something like a grand total may span all the available levels at a particular
 *                  axis value location
 * @export
 */
oj.CubeAxisValue.prototype.getDepth = function() {
    return 1;
};
 
/**
 * Get the parent oj.CubeAxisValues of this value
 * @return {Array} an array of oj.CubeAxisValues--all the slower-varying level axis values under which this value is grouped
 * @export
 */
oj.CubeAxisValue.prototype.getParents = function() {
    var parents = [];
    var parent = this._parent;
    // Add parents, don't add root
    while (parent && parent._parent) {
        parents.unshift(parent);
        parent = parent._parent;
    }
    return parents;
};
 
/**
 * Get an ordered list of the child oj.CubeAxisValues of this value, at the next level
 * @return {Array} an array of the children of this oj.CubeAxisValue
 * @export
 */
oj.CubeAxisValue.prototype.getChildren = function() {
    return this._children;
};

/**
 * Get the number of indices spanned by this value
 * @return {number} the number of indices spanned by this value
 * @export
 */
oj.CubeAxisValue.prototype.getExtent = function() {
    if (this._extent > -1) {
        return this._extent;
    }
    // Calculate it: add up all my children's extents--if there are none, my extent is one as I'm the innermost level
    if (!this._children || this._children.length === 0) {
        this._extent = 1;
    }
    else {
        this._extent = 0;
        for (var c = 0; c < this.getChildren().length; c++) {
            this._extent += this.getChildren()[c].getExtent();
        }
    }
    return this._extent;
};

/**
 * Get the starting index of this value within the axis
 * 
 * @return {number} the starting index of this value within the axis
 * @export
 */
oj.CubeAxisValue.prototype.getStart = function() {
    if (this._start > -1) {
        return this._start;
    }
    if (!this._parent) {
        // We're the root
        return 0;
    }
    // Add up all my earlier siblings' extents plus my parent's start--that's my start
    var start = this._parent.getStart();
    var currChild = this._parent._getPrevChild(this);    
    while (currChild) {
        start += currChild.getExtent();
        currChild = this._parent._getPrevChild(currChild);
    }
    this._start = start;
    return start;
};

/**
 * Get the actual value of this axis header location
 * @return {Object} the value at this location in the header
 * @export
 */
oj.CubeAxisValue.prototype.getValue = function() {
    return this._data.value;
};

/**
 * Get the label for this axis header location, if any.  If none, falls back to {@link getValue}
 * @returns {Object} the label for this axis header value
 * @export
 */
oj.CubeAxisValue.prototype.getLabel = function() {
    if (this._data.label) {
        return this._data.label;
    }
    return this.getValue();
};

// Return the axis value child with the level/value pair found in key
oj.CubeAxisValue.prototype.GetChild = function(key) {
    var childLevel = this._getChildLevel();
    if (childLevel === null) {
        return null;
    }
    
    if (childLevel.isDataValue()) {
        // Special case: the key is the value
        return this._getDataValueChild(key);
    }
    var levelAttr = childLevel['attribute'];
    // Do we have a key value for this?
    var val = key[levelAttr];
    if (val) {
        // Yes, see if any of the children have this value
        for (var c = 0; c < this._children.length; c++) {
            if (this._children[c].getValue() === val) {
                return this._children[c];
            }
        }
    }
    return null;
};

oj.CubeAxisValue.prototype._getDataValueChild = function(key) {
    for (var c = 0; c < this._children.length; c++) {
        var val = this._children[c].getValue();
        if (key.hasOwnProperty(val) && key[val] === val) {
            // found it
            return this._children[c];
        }
    }
    return null;
};

oj.CubeAxisValue.prototype._getChildLevel = function() {
    if (this._children && this._children.length > 0) {
        return this._children[0].getLevel();
    }
    return null;
};

// Return the axis value child at the given index
oj.CubeAxisValue.prototype.GetChildAt = function(index) {
  return this._findChild(index, 0, this._children.length - 1);
};

oj.CubeAxisValue.prototype._findChild = function(index, start, end) {
    if (start > end) {
            return null;
    }

    var mid = Math.floor((start + end) / 2);
    var value = this._children[mid];

    var valStart = value.getStart();
    if (valStart > index) {
          return this._findChild(index, start, mid-1);
    }
    if (valStart + value.getExtent() - 1 < index) {
        return this._findChild(index, mid+1, end);
    }
    return value;
}
    
// Add this value to the node if not already there; return either the new cube axis value or the one where it was found
oj.CubeAxisValue.prototype.AddNode = function(value, label, level) {
    // Check if this value is already in the child list
    for (var c = 0; c < this._children.length; c++) {
        if (this._children[c].getValue() === value) {
            // We already have this node: just return it so any other members below its level get put in the right place
            return this._children[c];
        }
    }
    // Not found: add a new child
    var newValue = new oj.CubeAxisValue(value, label, level, this);
    this._children.push(newValue);
    return newValue;
};

// Get a "hash value" for this axis value.  Format is levelAttr:value
oj.CubeAxisValue.prototype.GetHashCode = function() {
    var obj = {};
    obj[this.getLevel()['attribute']] = this.getValue();
    return obj;
};
    
// Return the child immediately preceding this one
oj.CubeAxisValue.prototype._getPrevChild = function(currChild) {
    for (var c = 0; c < this._children.length; c++) {
        if (this._children[c] === currChild) {
            // Found this child: see if there's a previous one
            if (c > 0) {
                return this._children[c-1];
            }
            // First child
            return null;
        }
    }
    // Not found
    return null;
};