001    /**
002     * Implements the CFML Function numberformat
003     */
004    package railo.runtime.functions.displayFormatting;
005    
006    import java.util.Locale;
007    
008    import railo.runtime.PageContext;
009    import railo.runtime.exp.ExpressionException;
010    import railo.runtime.exp.FunctionException;
011    import railo.runtime.exp.PageException;
012    import railo.runtime.ext.function.Function;
013    import railo.runtime.op.Caster;
014    import railo.runtime.op.Decision;
015    import railo.runtime.util.InvalidMaskException;
016    
017    /**
018     * Formats a Number by given pattern
019     */
020    public final class NumberFormat implements Function {
021    
022        /**
023         * @param pc
024         * @param object
025         * @return formated number
026         * @throws ExpressionException
027         */
028        public static String call(PageContext pc, Object object) throws PageException {
029            return new railo.runtime.util.NumberFormat().format(Locale.US,toNumber(pc,object));
030        }
031        
032        /**
033         * @param pc
034         * @param object
035         * @param mask
036         * @return formated number
037         * @throws ExpressionException
038         */
039        public static String call(PageContext pc , Object object, String mask) throws PageException {
040            if(mask==null) return call(pc, object);
041            if(mask.equalsIgnoreCase("roman")) {
042                 return intToRoman(pc,(int)toNumber(pc,object));
043             }
044             else if(mask.equalsIgnoreCase("hex")) {
045                 return Integer.toHexString((int)toNumber(pc,object));
046             }
047            else if(mask.equalsIgnoreCase(",")) {
048                return call(pc, object);
049            }
050            
051            try {
052                return new railo.runtime.util.NumberFormat().format(Locale.US,toNumber(pc,object),mask);
053            } 
054            catch (InvalidMaskException e) {
055                throw new FunctionException(pc,"numberFormat",2,"mask",e.getMessage());
056            }
057        }
058        
059        public static double toNumber(PageContext pc, Object object) throws PageException {
060            double d=Caster.toDoubleValue(object,Double.NaN);
061            if(Decision.isValid(d)) return d;
062            
063            String str=Caster.toString(object);
064            if(str.length()==0) return 0;
065            throw new FunctionException(pc,"numberFormat",1,"number","can't cast value ["+str+"] to a number");
066        }
067        
068    
069        private static String intToRoman(PageContext pc, int value) throws FunctionException {
070            if(value == 0) 
071                throw new FunctionException(pc,"numberFormat",1,"number","a roman value can't be 0");
072            if(value < 0)
073                throw new FunctionException(pc,"numberFormat",1,"number","a roman value can't be less than 0");
074            if(value > 3999)
075                throw new FunctionException(pc,"numberFormat",1,"number","a roman value can't be greater than 3999");
076            
077            StringBuffer roman = new StringBuffer();
078            
079            
080            
081                while (value / 1000 >= 1) {
082                    roman.append('M');
083                    value = value - 1000;
084                }
085                if (value / 900 >= 1) {
086                    roman.append("CM");
087                    value = value - 900;
088                }
089                if (value / 500 >= 1) {
090                    roman.append("D");
091                    value = value - 500;
092                }
093                if (value / 400 >= 1) {
094                    roman.append("CD");
095                    value = value - 400;
096                }
097                while (value / 100 >= 1) {
098                    roman.append("C");
099                    value = value - 100;
100                }
101                if (value / 90 >= 1) {
102                    roman.append("XC");
103                    value = value - 90;
104                }
105                if (value / 50 >= 1) {
106                    roman.append("L");
107                    value = value - 50;
108                }
109                if (value / 40 >= 1) {
110                    roman.append("XL");
111                    value = value - 40;
112                }
113                while (value / 10 >= 1) {
114                    roman.append("X");
115                    value = value - 10;
116                }
117                if (value / 9 >= 1) {
118                    roman.append("IX");
119                    value = value - 9;
120                }
121                if (value / 5 >= 1) {
122                    roman.append("V");
123                    value = value - 5;
124                }
125                if (value / 4 >= 1) {
126                    roman.append("IV");
127                    value = value - 4;
128                }
129                while (value >= 1) {
130                    roman.append("I");
131                    value = value - 1;
132                }
133                return roman.toString();
134        }
135        
136    }