package com.ql.util.express.instruction.detail;

import java.util.List;

import com.ql.util.express.exception.QLException;
import org.apache.commons.logging.Log;

import com.ql.util.express.ArraySwap;
import com.ql.util.express.InstructionSet;
import com.ql.util.express.InstructionSetContext;
import com.ql.util.express.InstructionSetRunner;
import com.ql.util.express.OperateData;
import com.ql.util.express.RunEnvironment;
import com.ql.util.express.instruction.OperateDataCacheManager;
import com.ql.util.express.instruction.opdata.OperateDataAttr;
import com.ql.util.express.instruction.opdata.OperateDataLocalVar;

public class InstructionCallSelfDefineFunction extends Instruction{
	private static final long serialVersionUID = 8315682251443515151L;
	String functionName;
	int opDataNumber;
	public InstructionCallSelfDefineFunction(String name,int aOpDataNumber){
	  this.functionName = name;
	  this.opDataNumber =aOpDataNumber;
	}

	public String getFunctionName() {
		return functionName;
	}

	public int getOpDataNumber() {
		return opDataNumber;
	}

	public void execute(RunEnvironment environment, List<String> errorList)
			throws Exception {
			ArraySwap parameters = environment.popArray(
					environment.getContext(), this.opDataNumber);
			if (environment.isTrace() && log.isDebugEnabled()) {
				String str = this.functionName + "(";
				OperateData p;
				for (int i = 0; i < parameters.length; i++) {
					p = parameters.get(i);
					if (i > 0) {
						str = str + ",";
					}
					if (p instanceof OperateDataAttr) {
						str = str
								+ p
								+ ":"
								+ p.getObject(environment
										.getContext());
					} else {
						str = str + p;
					}
				}
				str = str + ")";
				log.debug(str);
			}

			Object function = environment.getContext().getSymbol(functionName);
			if (function == null || function instanceof InstructionSet == false) {
				throw new QLException(getExceptionPrefix()+"在Runner的操作符定义和自定义函数中都没有找到\""
						+ this.functionName + "\"的定义");
			}
			InstructionSet functionSet = (InstructionSet)function;
			OperateData result = InstructionCallSelfDefineFunction
					.executeSelfFunction(environment, functionSet, parameters,
							errorList, this.log);
			environment.push(result);
			environment.programPointAddOne();
	}	
	public static OperateData executeSelfFunction(RunEnvironment environment,InstructionSet functionSet,
			ArraySwap parameters,List<String> errorList,Log log)throws Exception{	
		InstructionSetContext  context = OperateDataCacheManager.fetchInstructionSetContext (
				true,environment.getContext().getExpressRunner(),environment.getContext(),environment.getContext().getExpressLoader(),environment.getContext().isSupportDynamicFieldName());
		OperateDataLocalVar[] vars = functionSet.getParameters();
		for(int i=0;i<vars.length;i++){
			//注意此处必须new 一个新的对象,否则就会在多次调用的时候导致数据冲突
			OperateDataLocalVar var = OperateDataCacheManager.fetchOperateDataLocalVar(vars[i].getName(),vars[i].getOrgiType());
			context.addSymbol(var.getName(), var);
			var.setObject(context, parameters.get(i).getObject(environment.getContext()));
		}
		Object result =InstructionSetRunner.execute((InstructionSet)functionSet,
				context,errorList,environment.isTrace(),false,true,log);
		return OperateDataCacheManager.fetchOperateData(result,null);
	}
	public String toString(){
	  return "call Function[" + this.functionName +"] OPNUMBER["+ this.opDataNumber +"]"  ;	
	}

}