/*
 * [Age.java]
 *
 * Summary: Calculate Age from birthdate.
 *
 * Copyright: (c) 2005-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.6+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2005-03-19
 */
package com.mindprod.htmlmacros;

import com.mindprod.common11.BigDate;
import com.mindprod.fastcat.FastCat;

import static java.lang.System.out;

/**
 * Calculate Age from birthdate.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2005-03-19
 * @since 2005-03-19
 */
@SuppressWarnings( { "UnusedDeclaration" } )
final class Age extends Macro
    {
    // ------------------------------ CONSTANTS ------------------------------

    /**
     * how to use the macro
     */
    private static final String USAGE = "Age macro needs date yyyy-mm-dd [on yyyy-mm-dd] [years/months/days/puredays]";

    // -------------------------- PUBLIC INSTANCE  METHODS --------------------------

    /**
     * Generate Age from birthdate . expands <!-- macro Age 1948-02-04 --> to age in years. or <!-- macro Age 1948-02-04
     * years --> <!-- macro Age 1948-02-04 months --> <!-- macro Age 1948-02-04 days -->
     *
     * @param parms   date as ISO string.
     * @param quiet   true if want output suppressed.
     * @param verbose @return expanded macro text
     */
    public String expandMacro( String[] parms,
                               final boolean quiet, final boolean verbose )
        {
        if ( !quiet )
            {
            out.print( "A" );
            }
        if ( !( 1 <= parms.length && parms.length <= 4 ) )
            {
            throw new IllegalArgumentException( USAGE );
            }
        try
            {
            final BigDate birthDate = new BigDate( parms[ 0 ] );
            final BigDate onDate;
            final int granularityParmIndex;
            if ( parms.length > 2 && parms[ 1 ].equals( "on" ) )
                {
                onDate = new BigDate( parms[ 2 ] );
                granularityParmIndex = 3;
                }
            else
                {
                onDate = BigDate.localToday();
                granularityParmIndex = 1;
                }
            final int granularity;
            if ( parms.length > granularityParmIndex )
                {
                final String units = parms[ granularityParmIndex ];
                if ( units.equalsIgnoreCase( "years" ) )
                    {
                    granularity = 0;
                    }
                else if ( units.equalsIgnoreCase( "months" ) )
                    {
                    granularity = 1;
                    }
                else if ( units.equalsIgnoreCase( "days" ) )
                    {
                    granularity = 2;
                    }
                else if ( units.equalsIgnoreCase( "puredays" ) )
                    {
                    granularity = 3;
                    }
                else
                    {
                    throw new IllegalArgumentException( USAGE );
                    }
                }
            else
                {
                granularity = -1;
                }
            return expand( birthDate, onDate, granularity );
            }
        catch ( StringIndexOutOfBoundsException e )
            {
            throw new IllegalArgumentException( USAGE );
            }
        catch ( NumberFormatException e )
            {
            throw new IllegalArgumentException( USAGE );
            }
        }

    // -------------------------- OTHER METHODS --------------------------

    /**
     * guts of Age macro expansion
     *
     * @param birthDate   person's birth date whose age you want expanded
     * @param onDate      usually today, date on which to compute the age.
     * @param granularity -1 = years without wording 0=years 1=months 2=days
     *
     * @return age in years
     */
    private String expand( BigDate birthDate, BigDate onDate, int granularity )
        {
        // usually OnDate >= birthDate , but for future elapsed time to some future date, OnDate < birthDate;
        final int[] ymd = BigDate.age( birthDate, onDate );
        int ageInYears = ymd[ 0 ];
        int ageInMonths = ymd[ 1 ];
        int ageInDays = ymd[ 2 ];
        switch ( granularity )
            {
            case -1:
            case 0:
                ageInMonths = 0;
                ageInDays = 0;
                break;
            case 1:
                ageInDays = 0;
                break;
            case 2:
                break;
            case 3:
                ageInYears = 0;
                ageInMonths = 0;
                ageInDays = onDate.getOrdinal() - birthDate.getOrdinal();
                break;
            }
        // Leave as StringBuilder
        final FastCat sb = new FastCat( 16 );
        if ( ageInYears != 0 )
            {
            sb.append( "<span class=\"age\">" );
            sb.append( ageInYears );
            sb.append( "</span>" );
            if ( granularity != -1 )
                {
                sb.append( " year" );
                if ( ageInYears > 1 )
                    {
                    sb.append( "s" );
                    }
                }
            }
        if ( ageInMonths != 0 )
            {
            if ( ageInYears != 0 )
                {
                if ( ageInDays != 0 )
                    {
                    sb.append( ", " );
                    }
                else
                    {
                    sb.append( " and " );
                    }
                }
            sb.append( "<span class=\"age\">" );
            sb.append( ageInMonths );
            sb.append( "</span> month" );
            if ( ageInMonths > 1 )
                {
                sb.append( "s" );
                }
            }
        if ( ageInDays != 0 )
            {
            if ( ageInYears != 0 || ageInMonths != 0 )
                {
                sb.append( " and " );
                }
            sb.append( "<span class=\"age\">" );
            sb.append( ageInDays );
            sb.append( "</span> day" );
            if ( ageInDays > 1 )
                {
                sb.append( "s" );
                }
            }
        return sb.toString();
        }
    }