package pbl2011.model;

import java.awt.Point;

import pbl2011.common.CommonConst;

/**
 * 関連
 * <p>
 *
 * @author 10745104 Y.Ishii
 *
 */
public class AssociationArc implements CommonConst, Cloneable {
	public AssociationArc(String line) {
		String[] tokens = line.split(DELIMITER);

		int i = 1;
		classIdSource = Integer.parseInt(tokens[i++]);
		classIdTarget = Integer.parseInt(tokens[i++]);

		try {
			assocId = Integer.parseInt(tokens[i++]);
		} catch (NumberFormatException e){
			assocId = -1;
		}
		multiplSource = tokens[i++];
		multiplTarget = tokens[i++];
		naviSource = Boolean.valueOf(tokens[i++]);
		naviTarget = Boolean.valueOf(tokens[i++]);
		roleSource = tokens[i++];
		roleTarget = tokens[i++];
		kind = AssocType.aliasOf(tokens[0]);
		try {
			lineStyle = AssocLineType.valueOf(tokens[i++]);
		} catch (ArrayIndexOutOfBoundsException e) {
			lineStyle = AssocLineType.STRAIGHT_LINE;
		}
		try {
			pointList = editPointList(tokens[i++]);
		} catch (ArrayIndexOutOfBoundsException e) {
			pointList = null;
		}
	}

	public AssociationArc(int id, int source, int target, AssocType kind) {
		delFlag = false;
		classIdSource = source;
		classIdTarget = target;
		assocId = id;
		multiplSource = "null";
		multiplTarget = "null";
		naviSource = false;
		naviTarget = true;
		roleSource = "null";
		roleTarget = "null";
		this.kind = kind;
		lineStyle = AssocLineType.STRAIGHT_LINE;
		pointList = null;
		undoredoModel = new UndoRedoModel();

	}

	public AssociationArc(AssociationArc clone) {
		delFlag = clone.delFlag;
		classIdSource = clone.classIdSource;
		classIdTarget = clone.classIdTarget;
		assocId = clone.assocId;
		multiplSource = clone.multiplSource;
		multiplTarget = clone.multiplTarget;
		naviSource = clone.naviSource;
		naviTarget = clone.naviTarget;
		roleSource = clone.roleSource;
		roleTarget = clone.roleTarget;
		kind = clone.kind;
		lineStyle = clone.lineStyle;
		String str = pointListToString(clone.pointList);
		pointList = editPointList(str);
		undoredoModel = clone.undoredoModel;

	}

	/** 削除フラグ */
	public boolean delFlag;

	/** クラスId Source */
	public int classIdSource;

	/** クラスId Target */
	public int classIdTarget;

	/** 関連ID */
	public int assocId;

	/** 多重度Source */
	public String multiplSource;

	/** 多重度Target */
	public String multiplTarget;

	/** 誘導可能性Source */
	public boolean naviSource;

	/** 誘導可能性Target */
	public boolean naviTarget;

	/** ロール名Source */
	public String roleSource;

	/** ロール名Target */
	public String roleTarget;

	/** 種別 */
	private AssocType kind;

	/** 線のスタイル */
	public AssocLineType lineStyle;

	/** 自由な線のポイントリスト */
	public Point[] pointList;
	
	/** UndoRedoモデル **/
	public UndoRedoModel undoredoModel = new UndoRedoModel();

	public String toString() {
		return kind + DELIMITER + classIdSource + DELIMITER + classIdTarget
				+ DELIMITER + assocId + DELIMITER
				+ multiplSource + DELIMITER + multiplTarget + DELIMITER
				+ naviSource + DELIMITER + naviTarget + DELIMITER + roleSource
				+ DELIMITER + roleTarget + DELIMITER + lineStyle
//				+ DELIMITER + pointListToString(pointList);
				+ DELIMITER + pointListToString(pointList)+ DELIMITER+delFlag;
	}

	// ポイントリストをポイントの配列に変換
	private Point[] editPointList(String str) {
		if ("null".equals(str)) {
			return null;
		}
		String[] tokens = str.split(DELIMITER_P);
		int n = Integer.parseInt(tokens[0]);
		Point[] list = new Point[n];
		int no = 1;
		for (int i = 0; i < n; i++) {
			list[i] = new Point(Integer.parseInt(tokens[no++]), Integer
					.parseInt(tokens[no++]));
		}
		return list;
	}

	// ポイントリストを文字列に変換
	private String pointListToString(Point[] pointList) {
		if (pointList == null) {
			return "null";
		}
		StringBuffer sb = new StringBuffer(String.valueOf(pointList.length));
		for (int i = 0; i < pointList.length; i++) {
			sb.append(DELIMITER_P).append(pointList[i].x);
			sb.append(DELIMITER_P).append(pointList[i].y);
		}
		return sb.toString();

	}

	public void changeT(String role, Boolean navi, String multi) {
		roleTarget = role;
		naviTarget = navi;
		multiplTarget = multi;
	}

	public void changeS(String role, Boolean navi, String multi) {
		roleSource = role;
		naviSource = navi;
		multiplSource = multi;
	}

	// ポイントを追加
	public void addPoint(int poz, Point p) {
		Point[] newPoint = new Point[pointList.length +1];
		for(int i = 0; i < newPoint.length; i++) {
			if ( i == poz ) {
				newPoint[i++] = p;
			}
			if (i < poz) {
				newPoint[i] = pointList[i];
			} else {
				newPoint[i] = pointList[i-1];
			}
		}
		pointList = newPoint;
	}

	// ポイントを削除
	public void delPoint(int poz) {
		Point[] newPoint = new Point[pointList.length -1];

		// ポイントが2個以下になる場合は直線に変更
		if (newPoint.length < 2) {
			lineStyle = AssocLineType.STRAIGHT_LINE;
			pointList = null;
			return;
		}
		for(int i = 0; i < pointList.length; i++) {
			if (i < poz) {
				newPoint[i] = pointList[i];
			} else if (i > poz)  {
				newPoint[i-1] = pointList[i];
			}
		}
		pointList = newPoint;
	}
	
	public void clearUndoRedoModel() {
		this.undoredoModel = new UndoRedoModel();
	}

	public AssociationArc clone() {
        try {
            return new AssociationArc((AssociationArc)super.clone());
        } catch(CloneNotSupportedException e) {
            throw new InternalError();
        }
    }
	
	public boolean equals(Object o) {
		
		if (o == null) {
			return false;
		}
		AssociationArc aa = (AssociationArc)o;
		
		if (this.delFlag != aa.delFlag) {
			return false;
		}
		
		if (this.classIdSource != aa.classIdSource) {
			return false;
		}
		
		if (this.classIdTarget != aa.classIdTarget){
			return false;
		}
		
		if (this.assocId != aa.assocId) {
			return false;
		}
		
		if (!this.multiplSource.equals(aa.multiplSource)) {
			return false;
		}
		
		if (!this.multiplTarget.equals(aa.multiplTarget)){
			return false;
		}
		
		if (this.naviSource != aa.naviSource) {
			return false;
		}
		
		if (!this.roleSource.equals(aa.roleSource)) {
			return false;
		}
		
		if (!this.roleTarget.equals(aa.roleTarget)) {
			return false;
		}
		
		if (!this.kind.equals(aa.kind)) {
			return false;
		}
		
		if (!this.lineStyle.equals(aa.lineStyle)) {
			return false;
		}

		if (this.pointList == null) {
			if (aa.pointList == null) {
				return true;
			}
			return false;
		} else if (!pointListToString(this.pointList).
				equals(pointListToString(aa.pointList))) {
			return false;
		}
		
		return true;
	}
	
	public AssocType getKind() {
		return kind;
	}
}
