/*
 * [HexNumberFormatter.java]
 *
 * Summary: hex unsigned long NumberFormatter for a JSpinner.
 *
 * Copyright: (c) 2007-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.8+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2007-08-15 initial version
 */
package com.mindprod.spinner;
import javax.swing.text.DefaultFormatter;
import java.text.ParseException;
/**
 * hex unsigned long NumberFormatter for a JSpinner.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2007-08-15 initial version
 * @since 2007-08-15
 */
@SuppressWarnings( { "WeakerAccess" } )
public final class HexNumberFormatter extends DefaultFormatter
    {
    // max chars with in hex digits.
    private final int width;
    /**
     * constructor
     *
     * @param width how many chars wide is the field.
     */
    public HexNumberFormatter( int width )
        {
        if ( width > 16 )
            {
            throw new IllegalArgumentException( "HexFormat width > 16" );
            }
        this.width = width;
        }
    /**
     * Converts the passed in String into an instance of <code>getValueClass</code> by way of the constructor that takes
     * a String argument. If <code>getValueClass</code> returns null, the class of the current value in the
     * <code>JFormattedTextField</code> will be used. If this is null, a String will be returned. If the constructor
     * thows an exception, a <code>ParseException</code> will be thrown. If there is no single argument String
     * constructor, <code>string</code> will be returned.
     *
     * @param string String to convert
     *
     * @return Object representation of text, namely Long, must match what JSpinnerNumberModel uses.
     * @throws java.text.ParseException if there is an error in the conversion
     */
    @SuppressWarnings( { "QuestionableName" } )
    public Object stringToValue( String string ) throws ParseException
        {
        try
            {
            if ( string.length() > width )
                {
                throw new ParseException( "Max " + width + " digits allowed.",
                        0 );
                }
            // find out what sort of Number object is desired.
            // Pick one matching value in NumberModel.
            Object value = getFormattedTextField().getValue();
            if ( value instanceof Integer )
                {
                return Integer.valueOf( string, 16/* radix */ );
                }
            else if ( value instanceof Long )
                {
                return Long.valueOf( string, 16/* radix */ );
                }
            else
                {
                throw new IllegalArgumentException(
                        "HexNumberFormatter only works with Integer and Long" );
                }
            }
        catch ( NumberFormatException nfe )
            {
            throw new ParseException( string, 0 );
            }
        }
    /**
     * Converts the passed in Object into a String by way of the <code>toString</code> method.
     *
     * @param value Value to convert, some sort of Number
     *
     * @return String representation of value, padded with left zeroes to width.
     * @throws ParseException if there is an error in the conversion
     */
    public String valueToString( Object value ) throws ParseException
        {
        // treat as unsigned
        final long asLong = ( ( Number ) value ).longValue();
        final String hex = Long.toHexString( asLong );
        // apply lead zeroes as needed.
        final int lz = width - hex.length();
        return lz <= 0 ? hex : "0000000000000000".substring( 0, lz ) + hex;
        }
    }