import java.util.*;

/**
 * An encapsulation of a picture frame.
 *
 * This version has overloaded methods.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 7.0
 */
public class PictureFrame
{
    private static final double DOLLARS_PER_IN_OF_FRAME    = 0.15;
    private static final double DOLLARS_PER_SQ_IN_OF_GLASS = 0.05;    

    private boolean    stand;    
    private double     height, matte, width;

    /**
     * Construct a PictureFrame object.
     *
     * Note: Negative values are converted to positive values 
     * and the width and height are put in canonical form 
     * (i.e., a portrait orientation).
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     * @param matte   The size of the matte (in inches) on all 4 sides
     * @param stand   true if there is a built-in stand
     */
    public PictureFrame(double width, double height, double matte, 
                        boolean stand)
    {
        double     h, w;
        
        h = Math.abs(height);
        w = Math.abs(width);

        this.width  = Math.min(w, h);
        this.height = Math.max(w, h);
        this.matte  = Math.abs(matte);
        this.stand  = stand;
    }
    
    /**
     * Construct a PictureFrame object with no matte and no stand.
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     */
    public PictureFrame(double width, double height)
    {
        this(width, height, 0.0, false);
    }
    
    /**
     * Default Constructor.
     *
     * Construct a 3x5 PictureFrame with no matte and no stand.
     */
    public PictureFrame()
    {
        this(3.0, 5.0, 0.0, false);
    }
    
    /**
     * Copy Constructor.
     *
     * @param other   The PictureFrame to copy
     */
    public PictureFrame(PictureFrame other)
    {
        this(other.width, other.height, other.matte, other.stand);
    }

    /**
     * Calculate the area of this PictureFrame.
     *
     * @return  The area (in square inches)
     */
    private double area()
    {
        return width * height;
    }

    /**
     * Calculate the area of the matte.
     *
     * @return  The area (in square inches)
     */
    private double matteArea()
    {
               // Top and Bottom   + Sides (not including the top and bottom)
        return 2.0*(matte * width) + 2.0*(matte * (height - 2.0*matte));
    }

    /**
     * Calculate the perimeter of this PictureFrame.
     *
     * @return  The area (in inches)
     */
    private double perimeter()
    {
        return 2.0*width + 2.0*height;
    }

    /**
     * Return true of the owning PictureFrame and the given PictureFrame
     * have the same attributes.
     *
     * @return  true if the attributes are the same; false otherwise
     */
    public boolean equals(PictureFrame other)
    {
        return (this.width == other.width) && (this.height == other.height)
            && (this.matte == other.matte) && (this.stand == other.stand);
    }

    /**
     * Return the cost of this PictureFrame (which is a function
     * of the perimeter and the area) in dollars.
     *
     * @return   The cost
     */
    public double getCost()
    {
        double     frame, glass;
        
        frame = perimeter() * DOLLARS_PER_IN_OF_FRAME;
        glass = area() * DOLLARS_PER_SQ_IN_OF_GLASS;

        return frame+glass;
    }

    /**
     * Get the height of this PictureFrame.
     *
     * @return   The height
     */
    public double getHeight()
    {
        return height;
    }

    /**
     * Get the size of the matte.
     *
     * @return   The size of the matte
     */
    public double getMatte()
    {
        return matte;
    }

    /**
     * Get the width of this PictureFrame.
     *
     * @return   The width
     */
    public double getWidth()
    {
        return width;
    }

    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @param    max   true for the maximum possible (i.e., unmatted) area 
     * @return   The visible area
     */
    public double getVisibleArea(boolean max)
    {
        double   result;
        
        result = area();
        if (!max) result -= matteArea();

        return result;
    }

    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @return   The visible area
     */
    public double getVisibleArea()
    {
        return getVisibleArea(false);
    }

//[parse
    /**
     * Create a PictureFrame object from a comma-delimited
     * String representation.
     *
     * @param s   The String representation
     * @return    The PictureFrame object (or null)
     */
    public static PictureFrame parsePictureFrame(String s)
    {
        double               height, matte, width;        
        PictureFrame         result;        
        String               token;        
        StringTokenizer      st;
        
        st = new StringTokenizer(s, ",");
        try
        {
            token = st.nextToken();
            width = Double.parseDouble(token);
            
            token = st.nextToken();
            height = Double.parseDouble(token);

            token = st.nextToken();
            matte = Double.parseDouble(token);
            
            token = st.nextToken();
            result = new PictureFrame(width, height, matte,
                                      token.equalsIgnoreCase("TRUE"));
        }
        catch (NumberFormatException nfe)
        {
            result = null;
        }
        catch (NoSuchElementException msee)
        {
            result = null;
        }

        return result;
    }
//]parse    

    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @param   terse  true for a terse representation
     * @return         The String representation
     */
    public String toString(boolean terse)
    {
        String      result;

        if (terse)
        {
            result = ""+width+"x"+height;
        }
        else
        {
            result = ""+width+"in. x "+height+"in.";
            if (matte > 0.0) result += " with a "+matte+"in. matte";
            if (stand)       result += " (w/ stand)";
        }
        
        return result;
    }

    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @return         The String representation
     */
    public String toString()
    {
        return toString(false);
    }
}
