/*
 * [Roman.java]
 *
 * Summary: Display a number in Roman numerals.
 *
 * Copyright: (c) 1999-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 1999-01-19
 *  1.1 1999-01-20 remove 0 and negative number support
 *  1.2 1999-08-11 correct code for 8 to VIII not VII.
 *                 thanks to bug report from "Oliver
 *                 Borchert" <oliver.borchert@nist.gov>
 */
package com.mindprod.inwords;

/**
 * Display a number in Roman numerals.
 * <p/>
 * e.g.
 * 12345 -&gt; &quot; MMMMMMMMMMMMCCCXLV&quot;
 * <p/>
 * You can think of Roman numerals as a sort of base 5 representation.
 * It likely originated from counting on the fingers, where V represents one handful of fingers.
 * The Mayans counted similarly with a dot for one and a horizontal bar for five.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.2 1999-08-11 correct code for 8 to VIII not VII.
 * thanks to bug report from &quot;Oliver
 * Borchert&quot; &lt;oliver.borchert@nist.gov&gt;
 * Why is this code written in an unusual way? see inwords.use
 * There are terser algorithms, such as the Pascal version posted at
 * http://www.merlyn.demon.co.uk/programs/cvt_rome.pas
 * but they don't show the parallelism with other numbering systems
 * and I think they are harder to understand.
 * @since 1999-01-19
 */
public final class Roman implements ToWords
    {
    private static final int FIRST_COPYRIGHT_YEAR = 1999;

    /**
     * undisplayed copyright notice
     *
     * @noinspection UnusedDeclaration
     */
    private static final String EMBEDDED_COPYRIGHT =
            "Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com";

    private static final char[] fiveLetter = { 'V', 'L', 'D' };

    private static final char[] unitLetter = { 'I', 'X', 'C', 'M' };

    private static final int[] divisor = {
            /*
            * HowToProcess many of this group is needed to form one of the succeeding group.
            */
            /* 1 10 100 1000 */
            10, 10, 10, 1000000 };

    /**
     * test harness
     *
     * @param args not used
     */
    public static void main( String[] args )
        {
        Test.test( new Roman() );
        } // end main

    /**
     * convert long integer into Roman Numerals. e.g. -12345 -> "minus MMMMMMMMMMMMCCCXLV" Handles negative and positive
     * integers on range -Long.MAX_VALUE .. Long.MAX_VALUE; It cannot handle Long.MIN_VALUE;
     *
     * @param num number to convert to words
     *
     * @return words
     */
    @SuppressWarnings( { "WeakerAccess" } )
    public String toWords( long num )
        {
        if ( num < 0 )
            {
            return "The Romans had no negative numbers.";
            }
        if ( num == 0 )
            {
            return "The Romans had no zero.";
            }
        if ( num > 100000 )
            {
            return "too unwieldy for Roman numerals";
            }
        String s = "";
        // Work least significant digit to most, right to left.
        // until high order part is all 0s.
        for ( int group = 0; num > 0; group++ )
            {
            int remdr = ( int ) ( num % divisor[ group ] );
            num = num / divisor[ group ];
            StringBuilder t;
            if ( group == 3 )
                {
                /* M is as big as it gets, just repeat */
                t = new StringBuilder( remdr );
                for ( int j = 0; j < remdr; j++ )
                    {
                    t.append( unitLetter[ group ] );
                    }
                }
            else
                {
                t = new StringBuilder( 3 );
                switch ( remdr )
                    {
                    case 0:
                        break;
                    case 1:
                        t.append( unitLetter[ group ] );
                        break;
                    case 2:
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        break;
                    case 3:
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        break;
                    case 4:
                        t.append( unitLetter[ group ] );
                        t.append( fiveLetter[ group ] );
                        break;
                    case 5:
                        t.append( fiveLetter[ group ] );
                        break;
                    case 6:
                        t.append( fiveLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        break;
                    case 7:
                        t.append( fiveLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        break;
                    case 8:
                        t.append( fiveLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group ] );
                        break;
                    case 9:
                        t.append( unitLetter[ group ] );
                        t.append( unitLetter[ group + 1 ] );
                        break;
                    } // end switch
                } // end else
            s = t + s;
            } // end for
        return s;
        } // end inWords
    } // end Roman