001package net.filebot.format;
002
003import java.math.BigDecimal;
004import java.math.RoundingMode;
005import java.text.DecimalFormat;
006import java.text.DecimalFormatSymbols;
007import java.text.NumberFormat;
008import java.util.Locale;
009import java.util.Map;
010import java.util.Map.Entry;
011
012import net.filebot.util.AlphanumComparator;
013
014public abstract class AutoUnitDecimal implements StringBinding, Comparable<Object> {
015
016        protected final double value;
017
018        public AutoUnitDecimal(double value) {
019                this.value = value;
020        }
021
022        public double getValue() {
023                return value;
024        }
025
026        public long toLong() {
027                return (long) value;
028        }
029
030        public double toDouble() {
031                return value;
032        }
033
034        public int toInteger() {
035                return (int) value;
036        }
037
038        public float toFloat() {
039                return (float) value;
040        }
041
042        public BigDecimal toNumber() {
043                return BigDecimal.valueOf(value);
044        }
045
046        @Override
047        public int compareTo(Object other) {
048                if (other instanceof Number) {
049                        Number n = (Number) other;
050                        return Double.compare(value, n.doubleValue());
051                }
052
053                if (other instanceof AutoUnitDecimal) {
054                        AutoUnitDecimal n = (AutoUnitDecimal) other;
055                        return Double.compare(value, n.value);
056                }
057
058                return AlphanumComparator.getInstance().compare(toString(), other.toString());
059        }
060
061        @Override
062        public boolean equals(Object other) {
063                return (other instanceof Number && compareTo(other) == 0) || (other instanceof CharSequence && toString().equals(other));
064        }
065
066        public Object asType(Class<?> c) {
067                if (c == int.class || c == Integer.class) {
068                        return toInteger();
069                }
070
071                if (c == long.class || c == Long.class) {
072                        return toLong();
073                }
074
075                if (c == float.class || c == Float.class) {
076                        return toFloat();
077                }
078
079                if (c == double.class || c == Double.class) {
080                        return toDouble();
081                }
082
083                if (c == Number.class) {
084                        return toNumber();
085                }
086
087                if (c == String.class) {
088                        return toString();
089                }
090
091                // fail with type cast exception message
092                return c.cast(this);
093        }
094
095        public Number div(Number divisor) {
096                return BigDecimal.valueOf(value / divisor.doubleValue());
097        }
098
099        public Number round(int precision) {
100                return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP);
101        }
102
103        public String format(String pattern) {
104                return format(pattern, Locale.ROOT);
105        }
106
107        public String format(String pattern, String locale) {
108                return format(pattern, Locale.forLanguageTag(locale));
109        }
110
111        public String format(String pattern, Locale locale) {
112                DecimalFormat f = new DecimalFormat(pattern, new DecimalFormatSymbols(locale));
113                return f.format(value);
114        }
115
116        public String format(Map<Object, String> replacement) {
117                // the first two parameters are required, the rest of the parameter sequence is optional
118                for (Entry<Object, String> m : replacement.entrySet()) {
119                        // check Number match or String match
120                        if (equals(m.getKey())) {
121                                return m.getValue();
122                        }
123                }
124                return toString();
125        }
126
127        public boolean isFraction() {
128                return value % 1 != 0;
129        }
130
131        public int getFractionDigits() {
132                return isFraction() ? 3 : 0;
133        }
134
135        public String getNumber() {
136                NumberFormat format = NumberFormat.getNumberInstance(Locale.ROOT);
137                format.setGroupingUsed(true);
138                int fractionDigits = getFractionDigits();
139                format.setMinimumFractionDigits(fractionDigits);
140                format.setMaximumFractionDigits(fractionDigits);
141                return format.format(value);
142        }
143
144        public abstract String getUnit();
145
146        @Override
147        public String toString() {
148                return getNumber() + getUnit();
149        }
150
151}