/*
 *******************************************************************************
 * Copyright (C) 2001-2010, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */

/** 
 * Porting From: ICU4C v1.8.1 : format : NumberFormatRoundTripTest
 * Source File: $ICU4CRoot/source/test/intltest/nmfmtrt.cpp
 **/

package com.ibm.icu.dev.test.format;

import java.util.Locale;
import java.util.Random;

import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.NumberFormat;

/** 
 * Performs round-trip tests for NumberFormat
 **/
public class NumberFormatRoundTripTest extends com.ibm.icu.dev.test.TestFmwk {
    
    public double MAX_ERROR = 1e-14;
    public double max_numeric_error = 0.0;
    public double min_numeric_error = 1.0;
    public boolean verbose = false;
    public boolean STRING_COMPARE = false;
    public boolean EXACT_NUMERIC_COMPARE = false;
    public boolean DEBUG = false;
    public boolean quick = true;
    
    public static void main(String[] args) throws Exception {
        new NumberFormatRoundTripTest().run(args);
    }
    
    public void TestNumberFormatRoundTrip() {
    
        NumberFormat fmt = null;
    
        logln("Default Locale");
        
        logln("Default Number format");
        fmt = NumberFormat.getInstance();
        _test(fmt);
    
        logln("Currency Format");
        fmt = NumberFormat.getCurrencyInstance();
        _test(fmt);
    
        logln("Percent Format");
        fmt = NumberFormat.getPercentInstance();
        _test(fmt);
    
    
        int locCount = 0;
        final Locale[] loc = NumberFormat.getAvailableLocales();
        if(quick) {
            if(locCount > 5)
                locCount = 5;
            logln("Quick mode: only _testing first 5 Locales");
        }
        for(int i = 0; i < locCount; ++i) {
            logln(loc[i].getDisplayName());
    
            fmt = NumberFormat.getInstance(loc[i]);
            _test(fmt);
        
            fmt = NumberFormat.getCurrencyInstance(loc[i]);
            _test(fmt);
        
            fmt = NumberFormat.getPercentInstance(loc[i]);
            _test(fmt);
        }
    
        logln("Numeric error " + min_numeric_error + " to " + max_numeric_error);
    }
    
    /**
     * Return a random value from -range..+range.
     */
    private Random random;
    public double randomDouble(double range) {
        if (random == null) {
            random = createRandom(); // use test framework's random seed
        }
        return  random.nextDouble() * range;
    } 
    
    public void _test(NumberFormat fmt) {
    
        _test(fmt, Double.NaN);
        _test(fmt, Double.POSITIVE_INFINITY);
        _test(fmt, Double.NEGATIVE_INFINITY);
    
        _test(fmt, 500);
        _test(fmt, 0);
        _test(fmt, -0);
        _test(fmt, 0.0);
        double negZero = 0.0;
        negZero /= -1.0;
        _test(fmt, negZero);
        _test(fmt, 9223372036854775808.0d);
        _test(fmt, -9223372036854775809.0d);
        //_test(fmt, 6.936065876100493E74d);
        
    //    _test(fmt, 6.212122845281909E48d);
        for (int i = 0; i < 10; ++i) {
    
            _test(fmt, randomDouble(1));
            
            _test(fmt, randomDouble(10000));
    
            _test(fmt, Math.floor((randomDouble(10000))));
    
            _test(fmt, randomDouble(1e50));
    
            _test(fmt, randomDouble(1e-50));
    
            _test(fmt, randomDouble(1e100));
    
            _test(fmt, randomDouble(1e75));
    
            _test(fmt, randomDouble(1e308) / ((DecimalFormat) fmt).getMultiplier());
    
            _test(fmt, randomDouble(1e75) / ((DecimalFormat) fmt).getMultiplier());
    
            _test(fmt, randomDouble(1e65) / ((DecimalFormat) fmt).getMultiplier());
    
            _test(fmt, randomDouble(1e-292));
    
            _test(fmt, randomDouble(1e-78));
    
            _test(fmt, randomDouble(1e-323));
    
            _test(fmt, randomDouble(1e-100));
    
            _test(fmt, randomDouble(1e-78));
        }
    }
    
    public void _test(NumberFormat fmt, double value) {
        _test(fmt, new Double(value));
    }
    
    public void _test(NumberFormat fmt, long value) {
        _test(fmt, new Long(value));
    }
    
    public void _test(NumberFormat fmt, Number value) {
        logln("test data = " + value);
        fmt.setMaximumFractionDigits(999);
        String s, s2;
        if (value.getClass().getName().equalsIgnoreCase("java.lang.Double"))
            s = fmt.format(value.doubleValue());
        else
            s = fmt.format(value.longValue());
    
        Number n = new Double(0);
        boolean show = verbose;
        if (DEBUG)
            logln(
            /*value.getString(temp) +*/ " F> " + s);
        try {
            n = fmt.parse(s);
        } catch (java.text.ParseException e) {
            System.out.println(e);
        }
    
        if (DEBUG)
            logln(s + " P> " /*+ n.getString(temp)*/);
    
        if (value.getClass().getName().equalsIgnoreCase("java.lang.Double"))
            s2 = fmt.format(n.doubleValue());
        else
            s2 = fmt.format(n.longValue());
    
        if (DEBUG)
            logln(/*n.getString(temp) +*/ " F> " + s2);
    
        if (STRING_COMPARE) {
            if (!s.equals(s2)) {
                errln("*** STRING ERROR \"" + s + "\" != \"" + s2 + "\"");
                show = true;
            }
        }
    
        if (EXACT_NUMERIC_COMPARE) {
            if (value != n) {
                errln("*** NUMERIC ERROR");
                show = true;
            }
        } else {
            // Compute proportional error
            double error = proportionalError(value, n);
    
            if (error > MAX_ERROR) {
                errln("*** NUMERIC ERROR " + error);
                show = true;
            }
    
            if (error > max_numeric_error)
                max_numeric_error = error;
            if (error < min_numeric_error)
                min_numeric_error = error;
        }
    
        if (show)
            logln(
            /*value.getString(temp) +*/ value.getClass().getName() + " F> " + s + " P> " +
            /*n.getString(temp) +*/ n.getClass().getName() + " F> " + s2);
    
    }
        
    public double proportionalError(Number a, Number b) {
        double aa,bb;
        
        if(a.getClass().getName().equalsIgnoreCase("java.lang.Double"))
            aa = a.doubleValue();
        else
            aa = a.longValue();
    
        if(a.getClass().getName().equalsIgnoreCase("java.lang.Double"))
            bb = b.doubleValue();
        else
            bb = b.longValue();
    
        double error = aa - bb;
        if(aa != 0 && bb != 0) 
            error /= aa;
           
        return Math.abs(error);
    }   
}
