/**
 * $Id:  $
 */

define( [], function( ) {
	
	TimeSeries = function( key ) {
		// Series.call( this, key );
        this.key = key;
        this.series = {
            "data": [],
            "maxlen": 0,
        };

        this.load();
	}

	// TimeSeries.prototype = Object.create(Series.prototype);
    // TimeSeries.prototype.constructor = TimeSeries;

	TimeSeries.prototype.load = function() {
        var s = localStorage.getItem( this.key );
        if ( s !== undefined )
            this.series = JSON.parse( s );
        else
            this.clear();
	}
    
    TimeSeries.prototype.save = function() {
        return localStorage.setItem( key, JSON.stringify( this.series ) );
	
	TimeSeries.prototype.setMaxLength = function( m ) {
        if ( m === undefined || m < 0 ) m = 0;
		this.series.maxlen = m;
		while ( m > 0 && this.series.data.length > m ) this.series.data.shift();
	}
    
    TimeSeries.prototype.getData() {
        return this.series.data;
    }
    
    TimeSeries.prototype.clear = function() {
        this.series.data = [];
    }
    
    TimeSeries.prototype.add = function( val ) {
        return this.addEvent( (new Date()).getTime(), val );
    }
    
    TimeSeries.prototype.findInsert = function( timestamp ) {
        // ??? Maybe binary search here instead?
        var start = 0, end = this.series.data.length-1;
        // Quickly solve the boundary cases.
        if (this.series.data.length == 0) return 0;
        if (timestamp < this.series.data[0]) return 0;
        if (timestamp >= this.series.data[end]) return end+1;
        
        /* Linear search version */
        while ( start <= end )
            if ( this.series.data[start].x > timestamp )
                break;
            ++start;
        }
        return start;
/*
        // Binary search version.
        while (start < end) {
            var mid = start + (end - start) / 2;
            if ( this.series.data[mid].x == timestamp ) 
                return mid;
            else if ( this.series.data[mid].x < timestamp )
                start = mid + 1;
            else 
                end = mid;
        }
        return start;
    }
*/
    
    TimeSeries.prototype.addEvent = function( timestamp, val ) {
        // ??? Concurrency?
        // ??? Insert in order if timestamp isn't increasing?
		while ( this.series.maxlen > 0 && this.series.data.length >= this.series.maxlen )
			this.series.data.shift();
		if ( val === undefined )
			val = null;
        // If element is after last element in list, add it to end
        if ( this.series.data.length == 0 || timestamp > this.series.data[this.series.data.length-1].x ) {
            this.series.data.push( { "x":timestamp, "y":val } );
            return true;
        }
        var pos = findInsert( timestamp );
        this.series.data.splice(pos, 0, { "x":timestamp, "y":val } );
        return true;
	}
    
    TimeSeries.prototype.getValueAtTime = function( timestamp ) {
        // ??? Maybe binary search here instead?
        var pos = findInsert( timestamp );
        if ( this.series.data[pos].x == timestamp ) // If we find dead-on what we need, just return it.
            return this.series.data[pos].y;
        
        // This leaves "pos" pointing at the next element greater than our search value (or off the end of the array)
        // We need to interpolate or extrapolate, and for that, at least two data points are always required.
        if (this.series.data.length < 2) return undefined;
        
        // Otherwise interpolate (if between values) or extrapolate (if beyond)
        var x1, x2, y1, y2;
        if ( pos == 0 ) {
            // First in array is beyond our goal time, so extrapolate backwards using first two elements.
            ++pos;
        } else if ( pos == this.series.data.length ) {
            // If we're off the end of the array, reposition to extrapolate forward from last two elements.
            --pos;
        }
        x1 = this.series.data[pos-1].x;
        y1 = this.series.data[pos-1].y;
        x2 = this.series.data[pos].x;
        y2 = this.series.data[pos].y;
        
        var dx = x2 - x1;
        var dy = y2 - y1;
        var f = (timestamp - x1) / dx;
        return y1 + dy * f;
    }
	
	return TimeSeries;

}); // define
