package lab3;

/**
 * @author martin
 *
 */
public class AutoSortInteger{
	/*properties*/
	private final int _val;
	private final AutoSortInteger _last;

	/*constructor*/
	/**
	 * constructor
	 * @param val as new value to compare
	 * @param last as value added
	 */
	private AutoSortInteger(int val, AutoSortInteger last){
		_val = val;
		_last = last;
	}

	/*static factory*/
	/**
	 * build object from new value
	 * @param val as value
	 * @return new AutoSortInt object
	 */
	public static AutoSortInteger fromIntOnly(int val){
		return new AutoSortInteger(val, null);
	}

	/**
	 * build object from value and another AutoSortInt to sort with
	 * @param val as value
	 * @param last as value
	 * @return new AutoSortInt object
	 */
	public static AutoSortInteger fromIntAndAutosort(int val, final AutoSortInteger last){
		return new AutoSortInteger(val, last);
	}

	/*functor
	 * function object
	 * make function as value you can pass as argument or return value*/
	private interface Comparator{
		/**
		 * compare interface
		 * @param a first value as int
		 * @param b second value as int
		 * @return result of comparison as boolean
		 */
		boolean compare(int a, int b);
	}

	private static Comparator Bigger = new Comparator(){
		public boolean compare(int a, int b){
			return a > b;
		}
	};

	private static Comparator Smaller = new Comparator(){
		public boolean compare(int a, int b){
			return a < b;
		}
	};

	/*getter*/
	/**
	 * get last created value
	 * @return value
	 */
	public int getVal(){
		return _val;
	}

	/**
	 * from give value return the first number that met Comparator Q param
	 * @param val starting value as int
	 * @param bestNow best found number yet
	 * @param Q comparator functor
	 * @return best number
	 */
	private int fromValFindNext(int val, int bestNow, final Comparator Q){
		if(_last!=null)
			bestNow = _last.fromValFindNext(val, bestNow, Q);
		if (Q.compare(val, _val) && Q.compare(_val, bestNow))
			return _val;
		else
			return bestNow;
	}

	/**
	 * return value that meet comparator Q functor
	 * @param Q as comparator functor
	 * @return best number
	 */
	private int findBest(final Comparator Q){
		if (_last == null)
			return _val;

		int best = _last.findBest(Q);
		if (Q.compare(best, _val))
			return best;
		else
			return _val;
	}

	/**
	 * return smallest number after given val
	 * @param val as starting value
	 * @return smallest number who is bigger than val
	 */
	public int getSmallestBiggerThan(int val){
		return fromValFindNext(val, getBiggest(), Smaller);
	}

	/**
	 * return biggest number who is smaller than val
	 * @param val as starting value
	 * @return smallest number who is bigger than val
	 */
	public int getBiggestSmallerThan(int val){
		return fromValFindNext(val, getSmallest(), Bigger);
	}

	/**
	 * get biggest number in the structure
	 * @return biggest number
	 */
	public int getBiggest(){
		return findBest(Bigger);
	}

	/**
	 * get smallest number in the structure
	 * @return smallest number in the structure
	 */
	public int getSmallest(){
		return findBest(Smaller);
	}
}
