All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snapscript.core.convert.NumberConverter Maven / Gradle / Ivy

package org.snapscript.core.convert;

import static org.snapscript.core.convert.Score.EXACT;
import static org.snapscript.core.convert.Score.INVALID;
import static org.snapscript.core.convert.Score.POSSIBLE;
import static org.snapscript.core.convert.Score.SIMILAR;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.snapscript.core.error.InternalArgumentException;
import org.snapscript.core.type.Type;

public class NumberConverter extends ConstraintConverter {
   
   private static final Class[] NUMBER_TYPES = {
      Number.class,
      Integer.class, 
      Long.class, 
      Double.class, 
      Float.class, 
      Short.class, 
      Byte.class,
      BigInteger.class, 
      AtomicInteger.class, 
      AtomicLong.class,
      BigDecimal.class
   };
   
   private static final Score[] NUMBER_SCORES = {
      EXACT,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR,
      SIMILAR
   };
   
   protected final NumberMatcher matcher;
   protected final ScoreMapper mapper;
   protected final Type type;
   
   public NumberConverter(Type type) {
      this(type, NUMBER_TYPES, NUMBER_SCORES);
   }
   
   public NumberConverter(Type type, Class[] types, Score[] scores) {
      this.mapper = new ScoreMapper(types, scores);
      this.matcher = new NumberMatcher();
      this.type = type;
   }
   
   @Override
   public Score score(Type actual) throws Exception {
      if(actual != null) {
         Class real = actual.getType();
         
         if(real != null) {
            Class promote = promoter.promote(real);
            Score score = mapper.map(promote);
            
            if(score != null) {
               return score;
            }
            if(real == String.class) {
               return POSSIBLE;
            }
         }
         return INVALID;
      }
      return POSSIBLE;
   }
   
   @Override
   public Score score(Object value) throws Exception {
      Class require = type.getType();
      
      if(value != null) {
         Class actual = value.getClass();
         Score score = mapper.map(actual);
         
         if(score == null) {
            if(actual == String.class) {
               String text = String.valueOf(value);
               NumberType type = matcher.matchNumber(text);
               
               if(type.isDecimal()) {
                  return POSSIBLE;
               }
            }
            return INVALID;
         }
         return score;
      }
      if(require.isPrimitive()) {
         return INVALID;
      }
      return POSSIBLE;
   }
   
   @Override
   public Object convert(Object value) throws Exception {
      Class require = type.getType();
      
      if(value != null) {
         Class actual = value.getClass();
         
         if(actual == String.class) {
            return convert(require, (String)value);
         }
         Class parent = actual.getSuperclass();
         
         if(parent == Number.class) {
            return convert(require, (Number)value);
         }
         throw new InternalArgumentException("Conversion from " + actual + " to " + require + " is not possible");
      }
      if(require.isPrimitive()) {
         throw new InternalArgumentException("Invalid conversion from null to primitive number");
      }
      return null;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy