package de.skuzzle.polly.sdk;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import de.skuzzle.polly.sdk.time.Time;
/**
* <p>These class represents a Type for a signature. Each Types-instance represents a
* type as well as its value.</p>
*
* <p>For each type exists only one instance that represents only the type with no value
* (for formal signatures). These isntances can be retrieved using the static constants</p>
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public class Types {
/**
* Valueless type constant for the type User
* @since 0.9
*/
public final static UserType USER = new UserType();
/**
* Valueless type constant for the type String
* @since 0.9
*/
public final static StringType STRING = new StringType();
/**
* Valueless type constant for the type Number
* @since 0.9
*/
public final static NumberType NUMBER = new NumberType();
/**
* Valueless type constant for the type Date
* @since 0.9
*/
public final static DateType DATE = new DateType();
/**
* Valueless type constant for the type Timespan
* @since 0.9
*/
public final static TimespanType TIMESPAN = new TimespanType();
/**
* Valueless type constant for the type Boolean
* @since 0.9
*/
public final static BooleanType BOOLEAN = new BooleanType();
/**
* Valueless type constant for the type Channel
* @since 0.9
*/
public final static ChannelType CHANNEL = new ChannelType();
/**
* Valueless type constant for the type Help
* @since 0.9
*/
public final static HelpType HELP = new HelpType();
/**
* Valueless type constant for the type Any
* @since 0.9
*/
public final static AnyType ANY = new AnyType();
private Types() {};
/**
* This class represents a Number type. Note that a Number parameter matches any
* expression that evaluates to a number.
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class NumberType extends Types {
private double value;
private int radix;
/**
* Creates a new Number-type with the given value and default radix = 10.
* @param value The value of this type.
*/
public NumberType(double value) {
this(value, 10);
}
/**
* Creates a new Number-type with the given value and radix.
* @param value The value of this type.
* @param radix The radix of the value.
* @since 0.6.1
*/
public NumberType(double value, int radix) {
this.value = value;
this.radix = radix;
}
/**
* Creates a new Number-type with a default value. This may be used for
* formal signature parameters.
*/
protected NumberType() {
this(0.0, 10);
}
@Override
public String getSample() {
return "27.45"; //$NON-NLS-1$
};
/**
* Returns the number.
* @return the number.
*/
public double getValue() {
return this.value;
}
/**
* Determines whether this is an integer number.
* @return <code>true</code> if this number is integer.
*/
public boolean isInteger() {
int val = (int) this.getValue();
return (double)val == this.getValue();
}
/**
* @return Returns this values String representation. If this is an integer
* number, the String is formatted in this numbers radix.
*/
@Override
public String valueString(FormatManager formatter) {
if (this.isInteger()) {
return Integer.toString((int) this.getValue(), this.radix);
}
return formatter.formatNumber(this.value);
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("Number"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.value);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents a Boolean-type.
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class BooleanType extends Types {
private boolean value;
/**
* Creates a new Boolean-type with the given value.
* @param value The value for this type.
*/
public BooleanType(boolean value) {
this.value = value;
}
/**
* Creates a new Boolean-type with a default value. This may be used for
* formal signature parameters.
*/
protected BooleanType() {
this(false);
}
@Override
public String getSample() {
return "true"; //$NON-NLS-1$
};
/**
* Returns the boolean value.
* @return The boolean value.
*/
public boolean getValue() {
return this.value;
}
/**
* @return Returns this values String representation.
*/
@Override
public String valueString(FormatManager formatter) {
return Boolean.toString(this.value);
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("Boolean"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.value);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents a String-type.
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class StringType extends Types {
private String value;
/**
* Creates a new String-type with given value.
* @param value The string value.
*/
public StringType(String value) {
this.value = value;
}
/**
* Creates a new String-type with a default value. This may be used for
* formal signature parameters.
*/
protected StringType() {
this(""); //$NON-NLS-1$
}
@Override
public String getSample() {
return Messages.typesStringSample;
}
/**
* Returns the string.
* @return the string.
*/
public String getValue() {
return this.value;
}
/**
* @return Returns this values String representation.
*/
@Override
public String valueString(FormatManager formatter) {
return "\"" + this.value + "\""; //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("String"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.value);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents a Channel-type.
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class ChannelType extends Types {
private String value;
/**
* Creates a new Channel-type with the given channel.
* @param value The channel of this type.
*/
public ChannelType(String value) {
this.value = value;
}
/**
* Creates a new Channel-type with a default value. This may be used for
* formal signature parameters.
*/
protected ChannelType() {
this(""); //$NON-NLS-1$
}
@Override
public String getSample() {
return "#channel"; //$NON-NLS-1$
};
/**
* Returns the channel name.
* @return the channel name.
*/
public String getValue() {
return this.value;
}
/**
* @return Returns this values String representation.
*/
@Override
public String valueString(FormatManager formatter) {
return this.value;
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("Channel"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.value);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents a User-type.
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class UserType extends Types {
private String value;
/**
* Creates a new User-type with the given user name.
* @param value The username.
*/
public UserType(String value) {
this.value = value;
}
/**
* Creates a new User-type with a default value. This may be used for
* formal signature parameters.
*/
protected UserType() {
this(""); //$NON-NLS-1$
}
@Override
public String getSample() {
return "@Hans"; //$NON-NLS-1$
};
/**
* Returns the user name
* @return the user name.
*/
public String getValue() {
return this.value;
}
/**
* @return Returns this values String representation.
*/
@Override
public String valueString(FormatManager formatter) {
return this.value;
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("User"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.value);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents a Date-type.
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class DateType extends Types {
private Date value;
/**
* Creates a new User-type with the given user name.
* @param value The username.
*/
public DateType(Date value) {
this.value = value;
}
/**
* Creates a new Date-type with a default value. This may be used for
* formal signature parameters.
*/
protected DateType() {
this(Time.currentTime());
}
@Override
public String getSample() {
return "24.12.2012@17:30"; //$NON-NLS-1$
};
/**
* Returns the date.
* @return the date.
*/
public Date getValue() {
return this.value;
}
/**
* @return Returns this values String representation.
*/
@Override
public String valueString(FormatManager formatter) {
return formatter.formatDate(this.value);
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("Date"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.value);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents a timespan-type. Timespans are fully compatible to
* {@link DateType}, but return another String when calling
* {@link #valueString(FormatManager)}.
*
* @author Simon
* @since Beta 0.2
*/
public static class TimespanType extends DateType implements Comparable<TimespanType> {
private long span;
/**
* Creates a new Timespan-Type.
* @param span The timespan in seconds.
*/
public TimespanType(long span) {
super(Time.currentTime());
this.span = span;
}
protected TimespanType() {}
/**
* Gets the timespan in seconds.
* @return The timespan.
*/
public long getSpan() {
return this.span;
}
@Override
public Date getValue() {
Calendar c = Calendar.getInstance();
c.setTime(Time.currentTime());
c.add(Calendar.SECOND, (int) this.span);
return c.getTime();
}
@Override
public String getSample() {
return "8h22m7s"; //$NON-NLS-1$
};
/**
* Formats this timespan as a string.
*
* @param formatter The formatter which is used to format this timespan.
* @return The formatted String.
*/
@Override
public String valueString(FormatManager formatter) {
return formatter.formatTimeSpan(this.span);
}
public String toString() {
return "Timespan"; //$NON-NLS-1$
}
@Override
public int compareTo(TimespanType obj) {
return (int) (this.span - obj.span);
}
}
/**
* This class represents a List of other types. It holds an element list of
* {@link Types} which define this ListTypes subtype.
*
* A ListType is only compatible to a ListType with the same subtype.
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class ListType extends Types {
private List<Types> elements;
Types subtype;
/**
* Creates a new ListType which holds the given values. The new ListTypes
* subType is determined by the first element of the List of values.
*
* If the values-list is empty, the subType of this ListType is {@link AnyType}.
* @param values The elements of this ListType.
*/
public ListType(List<Types> values) {
this.elements = values;
this.subtype = new AnyType();
if (!this.elements.isEmpty()) {
this.subtype = this.elements.get(0);
}
}
/**
* Creates a new empty ListType with the given Type as subType.
* @param subtype The subType of this {@link ListType}.
*/
public ListType(Types subtype) {
this.elements = new ArrayList<Types>();
this.subtype = subtype;
}
@Override
public String getSample() {
return "{" + //$NON-NLS-1$
this.subtype.getSample() + "," + //$NON-NLS-1$
this.subtype.getSample()
+ "}"; //$NON-NLS-1$
}
/**
* Returns the elements of this ListType.
* @return The elements.
*/
public List<Types> getElements() {
return this.elements;
}
/**
* @return Returns this values String representation.
*/
@Override
public String valueString(FormatManager formatter) {
StringBuilder b = new StringBuilder();
b.append("{"); //$NON-NLS-1$
Iterator<Types> it = this.elements.iterator();
while (it.hasNext()) {
b.append(it.next().valueString(formatter));
if (it.hasNext()) {
b.append(", "); //$NON-NLS-1$
}
}
b.append("}"); //$NON-NLS-1$
return b.toString();
}
/**
* Checks this ListType against another type. Their are only considered
* compatible if the other type is a ListType and their subTypes are compatible.
* @param other The type to check against this list type.
* @return <code>true</code> if the types are compatible, <code>false</code>
* otherwise.
*/
public boolean check(Types other) {
if (!(other instanceof ListType)) {
return false;
}
ListType o = (ListType) other;
return o.getElementType().check(this.getElementType());
}
/**
* Returns the subtype of this ListType.
* @return The subtype.
*/
public Types getElementType() {
return this.subtype;
}
@Override
public String toString() {
return this.toString(false);
}
public String toString(boolean withValue) {
StringBuilder b = new StringBuilder();
b.append("List<"); //$NON-NLS-1$
b.append(this.getElementType().toString());
b.append(">"); //$NON-NLS-1$
if (withValue) {
b.append(" ("); //$NON-NLS-1$
b.append(this.elements);
b.append(")"); //$NON-NLS-1$
}
return b.toString();
}
}
/**
* This class represents the Any type which has no value and is compatible to all
* other types.
*
* @author Simon
* @since zero day
* @version RC 1.0
*/
public static class AnyType extends Types {
/**
* Creates a new AnyType with no value. Mind: value will remain <code>null</code>.
*/
protected AnyType() {}
@Override
public String toString() {
return "Any"; //$NON-NLS-1$
}
public String getSample() {
return "5.8"; //$NON-NLS-1$
};
}
/**
* This class represents the help parameter type "?"
*
* @author Simon
* @since 0.9
*/
public static class HelpType extends Types {
protected HelpType() {}
public String toString() {
return "?"; //$NON-NLS-1$
}
}
/**
* Placeholder class for probably to come function types which are already
* supported by the parser.
*
* @author Simon Taddiken
*/
public static class FunctionType extends Types {
public FunctionType() {}
}
public String valueString(FormatManager formatter) {
return ""; //$NON-NLS-1$
}
/**
* Gets a valid sample string representation of this type.
*
* @return A String sample for this type.
*/
public String getSample() { return ""; }; //$NON-NLS-1$
/**
* Checks if two types are compatible. The {@link AnyType} is compatible with
* every other type.
* Two types are considered compatible if this type is assignable from the
* other type (as determined by {@link Class#isAssignableFrom(Class)}).
*
* @param other The type to check this type against.
* @return <code>true</code> if the types are compatible, <code>false</code>
* otherwise.
*/
public boolean check(Types other) {
if (other == this) {
return true;
} else if (other instanceof AnyType || this instanceof AnyType) {
return true;
}
return this.getClass().isAssignableFrom(other.getClass());
}
}