001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.myfaces.tobago.convert;
021    
022    import org.apache.commons.logging.Log;
023    import org.apache.commons.logging.LogFactory;
024    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_UNIT;
025    
026    import javax.faces.component.UIComponent;
027    import javax.faces.context.FacesContext;
028    import javax.faces.convert.Converter;
029    import javax.faces.convert.ConverterException;
030    import java.text.DecimalFormat;
031    import java.text.NumberFormat;
032    import java.util.ArrayList;
033    import java.util.List;
034    import java.util.StringTokenizer;
035    
036    @org.apache.myfaces.tobago.apt.annotation.Converter(id = DurationConverter.CONVERTER_ID)
037    public class DurationConverter implements Converter {
038    
039      private static final Log LOG = LogFactory.getLog(DurationConverter.class);
040    
041      public static final String CONVERTER_ID = "org.apache.myfaces.tobago.Duration";
042    
043      private static final String NANO = "nano";
044      private static final String MILLI = "milli";
045      private static final String SECOND = "second";
046      private static final String MINUTE = "minute";
047      private static final String HOUR = "hour";
048      private static final String DAY = "day";
049      private static final String YEAR = "year";
050    
051      public String getAsString(
052          FacesContext facesContext, UIComponent component, Object object)
053          throws ConverterException {
054        if (object == null || object instanceof String) {
055          return (String) object;
056        }
057        double aDouble = ((Number) object).doubleValue();
058        boolean negative = false;
059        if (aDouble < 0) {
060          negative = true;
061          aDouble = -aDouble;
062        }
063        double factor = getUnitFactor(component);
064        aDouble = aDouble * factor;
065    
066        NumberFormat format = new DecimalFormat("00");
067        long value = Double.valueOf(aDouble).longValue();
068        int seconds = (int) (value % 60);
069        value = value / 60;
070        int minutes = (int) (value % 60);
071        value = value / 60;
072        String string;
073        if (value > 0) {
074          string = (negative ? "-" : "") + value + ":"
075              + format.format(minutes) + ":"
076              + format.format(seconds);
077        } else {
078          string = (negative ? "-" : "") + minutes + ":"
079              + format.format(seconds);
080        }
081        if (LOG.isDebugEnabled()) {
082          LOG.debug("string = '" + string + "'");
083        }
084        return string;
085      }
086    
087      public Object getAsObject(
088          FacesContext facesContext, UIComponent component, String string)
089          throws ConverterException {
090        boolean negative = string.indexOf('-') > -1;
091        StringTokenizer tokenizer = new StringTokenizer(string, " :-");
092        List elements = new ArrayList();
093        while (tokenizer.hasMoreElements()) {
094          elements.add(tokenizer.nextElement());
095        }
096        int hours = 0;
097        int minutes;
098        int seconds;
099        switch (elements.size()) {
100          case 3:
101            hours = Integer.parseInt((String) elements.get(0));
102            minutes = Integer.parseInt((String) elements.get(1));
103            seconds = Integer.parseInt((String) elements.get(2));
104            break;
105          case 2:
106            minutes = Integer.parseInt((String) elements.get(0));
107            seconds = Integer.parseInt((String) elements.get(1));
108            break;
109          default:
110            throw new ConverterException("Cannot parse string='" + string + "'");
111        }
112        double factor = getUnitFactor(component);
113        long value = (long) (((hours * 60L + minutes) * 60L + seconds) / factor);
114        if (negative) {
115          return Long.valueOf(-value);
116        } else {
117          return Long.valueOf(value);
118        }
119      }
120    
121      private static double getUnitFactor(UIComponent component) {
122        String unit = null;
123        if (component != null) {
124          unit = (String) component.getAttributes().get(ATTR_UNIT);
125        }
126        double factor;
127        if (unit == null) {
128          factor = 0.001;
129        } else if (NANO.equals(unit)) {
130          factor = 0.000000001;
131        } else if (MILLI.equals(unit)) {
132          factor = 0.001;
133        } else if (SECOND.equals(unit)) {
134          factor = 1.0;
135        } else if (MINUTE.equals(unit)) {
136          factor = 60.0;
137        } else if (HOUR.equals(unit)) {
138          factor = 3600.0;
139        } else if (DAY.equals(unit)) {
140          factor = 86400.0;
141        } else if (YEAR.equals(unit)) {
142          factor = 31556736.0;
143        } else {
144          LOG.warn("Unsupported unit: '" + unit + "'");
145          factor = 0.001;
146        }
147        return factor;
148      }
149    
150    }