/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>, Martin Škurla, Cezary Bartosiak
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.data.attributes.api;
import java.math.BigInteger;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.gephi.data.attributes.type.DynamicByte;
import org.gephi.data.attributes.type.DynamicShort;
import org.gephi.data.attributes.type.DynamicInteger;
import org.gephi.data.attributes.type.DynamicLong;
import org.gephi.data.attributes.type.DynamicFloat;
import org.gephi.data.attributes.type.DynamicDouble;
import org.gephi.data.attributes.type.DynamicBoolean;
import org.gephi.data.attributes.type.DynamicCharacter;
import org.gephi.data.attributes.type.DynamicString;
import org.gephi.data.attributes.type.DynamicBigInteger;
import org.gephi.data.attributes.type.DynamicBigDecimal;
import org.gephi.data.attributes.type.TimeInterval;
import org.gephi.data.attributes.type.ByteList;
import org.gephi.data.attributes.type.ShortList;
import org.gephi.data.attributes.type.IntegerList;
import org.gephi.data.attributes.type.LongList;
import org.gephi.data.attributes.type.FloatList;
import org.gephi.data.attributes.type.DoubleList;
import org.gephi.data.attributes.type.BooleanList;
import org.gephi.data.attributes.type.CharacterList;
import org.gephi.data.attributes.type.StringList;
import org.gephi.data.attributes.type.BigIntegerList;
import org.gephi.data.attributes.type.BigDecimalList;
import org.gephi.data.attributes.type.DynamicType;
import org.gephi.data.attributes.type.Interval;
/**
* The different type an {@link AttributeColumn} can have.
*
* @author Mathieu Bastian
* @author Martin Škurla
* @author Cezary Bartosiak
*/
public enum AttributeType {
BYTE(Byte.class),
SHORT(Short.class),
INT(Integer.class),
LONG(Long.class),
FLOAT(Float.class),
DOUBLE(Double.class),
BOOLEAN(Boolean.class),
CHAR(Character.class),
STRING(String.class),
BIGINTEGER(BigInteger.class),
BIGDECIMAL(BigDecimal.class),
DYNAMIC_BYTE(DynamicByte.class),
DYNAMIC_SHORT(DynamicShort.class),
DYNAMIC_INT(DynamicInteger.class),
DYNAMIC_LONG(DynamicLong.class),
DYNAMIC_FLOAT(DynamicFloat.class),
DYNAMIC_DOUBLE(DynamicDouble.class),
DYNAMIC_BOOLEAN(DynamicBoolean.class),
DYNAMIC_CHAR(DynamicCharacter.class),
DYNAMIC_STRING(DynamicString.class),
DYNAMIC_BIGINTEGER(DynamicBigInteger.class),
DYNAMIC_BIGDECIMAL(DynamicBigDecimal.class),
TIME_INTERVAL(TimeInterval.class),
LIST_BYTE(ByteList.class),
LIST_SHORT(ShortList.class),
LIST_INTEGER(IntegerList.class),
LIST_LONG(LongList.class),
LIST_FLOAT(FloatList.class),
LIST_DOUBLE(DoubleList.class),
LIST_BOOLEAN(BooleanList.class),
LIST_CHARACTER(CharacterList.class),
LIST_STRING(StringList.class),
LIST_BIGINTEGER(BigIntegerList.class),
LIST_BIGDECIMAL(BigDecimalList.class);
private final Class type;
AttributeType(Class type) {
this.type = type;
}
@Override
public String toString() {
return type.getSimpleName();
}
/**
* The name of the enum constant.
*
* @return the name of the enum constant
*/
public String getTypeString() {
return super.toString();
}
/**
* Returns the <code>Class</code> the type is associated with.
*
* @return the <code>class</code> the type is associated with
*/
public Class getType() {
return type;
}
/**
* Try to parse the given <code>str</code> snippet in an object of the type
* associated to this <code>AttributeType</code>. For instance if the type
* is <b>Boolean</b>, and <code>str</code> equals <code>true</code>, this
* method will succeed to return a <code>Boolean</code> instance. May
* throw <code>NumberFormatException</code>.
*
* <code>DYNAMIC</code> types and <code>TIME_INTERVAL</code> cannot be parsed with this method (see <code>isDynamicType</code> method) and a UnsupportedOperationException will be thrown if it is tried.
*
* @param str the string that is to be parsed
* @return an instance of the type of this <code>AttributeType</code>.
*/
public Object parse(String str) {
switch (this) {
case BYTE:
return new Byte(removeDecimalDigitsFromString(str));
case SHORT:
return new Short(removeDecimalDigitsFromString(str));
case INT:
return new Integer(removeDecimalDigitsFromString(str));
case LONG:
return new Long(removeDecimalDigitsFromString(str));
case FLOAT:
return new Float(str);
case DOUBLE:
return new Double(str);
case BOOLEAN:
return new Boolean(str);
case CHAR:
return new Character(str.charAt(0));
case BIGINTEGER:
return new BigInteger(removeDecimalDigitsFromString(str));
case BIGDECIMAL:
return new BigDecimal(str);
case DYNAMIC_BYTE:
case DYNAMIC_SHORT:
case DYNAMIC_INT:
case DYNAMIC_LONG:
case DYNAMIC_FLOAT:
case DYNAMIC_DOUBLE:
case DYNAMIC_BOOLEAN:
case DYNAMIC_CHAR:
case DYNAMIC_STRING:
case DYNAMIC_BIGINTEGER:
case DYNAMIC_BIGDECIMAL:
case TIME_INTERVAL:
return parseDynamic(str);
case LIST_BYTE:
return new ByteList(removeDecimalDigitsFromString(str));
case LIST_SHORT:
return new ShortList(removeDecimalDigitsFromString(str));
case LIST_INTEGER:
return new IntegerList(removeDecimalDigitsFromString(str));
case LIST_LONG:
return new LongList(removeDecimalDigitsFromString(str));
case LIST_FLOAT:
return new FloatList(str);
case LIST_DOUBLE:
return new DoubleList(str);
case LIST_BOOLEAN:
return new BooleanList(str);
case LIST_CHARACTER:
return new CharacterList(str);
case LIST_STRING:
return new StringList(str);
case LIST_BIGINTEGER:
return new BigIntegerList(removeDecimalDigitsFromString(str));
case LIST_BIGDECIMAL:
return new BigDecimalList(str);
}
return str;
}
private Object parseDynamic(String str) {
if (str.equals("<empty>"))
return createDynamicObject(null);
if(str.startsWith("<")){
str=str.substring(1);
}
if(str.endsWith(">")){
str=str.substring(0, str.length()-1);
}
String[] intervals = str.split("; *");
List<Interval> in = new ArrayList<Interval>();
for (String interval : intervals) {
boolean lopen = interval.startsWith("(");
boolean ropen = interval.endsWith(")");
interval = interval.substring(1, interval.length() - 1);
String[] parts = interval.split(", *", 3);
double low = Double.parseDouble(parts[0]);
double high = Double.parseDouble(parts[1]);
Object value = null;
switch (this) {
case DYNAMIC_BYTE:
value = new Byte(removeDecimalDigitsFromString(parts[2]));
break;
case DYNAMIC_SHORT:
value = new Short(removeDecimalDigitsFromString(parts[2]));
break;
case DYNAMIC_INT:
value = new Integer(removeDecimalDigitsFromString(parts[2]));
break;
case DYNAMIC_LONG:
value = new Long(removeDecimalDigitsFromString(parts[2]));
break;
case DYNAMIC_FLOAT:
value = new Float(parts[2]);
break;
case DYNAMIC_DOUBLE:
value = new Double(parts[2]);
break;
case DYNAMIC_BOOLEAN:
value = new Boolean(parts[2]);
break;
case DYNAMIC_CHAR:
value = new Character(parts[2].charAt(0));
break;
case DYNAMIC_STRING:
value = parts[2];
break;
case DYNAMIC_BIGINTEGER:
value = new BigInteger(removeDecimalDigitsFromString(parts[2]));
break;
case DYNAMIC_BIGDECIMAL:
value = new BigDecimal(parts[2]);
break;
case TIME_INTERVAL:
default:
value = null;
break;
}
in.add(new Interval(low, high, lopen, ropen, value));
}
return createDynamicObject(in);
}
private DynamicType createDynamicObject(List<Interval> in) {
if (!this.isDynamicType())
return null;
switch (this) {
case DYNAMIC_BYTE: {
ArrayList<Interval<Byte>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Byte>>();
for (Interval interval : in)
lin.add(new Interval<Byte>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Byte)interval.getValue()));
}
return new DynamicByte(lin);
}
case DYNAMIC_SHORT: {
ArrayList<Interval<Short>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Short>>();
for (Interval interval : in)
lin.add(new Interval<Short>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Short)interval.getValue()));
}
return new DynamicShort(lin);
}
case DYNAMIC_INT: {
ArrayList<Interval<Integer>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Integer>>();
for (Interval interval : in)
lin.add(new Interval<Integer>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Integer)interval.getValue()));
}
return new DynamicInteger(lin);
}
case DYNAMIC_LONG: {
ArrayList<Interval<Long>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Long>>();
for (Interval interval : in)
lin.add(new Interval<Long>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Long)interval.getValue()));
}
return new DynamicLong(lin);
}
case DYNAMIC_FLOAT: {
ArrayList<Interval<Float>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Float>>();
for (Interval interval : in)
lin.add(new Interval<Float>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Float)interval.getValue()));
}
return new DynamicFloat(lin);
}
case DYNAMIC_DOUBLE: {
ArrayList<Interval<Double>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Double>>();
for (Interval interval : in)
lin.add(new Interval<Double>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Double)interval.getValue()));
}
return new DynamicDouble(lin);
}
case DYNAMIC_BOOLEAN: {
ArrayList<Interval<Boolean>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Boolean>>();
for (Interval interval : in)
lin.add(new Interval<Boolean>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Boolean)interval.getValue()));
}
return new DynamicBoolean(lin);
}
case DYNAMIC_CHAR: {
ArrayList<Interval<Character>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<Character>>();
for (Interval interval : in)
lin.add(new Interval<Character>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (Character)interval.getValue()));
}
return new DynamicCharacter(lin);
}
case DYNAMIC_STRING: {
ArrayList<Interval<String>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<String>>();
for (Interval interval : in)
lin.add(new Interval<String>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (String)interval.getValue()));
}
return new DynamicString(lin);
}
case DYNAMIC_BIGINTEGER: {
ArrayList<Interval<BigInteger>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<BigInteger>>();
for (Interval interval : in)
lin.add(new Interval<BigInteger>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (BigInteger)interval.getValue()));
}
return new DynamicBigInteger(lin);
}
case DYNAMIC_BIGDECIMAL: {
ArrayList<Interval<BigDecimal>> lin = null;
if (in != null) {
lin = new ArrayList<Interval<BigDecimal>>();
for (Interval interval : in)
lin.add(new Interval<BigDecimal>(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded(), (BigDecimal)interval.getValue()));
}
return new DynamicBigDecimal(lin);
}
case TIME_INTERVAL: {
ArrayList<Interval> lin = null;
if (in != null) {
lin = new ArrayList<Interval>();
for (Interval interval : in)
lin.add(new Interval(interval.getLow(), interval.getHigh(),
interval.isLowExcluded(), interval.isHighExcluded()));
}
return new TimeInterval(lin);
}
default:
return null;
}
}
/**
* Build an <code>AttributeType</code> from the given <code>obj</code> type.
* If the given <code>obj</code> class match with an
* <code>AttributeType</code> type, returns this type. Returns <code>null</code>
* otherwise.
* <p>
* For instance if
* <b>obj instanceof Float</b> equals <b>true</b>, returns
* <code>AttributeType.FLOAT</code>.
*
* @param obj the object that is to be parsed
* @return the compatible <code>AttributeType</code>, or <code>null</code> if no type is found or the input object is null
*/
public static AttributeType parse(Object obj) {
if (obj == null) {
return null;
}
Class<?> c = obj.getClass();
for (AttributeType attributeType : AttributeType.values()) {
if (c.equals(attributeType.getType())) {
return attributeType;
}
}
return null;
}
/**
* Build an dynamic <code>AttributeType</code> from the given <code>obj</code> type.
* If the given <code>obj</code> class match with an
* <code>AttributeType</code> type, returns this type. Returns <code>null</code>
* otherwise.
* <p>
* For instance if
* <b>obj instanceof Float</b> equals <b>true</b>, returns
* <code>AttributeType.DYNAMIC_FLOAT</code>.
*
* @param obj the object that is to be parsed
* @return the compatible <code>AttributeType</code>, or <code>null</code>
*/
public static AttributeType parseDynamic(Object obj) {
if (obj == null) {
return null;
}
Class<?> c = obj.getClass();
if (c.equals(Byte.class)) {
return DYNAMIC_BYTE;
}
if (c.equals(Short.class)) {
return DYNAMIC_SHORT;
}
if (c.equals(Integer.class)) {
return DYNAMIC_INT;
}
if (c.equals(Long.class)) {
return DYNAMIC_LONG;
}
if (c.equals(Float.class)) {
return DYNAMIC_FLOAT;
}
if (c.equals(Double.class)) {
return DYNAMIC_DOUBLE;
}
if (c.equals(Boolean.class)) {
return DYNAMIC_BOOLEAN;
}
if (c.equals(Character.class)) {
return DYNAMIC_CHAR;
}
if (c.equals(String.class)) {
return DYNAMIC_STRING;
}
if (c.equals(BigInteger.class)) {
return DYNAMIC_BIGINTEGER;
}
if (c.equals(BigDecimal.class)) {
return DYNAMIC_BIGDECIMAL;
}
return null;
}
/**
* Indicates if this type is a {@code DynamicType}.
*
* @return {@code true} if this is a {@code DynamicType}, {@code false}
* otherwise
*/
public boolean isDynamicType() {
switch (this) {
case DYNAMIC_BYTE:
case DYNAMIC_SHORT:
case DYNAMIC_INT:
case DYNAMIC_LONG:
case DYNAMIC_FLOAT:
case DYNAMIC_DOUBLE:
case DYNAMIC_BOOLEAN:
case DYNAMIC_CHAR:
case DYNAMIC_STRING:
case DYNAMIC_BIGINTEGER:
case DYNAMIC_BIGDECIMAL:
case TIME_INTERVAL:
return true;
default:
return false;
}
}
public boolean isListType() {
if (this.equals(LIST_BIGDECIMAL)
|| this.equals(LIST_BIGINTEGER)
|| this.equals(LIST_BOOLEAN)
|| this.equals(LIST_BYTE)
|| this.equals(LIST_CHARACTER)
|| this.equals(LIST_DOUBLE)
|| this.equals(LIST_FLOAT)
|| this.equals(LIST_INTEGER)
|| this.equals(LIST_LONG)
|| this.equals(LIST_SHORT)
|| this.equals(LIST_STRING)) {
return true;
}
return false;
}
/**
* Removes the decimal digits and point of the numbers of string when necessary.
* Used for trying to parse decimal numbers as not decimal.
* For example BigDecimal to BigInteger.
* @param s String to remove decimal digits
* @return String without dot and decimal digits.
*/
private String removeDecimalDigitsFromString(String s){
return removeDecimalDigitsFromStringPattern.matcher(s).replaceAll("");
}
private static final Pattern removeDecimalDigitsFromStringPattern=Pattern.compile("\\.[0-9]*");
}