/* * Copyright (C) 2011 Laurent Caillette * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.novelang.rendering.xslt; import com.google.common.base.Function; import com.google.common.base.Preconditions; import org.apache.commons.lang.ArrayUtils; import org.joda.time.ReadableDateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.novelang.logger.Logger; import org.novelang.logger.LoggerFactory; /** * @author Laurent Caillette */ public class Numbering { private static final Logger LOGGER = LoggerFactory.getLogger( Numbering.class ) ; private static final DateTimeFormatter DATE_TIME_FORMATTER_NOSEPARATOR = DateTimeFormat.forPattern( "yyyyMMddkkmm" ); private Numbering() { } public static String asString( final Object treeResultFragment ) { return asString( "", treeResultFragment ) ; } public static String numberAsText( final Object numberObject, final Object localeNameObject, final Object caseObject ) { final String numberAsString = asString( "number", numberObject ) ; final String localeAsString = asString( "locale", localeNameObject ) ; final String caseAsString = asString( "case", caseObject ) ; final CaseType caseType ; if( caseObject instanceof String ) { CaseType possibleCaseType ; try { possibleCaseType = CaseType.valueOf( ( ( String ) caseObject ).toUpperCase() ) ; } catch( IllegalArgumentException e ) { LOGGER.warn( "Not a supported case type: ", caseObject, " (supported: ", ArrayUtils.toString( CaseType.values() ), ")" ) ; possibleCaseType = CaseType.LOWER ; } caseType = possibleCaseType ; } else { LOGGER.warn( "Case type is not a String: ", caseAsString, "." ) ; caseType = CaseType.LOWER ; } final String numberAsText ; if( numberObject instanceof Number ) { final Number number = ( Number ) numberObject ; if( "FR".equals( localeNameObject ) ) { numberAsText = numberAsLocalizedText( number.intValue(), TO_FRENCH_TEXT, caseType ) ; } else if( "EN".equals( localeNameObject ) ) { numberAsText = numberAsLocalizedText( number.intValue(), TO_ENGLISH_TEXT, caseType ) ; } else { LOGGER.warn( "Locale not supported: ", localeAsString, "." ) ; numberAsText = number.toString() ; } return numberAsText ; } else { final String message = "!NAN! Cannot convert to number: " + numberAsString ; LOGGER.error( message ) ; return message ; } } private enum CaseType { LOWER, UPPER, CAPITAL } private static String numberAsLocalizedText( final int number, final Function< Number, String > textualizer, final CaseType caseType ) { switch( caseType ) { case CAPITAL: final String s = textualizer.apply( number ) ; return s.substring( 0, 1 ).toUpperCase() + s.substring( 1, s.length() ) ; case LOWER: return textualizer.apply( number ) ; case UPPER: return textualizer.apply( number ).toUpperCase() ; default : LOGGER.warn( "Unsupported case: ", caseType ) ; return textualizer.apply( number ) ; } } private static final Function< Number, String > TO_FRENCH_TEXT = new Function< Number, String >(){ @Override public String apply( final Number number ) { switch( number.intValue() ) { case 0 : return "z\u00e9ro" ; case 1 : return "un" ; case 2 : return "deux" ; case 3 : return "trois" ; case 4 : return "quatre" ; case 5 : return "cinq" ; case 6 : return "six" ; case 7 : return "sept" ; case 8 : return "huit" ; case 9 : return "neuf" ; case 10 : return "dix" ; case 11 : return "onze" ; case 12 : return "douze" ; case 13 : return "treize" ; case 14 : return "quatorze" ; case 15 : return "quinze" ; case 16 : return "seize" ; case 17 : return "dix-sept" ; case 18 : return "dix-huit" ; case 19 : return "dix-neuf" ; case 20 : return "vingt" ; case 21 : return "vingt et un" ; case 22 : return "vingt-deux" ; case 23 : return "vingt-trois" ; case 24 : return "vingt-quatre" ; case 25 : return "vingt-cinq" ; case 26 : return "vingt-six" ; case 27 : return "vingt-sept" ; case 28 : return "vingt-huit" ; case 29 : return "vingt-neuf" ; case 30 : return "trente" ; case 31 : return "trente-et-un" ; case 32 : return "trente-deux" ; case 33 : return "trente-trois" ; case 34 : return "trente-quatre" ; case 35 : return "trente-cinq" ; case 36 : return "trente-six" ; case 37 : return "trente-sept" ; case 38 : return "trente-huit" ; case 39 : return "trente-neuf" ; case 40 : return "quarante" ; case 41 : return "quarante-et-un" ; case 42 : return "quarante-deux" ; case 43 : return "quarante-trois" ; case 44 : return "quarante-quatre" ; case 45 : return "quarante-cinq" ; case 46 : return "quarante-six" ; case 47 : return "quarante-sept" ; case 48 : return "quarante-huit" ; case 49 : return "quarante-neuf" ; case 50 : return "cinquante" ; default : throw new UnsupportedOperationException( "Not supported: " + number.intValue() ) ; } } } ; private static final Function< Number, String > TO_ENGLISH_TEXT = new Function< Number, String >(){ @Override public String apply( final Number number ) { switch( number.intValue() ) { case 0 : return "zero" ; case 1 : return "one" ; case 2 : return "two" ; case 3 : return "three" ; case 4 : return "four" ; case 5 : return "five" ; case 6 : return "six" ; case 7 : return "seven" ; case 8 : return "eight" ; case 9 : return "nine" ; case 10 : return "ten" ; case 11 : return "eleven" ; case 12 : return "twelve" ; case 13 : return "thirteen" ; case 14 : return "fourteen" ; case 15 : return "fifteen" ; case 16 : return "sixteen" ; case 17 : return "seventeen" ; case 18 : return "eighteen" ; case 19 : return "nineteen" ; case 20 : return "twenty" ; case 21 : return "twenty-one" ; case 22 : return "twenty-two" ; case 23 : return "twenty-three" ; case 24 : return "twenty-four" ; case 25 : return "twenty-five" ; case 26 : return "twenty-six" ; case 27 : return "twenty-seven" ; case 28 : return "twenty-eight" ; case 29 : return "twenty-nine" ; case 30 : return "thirty" ; case 31 : return "thirty-one" ; case 32 : return "thirty-two" ; case 33 : return "thirty-three" ; case 34 : return "thirty-four" ; case 35 : return "thirty-five" ; case 36 : return "thirty-six" ; case 37 : return "thirty-seven" ; case 38 : return "thirty-eight" ; case 39 : return "thirty-nine" ; case 40 : return "fourty" ; case 41 : return "fourty-one" ; case 42 : return "fourty-two" ; case 43 : return "fourty-three" ; case 44 : return "fourty-four" ; case 45 : return "fourty-five" ; case 46 : return "fourty-six" ; case 47 : return "fourty-seven" ; case 48 : return "fourty-eight" ; case 49 : return "fourty-nine" ; case 50 : return "fifty" ; default : throw new UnsupportedOperationException( "Not supported: " + number.intValue() ) ; } } } ; public static String asString( final String name, final Object object ) { return ( null == name ? "" : name + ": " ) + "'" + object + "' " + ( null == object ? "" : object.getClass().getName() ) ; } public static String formatDateTime( final Object readableDateTimeObject, final Object formatDescriptionObject ) { final ReadableDateTime readableDateTime = Preconditions.checkNotNull( ( ReadableDateTime ) readableDateTimeObject ) ; final String formatDescription = Preconditions.checkNotNull( ( String ) formatDescriptionObject ) ; if( "BASE36".equals( formatDescription ) ) { final DateTimeFormatter format = DATE_TIME_FORMATTER_NOSEPARATOR ; final String formattedString = format.print( readableDateTime ) ; final long number = Long.parseLong( formattedString ) ; return Long.toString( number, 36 ) ; } else { final DateTimeFormatter format = DateTimeFormat.forPattern( formatDescription ) ; return format.print( readableDateTime ) ; } } protected static ReadableDateTime unformatDateTime( final String formattedDateTime, final String formatDescription ) { if( "BASE36".equals( formatDescription ) ) { final Long decimalNumber = Long.parseLong( formattedDateTime, 36 ) ; final String decimalNumberAsString = decimalNumber.toString() ; return DATE_TIME_FORMATTER_NOSEPARATOR.parseDateTime( decimalNumberAsString ) ; } else { final DateTimeFormatter formatter = DateTimeFormat.forPattern( formatDescription ) ; return formatter.parseDateTime( formattedDateTime ) ; } } }