/*
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.javafx.css;

import javafx.scene.text.Font;

/**
 * Represents a size specified in a particular unit, such as 14px or 0.2em.
 */
final public class Size {

    final private double value;
    final private SizeUnits units;
    public Size(double value, SizeUnits units) {
        this.value = value;
        this.units = (units != null) ? units : SizeUnits.PX;
    }

    /** */
    public double getValue() {
        return value;
    }

    /** */
    public SizeUnits getUnits() {
        return units;
    }

    /**
     * Return whether or not this Size is an absolute value or a relative value.
     */
    public boolean isAbsolute() {
        return units.isAbsolute();
    }

    /** Convert this size into Points units, a Point is 1/72 of a inch */
    public double points(Font font) {
        return points(1.0, font);
    }

    /**
      * Convert this size into points
      *
      * @param multiplier   The multiplier for PERCENTAGE sizes
      * @param font         The font for EM sizes
      */
    public double points(double multiplier, Font font) {
        return units.points(value, multiplier, font);
    }

    /**
      * Convert this size into pixels
      *
      * @param multiplier   The multiplier for PERCENTAGE sizes
      * @param font         The font for EM sizes
      */
    public double pixels(double multiplier, Font font) {
        return units.pixels(value, multiplier, font);
    }

    /**
      * If size is not an absolute size, return the product of font size in pixels
      * and value. Otherwise, return the absolute value.
      */
    public double pixels(Font font) {
        return pixels(1.0f, font);
    }

    /**
      * If size is not an absolute size, return the product of multiplier
      * and value. Otherwise, return the absolute value.
      */
    public double pixels(double multiplier) {
        return pixels(multiplier, null);
    }

    /**
      * A convenience method for calling <code>pixels(1)</code>
      */
    public double pixels() {
        return pixels(1.0f, null);
    }

    @Override public String toString() {
        return Double.toString(value) + units.toString();
    }

    @Override public int hashCode() {
        long bits = 17L;
        bits = 37L * bits + Double.doubleToLongBits(value);
        bits = 37L * bits + units.hashCode();
        return (int) (bits ^ (bits >> 32));
    }

    @Override public boolean equals(Object obj) {
        if (this == obj) return true;

        if (obj == null || obj.getClass() != this.getClass()) {
            return false;
        }
        final Size other = (Size)obj;

        if (units != other.units) {
            return false;
        }

        if (value == other.value) {
            return true;
        }

        if ((value > 0) ? other.value > 0 : other.value < 0) {
            //
            // double == double is not reliable since a double is kind of
            // a fuzzy value. And Double.compare is too precise.
            // For javafx, most sizes are rounded to the nearest tenth
            // (see SizeUnits.round) so comparing  here to the nearest
            // millionth is more than adequate. In the case of rads and
            // percents, this is also be more than adequate.
            //
            // Math.abs is too slow!
            final double v0 = value > 0 ? value : -value;
            final double v1 = other.value > 0 ? other.value : -other.value;
            final double diff = value  - other.value;
            if (diff < -0.000001 || 0.000001 < diff) {
                return false;
            }

            return true;
        }
        return false;
    }

}

