package ceylon.language;

public final class Natural
    extends Object
    implements Integral<Natural>, Invertable<Integer> {

    private final long value;
    private Natural(long l) {
        if (l < 0)
            throw new NegativeNumberException();
        value = l;
    }

    public static ceylon.language.Natural instance(long l) {
        assert l >= 0;
        return new ceylon.language.Natural(l);
    }

    public ceylon.language.Natural plus(ceylon.language.Natural op) {
        return instance(value + op.value);
    }

    public ceylon.language.Natural minus(ceylon.language.Natural op) {
        return instance(value - op.value);
    }

    public ceylon.language.Natural times(ceylon.language.Natural op) {
        return instance(value * op.value);
    }

    public ceylon.language.Natural divided(ceylon.language.Natural op) {
        return instance(value / op.value);
    }

    public ceylon.language.Natural power(ceylon.language.Natural op) {
        return instance((long) Math.pow(value, op.value)); // FIXME: ugly
    }

    public ceylon.language.Natural remainder(ceylon.language.Natural op) {
        return instance(value % op.value);
    }

    public ceylon.language.Integer inverse() {
        return ceylon.language.Integer.instance(-value);
    }

    public ceylon.language.Boolean test(ceylon.language.Natural op) {
        return ceylon.language.Boolean.instance(value == op.value);
    }

    public ceylon.language.Comparison compare(ceylon.language.Natural op) {
        long x = value;
        long y = op.value;
        return (x < y) ? Comparison.SMALLER :
            ((x == y) ? Comparison.EQUAL : Comparison.LARGER);
    }

    public ceylon.language.Boolean equalsXXX(ceylon.language.Natural s) {
        return Boolean.instance(value == s.value);
    }

    @Extension
    public ceylon.language.String string() {
        return ceylon.language.String.instance(java.lang.Long.toString(value));
    }

    // Conversions between numeric types

    public ceylon.language.Natural natural() {
        return this;
    }

    @Extension
    public ceylon.language.Integer integer() {
        return ceylon.language.Integer.instance(value);
    }

    @Extension
    public ceylon.language.Whole whole() {
        throw new RuntimeException("not implemented");
    }

    @Extension
    public ceylon.language.Float floatXXX() {
        return ceylon.language.Float.instance(value);
    }

    @Extension
    public ceylon.language.Decimal decimal() {
        throw new RuntimeException("not implemented");
    }

    // Just a kludge til we have full autoboxing
    @Extension
    public long longValue() {
        return value;
    }

    @Extension
    public int intValue() {
        return (int)value;
    }

    public ceylon.language.Natural getPredecessor() {
        return Natural.instance(value - 1);
    }

    public ceylon.language.Natural getSuccessor() {
        return Natural.instance(value + 1);
    }

    public ceylon.language.Natural and(ceylon.language.Natural op) {
        return Natural.instance(value & op.value);
    }

    public ceylon.language.Natural or(ceylon.language.Natural op) {
        return Natural.instance(value | op.value);
    }

    public ceylon.language.Natural xor(ceylon.language.Natural op) {
        return Natural.instance(value ^ op.value);
    }

    @Override
    public Boolean equals(Equality that) {
        // FIXME
        throw new RuntimeException("Not implemented");
    }
}

@@ -19,16 +19,308 @@
 guage;%0A%0A
+import com.redhat.ceylon.compiler.metadata.java.*;%0A%0A@SatisfiedTypes(%7B%0A    %22ceylon.language.Castable%3Cceylon.language.Natural%7Cceylon.language.Integer%7Cceylon.language.Float%3E%22,%0A    %22ceylon.language.Integral%3Cceylon.language.Natural%3E%22,%0A    %22ceylon.language.Invertable%3Cceylon.language.Integer%3E%22,%0A%7D)%0A
 public f
@@ -371,16 +371,35 @@
 plements
+ Castable%3CNumeric%3E,
  Integra
@@ -3795,11 +3795,121 @@
 );%0A    %7D
+%0A%0A    @Override%0A    public %3CCastValue extends Numeric%3E CastValue as() %7B%0A        return (CastValue) this;%0A    %7D
 %0A%7D%0A

Use @SatisfiedTypes on Natural to define proper satisfied with union type