API Docs for:
Show:

File: src/core/periodic_array_data.js

window.multigraph.util.namespace("window.multigraph.core", function (ns) {
    "use strict";

    /**
     * @module multigraph
     * @submodule core
     */

    /**
     * @class PeriodicArrayData
     * @for PeriodicArrayData
     * @constructor
     * @param {array} columns A array of DataVariables
     * @param {array} stringArray A array of strings which will later be parsed into DataValues
     */
    ns.PeriodicArrayData = window.jermaine.Model(function () {
        var PeriodicArrayData = this,
            emptyIterator = {
                "next"    : function () {},
                "hasNext" : function () { return false; }
            };

        this.isA(ns.ArrayData);
        this.hasA("period").which.validatesWith(ns.DataMeasure.isInstance);
        //this.hasA("column0RelativeRealValues").which.defaultsTo(null);
        this.isBuiltWith("columns", "stringArray", "period", function () {
            this.init();
            this.addListener("listenerAdded", function (event) {
                var data = this.array();
                if (event.targetType === "dataReady") {
                    event.listener(data[0][0], data[data.length-1][0]);
                }
            });
        });

/*
        this.respondsTo("initializeColumn0RelativeRealValues", function() {
            var array = this.array(),
                column0RelativeRealValues = [],
                i;
            for (i=0; i<array.length; ++i) {
                column0RelativeRealValues[i] = array[i][0] - array[0][0];
            }
            this.column0RelativeRealValues(column0RelativeRealValues);
        });
*/

        /**
         * @method getIterator
         * @param {string array} columnIDs
         * @param {DataValue} min
         * @param {DataValue} max
         * @param {Integer} buffer
         * @author jrfrimme
         */
        this.respondsTo("getIterator", function (columnIds, min, max, buffer) {
            return PeriodicArrayData.getArrayDataIterator(this, columnIds, min, max, buffer);
        });

        /**
         * @method getArrayDataIterator
         * @static
         * @param {ArrayData} arrayData
         * @param {string array} columnIDs
         * @param {DataValue} min
         * @param {DataValue} max
         * @param {Integer} buffer
         * @return iter
         * @author jrfrimme
         */
        PeriodicArrayData.getArrayDataIterator = function (periodicArrayData, columnIds, min, max, buffer) {
            var DataValue = ns.DataValue,
                iter = {},
                arraySlice = [],
                curr = 0,
                i, j,
                currentIndex,
                columnIndices,
                array = periodicArrayData.array();

            buffer = buffer || 0;

            // columnIds argument should be an array of strings
            if (Object.prototype.toString.apply(columnIds) !== "[object Array]") {
                throw new Error("ArrayData: getIterator method requires that the first parameter be an array of strings");
            } else {
                for (i = 0; i < columnIds.length; ++i) {
                    if (typeof(columnIds[i]) !== "string") {
                        throw new Error("ArrayData: getIterator method requires that the first parameter be an array of strings");
                    }
                }
            }

            //min,max arguments should be data values
            if (!DataValue.isInstance(min) || !DataValue.isInstance(max)) {
                throw new Error("ArrayData: getIterator method requires the second and third argument to be number values");
            }

            //buffer argument should be an integer
            if (typeof(buffer) !== "number") {
                throw new Error("ArrayData: getIterator method requires last argument to be an integer");
            }

            // if we have no data, return an empty iterator
            if (array.length === 0) {
                return emptyIterator;
            }

/*
            // populate the column0RelativeRealValues array if it hasn't yet been populated
            if (this.column0RelativeRealValues() === null) {
                this.initializeColumn0RelativeRealValues();
            }
*/

            // Let `baseValue` be the location of the first data point in the array
            var baseValue = array[0][0];

            // In the regular lattice of spacing `period` aligned with baseValue,
            // find the last point that is less than or equal to `min`.  Call this point `b`.
            var b = periodicArrayData.period().lastSpacingLocationAtOrBefore(min, baseValue);

            // Let `offsetRealValue` be the difference between b and baseValue, as a real value:
            var offsetRealValue = b.getRealValue() - baseValue.getRealValue();

            // Let `baseMin` be `min` shifted 'backward' by offsetRealValue; this is `min`
            // relative to the same period cycle as baseValue:
            var baseMin = DataValue.create(min.type, min.getRealValue() - offsetRealValue);

            // find the index of the first row in the array whose column0 value is >= baseMin;
            // this is the data point we start with
            for (currentIndex = 0; currentIndex < array.length; ++currentIndex) {
                if (array[currentIndex][0].ge(baseMin)) {
                    break;
                }
            }
            if (currentIndex === array.length) {
                return emptyIterator;
            }

            //
            //TODO later: back up 'buffer' steps
            //

            // set the current value to be the column0 value at this first index, shifted
            // 'forward' by offsetRealValue
            var currentValue = DataValue.create(array[currentIndex][0].type, array[currentIndex][0].getRealValue() + offsetRealValue);

            columnIndices = [];
            for (j = 0; j < columnIds.length; ++j) {
                var k = periodicArrayData.columnIdToColumnNumber(columnIds[j]);
                columnIndices.push( k );
            }

            return {
                next : function () {
                    var projection = [],
                        i, x;
                    if (currentIndex < 0) {
                        return null;
                    }
                    for (i = 0; i < columnIndices.length; ++i) {
                        if (columnIndices[i] === 0) {
                            projection.push(currentValue);
                        } else {
                            projection.push(array[currentIndex][columnIndices[i]]);
                        }
                    }
                    ++currentIndex;
                    if (currentIndex >= array.length) {
                        currentIndex = 0;
                        b = b.add(periodicArrayData.period());
                        offsetRealValue = b.getRealValue() - baseValue.getRealValue();
                    }
                    currentValue = ns.DataValue.create(array[currentIndex][0].type, array[currentIndex][0].getRealValue() + offsetRealValue);
                    if (currentValue.gt(max)) {
                        //TODO: actually need to figure out how to move forward `buffer` steps, but for
                        // now skip that part.
                        currentIndex = -1;
                    }
                    return projection;
                },
                hasNext : function () {
                    return (currentIndex >= 0);
                }
            };
            
        };

    });
});