/*
 * NPlot - A charting library for .NET
 * 
 * PageAlignedPhysicalAxis.cs
 * Copyright (C) 2003-2006 Matt Howlett and others.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of NPlot nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections;

namespace NPlot
{

    /// <summary>
    /// The bare minimum needed to do world->physical and physical->world transforms for
    /// vertical axes. Also includes tick placements. Built for speed.
    /// </summary>
    /// <remarks>currently unused</remarks>
    public class PageAlignedPhysicalAxis
    {

        private int pMin_;
        private int pMax_;
        private int pLength_;      // cached.

        private double worldMin_;
        private double worldMax_;
        private double worldLength_; // cached.
        

        /// <summary>
        /// Construct from a fully-blown physical axis.
        /// </summary>
        /// <param name="physicalAxis">the physical axis to get initial values from.</param>
        public PageAlignedPhysicalAxis( PhysicalAxis physicalAxis )
        {
            worldMin_ = physicalAxis.Axis.WorldMin;
            worldMax_ = physicalAxis.Axis.WorldMax;
            worldLength_ = worldMax_ - worldMin_;

            if ( physicalAxis.PhysicalMin.X == physicalAxis.PhysicalMax.X )
            {
                pMin_ = physicalAxis.PhysicalMin.Y;
                pMax_ = physicalAxis.PhysicalMax.Y;
            }
            else if ( physicalAxis.PhysicalMin.Y == physicalAxis.PhysicalMax.Y )
            {
                pMin_ = physicalAxis.PhysicalMin.X;
                pMax_ = physicalAxis.PhysicalMax.X;
            }
            else
            {
                throw new NPlotException( "Physical axis is not page aligned" );
            }

            pLength_ = pMax_ - pMin_;

        }

        
        /// <summary>
        /// return the physical coordinate corresponding to the supplied world coordinate.
        /// </summary>
        /// <param name="world">world coordinate to determine physical coordinate for.</param>
        /// <returns>the physical coordinate corresoindng to the supplied world coordinate.</returns>
        public float WorldToPhysical( double world )
        {
            return (float)(((world-worldMin_) / worldLength_) * (float)pLength_ + (float)pMin_);
        }


        /// <summary>
        /// return the physical coordinate corresponding to the supplied world coordinate,
        /// clipped if it is outside the bounds of the axis
        /// </summary>
        /// <param name="world">world coordinate to determine physical coordinate for.</param>
        /// <returns>the physical coordinate corresoindng to the supplied world coordinate.</returns>
        public float WorldToPhysicalClipped( double world )
        {
            if (world > worldMax_)
            {
                return pMax_;
            }
            
            if (world < worldMin_)
            {
                return pMin_;
            }
            
            // is this quicker than returning WorldToPhysical?
            return (float)(((world-worldMin_) / worldLength_) * (float)pLength_ + (float)pMin_);
        }
    

        /// <summary>
        /// return the world coordinate corresponding to the supplied physical coordinate.
        /// </summary>
        /// <param name="physical">physical coordinate to determine world coordinate for.</param>
        /// <returns>the world coordinate corresponding to the supplied </returns>
        public double PhysicalToWorld( float physical )
        {
            return ((float)(physical-pMin_) / (float)pLength_) * worldLength_ + worldMin_;
        }


    }
}
