001/* 002 * $Id: RomanNumberFactory.java 4847 2011-05-05 19:46:13Z redlab_b $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.factories; 045/** 046 * This class can produce String combinations representing a roman number. 047 */ 048public class RomanNumberFactory { 049 /** 050 * Helper class for Roman Digits 051 */ 052 private static class RomanDigit { 053 054 /** part of a roman number */ 055 public char digit; 056 057 /** value of the roman digit */ 058 public int value; 059 060 /** can the digit be used as a prefix */ 061 public boolean pre; 062 063 /** 064 * Constructs a roman digit 065 * @param digit the roman digit 066 * @param value the value 067 * @param pre can it be used as a prefix 068 */ 069 RomanDigit(final char digit, final int value, final boolean pre) { 070 this.digit = digit; 071 this.value = value; 072 this.pre = pre; 073 } 074 } 075 076 /** 077 * Array with Roman digits. 078 */ 079 private static final RomanDigit[] roman = { 080 new RomanDigit('m', 1000, false), 081 new RomanDigit('d', 500, false), 082 new RomanDigit('c', 100, true), 083 new RomanDigit('l', 50, false), 084 new RomanDigit('x', 10, true), 085 new RomanDigit('v', 5, false), 086 new RomanDigit('i', 1, true) 087 }; 088 089 /** 090 * Changes an int into a lower case roman number. 091 * @param index the original number 092 * @return the roman number (lower case) 093 */ 094 public static final String getString(int index) { 095 StringBuffer buf = new StringBuffer(); 096 097 // lower than 0 ? Add minus 098 if (index < 0) { 099 buf.append('-'); 100 index = -index; 101 } 102 103 // greater than 3000 104 if (index > 3000) { 105 buf.append('|'); 106 buf.append(getString(index / 1000)); 107 buf.append('|'); 108 // remainder 109 index = index - (index / 1000) * 1000; 110 } 111 112 // number between 1 and 3000 113 int pos = 0; 114 while (true) { 115 // loop over the array with values for m-d-c-l-x-v-i 116 RomanDigit dig = roman[pos]; 117 // adding as many digits as we can 118 while (index >= dig.value) { 119 buf.append(dig.digit); 120 index -= dig.value; 121 } 122 // we have the complete number 123 if (index <= 0) { 124 break; 125 } 126 // look for the next digit that can be used in a special way 127 int j = pos; 128 while (!roman[++j].pre); 129 130 // does the special notation apply? 131 if (index + roman[j].value >= dig.value) { 132 buf.append(roman[j].digit).append(dig.digit); 133 index -= dig.value - roman[j].value; 134 } 135 pos++; 136 } 137 return buf.toString(); 138 } 139 140 /** 141 * Changes an int into a lower case roman number. 142 * @param index the original number 143 * @return the roman number (lower case) 144 */ 145 public static final String getLowerCaseString(final int index) { 146 return getString(index); 147 } 148 149 /** 150 * Changes an int into an upper case roman number. 151 * @param index the original number 152 * @return the roman number (lower case) 153 */ 154 public static final String getUpperCaseString(final int index) { 155 return getString(index).toUpperCase(); 156 } 157 158 /** 159 * Changes an int into a roman number. 160 * @param index the original number 161 * @param lowercase true for lowercase, false otherwise 162 * @return the roman number (lower case) 163 */ 164 public static final String getString(final int index, final boolean lowercase) { 165 if (lowercase) { 166 return getLowerCaseString(index); 167 } 168 else { 169 return getUpperCaseString(index); 170 } 171 } 172}