001/*
002 *  Copyright 2018 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.model.type;
017
018import java.text.DecimalFormat;
019import java.text.DecimalFormatSymbols;
020import java.util.List;
021import java.util.Locale;
022import java.util.Optional;
023import java.util.stream.Stream;
024
025import org.apache.commons.lang3.StringUtils;
026import org.apache.commons.lang3.tuple.Triple;
027
028import org.ametys.runtime.model.compare.DataChangeType;
029import org.ametys.runtime.model.compare.DataChangeTypeDetail;
030import org.ametys.runtime.model.exception.BadItemTypeException;
031import org.ametys.runtime.model.type.DataContext;
032
033/**
034 * Abstract class for double element types
035 */
036public abstract class AbstractDoubleElementType extends AbstractElementType<Double>
037{
038    private static final ThreadLocal<DecimalFormat> __FORMATTER = new ThreadLocal<>();
039
040    @Override
041    public Double convertValue(Object value) throws BadItemTypeException
042    {
043        if (value instanceof Number)
044        {
045            return ((Number) value).doubleValue();
046        }
047        else if (value instanceof String)
048        {
049            if (StringUtils.isEmpty((String) value))
050            {
051                return null;
052            }
053            
054            try
055            {
056                return Double.valueOf((String) value);
057            }
058            catch (NumberFormatException e)
059            {
060                throw new BadItemTypeException("Unable to cast '" + value + "' to a double", e);
061            }
062        }
063        
064        return super.convertValue(value);
065    }
066    
067    public Object fromJSONForClient(Object json, DataContext context)
068    {
069        if (json == null)
070        {
071            return null;
072        }
073        else if (json instanceof Number || json instanceof String)
074        {
075            return convertValue(json);
076        }
077        else if (json instanceof List)
078        {
079            @SuppressWarnings("unchecked")
080            List<Object> jsonList = (List<Object>) json;
081            Double[] result = new Double[jsonList.size()];
082            for (int i = 0; i < jsonList.size(); i++)
083            {
084                Object singleJSON = jsonList.get(i);
085                if (singleJSON instanceof Number || singleJSON instanceof String)
086                {
087                    result[i] = convertValue(singleJSON);
088                }
089                else
090                {
091                    throw new IllegalArgumentException("Try to convert the non Double JSON object '" + json + "' into a Double");
092                }
093            }
094            return result;
095        }
096        else
097        {
098            throw new IllegalArgumentException("Try to convert the non Double JSON object '" + json + "' into a Double");
099        }
100    }
101    
102    @Override
103    protected Stream<Triple<DataChangeType, DataChangeTypeDetail, String>> _compareSingleValues(Double value1, Double value2)
104    {
105        return Stream.of(ModelItemTypeHelper.compareSingleNumbers(value1, value2, StringUtils.EMPTY))
106                     .filter(Optional::isPresent)
107                     .map(Optional::get);
108    }
109    
110    @Override
111    public boolean isCompatible(Object value)
112    {
113        return super.isCompatible(value) || value instanceof double[] || value instanceof Float || value instanceof Float[] || value instanceof float[];
114    }
115    
116    public boolean isSimple()
117    {
118        return true;
119    }
120    
121    @Override
122    public String toString(Double value)
123    {
124        DecimalFormat df = __FORMATTER.get(); 
125        if (df == null)
126        {
127            df = new DecimalFormat("0.0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); // English to have . as fraction separator
128            df.setMaximumFractionDigits(340); // 340 is the max supporter by the implementation (DecimalFormat.DOUBLE_FRACTION_DIGITS)
129            
130            __FORMATTER.set(df);
131        }
132        return df.format(value);
133    }    
134}