package railo.runtime.util;

import railo.runtime.PageContext;
import railo.runtime.exp.PageException;
import railo.runtime.op.Operator;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Query;

/**
 * A Number Iterator Implementation to iterate from to
 */
public final class NumberIterator {
	
	private int _from;
	private int _to;
	private int _current;
	private int recordcount;
	
	//private static int count=0;
	
	/**
	 * constructor of the number iterator
	 * @param from iterate from
	 * @param to iterate to
	 * @param recordcount 
	 */
	private NumberIterator(int from, int to, int recordcount) {
	    //railo.print.ln(count++);
        init(from,to,recordcount);
	}
	private NumberIterator init(int from, int to, int recordcount) {
	    this._from=from;
		this._current=from;
		this._to=to; 
		this.recordcount=recordcount;
		return this;
	}
		
	/**
	 * @return returns if there is a next value
	 */
	public boolean hasNext() {
		return _current<_to;
	}
	public boolean hasNext(boolean useRecordcount) {
		return _current<(useRecordcount?recordcount:_to);
	}
	
	/**
	 * @return increment and return new value
	 */
	public int next() {
	    return ++_current;
	}
	
	/**
	 * @return returns if there is a previous value
	 */
	public boolean hasPrevious() {
		return _current>_from;
	}
	
	/**
	 * @return decrement and return new value
	 */
	public int previous() {
		return --_current;
	}
	
	/**
	 * @return returns smallest possible value
	 */
	public int from() {
		return _from;
	}
	
	/**
	 * @return returns greatest value
	 */
	public int to() {
		return _to;
	}
	
	/**
	 * @return set value to first and return
	 */
	public int first() {
		return _current=_from;
	}
	
	/**
	 * @return set value to last and return thid value
	 */
	public int last() {
		return _current=_to;
	}
	/**
	 * @return returns current value
	 */
	public int current() {
		return _current;
	}
	
	/**
	 * sets the current position
	 * @param current
	 */
	public void setCurrent(int current) {
		_current=current;
	}

	/**
	 * @return is after last
	 */
	public boolean isAfterLast() {
		return _current>_to;
	}	
	/**
	 * @return is pointer on a valid position
	 */
	public boolean isValid() {
		return _current>=_from && _current<=_to;
	}	
	
	public boolean isValid(int current) {
		_current=current;
		return _current>=_from && _current<=_to;
	}	
	
	
	
	
	private static NumberIterator[] iterators=new NumberIterator[]{
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1),
		    new NumberIterator(1,1,1)
	};
	private static int pointer=0;
	
	/**
	 * load a iterator
	 * @param from
	 * @param to iterate to
	 * @return NumberIterator
	 */
	private static NumberIterator _load(int from, int to) {
		return _load(from, to, to);
	}
	private static NumberIterator _load(int from, int to, int recordcount) {
		if(pointer>=iterators.length) return new NumberIterator(from,to,recordcount);
	    return iterators[pointer++].init(from,to,recordcount);
	}
	
	/**
	 * create a Number Iterator with value from and to
	 * @param from
	 * @param to
	 * @return NumberIterator
	 */
	public static synchronized NumberIterator load(double from, double to) {
		return _load((int)from,(int)to,(int)to);
	}
	public static synchronized NumberIterator load(int from, int to) {
		return _load(from,to,to);
	}
	
	/**
	 * create a Number Iterator with value from and to
	 * @param from
	 * @param to
	 * @param max
	 * @return NumberIterator
	 */
	public static synchronized NumberIterator load(double from, double to, double max) {
	    return loadMax((int)from, (int)to, (int)max);
	}
	
	public static synchronized NumberIterator loadMax(int from, int to, int max) {
	    return _load(from,((from+max-1<to)?from+max-1:to),to);
	}
	
	public static synchronized NumberIterator loadEnd(int from, int to, int end) {
	    return _load(from,((end<to)?end:to),to);
	}
	
	/**
	 * @param ni
	 * @param query
	 * @param groupName
	 * @param caseSensitive
	 * @return number iterator for group
	 * @throws PageException
	 */
	public static synchronized NumberIterator load(PageContext pc, NumberIterator ni, Query query, String groupName, boolean caseSensitive) throws PageException {
		int startIndex=query.getCurrentrow(pc.getId()); 
		
        Object startValue=query.get(KeyImpl.init(groupName)); 
        while(ni.hasNext(true)) { 
            if(!Operator.equals(startValue,query.getAt(groupName,ni.next()),caseSensitive)) { 

                        ni.previous();
                        return _load(startIndex,ni.current());
            } 
        } 
        return _load(startIndex,ni.current());
    } 
	
	/**
	 * @param ni Iterator to release
	 */
	public static synchronized void release(NumberIterator ni) {
	    if(pointer>0) {
	        iterators[--pointer]=ni;
	    }
	}
	
	
	
	
	
	
	
}