package ash.reverse.uml;

import java.util.Map;
import java.awt.Rectangle;

/**
 * UMLクラス図の関係情報を記録する。
 */
class Relationship implements UMLConst {
	private String type;		// 関連の型（UMLフォーマットのタグ）
	protected int source;		// 関係のソース
	protected int target;		// 関係のターゲット
	private String label;		// 関係のラベル

	Relationship(String type, int source, int target, String label) {
		this.type = type;
		this.source = source;
		this.target = target;
		this.label = label;
	}

	String linkID() { return "" + source + "." + target; }

	/**
	 * UMLクラス図フォーマットでの関係情報の文字列表記を返す。
	 * @return 関係情報の文字列表記
	 */
	String umlFormat() {
		return type +SEP+ source +SEP+ target +SEP+ label;
	}
}

/**
 * UMLクラス図の内部クラスの内包関係を記録する。
 */
class InnerRel extends Relationship {
	InnerRel(int source, int target, String label) {
		super(INNER, source, target, label);
	}
	@Override String umlFormat() {		// 暫定処理★
		return super.umlFormat() + RELPARAMS;
	}
}

/**
 * UMLクラス図の拡張関係を記録する。
 */
class Extends extends Relationship {
	Extends(int source, int target, String label) {
		super(EXTENDS, source, target, label);
	}
	
	@Override String umlFormat() {		// 暫定処理★
		return super.umlFormat() + RELPARAMS;
	}
}

/**
 * UMLクラス図の依存関係を記録する。
 */
class Depends extends Relationship {
	int count = 0;
	int ncount = 0;
	int bcount = 0;
	int pcount = 0;
	int rcount = 0;
	Depends(int source, int target, String label) {
		super(DEPENDS, source, target, label);
	}
	Depends(int source, int target, Stereotype tag) {
		super(DEPENDS, source, target, tag.label);
		count(tag);
	}
	void count(Stereotype tag) {
		switch(tag) {
		case NEW: ncount++; break;
		case BODY: bcount++; break;
		case PARAM: pcount++; break;
		case RETURN: rcount++; break;
		}
		count++;
	}
	@Override String umlFormat() {		// 暫定処理★
		return super.umlFormat() + RELPARAMS;
	}
}

/**
 * UMLクラス図の関連を記録する。
 */
class Assoc extends Relationship {
	private String multiplicity_s;		// ソースの多重度
	private String multiplicity_t;		// ターゲットの多重度
	private boolean navigability_s;		// ソースの誘導可能性
	private boolean navigability_t;		// ターゲットの誘導可能性
	private String role_s;				// ソースの役割名
	private String role_t;				// ターゲットの役割名
	private ClassNode classNode;		// ソースとターゲットが同じ場合のノード

	Assoc(int source, int target, String label) {
		super(ASSOCIATION, source, target, label);
	}

	/**
	 * ソースのプロパティを設定する。
	 * @param multiplicity 多重度
	 * @param navigability 誘導可能性
	 * @param role 役割名
	 */
	void setSource(String multiplicity, boolean navigability, String role) {
		this.multiplicity_s = multiplicity;
		this.navigability_s  = navigability;
		this.role_s  = role;
	}

	/**
	 * ターゲットのプロパティを設定する。
	 * @param multiplicity 多重度
	 * @param navigability 誘導可能性
	 * @param role 役割名
	 */
	void setTarget(String multiplicity, boolean navigability, String role) {
		this.multiplicity_t = multiplicity;
		this.navigability_t = navigability;
		this.role_t = role;
	}

	/**
	 * 再帰的な関連だったらクラスノードを設定する。
	 * @param idMap ノードIDとクラスノードのマップ
	 */
	public void setRecursiveNode(Map<Integer,ClassNode> idMap) {
		if(source == target) classNode = idMap.get(source);
	}
	
	/**
	 * UMLクラス図フォーマットでの関連情報の文字列表記を返す。
	 * @return 関連情報の文字列表記
	 */
	@Override String umlFormat() {
		return super.umlFormat() +
			SEP + multiplicity_s + SEP + multiplicity_t +
			SEP + navigability_s + SEP + navigability_t + 
			SEP + role_s + SEP + role_t + recursiveArc();
	}
	private String recursiveArc() {
		if(classNode == null) return "";
		Rectangle b = classNode.bounds();
		int x1 = b.x + b.width;
		int x0 = x1 - 2 * UNIT;
		int x2 = x1 + 2 * UNIT;
		int y1 = b.y;
		int y0 = y1 - 2 * UNIT;
		int y2 = y1 + 2 * UNIT;
		return SEP + "FREE_LINE" + SEP + 5 +
			":" + x0 + ":" + y1 + ":" + x0 + ":" + y0 + ":" + x2 + ":" + y0 + 
			":" + x2 + ":" + y2 + ":" + x1 + ":" + y2;
	}
}
