package parser.ServletParser.library;

import java.io.*;
/** 이 클래스는 컨테이너 역할을 하는 리스트 클래스로서 관계 스트링들을
 * 관리하는 클래스이다.
 */
public final
	class StrRelation extends List {
	/** 생성자이다.
	 */
	public StrRelation() {
		super();
	}
	/** 이 리스트의 마지막에 새로운 객체를 insert 하는 함수이다.
	 * 리스트에 이미 객체가 있으면 insert 하지 않는다.
	 */
	public void insert(StrRelItem ptr) {
		if (inList(ptr)) return;
		_insert((Object)ptr,0);
	}
	/** 이 리스트에 스트링 관계 객체가 존재하는지 확인하는 함수이다.
	 */
	public boolean inList(StrRelItem item) {
		StrRelItem anItem = getFirst();
		while (anItem != null) {
			if (anItem.equals(item)) {
				return true;
			}
			anItem = getNext();
		}
		return false;
	}
	/** 이 리스트에 스트링 관계 객체의 위치를 찾는 함수이다.
	 */
	public StrRelItem find(StrRelItem item) {
		StrRelItem anItem = getFirst();
		while (anItem != null) {
			if (anItem.equals(item)) {
				return anItem;
			}
			anItem = getNext();
		}
		return null;
	}
	/** 이 리스트에서 Object 클래스가 언급된 경우를 삭제한 리스트를 생성하는 함수이다.
	 */
	public StrRelation removeObjectClass() {
		StrRelation newRelation = new StrRelation();
		StrRelItem anItem = getFirst();
		while (anItem != null) {
			if (anItem.first().equals("Object") == false &&
				anItem.second().equals("Object") == false) {
				newRelation.insert(anItem);
			}
			anItem = getNext();
		}
		return newRelation;
	}
	/** 이 리스트에서 너무 많이 reference된 클래스 튜플들을 삭제한 리스트를 생성하는 함수이다.
	 */
	public StrRelation removeCongestion(int max) {
		StrWithObjList firstList = new StrWithObjList();
		StrRelItem anItem = getFirst();
		while (anItem != null) {
			String firstName = anItem.first();
			boolean found = false;
			StrWithObj aRecord = firstList.getFirst();
			while (aRecord != null) {
				if (firstName.compareTo(aRecord.getName()) == 0) {
					aRecord.count++;
					found = true;
					break;
				}
				aRecord = firstList.getNext();
			}
			if (found == false) {
				firstList.insert(firstName);
			}
			anItem = getNext();
		}		

		StrWithObjList secondList = new StrWithObjList();
		anItem = getFirst();
		while (anItem != null) {
			String secondName = anItem.second();
			boolean found = false;
			StrWithObj aRecord = secondList.getFirst();
			while (aRecord != null) {
				if (secondName.compareTo(aRecord.getName()) == 0) {
					aRecord.count++;
					found = true;
					break;
				}
				aRecord = secondList.getNext();
			}
			if (found == false) {
				secondList.insert(secondName);
			}
			anItem = getNext();
		}		
	
		StringList listToRemoveFirst = new StringList();
		StrWithObj aRecord = firstList.getFirst();
		while(aRecord != null) {
			if (aRecord.count >= max) {
				listToRemoveFirst.insert(aRecord.getName());
			}
			aRecord = firstList.getNext();
		}

		StringList listToRemoveSecond = new StringList();
		aRecord = secondList.getFirst();
		while(aRecord != null) {
			if (aRecord.count >= max) {
				listToRemoveSecond.insert(aRecord.getName());
			}
			aRecord = secondList.getNext();
		}
		
		StrRelation refinedList = new StrRelation();
		anItem = getFirst();
		while (anItem != null) {
			String firstName = anItem.first();
			String secondName = anItem.second();
			if (listToRemoveFirst.inList(firstName) == false &&
				listToRemoveSecond.inList(secondName) == false) {
				refinedList.insert(new StrRelItem(firstName,secondName));
			}
			anItem = getNext();
		}		
		return refinedList;
	}
	/** 이 리스트로 부터 객체를 삭제하는 함수이다.
	 */
	public void remove(StrRelItem ptr) {
		super._remove((Object)ptr,0);
	}
	/** 이 리스트를 비우는 함수이다.
	 */
	public void clear() {
		super._clear();
	}
	/** 리스트의 객체들을 traverse 할 때 맨 첫번째 객체를 찾아오는 함수이다.
	 * 만약 리스트가 비어있게되면 null 값을 리턴한다.
	 */
	public StrRelItem getFirst() {
		return (StrRelItem)super._getFirst();
	}
	/** 리스트의 객체들을 반대 방향으로 traverse 하기위해 맨 마지막 객체를 찾아오는 함수이다.
	 * 만약 리스트가 비어있게되면 null 값을 리턴한다.
	 */
	public StrRelItem getLast() {
		return (StrRelItem)super._getLast();
	}
	/** 리스트의 객체들을 traverse 할 때 다음 객체를 찾아오는 함수이다.
	 * 만약 리스트의 끝에 도달하면 null 값을 리턴한다.
	 */
	public StrRelItem getNext() {
		return (StrRelItem)super._getNext();
	}
	/** 리스트의 객체들을 반대 방향으로 traverse 할 때 다음 객체를 찾아오는 함수이다.
	 * 만약 리스트의 앞에 도달하면 null 값을 리턴한다.
	 */
	public StrRelItem getPrevious() {
		return (StrRelItem)super._getPrevious();
	}
}
