/** =======================================================================
 *  Vincent Hardy
 *  License terms: see svg-wow.org
 *  CC0 http://creativecommons.org/publicdomain/zero/1.0/
 *  ======================================================================= */

var yui = yui || YAHOO;

sw.tools = sw.tools || {};

/** 
 * Provides a magnifying function and returns the modified position
 * and size of a given point.
 *
 * Inspired by Jared Tarbel's text sphere:
 * http://www.levitated.net/daily/levTextSphere.html
 *
 * @param radius the magnifier's radius.
 * @param x the magnifier's x position
 * @param y the magnifier's y position
 * @param maxMagnification the magnifier's maximum magnification (at
 *        it's center position).
 * @param minMagnification the magnifier's minimum magnification (at
 *        it's center position).
 * @param direction one of <code>DIRECTION_BOTH</code>, <code>DIRECTION_X</code>
 *        <code>DIRECTION_Y</code>
 */
sw.tools.Magnifier = function (radius, x, y, 
                               maxMagnification, 
                               minMagnification,
                               direction) {
    this.radius = radius;
    this.x = x;
    this.y = y;
    this.maxMagnification = maxMagnification;
    this.minMagnification = minMagnification;
    this.direction = direction;
    this.events = {
        onChange: new yui.util.CustomEvent(this.MAGNIFIER_CHANGE)
    }
}

/**
 * Constants
 */
sw.tools.Magnifier.prototype.MAGNIFIER_CHANGE = "MAGNIFIER_CHANGE";
sw.tools.Magnifier.prototype.DIRECTION_BOTH = 0;
sw.tools.Magnifier.prototype.DIRECTION_X = 1;
sw.tools.Magnifier.prototype.DIRECTION_Y= 2;

/**
 * Sets the current radius
 *
 * @param newRadius the new magnifier radius
 */
sw.tools.Magnifier.prototype.setRadius = function (newRadius) {
    if (this.radius !== newRadius) {
        this.radius = newRadius;
        this.events.onChange.fire();
    }
}

/**
 * Change the magnifier position.
 */
sw.tools.Magnifier.prototype.setPosition = function (x, y) {
    this.x = x;
    this.y = y;
    this.events.onChange.fire();
}

/**
 * Computes the displacement for the given point.
 *
 * @param x the input point's x coordinate
 * @param y the input point's y coordinate
 * @param result an object where the displaced coordinates and magnification
 *        factor will be stored.
 */
sw.tools.Magnifier.prototype.processPoint = function (x, y, result) {
    var dx = x - this.x;
    var dy = y - this.y;
    var displacement;
    
    var d = Math.sqrt(dx * dx + dy * dy);
    var p = d / this.radius;
    
    if (p >= 1) {
        result.x = x;
        result.y = y;
        result.magnification = this.minMagnification;
        result.displacement = 0;
        result.p = 1;
    } else {
        // On the edge of the magnifier, there is no displacement.
        // There is no displacement at the center either.
        // The maximum displacement is half way (p = 0.5) between
        // the edge of the lens and its center.
        displacement = Math.sin(Math.PI * p);
        
        result.x = x + dx * displacement;
        result.y = y + dy * displacement;
        
        // The maximum magnification is reached at the center of the lens (p = 0).
        // On the edge (p = 1), the magnification is 1 (no magnification).
        result.magnification = this.minMagnification + 
                               (this.maxMagnification - this.minMagnification) * 
            (1 - Math.sin(p * Math.PI / 2));
        result.displacement = displacement;
        result.p = p;
    }
    
    switch (this.direction) {
        case this.DIRECTION_X: {
            result.y = y;
            break;
        }
        case this.DIRECTION_Y: {
            result.x = x;
            break;
        }
        default:
            break;
    }
}
