Integer.java

/**
* Copyright 2010,2021 Nikolas S Boyd.
Permission is granted to copy this work provided this copyright statement is retained in all copies.

*/
package Hoot.Magnitudes;

import Hoot.Runtime.Functions.*;
import Hoot.Runtime.Faces.*;
import Hoot.Runtime.Values.*;
import Hoot.Runtime.Blocks.*;
import Smalltalk.Core.*;
import Smalltalk.Blocks.*;
import Smalltalk.Magnitudes.*;
import Hoot.Behaviors.*;
import Hoot.Behaviors.Nil;
import Hoot.Behaviors.Object;
import Hoot.Behaviors.True;
import Hoot.Behaviors.False;
import Hoot.Behaviors.Boolean;
import Hoot.Collections.*;
import Hoot.Collections.String;
import java.math.BigInteger;
import Hoot.Runtime.Names.Primitive;
import Hoot.Runtime.Faces.IntegerValue;
import Hoot.Streams.TextWriteStream;
import Smalltalk.Core.Posit;
import Smalltalk.Magnitudes.Code;
import Smalltalk.Magnitudes.Scalar;
import Smalltalk.Magnitudes.Ordinal;
import Smalltalk.Magnitudes.Numeric;
import Smalltalk.Streams.StreamedSink;

public abstract class Integer extends Rational implements Ordinal, IntegerValue
{

  public static Metaclass type() { return (Metaclass)Metaclass.$class; }
  @Override public Metaclass $class() { return (Metaclass)Metaclass.$class; }
  public static class Metaclass extends Rational.Metaclass implements Ordinal.Metatype, IntegerValue.Metatype
  {
    static final Integer.Metaclass $class = new Integer.Metaclass();
    public Metaclass() {
      this(Integer.Metaclass.class);
    }

    public Metaclass(java.lang.Class aClass) {
      super(aClass);
    }

    @Override public java.lang.Class outerClass() { return Integer.class; }


    /**
     * @return 
     */
    @Override public   Integer zero()
    {
      java.lang.String exitID = "IntegerMetatype>>zero";
      Frame f0 = new Frame(exitID);
      return f0.evaluate(() -> {
      return (Integer)f0.exit(exitID, SmallInteger.Zero);
      });
    }

    /**
     * @return 
     */
    @Override public   Integer unity()
    {
      java.lang.String exitID = "IntegerMetatype>>unity";
      Frame f0 = new Frame(exitID);
      return f0.evaluate(() -> {
      return (Integer)f0.exit(exitID, SmallInteger.Unity);
      });
    }

    /**
     * @return 
     */
    public   char radixDigit(final Number index)
    {
      java.lang.String exitID = "IntegerMetatype>>radixDigit";
      Frame f0 = new Frame(exitID);
      return f0.evaluate(() -> {
      return (char)f0.exit(exitID, RadixDigits.charAt(index.asSmallInteger().primitiveInteger()));
      });
    }
  }


  private static java.lang.String RadixDigits = String.from("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").primitiveString();

  /**
   * 
   */
  protected    Integer()
  {
    super();
    java.lang.String exitID = "Integer>>Integer";
    Frame f0 = new Frame(exitID);
  }

  /**
   * @return 
   */
  @Override public   Integer numerator()
  {
    java.lang.String exitID = "Integer>>numerator";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer denominator()
  {
    java.lang.String exitID = "Integer>>denominator";
    Frame f0 = new Frame(exitID);
    return (Integer)((Integer)this.$class().unity());
  }

  /**
   * @return 
   */
  @Override public   Boolean equals(final Magnitude aNumber)
  {
    java.lang.String exitID = "Integer>>equals";
    Frame f0 = new Frame(exitID);
    return (Boolean)Number.type().accepts(aNumber).and(Predicate.with(f2 -> {
      return (((Number)aNumber).asInteger().equals(this));
    }, ""));
  }

  /**
   * @return 
   */
  @Override public   Boolean lessThan(final Scalar upperBound)
  {
    java.lang.String exitID = "Integer>>lessThan";
    Frame f0 = new Frame(exitID);
    return (Boolean)Number.type().accepts(upperBound).and(Predicate.with(f2 -> {
      return (((Number)upperBound).asInteger().moreThan(this));
    }, ""));
  }

  /**
   * @return 
   */
  @Override public   Boolean moreThan(final Scalar lowerBound)
  {
    java.lang.String exitID = "Integer>>moreThan";
    Frame f0 = new Frame(exitID);
    return (Boolean)Number.type().accepts(lowerBound).and(Predicate.with(f2 -> {
      return (((Number)lowerBound).asInteger().lessThan(this));
    }, ""));
  }

  /**
   * @return 
   */
  public   Boolean equals(final Integer aNumber)
  {
    java.lang.String exitID = "Integer>>equals";
    Frame f0 = new Frame(exitID);
    return (Boolean)Boolean.from((0 == this.asBigInteger().compareTo(aNumber.asBigInteger())));
  }

  /**
   * @return 
   */
  public   Boolean lessThan(final Integer aNumber)
  {
    java.lang.String exitID = "Integer>>lessThan";
    Frame f0 = new Frame(exitID);
    return (Boolean)Boolean.from((0 > this.asBigInteger().compareTo(aNumber.asBigInteger())));
  }

  /**
   * @return 
   */
  public   Boolean moreThan(final Integer aNumber)
  {
    java.lang.String exitID = "Integer>>moreThan";
    Frame f0 = new Frame(exitID);
    return (Boolean)Boolean.from((0 < this.asBigInteger().compareTo(aNumber.asBigInteger())));
  }

  /**
   * @return 
   */
  @Override public   int hashCode()
  {
    java.lang.String exitID = "Integer>>hashCode";
    Frame f0 = new Frame(exitID);
    return (int)this.elementaryNumber().hashCode();
  }

  /**
   * @return 
   */
  @Override public   Integer min(final Scalar index)
  {
    java.lang.String exitID = "Integer>>min";
    Frame f0 = new Frame(exitID);
    return (Integer)this.min(((Integer)index));
  }

  /**
   * @return 
   */
  @Override public   Integer max(final Scalar index)
  {
    java.lang.String exitID = "Integer>>max";
    Frame f0 = new Frame(exitID);
    return (Integer)this.max(((Integer)index));
  }

  /**
   * @return 
   */
  public   Integer min(final Integer index)
  {
    java.lang.String exitID = "Integer>>min";
    Frame f0 = new Frame(exitID);
    if ((index == null)) {
      return this;
    };
    if (this.lessThan(index).primitiveBoolean()) {
      return this;
    };
    return (Integer)index;
  }

  /**
   * @return 
   */
  public   Integer max(final Integer index)
  {
    java.lang.String exitID = "Integer>>max";
    Frame f0 = new Frame(exitID);
    if ((index == null)) {
      return this;
    };
    if (this.moreThan(index).primitiveBoolean()) {
      return this;
    };
    return (Integer)index;
  }

  /**
   * @return 
   */
  @Override public   Integer asInteger()
  {
    java.lang.String exitID = "Integer>>asInteger";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  public   FastInteger faster()
  {
    java.lang.String exitID = "Integer>>faster";
    Frame f0 = new Frame(exitID);
    return (FastInteger)FastInteger.fromInteger(this);
  }

  /**
   * @return 
   */
  @Override public   int intValue()
  {
    java.lang.String exitID = "Integer>>intValue";
    Frame f0 = new Frame(exitID);
    return (int)this.primitiveInteger();
  }

  /**
   * @return 
   */
  @Override public   long longValue()
  {
    java.lang.String exitID = "Integer>>longValue";
    Frame f0 = new Frame(exitID);
    return (long)this.primitiveLong();
  }

  /**
   * @return 
   */
  public   Integer bitAnd(final Ordinal anInteger)
  {
    java.lang.String exitID = "Integer>>bitAnd";
    Frame f0 = new Frame(exitID);
    return (Integer)((Integer)anInteger).asSmallInteger().bitAnd(this);
  }

  /**
   * @return 
   */
  public   Integer bitOr(final Ordinal anInteger)
  {
    java.lang.String exitID = "Integer>>bitOr";
    Frame f0 = new Frame(exitID);
    return (Integer)((Integer)anInteger).asSmallInteger().bitOr(this);
  }

  /**
   * @return 
   */
  public   Integer bitXor(final Ordinal anInteger)
  {
    java.lang.String exitID = "Integer>>bitXor";
    Frame f0 = new Frame(exitID);
    return (Integer)((Integer)anInteger).asSmallInteger().bitXor(this);
  }

  /**
   * @return 
   */
  public   Integer bitInvert()
  {
    java.lang.String exitID = "Integer>>bitInvert";
    Frame f0 = new Frame(exitID);
    return (Integer)SmallInteger.from(Primitive.invertBits(this.primitiveInteger()));
  }

  /**
   * @return 
   */
  public   Integer and(final Ordinal anInteger)
  {
    java.lang.String exitID = "Integer>>and";
    Frame f0 = new Frame(exitID);
    return (Integer)this.bitAnd(anInteger);
  }

  /**
   * @return 
   */
  public   Integer or(final Ordinal anInteger)
  {
    java.lang.String exitID = "Integer>>or";
    Frame f0 = new Frame(exitID);
    return (Integer)this.bitOr(anInteger);
  }

  /**
   * @return 
   */
  public   Boolean allMask(final Ordinal mask)
  {
    java.lang.String exitID = "Integer>>allMask";
    Frame f0 = new Frame(exitID);
    return (Boolean)(this.bitAnd(mask).equals(mask));
  }

  /**
   * @return 
   */
  public   Boolean anyMask(final Ordinal mask)
  {
    java.lang.String exitID = "Integer>>anyMask";
    Frame f0 = new Frame(exitID);
    return (Boolean)(this.bitAnd(mask).notEqual(SmallInteger.from(0)));
  }

  /**
   * @return 
   */
  public   Boolean noMask(final Ordinal mask)
  {
    java.lang.String exitID = "Integer>>noMask";
    Frame f0 = new Frame(exitID);
    return (Boolean)(this.bitAnd(mask).isSame(SmallInteger.from(0)));
  }

  /**
   * @return 
   */
  public   Integer bitAt(final Ordinal index)
  {
    java.lang.String exitID = "Integer>>bitAt";
    Frame f0 = new Frame(exitID);
    return (Integer)this.asLongInteger().bitAt(((Integer)index).asSmallInteger());
  }

  /**
   * @return 
   */
  public   Integer bitAt_put(final Ordinal index, final Ordinal bitValue)
  {
    java.lang.String exitID = "Integer>>bitAt_put";
    Frame f0 = new Frame(exitID);
    return (Integer)this.bitAt_put(((Integer)index).asSmallInteger(), ((Integer)bitValue).asSmallInteger());
  }

  /**
   * @return 
   */
  public   Integer bitShift(final Ordinal count)
  {
    java.lang.String exitID = "Integer>>bitShift";
    Frame f0 = new Frame(exitID);
    return (Integer)this.asLongInteger().bitShift(((Integer)count).asSmallInteger());
  }

  /**
   * @return 
   */
  public   Integer highBit()
  {
    java.lang.String exitID = "Integer>>highBit";
    Frame f0 = new Frame(exitID);
    return (Integer)this.asLargeInteger().highBit();
  }

  /**
   * @return 
   */
  public   Boolean odd()
  {
    java.lang.String exitID = "Integer>>odd";
    Frame f0 = new Frame(exitID);
    return (Boolean)this.even().not();
  }

  /**
   * @return 
   */
  public   Boolean even()
  {
    java.lang.String exitID = "Integer>>even";
    Frame f0 = new Frame(exitID);
    return (Boolean)((this.remainderFrom(SmallInteger.from(2))).isSame(SmallInteger.from(0)));
  }

  /**
   * @return 
   */
  @Override public   Boolean isInteger()
  {
    java.lang.String exitID = "Integer>>isInteger";
    Frame f0 = new Frame(exitID);
    return (Boolean)True.literal();
  }

  /**
   * @return 
   */
  public   Integer minus(final Ordinal aNumber)
  {
    java.lang.String exitID = "Integer>>minus";
    Frame f0 = new Frame(exitID);
    return (Integer)(this.minus(((Integer)aNumber)));
  }

  /**
   * @return 
   */
  public   Integer plus(final Ordinal aNumber)
  {
    java.lang.String exitID = "Integer>>plus";
    Frame f0 = new Frame(exitID);
    return (Integer)(((Integer)aNumber).plus(this));
  }

  /**
   * @return 
   */
  public   Integer times(final Ordinal aNumber)
  {
    java.lang.String exitID = "Integer>>times";
    Frame f0 = new Frame(exitID);
    return (Integer)(((Integer)aNumber).times(this));
  }

  /**
   * @return 
   */
  @Override public   Integer minus(final Numeric aNumber)
  {
    java.lang.String exitID = "Integer>>minus";
    Frame f0 = new Frame(exitID);
    return (Integer)(this.minus(((Number)aNumber).asInteger()));
  }

  /**
   * @return 
   */
  @Override public   Integer plus(final Numeric aNumber)
  {
    java.lang.String exitID = "Integer>>plus";
    Frame f0 = new Frame(exitID);
    return (Integer)(((Number)aNumber).asInteger().plus(this));
  }

  /**
   * @return 
   */
  @Override public   Integer times(final Numeric aNumber)
  {
    java.lang.String exitID = "Integer>>times";
    Frame f0 = new Frame(exitID);
    return (Integer)(((Number)aNumber).asInteger().times(this));
  }

  /**
   * @return 
   */
  public   Integer minus(final Integer anInteger)
  {
    java.lang.String exitID = "Integer>>minus";
    Frame f0 = new Frame(exitID);
    return (Integer)new LargeInteger(this.asBigInteger().subtract(anInteger.asBigInteger())).narrowGenerality();
  }

  /**
   * @return 
   */
  public   Integer plus(final Integer anInteger)
  {
    java.lang.String exitID = "Integer>>plus";
    Frame f0 = new Frame(exitID);
    return (Integer)new LargeInteger(this.asBigInteger().add(anInteger.asBigInteger())).narrowGenerality();
  }

  /**
   * @return 
   */
  public   Integer times(final Integer anInteger)
  {
    java.lang.String exitID = "Integer>>times";
    Frame f0 = new Frame(exitID);
    return (Integer)new LargeInteger(this.asBigInteger().multiply(anInteger.asBigInteger())).narrowGenerality();
  }

  /**
   * @return 
   */
  @Override public   Integer floor()
  {
    java.lang.String exitID = "Integer>>floor";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer ceiling()
  {
    java.lang.String exitID = "Integer>>ceiling";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer truncated()
  {
    java.lang.String exitID = "Integer>>truncated";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer rounded()
  {
    java.lang.String exitID = "Integer>>rounded";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer integerPart()
  {
    java.lang.String exitID = "Integer>>integerPart";
    Frame f0 = new Frame(exitID);
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer negated()
  {
    java.lang.String exitID = "Integer>>negated";
    Frame f0 = new Frame(exitID);
    return (Integer)(SmallInteger.from(0).minus(this));
  }

  /**
   * @return 
   */
  public   Integer raisedToInteger(final Integer anInteger)
  {
    java.lang.String exitID = "Integer>>raisedToInteger";
    Frame f0 = new Frame(exitID);
    return (Integer)this.asLargeInteger().raisedToInteger(anInteger).narrowGenerality();
  }

  /**
   * @return 
   */
  public   Integer factorial()
  {
    java.lang.String exitID = "Integer>>factorial";
    Frame f0 = new Frame(exitID);
    (this.lessThan(this.$class().zero())).ifTrue(Closure.with(f2 -> {
      this.error(String.from("Negative integers cannot use #factorial"));
    }, ""));

    FastInteger result = this.$class().unity().faster();
    this.$class().unity().to_do(this, Closure.with(f2 -> {
      SmallInteger n = f2.getValue(0).value();
      return result.multiplyBy(n);
    }, "n"));
    return (Integer)result.asInteger();
  }

  /**
   * @return 
   */
  public   Integer gcd(final Ordinal aNumber)
  {
    java.lang.String exitID = "Integer>>gcd";
    Frame f0 = new Frame(exitID);
    return (Integer)this.asLargeInteger().gcd(aNumber).narrowGenerality();
  }

  /**
   * @return 
   */
  public   Integer lcm(final Ordinal aNumber)
  {
    java.lang.String exitID = "Integer>>lcm";
    Frame f0 = new Frame(exitID);
    return f0.evaluate(() -> {
    Integer gcd = this.gcd(((Integer)aNumber));
    (gcd.equals(SmallInteger.from(0))).ifFalse(Closure.with(f2 -> {
      return (Integer)f0.exit(exitID, this.truncateWith(gcd).times(aNumber).abs());
    }, ""));
    return (Integer)f0.exit(exitID, SmallInteger.from(1));
    });
  }

  /**
   * @return 
   */
  public   Integer timesRepeat(final NiladicValuable aBlock)
  {
    java.lang.String exitID = "Integer>>timesRepeat";
    Frame f0 = new Frame(exitID);
    FastInteger count = this.$class().unity().faster();
    Predicate.with(f2 -> {
      return (count.notMore(this));
    }, "").whileTrue(Closure.with(f2 -> {
      aBlock.value();
    count.increment();
    }, ""));
    return (Integer)this;
  }

  /**
   * @return 
   */
  @Override public   Integer printOn(final StreamedSink aStream)
  {
    java.lang.String exitID = "Integer>>printOn";
    Frame f0 = new Frame(exitID);
    this.printOn_base_showRadix(aStream, SmallInteger.from(10), False.literal());
    return (Integer)this;
  }

  /**
   * @return 
   */
  public   Integer printOn_base_showRadix(final StreamedSink aStream, final Ordinal radix, final Posit showRadix)
  {
    java.lang.String exitID = "Integer>>printOn_base_showRadix";
    Frame f0 = new Frame(exitID);
    this.negative().ifTrue_ifFalse(Closure.with(f2 -> {
      aStream.nextPut(((Character)Character.from('-')));
    this.negated().asInteger().printOn_base_showRadix(aStream, radix, showRadix);
    }, ""), Closure.with(f2 -> {
      showRadix.ifTrue(Closure.with(f3 -> {
      radix.printOn(aStream);
    aStream.nextPut(((Character)Character.from('r')));
    }, ""));
    this.printDigitsOn_base(aStream, radix);
    }, ""));
    return (Integer)this;
  }

  /**
   * @return 
   */
  public   Integer printDigitsOn_base(final StreamedSink aStream, final Ordinal radix)
  {
    java.lang.String exitID = "Integer>>printDigitsOn_base";
    Frame f0 = new Frame(exitID);
    (this.notLess(radix)).ifTrue(Closure.with(f2 -> {
      (this.truncateWith(radix)).printDigitsOn_base(aStream, radix);
    }, ""));
    aStream.nextPut(Character.from(this.$class().radixDigit((this.remainderFrom(radix)))));
    return (Integer)this;
  }

  /**
   * @return 
   */
  public   String printStringRadix(final Ordinal radix)
  {
    java.lang.String exitID = "Integer>>printStringRadix";
    Frame f0 = new Frame(exitID);
    return (String)this.printStringRadix_showRadix(radix, True.literal());
  }

  /**
   * @return 
   */
  public   String printStringRadix_showRadix(final Ordinal radix, final Boolean showRadix)
  {
    java.lang.String exitID = "Integer>>printStringRadix_showRadix";
    Frame f0 = new Frame(exitID);
    TextWriteStream aStream = String.type().writeStream(SmallInteger.from(16));
    this.printOn_base_showRadix(aStream, radix, showRadix);
    return (String)aStream.contents();
  }
}