/*
 * Copyright (c) 2005- Shinji Kashihara.
 * All rights reserved. This program are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at epl-v10.html.
 */
package jp.sourceforge.mergedoc.pleiades.runtime.advice;

import jp.sourceforge.mergedoc.org.apache.commons.lang.StringUtils;
import jp.sourceforge.mergedoc.org.apache.commons.lang.builder.EqualsBuilder;
import jp.sourceforge.mergedoc.org.apache.commons.lang.builder.HashCodeBuilder;
import jp.sourceforge.mergedoc.org.apache.commons.lang.builder.ToStringBuilder;
import jp.sourceforge.mergedoc.org.apache.commons.lang.builder.ToStringStyle;

/**
 * ジョイント・ポイントです。
 * <p>
 * @author cypher256
 */
public class JointPoint {

	/** 編集ポイント enum */
	public enum EditPoint {
		/** 呼び出し */
		CALL,
		/** 実行 */
		EXECUTION
	}

	/** 編集ポイント */
	private EditPoint editPoint;

	/** クラス名 */
	private String className;

	/** メソッド名 */
	private String methodName;

	/** メソッド記述子 */
	private String descriptor;

	/**
	 * ジョイント・ポイントを構築します。
	 */
	public JointPoint() {
	}

	/**
	 * ジョイント・ポイントを構築します。
	 * @param jointPoint ジョイント・ポイント
	 */
	public JointPoint(JointPoint jointPoint) {
		this(
			jointPoint.editPoint,
			jointPoint.className,
			jointPoint.methodName,
			jointPoint.descriptor);
	}

	/**
	 * ジョイント・ポイントを構築します。
	 * <p>
	 * @param editPoint 編集ポイント
	 * @param className クラス名
	 * @param methodName メソッド名
	 * @param descriptor メソッド記述子
	 */
	public JointPoint(
			EditPoint editPoint,
			String className,
			String methodName,
			String descriptor
			) {

		this.editPoint = editPoint;
		this.className = className;
		this.methodName = methodName;
		this.descriptor = descriptor;
	}

	/**
	 * 編集ポイントを取得します。
	 * <p>
	 * @return 編集ポイント
	 */
	public EditPoint getEditPoint() {
		return editPoint;
	}

	/**
	 * 編集ポイントをセットします。
	 * <p>
	 * @param editPoint 編集ポイント
	 */
	public void setEditPoint(EditPoint editPoint) {
		this.editPoint = editPoint;
	}

	/**
	 * 編集ポイント（文字列）をセットします。
	 * <p>
	 * @param editPoint 編集ポイント（文字列）
	 */
	public void setEditPoint(String editPoint) {
		try {
			this.editPoint = EditPoint.valueOf(editPoint.toUpperCase());
		} catch (RuntimeException e) {
			throw new IllegalArgumentException(
				editPoint + " is illegal editPoint. " +
				StringUtils.join(EditPoint.values(), " or "));
		}
	}

	/**
	 * クラス名を取得します。
	 * <p>
	 * @return クラス名
	 */
	public String getClassName() {
		return className;
	}

	/**
	 * クラス名をセットします。
	 * <p>
	 * @param className クラス名
	 */
	public void setClassName(String className) {
		this.className = className;
	}

	/**
	 * メソッド名を取得します。
	 * <p>
	 * @return メソッド名
	 */
	public String getMethodName() {
		return methodName;
	}

	/**
	 * メソッド名をセットします。
	 * コンストラクターの場合は this または super のどちらかです。
	 * <p>
	 * @param methodName メソッド名
	 */
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}

	/**
	 * メソッド記述子を取得します。
	 * <p>
	 * @return メソッド記述子
	 */
	public String getDescriptor() {
		return descriptor;
	}

	/**
	 * メソッド記述子をセットします。
	 * <p>
	 * @param descriptor メソッド記述子
	 */
	public void setDescriptor(String descriptor) {
		this.descriptor = descriptor;
	}

	/**
	 * ハッシュコードを取得します。
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder(-1398227719, -1807208065)
			.append(this.editPoint)
			.append(this.className)
			.append(this.methodName)
			.append(this.descriptor)
			.toHashCode();
	}

	/**
	 * このオブジェクトと他のオブジェクトを比較します。
	 */
	@Override
	public boolean equals(Object object) {
		if (!(object instanceof JointPoint)) {
			return false;
		}
		JointPoint rhs = (JointPoint) object;
		return new EqualsBuilder()
			.append(this.editPoint, rhs.editPoint)
			.append(this.className, rhs.className)
			.append(this.methodName, rhs.methodName)
			.append(this.descriptor, rhs.descriptor)
			.isEquals();
	}

	/**
	 * このオブジェクトの文字列表現を取得します。
	 */
	@Override
	public String toString() {
		return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
			.append("editPoint", String.valueOf(this.editPoint).toLowerCase())
			.append("className", this.className)
			.append("methodName", this.methodName)
			.append("descriptor", this.descriptor)
			.toString();
	}
}
