package parser.ServletParser.javapass2;

import java.awt.*;
import java.util.*;
import java.lang.*;
import parser.ServletParser.library.*;
import parser.ServletParser.javapass2.ParseTreeNode2;
import java.io.*;
import visualizer.figure.*;

/** 이 클래스는 expression을 파싱하는 중에 사용되며 호출 명령어에 대한 처리를 담당한다.
  */
public class CallInfo extends Object implements Serializable {
	/** 버전 제어를 위한 시리얼 넘버이다.
	 */
	public static final long serialVersionUID = 2693664209206503200L;
	/** 객체 이름
	 */
	public String receiverName;
	/** 객체 타입
	 */
	public String receiverType;
	/** 함수 이름
	 */
	public String functionName;
	/** 프린트용 실인자 스트링 
	 */
	public String argsString;
	/** 인자 정보 리스트
	 */
	public StringList argTypes;
	/** 함수 호출이 정의된 곳의 링크
	 */
	public MethodInfoNode methodNode;
	/** 함수 호출을 포함하는 곳의 링크
	 */
	public transient MethodInfoNode thisNode;
	/** 이 호출에 대한 모든 스트링 값
	 */
	public String fullString;
	/** 이게 만약 PrinterWriter의 HTML출력인 경우 HTML string을 저장하는데 사용된다.
	 */
	public String htmlString;
	/** 이게 만약 SQL 문장인 경우 SQL 문장의 파싱 결과이다.
	 */
	public SQLInfo sqlInfo;
	/** UNDOABLE에 대한 상수값이다.
	 */
	public static final int UNDOABLE = 100;
	/** NONUNDOABLE에 대한 상수값이다.
	 */
	public static final int NONUNDOABLE = 200;
	public static int activationLastY = 0;
//	public static ActivationNT lastActivation = null;
	/** 생성자이다.
	 */
	CallInfo(String name) {
		functionName = new String(name);
		receiverName = new String("");
		receiverType = new String("");
		argsString = new String("()");
		argTypes = new StringList();
		methodNode = null;
		thisNode = null;
		fullString = new String("");
		htmlString = null;
		sqlInfo = null;
	}
	/** 조인 테이블 경우 필드가 어느 테이블에 속하는지 결정하는 함수이다.
	 */
	public void determineAmbiguousFieldNamesForJoinTablesAndCollectSQL(SQLTableInfoList allTableInfos,SQLInfoList classSqlList,SQLInfoList methodSqlList) {
		if (sqlInfo == null) return;
		classSqlList.insert(sqlInfo);
		methodSqlList.insert(sqlInfo);
		if (sqlInfo.tableInfos.nOfList() <= 1) return;

		StringList allFields = new StringList();
		SQLTableInfo aTable = sqlInfo.tableInfos.getFirst();
		while (aTable != null) {
			String aField = aTable.fieldNames.getFirst();
			while (aField != null) {
				allFields.insertIgnoreCase(aField);
				aField = aTable.fieldNames.getNext();
			}
			aTable = sqlInfo.tableInfos.getNext();
		}
		allFields.remove("*");

		aTable = sqlInfo.tableInfos.getFirst();
		while (aTable != null) {
			StringList candidate = new StringList();

			SQLTableInfo definitionTable = allTableInfos.findTable(aTable.tableName);
			if (definitionTable != null) {
				String aField = aTable.fieldNames.getFirst();
				while (aField != null) {
					if (definitionTable.fieldExistsIgnoreCase(aField) == true) {
						candidate.insertIgnoreCase(aField);
						allFields.remove(aField);
					}
					aField = aTable.fieldNames.getNext();
				}
				boolean starFlag = aTable.fieldNames.inList("*");
				aTable.fieldNames.clear();
				if (starFlag) {
					aTable.fieldNames.insert("*");
				}
				String aName = candidate.getFirst();
				while(aName != null) {
					aTable.fieldNames.insertIgnoreCase(aName);
					aName = candidate.getNext();
				}
			} else {
			// 에러 경우: 아마도 이런 경우는 없어야 함
				String aField = aTable.fieldNames.getFirst();
				while (aField != null) {
					allFields.remove(aField);
					aField = aTable.fieldNames.getNext();
				}				
			}

			aTable = sqlInfo.tableInfos.getNext();
		}

		if (allFields.nOfList() > 0) {
			aTable = sqlInfo.tableInfos.getFirst();
			// 이 경우는 정보가 부족해서 무조건 첫번째 테이블의 필드 이름으로 가정함
			String aName = allFields.getFirst();
			while(aName != null) {
				aTable.fieldNames.insertIgnoreCase(aName);
				aName = allFields.getNext();
			}
		}
	}
	/** 파스트리 노드로 부터 인자 타입들의 리스트를 구성한다.
	 */
	public void makeArgTypes(ParseTreeNode2 args) {
		argsString = "("+args.fullString+")";
		ParseTreeNode2 anArg = args;
		if (args.value.length() > 0) {
			while(anArg != null) {
				if (anArg.type.length() > 0) {
					argTypes.addTail(new String(anArg.type));
				} else {
					argTypes.addTail(new String("Object"));
				}
				anArg = anArg.nextArg;
			}
		}
	}
	/** full string을 시퀀스 다이어그램에서 필요한 양식으로 변환하는 함수이다.
	 */
	private String getMessageString() {
		String beginString = new String(functionName) + "(";
		int index = fullString.indexOf(beginString);
		if (index < 0)
		{
			return fullString;
		}
		String returnType = "";
		if (methodNode != null)
		{
			returnType = new String(":") + methodNode.getType();
		}
		return fullString.substring(index)+returnType;
	}
	public int drawCascadeMessages(GraphicController controller,SFDObject fromObject,
							SFDObjectList objectList,StringList calledStringList,int startY,int vGap) {
		int newStartY = startY;

		if (sqlInfo != null) {
			// DB query 경우: 함수 호출이 excuteQuery() 경우

			SQLTableInfo tmpPtr = sqlInfo.tableInfos.getFirst();
			if (tmpPtr != null) {
				String tableName = tmpPtr.tableName;
				String fullName = new String(tableName) + ":Database";
				SFDObject toObject = null;
				toObject = objectList.findObject(fullName);
				if (toObject == null) {
					// end object가 현재까지 없는 경우
					// 새로 리스트에 추가
					toObject = DBObjectTemplate.makeDBObjectTemplate(controller,tableName);
					objectList.insert(toObject);
				}
				if (fromObject != null && toObject != null) {
					String messageName = new String(sqlInfo.queryFullString);

					newStartY = newStartY + vGap;
					Message.makeNewMessage(controller,fromObject,toObject,messageName,newStartY,vGap);
					return newStartY;
				}
			}
		}

		if (receiverName.length() == 0) {
			receiverName = new String("static");
		}

		String fullName = new String(receiverName) + ":" + receiverType;
		SFDObject toObject = null;
		if (receiverName.equals("this") == false && receiverName.equals("super") == false &&
			receiverType.equals("UnknownClass") == false) {
				toObject = objectList.findObject(fullName);
				if (toObject == null) {
					// end object가 현재까지 없는 경우
					// 새로 리스트에 추가
					toObject = ObjectTemplate.makeObjectTemplate(controller,receiverName,receiverType);
					objectList.insert(toObject);
				}
		}
		if (fromObject != null && toObject != null) {
			String messageName = new String(functionName) + argsString;

			if (calledStringList.inList(messageName) == false) {
				calledStringList.insert(messageName);
				newStartY = newStartY + vGap;
				Message.makeNewMessage(controller,fromObject,toObject,messageName,newStartY,vGap);
			}

		}

		if (thisNode != methodNode) {
			if (methodNode != null && toObject != null) {
				newStartY = methodNode.drawCascadeMessages(controller,toObject,objectList,calledStringList,newStartY,vGap);
			}
		}
		return newStartY;
	}

	/** 테스트 용 함수
	public void printCallGraph(FileWriter writer,String senderClass,String senderObject,int level) {
try
{
		for (int i=0;i<level;i++) writer.write("  ");
		writer.write("["+senderObject+":"+senderClass+"]--->"+functionName+argsString+"--->["+receiverName+":"+receiverType+"]\r\n");
		if (thisNode == methodNode) {
			// recursive call
			return;
		}
		if (methodNode != null)
		{
			methodNode.printCallGraph(writer,receiverType,receiverName);
		}
}
catch (IOException e)
{
}
	}
	 */
};