/*
 * @(#)ParserUtilities.java    2.5.0   21 August 2006
 *
 * Copyright 2006
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.parser;

import edu.neu.ccs.*;
import edu.neu.ccs.util.*;
import java.text.*;
import java.util.Hashtable;
import java.math.*;

/**
 * <p>Provides access to the current default parser and
 * static utility methods for use with parser operations.</p>
 *
 * <p>As of 2.5.0, requires the default parser to be a
 * parser derived from class <code>BaseParser</code>
 * rather than simply to be a parser that implements
 * <code>Parser</code>.  This guarantees that certain
 * parser functionality is available.</p>
 * 
 * <p>This class contains only static data and methods
 * and may not be instantiated.</p>
 * 
 * @author  Richard Rasala
 * @author  Jeff Raab
 * @version 2.5
 * @see BaseParser
 * @see JPTParser
 */
public class ParserUtilities {
    
    /** Prevent instantiation. */
    private ParserUtilities() {}
    
    
    /** Default parser used by JPT classes. */
    private static BaseParser parser = new JPTParser();
    
    
    /**
     * Returns the default parser used by JPT classes.
     */
    public static BaseParser getDefaultParser() {
        return parser;
    }
    
    
    /**
     * <p>Sets the default parser used by JPT classes
     * to the given parser.</p>
     *
     * <p>If <CODE>null</CODE>, the default parser is
     * set to a new standard default parser for JPT,
     * that is, a new <code>JPTParser</code>.</p>
     *
     * @param p the desired default parser
     */
    public static void setDefaultParser(BaseParser p) {
        if (p == null)
            p = new JPTParser();
            
        parser = p;
    }
    
    
    /** Return true if x is an <CODE>XNumber</CODE>. */
    public static boolean isXNumber(Object x) {
        return x instanceof XNumber;
    }
    
    /**
     * Return true if x is integral, that is, if
     * x is one of the types:
     * <CODE>XBigInteger</CODE>,
     * <CODE>XLong</CODE>,
     * <CODE>XInt</CODE>,
     * <CODE>XShort</CODE>,
     * <CODE>XByte</CODE>.
     */
    public static boolean isXIntegral(Object x) {
        return
               (x instanceof XBigInteger)
            || (x instanceof XLong)
            || (x instanceof XInt)
            || (x instanceof XShort)
            || (x instanceof XByte);
    }
    
    /**
     * Return true if x is floating, that is, if
     * x is one of the types:
     * <CODE>XBigDecimal</CODE>,
     * <CODE>XDouble</CODE>,
     * <CODE>XFloat</CODE>.
     */
    public static boolean isXFloating(Object x) {
        return
               (x instanceof XBigDecimal)
            || (x instanceof XDouble)
            || (x instanceof XFloat);
    }
    
    /** Return true if x is XBoolean. */
    public static boolean isXBoolean(Object x) {
        return x instanceof XBoolean;
    }
    
    /**
     * Converts the given value to XLong.
     *
     * @param value the value to be converted
     */
    public static XLong toXLong(XNumber value) {
        if (value instanceof XLong)
            return (XLong)value;
        
        return new XLong(value.longValue());
    }
    
    /**
     * Converts the given value to XDouble.
     *
     * @param value the value to be converted
     */
    public static XDouble toXDouble(XNumber value) {
        if (value instanceof XDouble)
            return (XDouble)value;
        
        return new XDouble(value.doubleValue());
    }

    /**
     * Converts the given value to XBigInteger.
     *
     * @param value the value to be converted
     */
    public static XBigInteger toXBigInteger(XNumber value) {
        if (value instanceof XBigInteger)
            return (XBigInteger)value;
        
        if (value instanceof XBigDecimal) {
            XBigDecimal v = (XBigDecimal) value;
            BigDecimal  x = v.getValue();
            return new XBigInteger(x.toBigInteger());
        }
        
        String s = "0";
        
        if (isXIntegral(value)) {
            s = value.longValue() + "";
        }
        else {
            // construct the best integral string s representing value
            double x = value.doubleValue();
            x = Math.rint(x);
            
            DecimalFormat f = new DecimalFormat("#0");
            StringBuffer  b = new StringBuffer(1024);
            FieldPosition p = new FieldPosition(NumberFormat.INTEGER_FIELD);
            
            b = f.format(x, b, p);
            s = b.toString();
        }
        
        return new XBigInteger(new BigInteger(s));
    }

    /**
     * Converts the given value to XBigDecimal.
     *
     * @param value the value to be converted
     */
    public static XBigDecimal toXBigDecimal(XNumber value) {
        if (value instanceof XBigDecimal)
            return (XBigDecimal)value;
        
        if (value instanceof XBigInteger) {
            XBigInteger v = (XBigInteger) value;
            BigInteger  x = v.getValue();
            
            return new XBigDecimal(new BigDecimal(x));
        }
        
        if (isXIntegral(value)) {
            String s = value.longValue() + "";
            
            return new XBigDecimal(new BigDecimal(s));
        }
        
        double z = value.doubleValue();
        
        return new XBigDecimal(new BigDecimal(z));
    }

}
