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