/*
 * Copyright (c) 2011 David Saff
 * Copyright (c) 2011 Christian Gruber
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.junit.contrib.truth.subjects;

import org.junit.contrib.truth.FailureStrategy;

/**
 * Propositions for Integral numeric subjects
 * 
 * @author David Saff
 * @author Christian Gruber (cgruber@israfil.net)
 */
public class IntegerSubject extends Subject<IntegerSubject, Long> {

  private static final String RANGE_BOUNDS_OUT_OF_ORDER_MSG = "Range inclusion parameter lower (%d) should not be greater than upper (%d)";

  public IntegerSubject(FailureStrategy failureStrategy, Long i) {
    super(failureStrategy, i);
  }
  
  public IntegerSubject(FailureStrategy failureStrategy, Integer i) {
    super(failureStrategy, i == null ? null : new Long(i.longValue()));
  }

  /**
   * Attests that a Subject<Integer> is inclusively within the {@code lower} and
   * {@code upper} bounds provided or fails.
   * 
   * @throws IllegalArgumentException
   *           if the lower bound is greater than the upper.
   */
  public And<IntegerSubject> isInclusivelyInRange(long lower, long upper) {
    ensureOrderedBoundaries(lower, upper);
    if (!(lower <= getSubject() && getSubject() <= upper)) {
      fail("is inclusively in range", lower, upper);
    }
    return nextChain();
  }

  /**
   * Attests that a Subject<Integer> is exclusively within the {@code lower} and
   * {@code upper} bounds provided or fails.
   * 
   * @throws IllegalArgumentException
   *           if the lower bound is greater than the upper.
   */
  public And<IntegerSubject> isBetween(long lower, long upper) {
    ensureOrderedBoundaries(lower, upper);
    if (!(lower < getSubject() && getSubject() < upper)) {
      fail("is in between", lower, upper);
    }
    return nextChain();
  }

  /**
   * Guards against inverted lower/upper boundaries, and throws if 
   * they are so inverted.
   */
  private void ensureOrderedBoundaries(long lower, long upper) {
    if (lower > upper) {
      throw new IllegalArgumentException(String.format(
          RANGE_BOUNDS_OUT_OF_ORDER_MSG, lower, upper));
    }
  }

  public And<IntegerSubject> is(Integer other) {
    return isEqualTo(other);
  }

  public And<IntegerSubject> isEqualTo(Integer other) {
    return isEqualTo((other == null) ? null : new Long(other.longValue()));
  }
  
  public And<IntegerSubject> isEqualTo(Long other) {
    if (getSubject() == null) { 
      if(other != null) {
        fail("is equal to", other);
      }
    } else {
      // Coerce to a long.
      if (!new Long(getSubject().longValue()).equals(other)) {
        fail("is equal to", other);
      }
    }
    return nextChain();
  }

  public And<IntegerSubject> isNotEqualTo(Integer other) {
    return isNotEqualTo((other == null) ? null : new Long(other.longValue()));
  }

  public And<IntegerSubject> isNotEqualTo(Long other) {
    if (getSubject() == null) { 
      if(other == null) {
        fail("is not equal to", other);
      }
    } else {
      // Coerce to a long.
      if (new Long(getSubject().longValue()).equals(other)) {
        fail("is not equal to", other);
      }
    }
    return nextChain();
  }
  
  
}

@@ -70,18 +70,17 @@
 ruber%0A *
- 
 %0A
+
  * Licen
@@ -770,17 +770,16 @@
 jects%0A *
- 
 %0A * @aut
@@ -1155,27 +1155,25 @@
 gy, i);%0A  %7D%0A
-  
 %0A
+
   public Int
@@ -1435,33 +1435,32 @@
 d or fails.%0A   *
- 
 %0A   * @throws Il
@@ -1953,17 +1953,16 @@
 ls.%0A   *
- 
 %0A   * @t
@@ -2376,17 +2376,16 @@
 hrows if
- 
 %0A   * th
@@ -2843,19 +2843,17 @@
 ));%0A  %7D%0A
-  
 %0A
+
   public
@@ -2920,33 +2920,32 @@
 ect() == null) %7B
- 
 %0A      if(other 
@@ -3411,17 +3411,16 @@
  null) %7B
- 
 %0A      i
@@ -3674,12 +3674,262 @@
   %7D%0A
-  
 %0A  
+public And%3CIntegerSubject%3E is(int other) %7B%0A    return super.is((long)other);%0A  %7D%0A%0A  public And%3CIntegerSubject%3E is(short other) %7B%0A    return super.is((long)other);%0A  %7D%0A%0A  public And%3CIntegerSubject%3E is(byte other) %7B%0A    return super.is((long)other);%0A  %7D%0A
 %0A%7D%0A

Fix integral is() so it works with other integral types without a cast to long. In the words of D. Beaumont... ASSERT.that(4).is(4); should compile.