package parser.ServletParser.library;

import parser.ServletParser.javapass2.CallInfo;
import java.util.ListIterator;
import java.io.*; 
import java.awt.*;
import java.util.*;
import visualizer.figure.*;

/** 이 클래스는 컨테이너 객체로서 함수 호출이나 InstructionBlock 객체를 저장한다.
 */
public final
class InstructionBlock extends List 
{
	/** 버전 제어를 위한 시리얼 넘버이다.
	 */
	public static final long serialVersionUID = 3224356100242348530L;
	public int level;
	public String cond;
	/** 생성자이다.
	 */
	public InstructionBlock() {
		super();
		level = -1;
		cond = new String("");
	}
	/** 블럭의 최대 레벨을 구하는 함수이다.
	 */
	public int getLevel() {
		int maxLevel = 0;
		
		Object obj = getFirst();
		while(obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock aBlock = (InstructionBlock)obj;
				int l = aBlock.getLevel() + 1;
				if (l > maxLevel) maxLevel = l;
			}
			obj = getNext();
		}
		return maxLevel;
	}
	/** 블럭에서 호출하는 remote call의 갯수를 구하는 함수이다.
	 */
	public int collectRemoteCalls(StringList calls,StringList allMethods) {
		int totalRemoteCalls = 0;
		
		Object obj = getFirst();
		while(obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock aBlock = (InstructionBlock)obj;
				totalRemoteCalls = totalRemoteCalls + aBlock.collectRemoteCalls(calls,allMethods);
			} else if (obj.getClass().getName().equals("parser.ServletParser.javapass2.CallInfo")) {
				CallInfo info = (CallInfo)obj;
				if (info.receiverName.equals("this") == false &&
					info.receiverName.equals("super") == false &&
					// allMethods에 있는가 확인 (현재 클래스와 슈퍼 클래스 함수들)
					allMethods.inList(info.functionName) == false &&
					// Object에 있는 메소드들 뺄것
					info.functionName.equals("clone") == false &&
					info.functionName.equals("equals") == false &&
					info.functionName.equals("finalize") == false &&
					info.functionName.equals("getClass") == false &&
					info.functionName.equals("hashCode") == false &&
					info.functionName.equals("notify") == false &&
					info.functionName.equals("notifyAll") == false &&
					info.functionName.equals("toString") == false &&
					info.functionName.equals("wait") == false) {
					totalRemoteCalls++;
					calls.insert(info.functionName);
				}
			}
			obj = getNext();
		}
		return totalRemoteCalls;
	}
	/** 이 리스트의 마지막에 새로운 객체를 insert 하는 함수이다.
	 * 리스트에 이미 객체가 있으면 insert 하지 않는다.
	 */
	public void insert(Object ptr) {
		_insert(ptr,ABSOLUTELY);
	}
	/** 이 리스트로 부터 객체를 삭제하는 함수이다.
	 */
	public void delete(Object ptr) {
		super._remove((Object)ptr,0);
	}
	/** 이 리스트를 비우는 함수이다.
	 */
	public void clear() {
		super._clear();
	}
	/** 이 블럭에 self 함수 호출이 몇개인가 알아보는 함수이다.
	 */
	public int getNumberOfSelfCall() {
		if (nOfList() == 0) return 0;
		int total = 0;
		Object obj = getFirst();
		while (obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.javapass2.CallInfo")) {
				CallInfo info = (CallInfo)obj;
				if (info.receiverName.equals("this") ||
					info.receiverName.equals("super"))
				{
					total++;
				}
			} else if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock block = (InstructionBlock)obj;
				total = total + block.getNumberOfSelfCall();
			}
			obj = getNext();
		}
		return total;
	}
	/** 이 블럭에 함수 호출이 포함되는가 알아보는 함수이다.
	 */
	public boolean hasNoCall() {
		if (nOfList() == 0) return true;
		Object obj = getFirst();
		while (obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.javapass2.CallInfo")) {
				return false;
			} else if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				if (((InstructionBlock)obj).hasNoCall() == false)
					return false;
			}
			obj = getNext();
		}
		return true;
	}
	/** 조인 테이블 경우 필드가 어느 테이블에 속하는지 결정하는 함수이다.
	 */
	public void determineAmbiguousFieldNamesForJoinTablesAndCollectSQL(SQLTableInfoList allTableInfos,SQLInfoList classSqlList,SQLInfoList methodSqlList) {
		if (nOfList() == 0) return;
		Object obj = getFirst();
		while (obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.javapass2.CallInfo")) {
				CallInfo info = (CallInfo)obj;
				info.determineAmbiguousFieldNamesForJoinTablesAndCollectSQL(allTableInfos,classSqlList,methodSqlList);
			} else if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock aBlock = (InstructionBlock)obj;
				aBlock.determineAmbiguousFieldNamesForJoinTablesAndCollectSQL(allTableInfos,classSqlList,methodSqlList);
			}
			obj = getNext();
		}
	}
	/** 복사함수이다.
	 */
	public void copy(InstructionBlock from) {
		_clear();
		ListIterator i = from.listIterator();
		while (i.hasNext()) {
			Object o = i.next();
			if (o.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock aBlock = new InstructionBlock();
				aBlock.copy((InstructionBlock)o);
				super.add(aBlock);
			} else { 
				super.add(o);
			}
		}
		level = from.level;
		cond = new String(from.cond);
	}
	/** 리스트의 객체들을 traverse 할 때 맨 첫번째 객체를 찾아오는 함수이다.
	 * 만약 리스트가 비어있게되면 null 값을 리턴한다.
	 */
	public Object getFirst() {
		return (Object)super._getFirst();
	}
	/** 리스트의 객체들을 반대 방향으로 traverse 하기위해 맨 마지막 객체를 찾아오는 함수이다.
	 * 만약 리스트가 비어있게되면 null 값을 리턴한다.
	 */
	public Object getLast() {
		return (Object)super._getLast();
	}
	/** 리스트의 객체들을 traverse 할 때 다음 객체를 찾아오는 함수이다.
	 * 만약 리스트의 끝에 도달하면 null 값을 리턴한다.
	 */
	public Object getNext() {
		return (Object)super._getNext();
	}
	/** 리스트의 객체들을 반대 방향으로 traverse 할 때 다음 객체를 찾아오는 함수이다.
	 * 만약 리스트의 앞에 도달하면 null 값을 리턴한다.
	 */
	public Object getPrevious() {
		return (Object)super._getPrevious();
	}
	public int drawCascadeMessages(GraphicController controller,SFDObject fromObject,
							SFDObjectList objectList,StringList calledStringList,int startY,int vGap) {

		InstructionBlock copiedBlock = new InstructionBlock();
		copiedBlock.copy(this);

		int newStartY = startY;
		Object obj = copiedBlock.getFirst();
		while(obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock aBlock = new InstructionBlock();
				aBlock.copy((InstructionBlock)obj);
				if (aBlock.hasNoCall() == false) {
					newStartY = aBlock.drawCascadeMessages(controller,fromObject,objectList,calledStringList,newStartY,vGap);
				}
			} else if (obj.getClass().getName().equals("parser.ServletParser.javapass2.CallInfo")) {
				CallInfo info = (CallInfo)obj;

				newStartY = info.drawCascadeMessages(controller,fromObject,objectList,calledStringList,newStartY,vGap);
			}
			obj = copiedBlock.getNext();
		}
		return newStartY;
	}

	/** 테스트 용 함수
	public void printCallGraph(FileWriter writer,String senderClass,String senderObject) {
		InstructionBlock copiedBlock = new InstructionBlock();
		copiedBlock.copy(this);
		Object obj = copiedBlock.getFirst();
		while(obj != null) {
			if (obj.getClass().getName().equals("parser.ServletParser.library.InstructionBlock")) {
				InstructionBlock aBlock = new InstructionBlock();
				aBlock.copy((InstructionBlock)obj);
				aBlock.printCallGraph(writer,senderClass,senderObject);
			} else if (obj.getClass().getName().equals("parser.ServletParser.javapass2.CallInfo")) {
				CallInfo info = (CallInfo)obj;
				info.printCallGraph(writer,senderClass,senderObject,level);
			}
			obj = copiedBlock.getNext();
		}
	}
	 */
}
