package railo.transformer.bytecode.statement.tag;

import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

import railo.runtime.type.scope.Undefined;
import railo.runtime.util.NumberIterator;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Statement;
import railo.transformer.bytecode.cast.CastInt;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.literal.LitString;
import railo.transformer.bytecode.util.Types;
import railo.transformer.bytecode.visitor.DecisionIntVisitor;
import railo.transformer.bytecode.visitor.NotVisitor;
import railo.transformer.bytecode.visitor.OnFinally;
import railo.transformer.bytecode.visitor.ParseBodyVisitor;
import railo.transformer.bytecode.visitor.TryFinallyVisitor;
import railo.transformer.bytecode.visitor.WhileVisitor;

public class TagGroupUtil {
	

	// Undefined us()
	public static final Type UNDEFINED = Type.getType(Undefined.class);
	public static final Method US = new Method(
			"us",
			UNDEFINED,
			new Type[]{});

	// void addQuery(Query coll)
	public static final Method ADD_QUERY = new Method(
			"addQuery",
			Types.VOID,
			new Type[]{Types.QUERY});

	// void removeQuery()
	public static final Method REMOVE_QUERY = new Method(
			"removeQuery",
			Types.VOID,
			new Type[]{});

	
	// int getRecordcount()
	public static final Method GET_RECORDCOUNT = new Method(
			"getRecordcount",
			Types.INT_VALUE,
			new Type[]{});

	// double range(double number, double from)
	public static final Method RANGE = new Method(
			"range",
			Types.INT_VALUE,
			new Type[]{Types.INT_VALUE,Types.INT_VALUE});

	public static final Type NUMBER_ITERATOR = Type.getType(NumberIterator.class);

	// NumberIterator load(double from, double to, double max) 
	public static final Method LOAD_MAX = new Method(
			"loadMax",
			NUMBER_ITERATOR,
			new Type[]{Types.INT_VALUE,Types.INT_VALUE,Types.INT_VALUE});

	public static final Method LOAD_END = new Method(
			"loadEnd",
			NUMBER_ITERATOR,
			new Type[]{Types.INT_VALUE,Types.INT_VALUE,Types.INT_VALUE});


	// NumberIterator load(double from, double to, double max) 
	public static final Method LOAD_2 = new Method(
			"load",
			NUMBER_ITERATOR,
			new Type[]{Types.INT_VALUE,Types.INT_VALUE});
	

	// NumberIterator load(NumberIterator ni, Query query, String groupName, boolean caseSensitive)
	public static final Method LOAD_5 = new Method(
			"load",
			NUMBER_ITERATOR,
			new Type[]{Types.PAGE_CONTEXT, NUMBER_ITERATOR,Types.QUERY,Types.STRING,Types.BOOLEAN_VALUE});

	// boolean isValid()
	/*public static final Method IS_VALID_0 = new Method(
			"isValid",
			Types.BOOLEAN_VALUE,
			new Type[]{});*/
	
	public static final Method IS_VALID_1 = new Method(
			"isValid",
			Types.BOOLEAN_VALUE,
			new Type[]{Types.INT_VALUE});

	// int current()
	public static final Method CURRENT = new Method(
			"current",
			Types.INT_VALUE,
			new Type[]{});

	// void release(NumberIterator ni)
	public static final Method REALEASE = new Method(
			"release",
			Types.VOID,
			new Type[]{NUMBER_ITERATOR});

	// void setCurrent(int current)
	public static final Method SET_CURRENT = new Method(
			"setCurrent",
			Types.VOID,
			new Type[]{Types.INT_VALUE});
	

	// void reset()
	public static final Method RESET = new Method(
			"reset",
			Types.VOID,
			new Type[]{Types.INT_VALUE});

	// int first()
	public static final Method FIRST = new Method(
			"first",
			Types.INT_VALUE,
			new Type[]{});
	public static final Method GET_ID = new Method(
			"getId",
			Types.INT_VALUE,
			new Type[]{});


	
	
	public static void writeOutTypeQuery(final TagGroup tag, BytecodeContext bc) throws BytecodeException {
		final GeneratorAdapter adapter = bc.getAdapter();

		tag.setNumberIterator(adapter.newLocal(NUMBER_ITERATOR));
		boolean isOutput=tag.getType()==TagGroup.TAG_OUTPUT;
		ParseBodyVisitor pbv=isOutput?new ParseBodyVisitor():null;
		if(isOutput)pbv.visitBegin(bc);
			
		
		// Query query=pc.getQuery(@query);
		tag.setQuery(adapter.newLocal(Types.QUERY));
		adapter.loadArg(0);
		Expression val = tag.getAttribute("query").getValue();
		val.writeOut(bc, Expression.MODE_REF);
		if(val instanceof LitString)
			adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_QUERY_STRING);
		else
			adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_QUERY_OBJ);
		
		adapter.storeLocal(tag.getQuery());
		
		
		tag.setPID(adapter.newLocal(Types.INT_VALUE));
		adapter.loadArg(0);
		adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID);
		adapter.storeLocal(tag.getPID());
		

		
		// int startAt=query.getCurrentrow();
		final int startAt=adapter.newLocal(Types.INT_VALUE);
		adapter.loadLocal(tag.getQuery());
		
		adapter.loadLocal(tag.getPID());
		//adapter.loadArg(0);
		//adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID);
		adapter.invokeInterface(Types.QUERY, TagLoop.GET_CURRENTROW_1);
		
		adapter.storeLocal(startAt);
		
		
		
		// if(query.getRecordcount()>0) {
		DecisionIntVisitor div=new DecisionIntVisitor();
		div.visitBegin();
			adapter.loadLocal(tag.getQuery());
			adapter.invokeInterface(Types.QUERY, GET_RECORDCOUNT);
		div.visitGT();
			adapter.push(0);
		div.visitEnd(bc);
		Label ifRecCount=new Label();
		adapter.ifZCmp(Opcodes.IFEQ, ifRecCount);
			
			// startrow
			int from = adapter.newLocal(Types.INT_VALUE);
			Attribute attrStartRow = tag.getAttribute("startrow");
			if(attrStartRow!=null){
				// NumberRange.range(@startrow,1)
				//attrStartRow.getValue().writeOut(bc, Expression.MODE_VALUE);
				CastInt.toExprInt(attrStartRow.getValue()).writeOut(bc, Expression.MODE_VALUE);
				//adapter.visitInsn(Opcodes.D2I);
				adapter.push(1);
				adapter.invokeStatic(Types.NUMBER_RANGE, RANGE);
				//adapter.visitInsn(Opcodes.D2I);
			}
			else {
				adapter.push(1);
			}
			adapter.storeLocal(from);
			
			// numberIterator
			
			
			adapter.loadLocal(from);
			adapter.loadLocal(tag.getQuery());
			adapter.invokeInterface(Types.QUERY, GET_RECORDCOUNT);
			//adapter.visitInsn(Opcodes.I2D);
			
			Attribute attrMaxRow = tag.getAttribute("maxrows");
			Attribute attrEndRow = tag.getAttribute("endrow");
			if(attrMaxRow!=null) {
				CastInt.toExprInt(attrMaxRow.getValue()).writeOut(bc, Expression.MODE_VALUE);
				adapter.invokeStatic(NUMBER_ITERATOR, LOAD_MAX);
			}
			else if(attrEndRow!=null) {
				CastInt.toExprInt(attrEndRow.getValue()).writeOut(bc, Expression.MODE_VALUE);
				adapter.invokeStatic(NUMBER_ITERATOR, LOAD_END);
			}
			else {
				adapter.invokeStatic(NUMBER_ITERATOR, LOAD_2);
			}
			adapter.storeLocal(tag.getNumberIterator());
			
			// Group
			Attribute attrGroup = tag.getAttribute("group");
			Attribute attrGroupCS = tag.getAttribute("groupcasesensitive");
			tag.setGroup(adapter.newLocal(Types.STRING));
			final int groupCaseSensitive=adapter.newLocal(Types.BOOLEAN_VALUE);
			if(attrGroup!=null)	{
				attrGroup.getValue().writeOut(bc, Expression.MODE_REF);
				adapter.storeLocal(tag.getGroup());
				
				if(attrGroupCS!=null)	attrGroupCS.getValue().writeOut(bc, Expression.MODE_VALUE);
				else 					adapter.push(false);
				adapter.storeLocal(groupCaseSensitive);
			}
			
			// pc.us().addQuery(query);
			adapter.loadArg(0);
			adapter.invokeVirtual(Types.PAGE_CONTEXT, US);
			adapter.loadLocal(tag.getQuery());
			adapter.invokeInterface(UNDEFINED, ADD_QUERY);
			
			// current
			final int current=adapter.newLocal(Types.INT_VALUE);
			adapter.loadLocal(from);
			adapter.push(1);
			adapter.visitInsn(Opcodes.ISUB);
			adapter.storeLocal(current);
			
			
			// Try
			TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() {
				public void writeOut(BytecodeContext bc) {
					// query.reset();
					
					// query.go(startAt);
					adapter.loadLocal(tag.getQuery());
					adapter.loadLocal(startAt);
					
					adapter.loadLocal(tag.getPID());
					//adapter.loadArg(0);
					//adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID);
					adapter.invokeInterface(Types.QUERY, TagLoop.GO);
					adapter.pop();
					
					
					
					
					// pc.us().removeQuery();
					adapter.loadArg(0);
					adapter.invokeVirtual(Types.PAGE_CONTEXT, US);
					adapter.invokeInterface(UNDEFINED, REMOVE_QUERY);
					
			    	// NumberIterator.release(ni);
					adapter.loadLocal(tag.getNumberIterator());
					adapter.invokeStatic(NUMBER_ITERATOR, REALEASE);
				}
			},null);
			tfv.visitTryBegin(bc);
				WhileVisitor wv = new WhileVisitor();
				if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
				wv.visitBeforeExpression(bc);
					
					//while(ni.isValid()) {
					adapter.loadLocal(tag.getNumberIterator());
					adapter.loadLocal(current);
					adapter.push(1);
					adapter.visitInsn(Opcodes.IADD);
					adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
					
				wv.visitAfterExpressionBeforeBody(bc);
				
					// if(!query.go(ni.current()))break; 
					adapter.loadLocal(tag.getQuery());
					adapter.loadLocal(tag.getNumberIterator());
					adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
					
					adapter.loadLocal(tag.getPID());
					adapter.invokeInterface(Types.QUERY, TagLoop.GO);
					
					NotVisitor.visitNot(bc);
					Label _if=new Label();
					adapter.ifZCmp(Opcodes.IFEQ, _if);
						wv.visitBreak(bc);
					adapter.visitLabel(_if);
					
					if(attrGroup!=null) {
						// NumberIterator oldNi=numberIterator;
						int oldNi=adapter.newLocal(NUMBER_ITERATOR);
						adapter.loadLocal(tag.getNumberIterator());
						adapter.storeLocal(oldNi);
						
						// numberIterator=NumberIterator.load(ni,query,group,grp_case);
						adapter.loadArg(0);
						adapter.loadLocal(tag.getNumberIterator());
						adapter.loadLocal(tag.getQuery());
						adapter.loadLocal(tag.getGroup());
						adapter.loadLocal(groupCaseSensitive);
						adapter.invokeStatic(NUMBER_ITERATOR, LOAD_5);
						adapter.storeLocal(tag.getNumberIterator());
						
						// current=oldNi.current();
						adapter.loadLocal(oldNi);
						adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
						adapter.storeLocal(current);
						
						tag.getBody().writeOut(bc);
						
						//tmp(adapter,current);
						
						// NumberIterator.release(ni);
						adapter.loadLocal(tag.getNumberIterator());
						adapter.invokeStatic(NUMBER_ITERATOR, REALEASE);
						
						// numberIterator=oldNi;
						adapter.loadLocal(oldNi);
						adapter.storeLocal(tag.getNumberIterator());
					}
					else {
						// current=ni.current();
						adapter.loadLocal(tag.getNumberIterator());
						adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
						adapter.storeLocal(current);
						
						tag.getBody().writeOut(bc);
					}

					// ni.setCurrent(current+1);
					/*adapter.loadLocal(tag.getNumberIterator());
					adapter.loadLocal(current);
					adapter.push(1);
					adapter.visitInsn(Opcodes.IADD);
					adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/
			
				wv.visitAfterBody(bc,tag.getEnd());
			
				tfv.visitTryEnd(bc);

		adapter.visitLabel(ifRecCount);
		

		if(isOutput)pbv.visitEnd(bc);
	}
	
	

	public static void writeOutTypeGroup(TagGroup tag,BytecodeContext bc) throws BytecodeException {
		GeneratorAdapter adapter = bc.getAdapter();
		boolean isOutput=tag.getType()==TagGroup.TAG_OUTPUT;
		ParseBodyVisitor pbv=isOutput?new ParseBodyVisitor():null;
		if(isOutput)pbv.visitBegin(bc);
		
		// Group
		Attribute attrGroup = tag.getAttribute("group");
		tag.setGroup(adapter.newLocal(Types.STRING));
		attrGroup.getValue().writeOut(bc, Expression.MODE_REF);
		adapter.storeLocal(tag.getGroup());
		
		// Group Case Sensitve
		Attribute attrGroupCS = tag.getAttribute("groupcasesensitive");
		int groupCaseSensitive=adapter.newLocal(Types.BOOLEAN_VALUE);
		if(attrGroupCS!=null)	attrGroupCS.getValue().writeOut(bc, Expression.MODE_VALUE);
		else 					adapter.push(true);
		adapter.storeLocal(groupCaseSensitive);
		
		TagGroup parent = getParentTagGroupQuery(tag,tag.getType());
		tag.setNumberIterator(parent.getNumberIterator());
		tag.setQuery(parent.getQuery());
		//queryImpl = parent.getQueryImpl();
		
		// current
		int current=adapter.newLocal(Types.INT_VALUE);
		adapter.loadLocal(tag.getNumberIterator());
		adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
		adapter.storeLocal(current);
		
		
		// current
		int icurrent=adapter.newLocal(Types.INT_VALUE);
		
		adapter.loadLocal(current);
		adapter.push(1);
		adapter.visitInsn(Opcodes.ISUB);
		adapter.storeLocal(icurrent);
		
		
		WhileVisitor wv = new WhileVisitor();
		if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
		wv.visitBeforeExpression(bc);
			
			//while(ni.isValid()) {
			adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(icurrent);
			adapter.push(1);
			adapter.visitInsn(Opcodes.IADD);
			adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
			
		wv.visitAfterExpressionBeforeBody(bc);
		
			// if(!query.go(ni.current()))break; 
			adapter.loadLocal(tag.getQuery());
			adapter.loadLocal(tag.getNumberIterator());
			adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
			
			adapter.loadArg(0);
			adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
			adapter.invokeInterface(Types.QUERY, TagLoop.GO);
			
			NotVisitor.visitNot(bc);
			Label _if=new Label();
			adapter.ifZCmp(Opcodes.IFEQ, _if);
				wv.visitBreak(bc);
			adapter.visitLabel(_if);
		
			// NumberIterator oldNi=numberIterator;
			int oldNi=adapter.newLocal(NUMBER_ITERATOR);
			
			adapter.loadLocal(tag.getNumberIterator());
			adapter.storeLocal(oldNi);
			
			// numberIterator=NumberIterator.load(ni,query,group,grp_case);
			adapter.loadArg(0);
			adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(tag.getQuery());
			adapter.loadLocal(tag.getGroup());
			adapter.loadLocal(groupCaseSensitive);
			adapter.invokeStatic(NUMBER_ITERATOR, LOAD_5);
			adapter.storeLocal(tag.getNumberIterator());
			
			// current=oldNi.current();
			adapter.loadLocal(oldNi);
			adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
			adapter.storeLocal(icurrent);
			
			tag.getBody().writeOut(bc);
			
			//tmp(adapter,current);
			
			
			// NumberIterator.release(ni);
			adapter.loadLocal(tag.getNumberIterator());
			adapter.invokeStatic(NUMBER_ITERATOR, REALEASE);
			
			// numberIterator=oldNi;
			adapter.loadLocal(oldNi);
			adapter.storeLocal(tag.getNumberIterator());
		
			// ni.setCurrent(current+1);
			/*adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(icurrent);
			adapter.push(1);
			adapter.visitInsn(Opcodes.IADD);
			adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);
			*/
		wv.visitAfterBody(bc,tag.getEnd());
	

		//query.go(ni.current(),pc.getId())
		resetCurrentrow(adapter,tag,current);
		
		// ni.first();
		adapter.loadLocal(tag.getNumberIterator());
		adapter.invokeVirtual(NUMBER_ITERATOR, FIRST);
		adapter.pop();
		

		if(isOutput)pbv.visitEnd(bc);
	}
	
	public static void writeOutTypeInnerGroup(TagGroup tag,BytecodeContext bc) throws BytecodeException {
		GeneratorAdapter adapter = bc.getAdapter();

		TagGroup parent = getParentTagGroupQuery(tag,tag.getType());
		tag.setNumberIterator(parent.getNumberIterator());
		tag.setQuery(parent.getQuery());
		//queryImpl = parent.getQueryImpl();
		
		int current=adapter.newLocal(Types.INT_VALUE);
		adapter.loadLocal(tag.getNumberIterator());
		adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
		adapter.storeLocal(current);
		
		
		// inner current
		int icurrent=adapter.newLocal(Types.INT_VALUE);
		
		adapter.loadLocal(current);
		adapter.push(1);
		adapter.visitInsn(Opcodes.ISUB);
		adapter.storeLocal(icurrent);
		
		
		
		WhileVisitor wv = new WhileVisitor();
		if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
		wv.visitBeforeExpression(bc);
			
			//while(ni.isValid()) {
			adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(icurrent);
			adapter.push(1);
			adapter.visitInsn(Opcodes.IADD);
			adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
			
		wv.visitAfterExpressionBeforeBody(bc);
		
			// if(!query.go(ni.current()))break; 
			
			adapter.loadLocal(tag.getQuery());
			adapter.loadLocal(tag.getNumberIterator());
			adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
			
			adapter.loadArg(0);
			adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
			adapter.invokeInterface(Types.QUERY, TagLoop.GO);
			
			/*OLD
			adapter.invokeInterface(Types.QUERY, TagLoop.GO_1);
			*/
			NotVisitor.visitNot(bc);
			Label _if=new Label();
			adapter.ifZCmp(Opcodes.IFEQ, _if);
				wv.visitBreak(bc);
			adapter.visitLabel(_if);
		
			// current=ni.current();
			adapter.loadLocal(tag.getNumberIterator());
			adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
			adapter.storeLocal(icurrent);
			
			tag.getBody().writeOut(bc);
			
			// ni.setCurrent(current+1);
			/*adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(icurrent);
			adapter.push(1);
			adapter.visitInsn(Opcodes.IADD);
			adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/
	
		wv.visitAfterBody(bc,tag.getEnd());
	
		resetCurrentrow(adapter,tag,current);
		
		
		// ni.first();
		adapter.loadLocal(tag.getNumberIterator());
		adapter.invokeVirtual(NUMBER_ITERATOR, FIRST);
		adapter.pop();
	}
	
	public static void writeOutTypeInnerQuery(TagGroup tag,BytecodeContext bc) throws BytecodeException {
		GeneratorAdapter adapter = bc.getAdapter();
		//if(tr ue)return ;
		TagGroup parent = getParentTagGroupQuery(tag,tag.getType());
		tag.setNumberIterator(parent.getNumberIterator());
		tag.setQuery(parent.getQuery());
		tag.setPID(parent.getPID());
		//queryImpl = parent.getQueryImpl();
		
		//int currentOuter=ni.current();
		int current=adapter.newLocal(Types.INT_VALUE);
		adapter.loadLocal(tag.getNumberIterator());
		adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
		adapter.storeLocal(current);
		
		// current
		int icurrent=adapter.newLocal(Types.INT_VALUE);
		
		adapter.loadLocal(current);
		adapter.push(1);
		adapter.visitInsn(Opcodes.ISUB);
		adapter.storeLocal(icurrent);
		
		
		WhileVisitor wv = new WhileVisitor();
		if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
		wv.visitBeforeExpression(bc);
			
			//while(ni.isValid()) {
			adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(icurrent);
			adapter.push(1);
			adapter.visitInsn(Opcodes.IADD);
			adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
			
		wv.visitAfterExpressionBeforeBody(bc);
		
			// if(!query.go(ni.current()))break; 
			adapter.loadLocal(tag.getQuery());
			adapter.loadLocal(tag.getNumberIterator());
			adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
			
			adapter.loadLocal(tag.getPID());
			adapter.invokeInterface(Types.QUERY, TagLoop.GO);
			
			NotVisitor.visitNot(bc);
			Label _if=new Label();
			adapter.ifZCmp(Opcodes.IFEQ, _if);
				wv.visitBreak(bc);
			adapter.visitLabel(_if);
		
			// current=ni.current();
			adapter.loadLocal(tag.getNumberIterator());
			adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
			adapter.storeLocal(icurrent);
			
			tag.getBody().writeOut(bc);
			
			// ni.setCurrent(current+1);
			/*adapter.loadLocal(tag.getNumberIterator());
			adapter.loadLocal(icurrent);
			adapter.push(1);
			adapter.visitInsn(Opcodes.IADD);
			adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/
	
		wv.visitAfterBody(bc,tag.getEnd());
	
		
		// ni.setCurrent(currentOuter);
		adapter.loadLocal(tag.getNumberIterator());
		adapter.loadLocal(current);
		adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);
		
		adapter.loadLocal(tag.getQuery());
		adapter.loadLocal(current);
		
		adapter.loadLocal(tag.getPID());
		//adapter.loadArg(0);
		//adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
		adapter.invokeInterface(Types.QUERY, TagLoop.GO);
		adapter.pop();
		//adapter.pop();
	}
	
	public static TagGroup getParentTagGroupQuery(Statement st, short type) throws BytecodeException {
		Statement parent=st.getParent();
		if(parent==null) throw new BytecodeException("there is no parent output with query",null);
		else if(parent instanceof TagGroup && type==((TagGroup)parent).getType()) {
			if(((TagGroup)parent).hasQuery())
				return ((TagGroup)parent);
		}
		return getParentTagGroupQuery(parent,type);
	}
	
	private static void resetCurrentrow(GeneratorAdapter adapter,TagGroup tg, int current) {
		//query.go(ni.current(),pc.getId())
		adapter.loadLocal(tg.getQuery());
		adapter.loadLocal(current);
		adapter.loadArg(0);
		adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
		adapter.invokeInterface(Types.QUERY, TagLoop.GO);
		
		/* OLD
		adapter.invokeInterface(Types.QUERY, TagLoop.GO_1);
		*/
		adapter.pop();
		
	}

}
