/**
 * Class: StrategyBBOX
 * A simple strategy that reads new features when the viewport invalidates
 *     some bounds.
 */
function StrategyBBOX(map, main, options) {
    /**
     * Property: bounds
     * {<OpenLayers.Bounds>} The current data bounds
     */
    this.bounds = null;

    /**
     * APIProperty: ratio
     * {Float} The ratio of the data bounds to the viewport bounds (in each
     *     dimension).  Default is 2.
     */
    this.ratio = 2;

    OpenLayers.Util.extend(this, options);

    this.map = map;
    this.main = main;
};

/**
 * Method: update
 * Callback function called on map "dragend" and "zoomend" events.
 *
 * Parameters:
 * options - {Object} An object with a property named "force", this
 *      property references a boolean value indicating if new data
 *      must be inconditionally read.
 *      
 *      Can also contains 'moreValues' and 'moreValueField' properties when
 *      there was selected overlays before zooming to a new data level.
 */
StrategyBBOX.prototype.update = function(options) {
    var oMapBounds = this.map.getBounds();
    if ((options && options.force) || this.invalidBounds(oMapBounds)) {
        this.calculateBounds(oMapBounds);

        if(options && options.moreValues && options.moreValueField) {
            this.triggerRead({
                'moreValues': options.moreValues,
                'moreValueField': options.moreValueField
            });
        } else {
            this.triggerRead();            
        }
    }
};

/**
 * Method: invalidBounds
 * Determine whether the previously requested set of features is invalid. 
 *     This occurs when the new map bounds do not contain the previously 
 *     requested bounds.  In addition, if <resFactor> is set, it will be 
 *     considered.
 *
 * Parameters:
 * oMapBounds - {<GLatLngBounds>} the current map extent, will be
 *      retrieved from the map object if not provided
 *
 * Returns:
 * {Boolean} 
 */
StrategyBBOX.prototype.invalidBounds = function(oMapBounds) {
    if(!oMapBounds) {
        oMapBounds = this.map.getBounds();
    }
    var invalid = !this.bounds || !this.bounds.containsBounds(oMapBounds);

    return invalid;
};

/**
 * Method: calculateBounds
 *
 * Parameters:
 * oMapBounds - {<GLatLngBounds>} the current map extent, will be
 *      retrieved from the map object if not provided
 */
StrategyBBOX.prototype.calculateBounds = function(oMapBounds) {
    if(!oMapBounds) {
        oMapBounds = this.map.getBounds();
    }
    var center = oMapBounds.getCenter();

    var oSize = oMapBounds.getSize();
    var dataWidth = oSize.width * this.ratio;
    var dataHeight = oSize.height * this.ratio;

    this.bounds = new GLatLngBounds(
        new GLatLng(center.lat() - (dataHeight / 2),
                    center.lng() - (dataWidth / 2)),
        new GLatLng(center.lat() + (dataHeight / 2),
                    center.lng() + (dataWidth / 2))
    );
};


/**
 * Method: triggerRead
 *
 * Triggers the getTempOverlays function with this bounds.
 *
 * Parameters:
 * options - {Object} An options object used for the getFeatures request.
 */
StrategyBBOX.prototype.triggerRead = function(options) {
    options = options || {};
    options['extent'] =  this.bounds.toBBOX()
    this.main.getFeatures(this.main.addTempOverlays, options);
};

