package jp.riken.brain.ni.samuraigraph.figure.java2d;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGICopiable;
import jp.riken.brain.ni.samuraigraph.base.SGIDisposable;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxis;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxisBreak;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGraph;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGrid;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementLegend;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementShape;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementSignificantDifference;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementString;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementTimingLine;
import jp.riken.brain.ni.samuraigraph.base.SGIMovable;
import jp.riken.brain.ni.samuraigraph.base.SGINode;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGIUndoable;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGPropertyDialog;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.base.SGUndoManager;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;
import jp.riken.brain.ni.samuraigraph.figure.SGISignificantDifferenceConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGIStringConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSignificantDifference.SigDiffProperties;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * A class managing significant difference symbols.
 */
public class SGFigureElementSignificantDifference extends SGFigureElement
		implements SGIFigureElementSignificantDifference,
		SGISignificantDifferenceConstants, SGIStringConstants, CaretListener,
		ActionListener {

	/**
	 * 
	 */
	private SGIFigureElementAxis mAxisElement = null;

	/**
	 * 
	 */
	private JTextField mEditField = null;

	/**
	 * A symbol which the user is editing the text.
	 */
	private SigDiffSymbol mEditingSymbol = null;

	/**
	 * 
	 */
	private SGSignificantDifferenceDialog mDialog = null;

	/**
	 * 
	 */
	public SGFigureElementSignificantDifference() {
		super();
		this.initEditField();
	}

	/**
	 * 
	 */
	public void dispose() {
		super.dispose();
		this.mDialog.dispose();
		this.mDialog = null;
		this.mAxisElement = null;
		this.mEditField = null;
	}

	/**
	 * 
	 */
	private boolean createSignificanceDialog() {

		final SGSignificantDifferenceDialog dg = new SGSignificantDifferenceDialog(
				this.mDialogOwner, true);

		this.mDialog = dg;

		return true;
	}

	/**
	 * zoom
	 */
	public boolean zoom(final float ratio) {
		// hide the text field
		if (this.terminateEditField() == false) {
			return false;
		}

		super.zoom(ratio);

		this.onZoomed(ratio);

		return true;

	}

	/**
	 * 
	 * @return
	 */
	public boolean setDialogOwner(final Frame frame) {
		super.setDialogOwner(frame);
		this.createSignificanceDialog();
		return true;
	}

	/**
	 * 
	 */
	public boolean addSignificantDifferenceSymbol(final SGAxis xAxis,
			final SGAxis yAxis, final int x, final int y) {
		SigDiffSymbol sd = new SigDiffSymbol();
		sd.zoom(this.mMagnification);

		// set axes
		sd.mXAxis = xAxis;
		sd.mYAxis = yAxis;

		// set the location
		sd.setLocation(x, y);

		// create drawing elements
		sd.createDrawingElement();

		// set axis values
		sd.setAxisValuesWithShape();

		//
		this.addToList(sd);

		//
		this.setChanged(true);

		// initialize history
		sd.initPropertiesHistory();

		this.notifyToRoot();

		return true;
	}

	/**
	 * 
	 */
	public boolean addSignificantDifferenceSymbol(final int x, final int y) {
		if (this.getGraphRect().contains(x, y) == false) {
			return false;
		}

		SGAxis xAxis = this.mAxisElement
				.getAxis(DEFAULT_SIGDIFF_HORIZONTAL_AXIS);
		SGAxis yAxis = this.mAxisElement
				.getAxis(DEFAULT_SIGDIFF_PERPENDICULAR_AXIS);

		return this.addSignificantDifferenceSymbol(xAxis, yAxis, x, y);
	}

	/**
	 * 
	 */
	private boolean onZoomed(final float ratio) {
		List list = this.mChildList;
		for (int ii = 0; ii < list.size(); ii++) {
			final SigDiffSymbol sd = (SigDiffSymbol) list.get(ii);
			sd.zoom(ratio);
		}

		return true;
	}

	/**
	 * 
	 * @param element
	 */
	public void setAxisElement(final SGIFigureElementAxis element) {
		this.mAxisElement = element;
	}

	/**
	 * synchronize
	 */
	public boolean synchronize(final SGIFigureElement element, final String msg) {

		boolean flag = true;
		if (element instanceof SGIFigureElementGraph) {

		} else if (element instanceof SGIFigureElementString) {

		} else if (element instanceof SGIFigureElementLegend) {

		} else if (element instanceof SGIFigureElementAxis) {
			flag = this.synchronizeToAxisElement(
					(SGIFigureElementAxis) element, msg);
		} else if (element instanceof SGIFigureElementAxisBreak) {

		} else if (element instanceof SGIFigureElementSignificantDifference) {

		} else if (element instanceof SGIFigureElementTimingLine) {

		} else if (element instanceof SGIFigureElementGrid) {

		} else if (element instanceof SGIFigureElementShape) {

		} else {
			flag = element.synchronizeArgument(this, msg);
		}

		return flag;
	}

	private boolean synchronizeToAxisElement(SGIFigureElementAxis element,
			String msg) {
		ArrayList list = this.getVisibleChildList();
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			el.setShapeWithAxesValues();
		}
		return true;
	}

	/**
	 * Synchronize the element given by the argument.
	 * 
	 * @param element
	 *            An object to be synchronized.
	 */
	public boolean synchronizeArgument(final SGIFigureElement element,
			final String msg) {
		// this shouldn't happen
		throw new Error();
	}

	/**
	 * 
	 */
	public SGProperties getProperties() {
		SGProperties p = new SigDiffElementProperties();
		if (this.getProperties(p) == false) {
			return null;
		}
		return p;
	}

	/**
	 * 
	 */
	public String getTagName() {
		return TAG_NAME_SIGNIFICANT_DIFFERENCE;
	}

	/**
	 * 
	 */
	public boolean writeProperty(Element el) {
		return true;
	}

	/**
	 * 
	 */
	public boolean readProperty(final Element element) {
		NodeList nList = element
				.getElementsByTagName(SGISignificantDifferenceConstants.TAG_NAME_SIGDIFF_SYMBOL);
		for (int ii = 0; ii < nList.getLength(); ii++) {
			Node node = nList.item(ii);
			if (node instanceof Element) {
				Element el = (Element) node;
				SigDiffSymbol sd = new SigDiffSymbol();
				if (sd.readProperty(el) == false) {
					return false;
				}
				sd.initPropertiesHistory();
				this.addToList(sd);
			}
		}

		return true;
	}

	/**
	 * 
	 */
	public void actionPerformed(ActionEvent e) {
		final Object source = e.getSource();
		// final String command = e.getActionCommand();

		if (source.equals(this.mEditField)) {
			this.terminateEditField();
		}

	}

	/**
	 * 
	 */
	public boolean setGraphRect(final float x, final float y,
			final float width, final float height) {
		if (super.setGraphRect(x, y, width, height) == false) {
			return false;
		}

		if (this.terminateEditField() == false) {
			return false;
		}

		List list = this.mChildList;
		for (int ii = 0; ii < list.size(); ii++) {
			final SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			el.setShapeWithAxesValues();
		}

		return true;
	}

	/**
	 * 
	 */
	public boolean getMarginAroundGraphRect(SGTuple2f topAndBottom,
			SGTuple2f leftAndRight) {

		if (super.getMarginAroundGraphRect(topAndBottom, leftAndRight) == false) {
			return false;
		}

		ArrayList sList = this.getVisibleChildList();
		ArrayList rectList = new ArrayList();
		for (int ii = 0; ii < sList.size(); ii++) {
			SigDiffSymbol el = (SigDiffSymbol) sList.get(ii);
			Rectangle2D rect = el.getElementBounds();
			rectList.add(rect);
		}
		if (rectList.size() == 0) {
			return true;
		}

		// create combined rectangle
		Rectangle2D uniRect = SGUtility.createUnion(rectList);

		// calculate width from combined rectangle
		final float top = this.mGraphRectY - (float) uniRect.getY();
		final float bottom = -(this.mGraphRectY + this.mGraphRectHeight)
				+ (float) (uniRect.getY() + uniRect.getHeight());
		final float left = this.mGraphRectX - (float) uniRect.getX();
		final float right = -(this.mGraphRectX + this.mGraphRectWidth)
				+ (float) (uniRect.getX() + uniRect.getWidth());

		// set arguments
		topAndBottom.x += top;
		topAndBottom.y += bottom;
		leftAndRight.x += left;
		leftAndRight.y += right;

		return true;
	}

	/**
	 * 
	 */
	public void paintGraphics(Graphics g, boolean clip) {
		final Graphics2D g2d = (Graphics2D) g;

		// draw significant difference symbols
		ArrayList list = this.getVisibleChildList();
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			if (el.isValid() == false) {
				continue;
			}
			el.paintElement(g2d);
		}

		// draw symbols around all objects
		if (this.mSymbolsVisibleFlagAroundAllObjects) {
			for (int ii = 0; ii < list.size(); ii++) {
				SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
				if (el.isValid() == false) {
					continue;
				}
				ArrayList pList = el.getAnchorPointList();
				SGUtilityForFigureElementJava2D.drawAnchorAsChildObject(pList,
						g2d);
			}
		}

		// draw symbols around focused objects
		if (this.mSymbolsVisibleFlagAroundFocusedObjects) {
			ArrayList fList = this.getFocusedObjectsList();
			for (int ii = 0; ii < fList.size(); ii++) {
				SigDiffSymbol el = (SigDiffSymbol) fList.get(ii);
				if (el.isValid() == false) {
					continue;
				}
				ArrayList pList = el.getAnchorPointList();
				SGUtilityForFigureElementJava2D.drawAnchorAsFocusedObject(
						pList, g2d);
			}
		}

	}

	/**
	 * 
	 */
	public void caretUpdate(final CaretEvent e) {
		final String str = this.mEditField.getText();

		if (this.mEditingSymbol != null) {
			final Font font = new Font(this.mEditingSymbol.getFontName(),
					this.mEditingSymbol.getFontStyle(),
					(int) (this.mEditingSymbol.getFontSize() * this
							.getMagnification()));
			final Rectangle2D stringRect = font.getStringBounds(str,
					new FontRenderContext(null, false, false));

			final double width = stringRect.getWidth();
			if (width > this.mEditField.getWidth()) {
				this.mEditField.setSize((int) (stringRect.getWidth() + this
						.getMagnification()
						* this.mEditingSymbol.getFontSize()), this.mEditField
						.getHeight());
			}
		}
	}

	/**
	 * 
	 * @param e
	 */
	public boolean onDrawingElement(final int x, final int y) {

		// significant difference symbols
		ArrayList list = this.getVisibleChildList();
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol sd = (SigDiffSymbol) list.get(ii);
			if (sd.isValid() == false) {
				continue;
			}
			if (sd.contains(x, y)) {
				if (sd.isSelected()) {
					sd.mMouseLocation = sd.getMouseLocation(x, y);
					setMouseCursor(sd.getCursor(sd.mMouseLocation));
					return true;
				}
				setMouseCursor(Cursor.HAND_CURSOR);
				return true;
			}
		}

		return false;
	}

	public boolean onKeyPressed(final KeyEvent e) {
		boolean effective = false;
		final int keycode = e.getKeyCode();
		final int mod = e.getModifiersEx();
		final boolean isShiftPressed = ((mod & InputEvent.SHIFT_DOWN_MASK) != 0);
		int dx = 0;
		int dy = 0;
		switch (keycode) {
		case KeyEvent.VK_UP:
			if (isShiftPressed) {
				dy = -1;
			} else {
				dy = -10;
			}
			break;
		case KeyEvent.VK_DOWN:
			if (isShiftPressed) {
				dy = 1;
			} else {
				dy = 10;
			}
			break;
		case KeyEvent.VK_LEFT:
			if (isShiftPressed) {
				dx = -1;
			} else {
				dx = -10;
			}
			break;
		case KeyEvent.VK_RIGHT:
			if (isShiftPressed) {
				dx = 1;
			} else {
				dx = 10;
			}
			break;
		}
		if (dx != 0 || dy != 0) {
			final ArrayList list = this.getVisibleChildList();
			for (int ii = list.size() - 1; ii >= 0; ii--) {
				final SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
				if (el.isSelected()) {
					if (this.setDirectlyBefore(el) == false)
						return false;
					el.translate((float) dx, (float) dy);
					if (this.setDirectlyAfter(el) == false)
						return false;
					effective = true;
				}
			}
		}
		return effective;
	}

	/**
	 * 
	 */
	public boolean onMouseClicked(final MouseEvent e) {
		ArrayList list = this.getVisibleChildList();
		for (int ii = list.size() - 1; ii >= 0; ii--) {
			SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			if (el.isValid() == false) {
				continue;
			}
			if (this.clickDrawingElements(el, e)) {
				return true;
			}
		}

		return false;
	}

	/**
	 * 
	 */
	private boolean clickDrawingElements(final SigDiffSymbol el,
			final MouseEvent e) {
		final int x = e.getX();
		final int y = e.getY();
		final int mod = e.getModifiers();
		final boolean ctrl = (mod & InputEvent.CTRL_MASK) != 0;
		final boolean shift = (mod & InputEvent.SHIFT_MASK) != 0;
		final int cnt = e.getClickCount();

		// clicked on the line elements
		if (el.contains(x, y)) {
			// clicked on the string element
			if (el.getStringElement().contains(x, y)) {
				if (SwingUtilities.isLeftMouseButton(e) & cnt == 1) {
					if (el.isSelected() & !ctrl & !shift) {
						this.mEditingSymbol = el;
						this.showEditField(el);
					} else {
						this.updateFocusedObjectsList(el, e);
					}
				} else if (SwingUtilities.isRightMouseButton(e) & cnt == 1) {
					this.updateFocusedObjectsList(el, e);
					el.getPopupMenu().show(this.getComponent(), x, y);
				}
			} else
			// otherwise
			{
				this.updateFocusedObjectsList(el, e);
				if (SwingUtilities.isLeftMouseButton(e) & cnt == 1) {

				} else if (SwingUtilities.isLeftMouseButton(e) & cnt == 2) {
					this.setPropertiesOfSelectedObjects();
				} else if (SwingUtilities.isRightMouseButton(e) & cnt == 1) {
					el.getPopupMenu().show(this.getComponent(), x, y);
				}
			}

			return true;
		}

		return false;
	}

	/**
	 * 
	 */
	public void translateFocusedObjects(final int dx, final int dy) {
		if (this.terminateEditField() == false) {
			return;
		}

		super.translateFocusedObjects(dx, dy);
	}

	/**
	 * 
	 * @param e
	 */
	public boolean onMousePressed(final MouseEvent e) {

		if (this.terminateEditField() == false) {
			return false;
		}

		// significant difference symbols
		ArrayList list = this.getVisibleChildList();
		for (int ii = list.size() - 1; ii >= 0; ii--) {
			SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			if (el.isValid() == false) {
				continue;
			}
			if (el.pressDrawingElements(e)) {
				this.mPressedPoint = e.getPoint();
				if (el.isSelected()) {
					this.mDraggableFlag = true;
				}
				return true;
			}
		}

		return false;
	}

	/**
	 * 
	 * @param e
	 */
	public boolean onMouseDragged(final MouseEvent e) {

		if (this.mDraggableFlag == false) {
			return false;
		}

		final int dx = e.getX() - this.mPressedPoint.x;
		final int dy = e.getY() - this.mPressedPoint.y;

		ArrayList list = this.getFocusedObjectsList();
		if (list.size() == 1) {
			SigDiffSymbol sd = (SigDiffSymbol) list.get(0);
			if (sd.isValid() == false) {
				return false;
			}
			if (sd.drag(e) == false) {
				return false;
			}

			sd.createDrawingElement();

			if (sd.setAxisValuesWithShape() == false) {
				return false;
			}
			if (sd.setShapeWithAxesValues() == false) {
				return false;
			}

			this.mPressedPoint = e.getPoint();

			return true;

		}
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol sd = (SigDiffSymbol) list.get(ii);

			sd.translate(dx, dy);

			sd.createDrawingElement();

			if (sd.setAxisValuesWithShape() == false) {
				return false;
			}
			if (sd.setShapeWithAxesValues() == false) {
				return false;
			}
		}

		this.mPressedPoint = e.getPoint();

		return true;

	}

	/**
	 * 
	 * @param e
	 */
	public boolean onMouseReleased(final MouseEvent e) {
		this.mDraggableFlag = false;
		return true;
	}

	/**
	 * 
	 * @return
	 */
	public boolean setTemporaryPropertiesOfFocusedObjects() {
		ArrayList list = this.getFocusedObjectsList();
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			el.mTemporaryProperties = el.getProperties();
		}
		return true;
	}

	/**
	 * 
	 * @return
	 */
	public ArrayList getPropertyDialogObserverList() {
		return this.getFocusedObjectsList();
	}

	/**
	 * 
	 * @return
	 */
	public boolean setChangedFocusedObjects() {
		ArrayList list = this.getFocusedObjectsList();
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol el = (SigDiffSymbol) list.get(ii);
			SGProperties temp = el.mTemporaryProperties;
			if (temp != null) {
				SGProperties p = el.getProperties();
				if (p.equals(temp) == false) {
					el.setChanged(true);
				}
			}
		}
		return true;
	}

	/**
	 * 
	 * @return
	 */
	public boolean clearFocusedObjects() {
		if (super.clearFocusedObjects() == false) {
			return false;
		}

		if (this.terminateEditField() == false) {
			return false;
		}

		return true;
	}

	/**
	 * 
	 */
	public String toString() {
		return "SGSignificantDifferenceElement";
	}

	/**
	 * 
	 * @return
	 */
	public String getClassDescription() {
		return "Significant Difference Symbols";
	}

	/**
	 * 
	 */
	private boolean initEditField() {
		this.mEditField = new JTextField(10);
		this.mEditField.setVisible(false);
		this.mEditField.addActionListener(this);
		this.mEditField.addCaretListener(this);

		return true;
	}

	public void setComponent(JComponent com) {
		super.setComponent(com);
		com.add(this.mEditField);
	}

	/**
	 * 
	 */
	private boolean showEditField(final SigDiffSymbol el) {
		SGDrawingElementString2DExtended sElement = (SGDrawingElementString2DExtended) el
				.getStringElement();
		final JTextField tf = this.mEditField;

		final Rectangle2D rect = sElement.getElementBounds();
		final Rectangle2D sRect = sElement.getStringRect();

		final float fontSize = el.getMagnification() * el.getFontSize();

		final int x = (int) (rect.getX() - tf.getInsets().left);
		final int y = (int) (rect.getY() - fontSize / 2.0f);
		final int w = (int) (sRect.getWidth() + fontSize);
		final int h = (int) (sRect.getHeight() + fontSize);

		tf.setLocation(x, y);
		tf.setSize(w, h);
		tf
				.setFont(new Font(el.getFontName(), el.getFontStyle(),
						(int) fontSize));
		tf.setForeground(el.getColor());
		tf.setText(sElement.getString());

		// show the text field
		tf.setVisible(true);
		tf.requestFocus();
		tf.setCaretPosition(0);

		return true;

	}

	/**
	 * 
	 */
	private boolean terminateEditField() {
		if (this.mEditField.isVisible()) {
			return this.commitEdit();
		}

		return true;
	}

	/**
	 * 
	 * @return
	 */
	private boolean hideEditField() {
		this.mEditField.setText("");
		this.mEditField.setVisible(false);
		return true;
	}

	/**
	 * 
	 * @return
	 */
	private boolean commitEdit() {
		if (this.mEditingSymbol == null) {
			return false;
		}

		String before = this.mEditingSymbol.getStringElement().getString();
		String after = this.mEditField.getText();
		if (SGUtilityText.isValidString(after)) {
			this.mEditingSymbol.setText(after);

			if (before.equals(after) == false) {
				this.mEditingSymbol.setChanged(true);
				this.notifyToRoot();
			}

			this.mEditingSymbol.createDrawingElement();
		}

		this.mEditingSymbol = null;
		this.hideEditField();
		this.repaint();

		return true;
	}

	/**
	 * 
	 */
	public boolean getProperties(final SGProperties p) {

		if ((p instanceof SigDiffElementProperties) == false) {
			return false;
		}

		SigDiffElementProperties gp = (SigDiffElementProperties) p;
		gp.visibleSigDiffSymbolList = this.getVisibleChildList();

		return true;

	}

	/**
	 * 
	 */
	public boolean setProperties(final SGProperties p) {
		if ((p instanceof SigDiffElementProperties) == false) {
			return false;
		}

		SigDiffElementProperties gp = (SigDiffElementProperties) p;

		boolean flag = this.setVisibleChildList(gp.visibleSigDiffSymbolList);
		if (!flag) {
			return false;
		}

		return true;

	}

	/**
	 * 
	 */
	public Element createElement(final Document document) {
		Element el = this.createThisElement(document);
		if (el == null) {
			return null;
		}

		ArrayList list = this.getVisibleChildList();
		for (int ii = 0; ii < list.size(); ii++) {
			SigDiffSymbol sd = (SigDiffSymbol) list.get(ii);
			if (sd.isValid() == false) {
				continue;
			}

			Element elSigDiff = sd.createElement(document);
			if (elSigDiff == null) {
				return null;
			}
			el.appendChild(elSigDiff);
		}
		return el;
	}

	/**
	 * 
	 */
	public boolean setMementoBackward() {
		boolean flag = super.setMementoBackward();
		if (!flag) {
			return false;
		}
		this.notifyChangeOnUndo();
		this.clearFocusedObjects();

		return true;
	}

	/**
	 * 
	 */
	public boolean setMementoForward() {
		boolean flag = super.setMementoForward();
		if (!flag) {
			return false;
		}
		this.notifyChangeOnUndo();
		this.clearFocusedObjects();

		return true;
	}

	/**
	 * Create copies of the focused objects.
	 * 
	 * @return
	 */
	public boolean duplicateFocusedObjects() {
		final int ox = (int) (this.mMagnification * OFFSET_DUPLICATED_OBJECT_X);
		final int oy = (int) (this.mMagnification * OFFSET_DUPLICATED_OBJECT_Y);

		ArrayList cList = this.duplicateObjects();
		for (int ii = 0; ii < cList.size(); ii++) {
			// duplicate
			SigDiffSymbol el = (SigDiffSymbol) cList.get(ii);
			el.setShapeWithAxesValues();

			// translate the duplicate
			el.translate(ox, oy);

			// set selected
			el.setSelected(true);

			// add to the list
			this.addToList(el);

			el.initPropertiesHistory();
		}

		if (cList.size() != 0) {
			this.setChanged(true);
		}

		// this.repaint();

		return true;
	}

	/**
	 * Paste the objects.
	 * 
	 * @param list
	 *            of the objects to be pasted
	 * @return true:succeeded, false:failed
	 */
	public boolean paste(ArrayList list) {
		final float mag = this.getMagnification();
		final int ox = (int) (mag * OFFSET_DUPLICATED_OBJECT_X);
		final int oy = (int) (mag * OFFSET_DUPLICATED_OBJECT_Y);

		int cnt = 0;
		for (int ii = 0; ii < list.size(); ii++) {
			Object obj = list.get(ii);
			if (obj instanceof SigDiffSymbol) {
				SigDiffSymbol sd = (SigDiffSymbol) obj;
				sd.setShapeWithAxesValues();

				// translate the instance to be pasted
				sd.translate(ox, oy);

				SGProperties p = sd.getProperties();

				SigDiffSymbol el = new SigDiffSymbol();
				el.setMagnification(mag);
				el.setProperties(p);

				el.mXAxis = this.mAxisElement.getAxisInCube(sd.mTempXAxis);
				el.mYAxis = this.mAxisElement.getAxisInCube(sd.mTempYAxis);

				// set the shape
				el.setShapeWithAxesValues();

				// add to the list
				this.addToList(el);

				// initialize history
				el.initPropertiesHistory();

				cnt++;
			}
		}

		if (cnt != 0) {
			this.setChanged(true);
		}

		return true;
	}

	/**
	 * 
	 */
	protected Set getAvailableChildSet() {
		Set set = new HashSet();
		List mList = this.getMementoList();
		for (int ii = 0; ii < mList.size(); ii++) {
			SigDiffElementProperties p = (SigDiffElementProperties) mList
					.get(ii);
			set.addAll(p.visibleSigDiffSymbolList);
		}

		return set;
	}

	//
	private SigDiffSymbol getSigDiffSymbol(final int id) {
		SigDiffSymbol el = (SigDiffSymbol) this.getChildObject(id);
		if (el == null)
			return null;
		if (el.isVisible() == false)
			return null;
		return el;
	}

	public boolean setAxisXDirectly(final int id, final int value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setXAxisLocation(value) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setAxisYDirectly(final int id, final int value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setYAxisLocation(value) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLocationHorizontalYDirectly(final int id,
			final double value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		el.setHorizontalYValue(value);
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLocationLeftXDirectly(final int id, final double value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		el.setLeftXValue(value);
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLocationLeftYDirectly(final int id, final double value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		el.setLeftYValue(value);
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLocationRightXDirectly(final int id, final double value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		el.setRightXValue(value);
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLocationRightYDirectly(final int id, final double value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		el.setRightYValue(value);
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLineVisibleDirectly(final int id, final boolean value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		el.setLineVisible(value);
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setSpaceDirectly(final int id, final float value,
			final String unit) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setSpace(value, unit) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setLineWidthDirectly(final int id, final float value,
			final String unit) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setLineWidth(value, unit) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setTextDirectly(final int id, final String value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setText(value) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setFontNameDirectly(final int id, final String value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setFontName(value) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setFontStyleDirectly(final int id, final int value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setFontStyle(value) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setFontSizeDirectly(final int id, final float value,
			final String unit) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setFontSize(value, unit) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	public boolean setFontColorDirectly(final int id, final Color value) {
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if (el == null)
			return false;
		if (this.setDirectlyBefore(el) == false)
			return false;
		if (el.setColor(value) == false)
			return false;
		if (this.setDirectlyAfter(el) == false)
			return false;
		return true;
	}

	private boolean setDirectlyBefore(SigDiffSymbol el) {
		return el.prepare();
	}

	private boolean setDirectlyAfter(SigDiffSymbol el) {
		if (el.commit() == false) {
			return false;
		}
		this.notifyChange();
		this.notifyToRoot();
		this.repaint();
		return true;
	}

	/**
	 * 
	 */
	public static class SigDiffElementProperties extends SGProperties {
		ArrayList visibleSigDiffSymbolList = new ArrayList();

		/**
		 * 
		 * 
		 */
		public SigDiffElementProperties() {
			super();
		}

		public void dispose() {
			this.visibleSigDiffSymbolList.clear();
			this.visibleSigDiffSymbolList = null;
		}

		/**
		 * 
		 */
		public boolean equals(final Object obj) {
			if ((obj instanceof SigDiffElementProperties) == false) {
				return false;
			}

			SigDiffElementProperties p = (SigDiffElementProperties) obj;

			if (p.visibleSigDiffSymbolList
					.equals(this.visibleSigDiffSymbolList) == false) {
				return false;
			}

			return true;
		}

		/**
		 * 
		 */
		public String toString() {
			String str = new String("[");
			str += this.visibleSigDiffSymbolList.toString();
			str += new String("]");

			return str;
		}

	}

	/**
	 * @author okumura
	 */
	private class SigDiffSymbol extends SGDrawingElementSignificantDifference2D
			implements ActionListener, SGIUndoable, SGISelectable, SGIMovable,
			SGICopiable, SGISignificantDifferenceDialogObserver, SGINode,
			SGIDisposable, ChildObject {

		/**
		 * 
		 */
		private int mID;

		public int getID() {
			return this.mID;
		}

		public boolean setID(final int id) {
			this.mID = id;
			return true;
		}

		/**
		 * 
		 */
		private SigDiffSymbol mTempSymbol = null;

		/**
		 * Flag whether this object is focused.
		 */
		private boolean mSelectedFlag = false;

		/**
		 * Get the flag as a focused object.
		 * 
		 * @return whether this object is focused.
		 */
		public boolean isSelected() {
			return this.mSelectedFlag;
		}

		/**
		 * Set the flag as a focused object.
		 * 
		 * @param b
		 *            focused
		 */
		public void setSelected(final boolean b) {
			this.mSelectedFlag = b;
		}

		/**
		 * 
		 */
		public String toString() {
			return "SigDiff:" + this.mID;
		}

		/**
		 * 
		 */
		public void finalize() {
		}

		/**
		 * 
		 */
		public void dispose() {
			super.dispose();

			this.mPopupMenu = null;

			this.mTemporaryProperties = null;

			if (this.mTempSymbol != null) {
				this.mTempSymbol.dispose();
				this.mTempSymbol = null;
			}

			this.mUndoManager.dispose();
			this.mUndoManager = null;

			this.mXAxis = null;
			this.mYAxis = null;
		}

		/**
		 * 
		 */
		private SGAxis mXAxis = null;

		/**
		 * 
		 */
		private SGAxis mYAxis = null;

		/**
		 * 
		 */
		private double mXValue1;

		/**
		 * 
		 */
		private double mXValue2;

		/**
		 * 
		 */
		private double mHorizontalYValue;

		/**
		 * 
		 */
		private double mYValue1;

		/**
		 * 
		 */
		private double mYValue2;

		/**
		 * 
		 */
		private SGProperties mTemporaryProperties = null;

		/**
		 * popup menu
		 */
		private JPopupMenu mPopupMenu = new JPopupMenu();

		/**
		 * 
		 */
		private SigDiffSymbol() {
			super();
			this.init();
		}

		/**
		 * 
		 */
		public String getClassDescription() {
			return "";
		}

		/**
		 * 
		 * @return
		 */
		public String getInstanceDescription() {
			String xAxis = SGFigureElementSignificantDifference.this.mAxisElement
					.getLocationName(this.mXAxis);
			String yAxis = SGFigureElementSignificantDifference.this.mAxisElement
					.getLocationName(this.mYAxis);

			String str = "";
			str += this.mID + ": " + this.getText() + ", ";
			str += xAxis + ", " + yAxis + ", ";
			str += "LeftX=" + this.getLeftXValue() + ", ";
			str += "RightX=" + this.getRightXValue() + ", ";
			str += "HorizontalY=" + this.getHorizontalYValue() + ", ";

			return str;
		}

		/**
		 * 
		 */
		public int getXAxisLocation() {
			return SGFigureElementSignificantDifference.this.mAxisElement
					.getLocationInPlane(this.mXAxis);
		}

		/**
		 * 
		 */
		public int getYAxisLocation() {
			return SGFigureElementSignificantDifference.this.mAxisElement
					.getLocationInPlane(this.mYAxis);
		}

		/**
		 * 
		 */
		public boolean setXAxisLocation(final int config) {
			if (config != SGIFigureElementAxis.AXIS_HORIZONTAL_1
					& config != SGIFigureElementAxis.AXIS_HORIZONTAL_2) {
				return false;
			}
			this.mXAxis = this.getAxis(config);
			return true;
		}

		/**
		 * 
		 */
		public boolean setYAxisLocation(final int config) {
			if (config != SGIFigureElementAxis.AXIS_PERPENDICULAR_1
					& config != SGIFigureElementAxis.AXIS_PERPENDICULAR_2) {
				return false;
			}
			this.mYAxis = this.getAxis(config);
			return true;
		}

		private SGAxis getAxis(final int config) {
			return SGFigureElementSignificantDifference.this.mAxisElement
					.getAxisInPlane(config);
		}

		/**
		 * 
		 */
		public float getSpace(final String unit) {
			return (float) SGUtilityText
					.convertFromPoint(this.getSpace(), unit);
		}

		/**
		 * 
		 */
		public float getLineWidth(final String unit) {
			return (float) SGUtilityText.convertFromPoint(this.getLineWidth(),
					unit);
		}

		/**
		 * 
		 */
		public float getFontSize(final String unit) {
			return (float) SGUtilityText.convertFromPoint(this.getFontSize(),
					unit);
		}

		/**
		 * 
		 */
		public boolean setSpace(final float space, final String unit) {
			final double conv = SGUtilityText.convert(space, unit,
					SIGDIFF_SPACE_UNIT);
			if (conv < SIGDIFF_SPACE_MIN)
				return false;
			if (conv > SIGDIFF_SPACE_MAX)
				return false;

			return super.setSpace(space, unit);
		}

		/**
		 * 
		 */
		public boolean setLineWidth(final float lw, final String unit) {
			final double conv = SGUtilityText
					.convert(lw, unit, LINE_WIDTH_UNIT);
			if (conv < LINE_WIDTH_MIN_VALUE)
				return false;
			if (conv > LINE_WIDTH_MAX_VALUE)
				return false;

			return super.setLineWidth(lw, unit);
		}

		/**
		 * 
		 */
		public boolean setText(final String text) {
			if (text == null)
				return false;
			if (text.length() == 0)
				return false;
			return super.setText(text);
		}

		/**
		 * 
		 */
		public Object copy() {
			SigDiffSymbol el = new SigDiffSymbol();
			el.setMagnification(this.getMagnification());
			el.setProperties(this.getProperties());
			el.setLocation(this.getX(), this.getY());
			el.mTempXAxis = SGFigureElementSignificantDifference.this.mAxisElement
					.getLocationInCube(this.mXAxis);
			el.mTempYAxis = SGFigureElementSignificantDifference.this.mAxisElement
					.getLocationInCube(this.mYAxis);
			return el;
		}

		private int mTempXAxis = -1;
		private int mTempYAxis = -1;

		/**
		 * 
		 */
		private SigDiffSymbol(final float x, final float y, final float w,
				final float hl, final float hr) {
			super(x, y, w, hl, hr);
			this.init();
		}

		/**
		 * 
		 */
		private boolean createPopupMenu() {
			JPopupMenu p = this.mPopupMenu;

			p.setBounds(0, 0, 100, 100);

			p.add(new JLabel("  -- Significant Difference --"));
			p.addSeparator();

			SGUtility.addItem(p, this, MENUCMD_MOVE_TO_FRONT);
			SGUtility.addItem(p, this, MENUCMD_MOVE_TO_BACK);

			p.addSeparator();

			SGUtility.addItem(p, this, MENUCMD_CUT);
			SGUtility.addItem(p, this, MENUCMD_COPY);
			SGUtility.addItem(p, this, MENUCMD_PASTE);

			p.addSeparator();

			SGUtility.addItem(p, this, MENUCMD_DELETE);
			SGUtility.addItem(p, this, MENUCMD_DUPLICATE);

			p.addSeparator();

			SGUtility.addItem(p, this, MENUCMD_PROPERTY);

			return true;
		}

		/**
		 * 
		 */
		private boolean init() {
			this.setWidth(DEFAULT_SIGDIFF_SYMBOL_WIDTH, cm);
			this
					.setPerpendicularHeight1(
							DEFAULT_SIGDIFF_SYMBOL_LEFT_HEIGHT, cm);
			this.setPerpendicularHeight2(DEFAULT_SIGDIFF_SYMBOL_RIGHT_HEIGHT,
					cm);

			this.setFontSize(DEFAULT_SIGDIFF_SYMBOL_FONT_SIZE, FONT_SIZE_UNIT);
			this.setFontName(DEFAULT_SIGDIFF_SYMBOL_FONT_NAME);
			this.setFontStyle(DEFAULT_SIGDIFF_SYMBOL_FONT_STYLE);

			this.setLineWidth(DEFAULT_SIGDIFF_SYMBOL_LINE_WIDTH,
					LINE_WIDTH_UNIT);
			this.setColor(DEFAULT_SIGDIFF_SYMBOL_COLOR);
			this.setSpace(DEFAULT_SIGDIFF_SYMBOL_SPACE, SIGDIFF_SPACE_UNIT);

			this.createPopupMenu();

			return true;
		}

		/**
		 * 
		 */
		private JPopupMenu getPopupMenu() {
			return this.mPopupMenu;
		}

		/**
		 * 
		 */
		public boolean prepare() {
			this.mTemporaryProperties = this.getProperties();
			return true;
		}

		/**
		 * @return
		 */
		public String getTagName() {
			return TAG_NAME_SIGDIFF_SYMBOL;
		}

		/**
		 * 
		 * @param document
		 * @return
		 */
		public Element createElement(final Document document) {
			Element el = document.createElement(this.getTagName());
			if (this.writeProperty(el) == false) {
				return null;
			}
			return el;
		}

		/**
		 * 
		 * @param el
		 * @return
		 */
		public boolean writeProperty(final Element el) {
			if (super.writeProperty(el) == false) {
				return false;
			}

			el.setAttribute(KEY_LEFT_X_VALUE, Double.toString(this
					.getLeftXValue()));
			el.setAttribute(KEY_LEFT_Y_VALUE, Double.toString(this
					.getLeftYValue()));
			el.setAttribute(KEY_RIGHT_X_VALUE, Double.toString(this
					.getRightXValue()));
			el.setAttribute(KEY_RIGHT_Y_VALUE, Double.toString(this
					.getRightYValue()));
			el.setAttribute(KEY_HORIZONTAL_Y_VALUE, Double.toString(this
					.getHorizontalYValue()));
			el.setAttribute(KEY_X_AXIS_POSITION,
					SGFigureElementSignificantDifference.this.mAxisElement
							.getLocationName(this.mXAxis));
			el.setAttribute(KEY_Y_AXIS_POSITION,
					SGFigureElementSignificantDifference.this.mAxisElement
							.getLocationName(this.mYAxis));

			return true;
		}

		/**
		 * 
		 */
		public boolean readProperty(final Element el) {
			if (super.readProperty(el) == false) {
				return false;
			}

			String str = null;
			Number num = null;
			// Boolean b = null;

			// x axis
			str = el.getAttribute(KEY_X_AXIS_POSITION);
			if (str.length() != 0) {
				SGAxis xAxis = SGFigureElementSignificantDifference.this.mAxisElement
						.getAxis(str);
				if (xAxis == null) {
					return false;
				}
				this.mXAxis = xAxis;
			}

			// y axis
			str = el.getAttribute(KEY_Y_AXIS_POSITION);
			if (str.length() != 0) {
				SGAxis yAxis = SGFigureElementSignificantDifference.this.mAxisElement
						.getAxis(str);
				if (yAxis == null) {
					return false;
				}
				this.mYAxis = yAxis;
			}

			// left x value
			str = el.getAttribute(KEY_LEFT_X_VALUE);
			if (str.length() != 0) {
				num = SGUtilityText.getDouble(str);
				if (num == null) {
					return false;
				}
				final double leftXValue = num.doubleValue();
				if (this.mXAxis.isValidValue(leftXValue) == false) {
					return false;
				}
				this.setLeftXValue(leftXValue);
			}

			// left y value
			str = el.getAttribute(KEY_LEFT_Y_VALUE);
			if (str.length() != 0) {
				num = SGUtilityText.getDouble(str);
				if (num == null) {
					return false;
				}
				final double leftYValue = num.doubleValue();
				if (this.mYAxis.isValidValue(leftYValue) == false) {
					return false;
				}
				this.setLeftYValue(leftYValue);
			}

			// right x value
			str = el.getAttribute(KEY_RIGHT_X_VALUE);
			if (str.length() != 0) {
				num = SGUtilityText.getDouble(str);
				if (num == null) {
					return false;
				}
				final double rightXValue = num.doubleValue();
				if (this.mXAxis.isValidValue(rightXValue) == false) {
					return false;
				}
				this.setRightXValue(rightXValue);
			}

			// right y value
			str = el.getAttribute(KEY_RIGHT_Y_VALUE);
			if (str.length() != 0) {
				num = SGUtilityText.getDouble(str);
				if (num == null) {
					return false;
				}
				final double rightYValue = num.doubleValue();
				if (this.mYAxis.isValidValue(rightYValue) == false) {
					return false;
				}
				this.setRightYValue(rightYValue);
			}

			// horizontal y value
			str = el.getAttribute(KEY_HORIZONTAL_Y_VALUE);
			if (str.length() != 0) {
				num = SGUtilityText.getDouble(str);
				if (num == null) {
					return false;
				}
				final double horizontalYValue = num.doubleValue();
				if (this.mYAxis.isValidValue(horizontalYValue) == false) {
					return false;
				}
				this.setHorizontalYValue(horizontalYValue);
			}

			return true;
		}

		/**
		 * 
		 */
		public SGProperties getProperties() {
			SigDiffPropertiesWithAxes p = new SigDiffPropertiesWithAxes();
			if (this.getProperties(p) == false)
				return null;
			return p;
		}

		/**
		 * 
		 */
		public boolean getProperties(SGProperties p) {
			if ((p instanceof SigDiffPropertiesWithAxes) == false)
				return false;

			if (super.getProperties(p) == false)
				return false;

			SigDiffPropertiesWithAxes sp = (SigDiffPropertiesWithAxes) p;
			sp.mLeftXValue = this.getLeftXValue();
			sp.mLeftYValue = this.getLeftYValue();
			sp.mRightXValue = this.getRightXValue();
			sp.mRightYValue = this.getRightYValue();
			sp.mHorizontalYValue = this.getHorizontalYValue();
			sp.mXAxis = this.mXAxis;
			sp.mYAxis = this.mYAxis;

			return true;
		}

		/**
		 * 
		 */
		public boolean setProperties(final SGProperties p) {
			if ((p instanceof SigDiffPropertiesWithAxes) == false)
				return false;

			if (super.setProperties(p) == false)
				return false;

			SigDiffPropertiesWithAxes sp = (SigDiffPropertiesWithAxes) p;
			this.setLeftXValue(sp.mLeftXValue);
			this.setLeftYValue(sp.mLeftYValue);
			this.setRightXValue(sp.mRightXValue);
			this.setRightYValue(sp.mRightYValue);
			this.setHorizontalYValue(sp.mHorizontalYValue);
			this.mXAxis = sp.mXAxis;
			this.mYAxis = sp.mYAxis;

			return true;
		}

		/**
		 * 
		 */
		public void actionPerformed(final ActionEvent e) {

			final String command = e.getActionCommand();
			// final Object source = e.getSource();

			if (command.equals(MENUCMD_PROPERTY)) {
				SGFigureElementSignificantDifference.this
						.setPropertiesOfSelectedObjects();
			} else if (command.equals(MENUCMD_COPY)
					| command.equals(MENUCMD_CUT)
					| command.equals(MENUCMD_PASTE)
					| command.equals(MENUCMD_DELETE)
					| command.equals(MENUCMD_DUPLICATE)
					| command.equals(MENUCMD_MOVE_TO_FRONT)
					| command.equals(MENUCMD_MOVE_TO_BACK)) {
				notifyToListener(command);
			}
		}

		/**
		 * 
		 */
		public boolean commit() {
			// update history if properties changed after dialog was closed

			SGProperties pTemp = this.mTemporaryProperties;
			SGProperties pPresent = this.getProperties();
			if (pTemp.equals(pPresent) == false) {
				this.mUndoManager.setChanged(true);
			}

			this.setShapeWithAxesValues();
			repaint();
			notifyChange();

			return true;
		}

		/**
		 * 
		 */
		public boolean cancel() {
			if (this.setProperties(this.mTemporaryProperties) == false) {
				return false;
			}
			this.mTemporaryProperties = null;

			this.setShapeWithAxesValues();
			repaint();
			notifyChange();

			return true;
		}

		/**
		 * 
		 */
		public boolean preview() {
			this.setShapeWithAxesValues();
			repaint();
			notifyChange();

			return true;
		}

		/**
		 * Returns a property dialog.
		 * 
		 * @return property dialog
		 */
		public SGPropertyDialog getPropertyDialog() {
			return SGFigureElementSignificantDifference.this.mDialog;
		}

		/**
		 * Returns a list of child nodes.
		 * 
		 * @return a list of chid nodes
		 */
		public ArrayList getChildNodes() {
			return new ArrayList();
		}

		/**
		 * 
		 */
		public float getX() {
			final float sx = super.getX();
			return this.getMagnification() * sx
					+ SGFigureElementSignificantDifference.this.mGraphRectX;
		}

		/**
		 * 
		 */
		public float getY() {
			final float sy = super.getY();
			return this.getMagnification() * sy
					+ SGFigureElementSignificantDifference.this.mGraphRectY;
		}

		/**
		 * 
		 * @param x
		 * @return
		 */
		public boolean setX(final float x) {
			final float nx = (x - SGFigureElementSignificantDifference.this.mGraphRectX)
					/ this.getMagnification();
			super.setX(nx);
			return true;
		}

		/**
		 * 
		 * @param y
		 * @return
		 */
		public boolean setY(final float y) {
			final float ny = (y - SGFigureElementSignificantDifference.this.mGraphRectY)
					/ this.getMagnification();
			super.setY(ny);
			return true;
		}

		/**
		 * 
		 */
		public void translate(final float dx, final float dy) {
			this.setLocation(this.getX() + dx, this.getY() + dy);
			this.createDrawingElement();
			this.setAxisValuesWithShape();
			this.setShapeWithAxesValues();
		}

		/**
		 * 
		 * @return
		 */
		public double getLeftXValue() {
			if (!this.isFlippingHorizontal()) {
				return this.mXValue1;
			}

			return this.mXValue2;
		}

		/**
		 * 
		 * @return
		 */
		public double getLeftYValue() {
			if (!this.isFlippingHorizontal()) {
				return this.mYValue1;
			}
			return this.mYValue2;
		}

		/**
		 * 
		 * @return
		 */
		public double getRightXValue() {
			if (!this.isFlippingHorizontal()) {
				return this.mXValue2;
			}
			return this.mXValue1;
		}

		/**
		 * 
		 * @return
		 */
		public double getRightYValue() {
			if (!this.isFlippingHorizontal()) {
				return this.mYValue2;
			}
			return this.mYValue1;
		}

		/**
		 * 
		 * @return
		 */
		public double getHorizontalYValue() {
			return this.mHorizontalYValue;
		}

		/**
		 * 
		 * @param value
		 */
		public boolean setLeftXValue(final double value) {
			if (!this.isFlippingHorizontal()) {
				this.mXValue1 = value;
			} else {
				this.mXValue2 = value;
			}
			return true;
		}

		/**
		 * 
		 * @param value
		 */
		public boolean setLeftYValue(final double value) {
			if (!this.isFlippingHorizontal()) {
				this.mYValue1 = value;
			} else {
				this.mYValue2 = value;
			}
			return true;
		}

		/**
		 * 
		 * @param value
		 */
		public boolean setRightXValue(final double value) {
			if (!this.isFlippingHorizontal()) {
				this.mXValue2 = value;
			} else {
				this.mXValue1 = value;
			}
			return true;
		}

		/**
		 * 
		 * @param value
		 */
		public boolean setRightYValue(final double value) {
			if (!this.isFlippingHorizontal()) {
				this.mYValue2 = value;
			} else {
				this.mYValue1 = value;
			}
			return true;
		}

		/**
		 * 
		 * @param value
		 */
		public boolean setHorizontalYValue(final double value) {
			this.mHorizontalYValue = value;
			return true;
		}

		/**
		 * 
		 * @param horizontalYValue
		 * @param leftXValue
		 * @param leftYValue
		 * @param rightXValue
		 * @param rightYValue
		 * @return
		 */
		public boolean hasValidValues() {
			Number horizontalY = new Double(this.getHorizontalYValue());
			Number leftX = new Double(this.getLeftXValue());
			Number leftY = new Double(this.getLeftYValue());
			Number rightX = new Double(this.getRightXValue());
			Number rightY = new Double(this.getRightYValue());

			if (this.mYAxis.isValidValue(horizontalY.doubleValue()) == false) {
				return false;
			}

			if (this.mXAxis.isValidValue(leftX.doubleValue()) == false) {
				return false;
			}

			if (this.mYAxis.isValidValue(leftY.doubleValue()) == false) {
				return false;
			}

			if (this.mXAxis.isValidValue(rightX.doubleValue()) == false) {
				return false;
			}

			if (this.mYAxis.isValidValue(rightY.doubleValue()) == false) {
				return false;
			}

			return true;
		}

		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidHorizontalYValue(final int config,
				final Number value) {
			final SGAxis axis = (config == -1) ? this.mYAxis
					: SGFigureElementSignificantDifference.this.mAxisElement
							.getAxisInPlane(config);
			final double v = (value != null) ? value.doubleValue() : this
					.getHorizontalYValue();
			return axis.isValidValue(v);
		}

		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidLeftXValue(final int config, final Number value) {
			final SGAxis axis = (config == -1) ? this.mXAxis
					: SGFigureElementSignificantDifference.this.mAxisElement
							.getAxisInPlane(config);
			final double v = (value != null) ? value.doubleValue() : this
					.getLeftXValue();
			return axis.isValidValue(v);
		}

		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidLeftYValue(final int config, final Number value) {
			final SGAxis axis = (config == -1) ? this.mYAxis
					: SGFigureElementSignificantDifference.this.mAxisElement
							.getAxisInPlane(config);
			final double v = (value != null) ? value.doubleValue() : this
					.getLeftYValue();
			return axis.isValidValue(v);
		}

		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidRightXValue(final int config, final Number value) {
			final SGAxis axis = (config == -1) ? this.mXAxis
					: SGFigureElementSignificantDifference.this.mAxisElement
							.getAxisInPlane(config);
			final double v = (value != null) ? value.doubleValue() : this
					.getRightXValue();
			return axis.isValidValue(v);
		}

		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidRightYValue(final int config, final Number value) {
			final SGAxis axis = (config == -1) ? this.mYAxis
					: SGFigureElementSignificantDifference.this.mAxisElement
							.getAxisInPlane(config);
			final double v = (value != null) ? value.doubleValue() : this
					.getRightYValue();
			return axis.isValidValue(v);
		}

		/**
		 * 
		 */
		private boolean pressDrawingElements(final MouseEvent e) {

			final int x = e.getX();
			final int y = e.getY();

			if (this.contains(x, y) || this.getStringElement().contains(x, y)) {

				final float mag = this.getMagnification();

				// set the temporary object
				this.mTempSymbol = new SigDiffSymbol();
				this.mTempSymbol.setMagnification(mag);
				this.mTempSymbol.setLocation(this.getX(), this.getY());
				this.mTempSymbol.setSize(this.getWidth(), this
						.getPerpendicularHeight1(), this
						.getPerpendicularHeight2());

				this.mFlippingHorizontalFlag = this.isFlippingHorizontal();

				this.mMouseLocation = this.getMouseLocation(x, y);
				Cursor cur = null;
				if (this.mMouseLocation == BODY
						|| this.mMouseLocation == ON_STRING) {
					cur = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
				} else {
					this.getCursor(this.mMouseLocation);
				}
				setMouseCursor(cur);

				return true;
			}

			return false;
		}

		/**
		 * 
		 */
		private boolean mFlippingHorizontalFlag;

		/**
		 * 
		 * @return
		 */
		private ArrayList getAnchorPointList() {
			ArrayList list = new ArrayList();
			if (this.isLineVisible()) {
				list.add(this.getLeftTerm());
				list.add(this.getLeftMiddle());
				list.add(this.getLeftJoint());
				list.add(this.getHorizontalMiddle());
				list.add(this.getRightJoint());
				list.add(this.getRightMiddle());
				list.add(this.getRightTerm());
			}

			Rectangle2D rect = ((SGDrawingElementString2DExtended) this
					.getStringElement()).getElementBounds();
			final float x = (float) rect.getX();
			final float y = (float) rect.getY();
			final float w = (float) rect.getWidth();
			final float h = (float) rect.getHeight();
			Point2D pos0 = new Point2D.Float(x, y);
			Point2D pos1 = new Point2D.Float(x + w, y);
			Point2D pos2 = new Point2D.Float(x, y + h);
			Point2D pos3 = new Point2D.Float(x + w, y + h);
			list.add(pos0);
			list.add(pos1);
			list.add(pos2);
			list.add(pos3);

			return list;
		}

		/**
		 * Location of mouse pointer.
		 */
		private int mMouseLocation;

		/**
		 * 
		 * @param pos
		 * @param radius
		 * @param x
		 * @param y
		 * @return
		 */
		private boolean isInside(final Point2D pos, final int radius,
				final int x, final int y) {
			return ((Math.abs(pos.getX() - x) < radius) && (Math.abs(pos.getY()
					- y) < radius));
		}

		/**
		 * マウス位置を属性に設定
		 */
		private int getMouseLocation(final int x, final int y) {
			final int radius = (int) (1.25f * ANCHOR_SIZE_FOR_FOCUSED_OBJECTS);

			final Point2D posHorizontalMiddle = this.getHorizontalMiddle();
			final Point2D posLeftMiddle = this.getLeftMiddle();
			final Point2D posRightMiddle = this.getRightMiddle();
			final Point2D posLeftJoint = this.getLeftJoint();
			final Point2D posRightJoint = this.getRightJoint();
			final Point2D posLeftTerm = this.getLeftTerm();
			final Point2D posRightTerm = this.getRightTerm();

			int location = -1;

			if (this.isLineVisible()) {
				// 水平線分中央
				if (this.isInside(posHorizontalMiddle, radius, x, y)) {
					location = HORIZONTAL_MIDDLE;
				}
				// 左側接合部
				else if (this.isInside(posLeftJoint, radius, x, y)) {
					location = LEFT_JOINT;
				}
				// 右側接合部
				else if (this.isInside(posRightJoint, radius, x, y)) {
					location = RIGHT_JOINT;
				}
				// 垂直線分左側の端
				else if (this.isInside(posLeftTerm, radius, x, y)) {
					location = LEFT_TERM;
				}
				// 垂直線分左側の中央
				else if (this.isInside(posLeftMiddle, radius, x, y)) {
					location = LEFT_MIDDLE;
				}
				// 垂直線分右側の端
				else if (this.isInside(posRightTerm, radius, x, y)) {
					location = RIGHT_TERM;
				}
				// 垂直線分右側の中央
				else if (this.isInside(posRightMiddle, radius, x, y)) {
					location = RIGHT_MIDDLE;
				} else {
					location = BODY;
				}
			}

			if (this.getStringElement().contains(x, y)) {
				location = ON_STRING;
			}

			return location;
		}

		/**
		 * 
		 */
		private Cursor getCursor(final int location) {

			// マウスの位置に応じてカーソルを変更
			Cursor cur = null;
			switch (location) {
			case HORIZONTAL_MIDDLE: {
				if (!this.isFlippingVertical()) {
					cur = new Cursor(Cursor.N_RESIZE_CURSOR);
				} else {
					cur = new Cursor(Cursor.S_RESIZE_CURSOR);
				}
				break;
			}
			case LEFT_MIDDLE: {
				cur = new Cursor(Cursor.W_RESIZE_CURSOR);
				break;
			}
			case RIGHT_MIDDLE: {
				cur = new Cursor(Cursor.E_RESIZE_CURSOR);
				break;
			}
			case LEFT_TERM: {
				if (!this.isFlippingVerticalLeft()) {
					cur = new Cursor(Cursor.SW_RESIZE_CURSOR);
				} else {
					cur = new Cursor(Cursor.NW_RESIZE_CURSOR);
				}
				break;
			}
			case LEFT_JOINT: {
				if (!this.isFlippingVerticalLeft()) {
					cur = new Cursor(Cursor.NW_RESIZE_CURSOR);
				} else {
					cur = new Cursor(Cursor.SW_RESIZE_CURSOR);
				}
				break;
			}
			case RIGHT_TERM: {
				if (!this.isFlippingVerticalRight()) {
					cur = new Cursor(Cursor.SE_RESIZE_CURSOR);
				} else {
					cur = new Cursor(Cursor.NE_RESIZE_CURSOR);
				}
				break;
			}
			case RIGHT_JOINT: {
				if (!this.isFlippingVerticalRight()) {
					cur = new Cursor(Cursor.NE_RESIZE_CURSOR);
				} else {
					cur = new Cursor(Cursor.SE_RESIZE_CURSOR);
				}
				break;
			}
			case ON_STRING: {
				cur = new Cursor(Cursor.HAND_CURSOR);
				break;
			}
			default: {
				cur = new Cursor(Cursor.HAND_CURSOR);
			}
			}

			// System.out.println(cur);

			return cur;

		}

		/**
		 * 
		 */
		private boolean drag(final MouseEvent e) {

			if (SGFigureElementSignificantDifference.this.mPressedPoint == null) {
				return false;
			}

			// translation
			if (this.mMouseLocation == BODY || this.mMouseLocation == ON_STRING) {
				final boolean flag = this.dragOtherPoint(e);
				return flag;
			}

			final float mag = this.getMagnification();

			SigDiffSymbol temp = this.mTempSymbol;
			final float xOld = temp.getX();
			final float yOld = temp.getY();
			final float wOld = mag * temp.getWidth();
			final float h1Old = mag * temp.getPerpendicularHeight1();
			final float h2Old = mag * temp.getPerpendicularHeight2();

			final int diffX = e.getX()
					- SGFigureElementSignificantDifference.this.mPressedPoint.x;
			final int diffY = e.getY()
					- SGFigureElementSignificantDifference.this.mPressedPoint.y;

			final float sizeOldX = wOld;
			final float sizeOldY1 = h1Old;
			final float sizeOldY2 = h2Old;

			float sizeNewX = 0.0f;
			float sizeNewY1 = 0.0f;
			float sizeNewY2 = 0.0f;

			// new values
			float x = xOld;
			float y = yOld;
			float w = wOld;
			float h1 = h1Old;
			float h2 = h2Old;

			// switch operation by different dragging point

			final int loc = this.mMouseLocation;
			final boolean flag = this.mFlippingHorizontalFlag;
			if (loc == HORIZONTAL_MIDDLE) {
				// System.out.println("NORTH");
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;

				y = yOld + sizeOldY1 - sizeNewY1;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			} else if ((loc == LEFT_MIDDLE && !flag)
					|| (loc == RIGHT_MIDDLE && flag)) {
				sizeNewX = sizeOldX - diffX;
				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
			} else if ((loc == RIGHT_MIDDLE && !flag)
					|| (loc == LEFT_MIDDLE && flag)) {
				sizeNewX = sizeOldX + diffX;
				w = sizeNewX;
			} else if ((loc == LEFT_JOINT && !flag)
					|| (loc == RIGHT_JOINT && flag)) {
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;
				sizeNewX = sizeOldX - diffX;

				x = xOld + sizeOldX - sizeNewX;
				y = yOld + sizeOldY1 - sizeNewY1;
				w = sizeNewX;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			} else if ((loc == RIGHT_JOINT && !flag)
					|| (loc == LEFT_JOINT && flag)) {
				sizeNewX = sizeOldX + diffX;
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;

				y = yOld + sizeOldY2 - sizeNewY2;
				w = sizeNewX;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			} else if ((loc == LEFT_TERM && !flag)
					|| (loc == RIGHT_TERM && flag)) {
				sizeNewX = sizeOldX - diffX;
				sizeNewY1 = sizeOldY1 + diffY;

				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
				h1 = sizeNewY1;
			} else if ((loc == RIGHT_TERM && !flag)
					|| (loc == LEFT_TERM && flag)) {
				sizeNewX = sizeOldX + diffX;
				sizeNewY2 = sizeOldY2 + diffY;

				w = sizeNewX;
				h2 = sizeNewY2;
			}

			// update the pressed point
			SGFigureElementSignificantDifference.this.mPressedPoint
					.setLocation(
							SGFigureElementSignificantDifference.this.mPressedPoint
									.getX()
									+ diffX,
							SGFigureElementSignificantDifference.this.mPressedPoint
									.getY()
									+ diffY);

			// set properties
			this.setLocation(x, y);
			this.setSize(w / mag, h1 / mag, h2 / mag);
			this.createDrawingElement();

			temp.setLocation(x, y);
			temp.setSize(w / mag, h1 / mag, h2 / mag);

			if (loc == LEFT_TERM | loc == LEFT_JOINT | loc == RIGHT_TERM
					| loc == RIGHT_JOINT) {
				final int location = this.getMouseLocation(e.getX(), e.getY());
				setMouseCursor(this.getCursor(location));
			}

			return true;

		}

		/**
		 * 
		 */
		private boolean dragOtherPoint(final MouseEvent e) {
			// parallel displacement
			if (SGFigureElementSignificantDifference.this.mPressedPoint != null) {
				// set the location to the symbol
				final int dx = e.getX()
						- SGFigureElementSignificantDifference.this.mPressedPoint.x;
				final int dy = e.getY()
						- SGFigureElementSignificantDifference.this.mPressedPoint.y;
				this.translate(dx, dy);

				SGFigureElementSignificantDifference.this.mPressedPoint = e
						.getPoint();
			}

			return true;
		}

		private boolean setShapeWithAxesValues() {
			final float x1 = calcLocation(this.mXValue1, this.mXAxis, true);
			final float x2 = calcLocation(this.mXValue2, this.mXAxis, true);
			final float y = calcLocation(this.mHorizontalYValue, this.mYAxis,
					false);
			final float y1 = calcLocation(this.mYValue1, this.mYAxis, false);
			final float y2 = calcLocation(this.mYValue2, this.mYAxis, false);

			if (Float.isNaN(x1) | Float.isNaN(x2) | Float.isNaN(y)
					| Float.isNaN(y1) | Float.isNaN(y2)) {
				this.setValid(false);
				return false;
			}
			this.setValid(true);

			this.setNodePointLocation(x1, y1, x2, y2, y);

			this.createDrawingElement();

			return true;
		}

		private boolean mValidFlag = true;

		public boolean isValid() {
			return this.mValidFlag;
		}

		public void setValid(final boolean b) {
			this.mValidFlag = b;
		}

		private boolean setAxisValuesWithShape() {
			final double xValue1 = calcValue(this.getX1(), this.mXAxis, true);
			final double yValue1 = calcValue(this.getY1(), this.mYAxis, false);
			final double xValue2 = calcValue(this.getX2(), this.mXAxis, true);
			final double yValue2 = calcValue(this.getY2(), this.mYAxis, false);
			final double hYValue = calcValue(this.getY(), this.mYAxis, false);

			this.mXValue1 = getNumberInRangeOrder(xValue1, this.mXAxis);
			this.mYValue1 = getNumberInRangeOrder(yValue1, this.mYAxis);
			this.mXValue2 = getNumberInRangeOrder(xValue2, this.mXAxis);
			this.mYValue2 = getNumberInRangeOrder(yValue2, this.mYAxis);
			this.mHorizontalYValue = getNumberInRangeOrder(hYValue, this.mYAxis);

			return true;
		}

		//
		private SGUndoManager mUndoManager = new SGUndoManager(this);

		/**
		 * 
		 * @return
		 */
		public SGProperties getMemento() {
			return this.getProperties();
		}

		/**
		 * 
		 * @param p
		 * @return
		 */
		public boolean setMemento(SGProperties p) {
			return this.setProperties(p);
		}

		/**
		 * 
		 * @return
		 */
		public boolean isUndoable() {
			return this.mUndoManager.isUndoable();
		}

		/**
		 * 
		 * @return
		 */
		public boolean isRedoable() {
			return this.mUndoManager.isRedoable();
		}

		/**
		 * 
		 */
		public boolean initPropertiesHistory() {
			return this.mUndoManager.initPropertiesHistory();
		}

		/**
		 * undo
		 */
		public boolean setMementoBackward() {
			if (this.mUndoManager.setMementoBackward() == false) {
				return false;
			}

			this.setShapeWithAxesValues();

			if (this.isValid()) {
				this.createDrawingElement();
			}

			return true;
		}

		/**
		 * redo
		 */
		public boolean setMementoForward() {
			if (this.mUndoManager.setMementoForward() == false) {
				return false;
			}

			this.setShapeWithAxesValues();

			if (this.isValid()) {
				this.createDrawingElement();
			}

			return true;
		}

		/**
		 * undo
		 */
		public boolean undo() {
			return this.setMementoBackward();
		}

		/**
		 * redo
		 */
		public boolean redo() {
			return this.setMementoForward();
		}

		/**
		 * update history. it will called first when undo
		 */
		public boolean updateHistory() {
			return this.mUndoManager.updateHistory();
		}

		/**
		 * 
		 */
		public void initUndoBuffer() {
			this.mUndoManager.initUndoBuffer();
		}

		/**
		 * 
		 */
		public boolean isChanged() {
			return this.mUndoManager.isChanged();
		}

		public void setChanged(final boolean b) {
			this.mUndoManager.setChanged(b);
		}

		public boolean isChangedRoot() {
			return this.isChanged();
		}

		/**
		 * 
		 * 
		 */
		public void notifyToRoot() {
			SGFigureElementSignificantDifference.this.notifyToRoot();
		}

	}

	/**
	 * @author okumura
	 */
	public static class SigDiffPropertiesWithAxes extends SigDiffProperties {

		private double mLeftXValue;
		private double mRightXValue;
		private double mLeftYValue;
		private double mRightYValue;
		private double mHorizontalYValue;
		private SGAxis mXAxis;
		private SGAxis mYAxis;

		public SigDiffPropertiesWithAxes() {
			super();
		}

		/**
		 * 
		 */
		public boolean equals(final Object obj) {
			if ((obj instanceof SigDiffPropertiesWithAxes) == false)
				return false;

			if (super.equals(obj) == false)
				return false;

			SigDiffPropertiesWithAxes p = (SigDiffPropertiesWithAxes) obj;

			if (p.mLeftXValue != this.mLeftXValue)
				return false;
			if (p.mRightXValue != this.mRightXValue)
				return false;
			if (p.mLeftYValue != this.mLeftYValue)
				return false;
			if (p.mRightYValue != this.mRightYValue)
				return false;
			if (p.mHorizontalYValue != this.mHorizontalYValue)
				return false;
			if (p.mXAxis.equals(this.mXAxis) == false)
				return false;
			if (p.mYAxis.equals(this.mYAxis) == false)
				return false;

			return true;
		}

		public double getLeftXValue() {
			return this.mLeftXValue;
		}

		public double getLeftYValue() {
			return this.mLeftYValue;
		}

		public double getRightXValue() {
			return this.mRightXValue;
		}

		public double getRightYValue() {
			return this.mRightYValue;
		}

		public double getHorizontalYValue() {
			return this.mHorizontalYValue;
		}

		public SGAxis getXAxis() {
			return this.mXAxis;
		}

		public SGAxis getYAxis() {
			return this.mYAxis;
		}

		public void setLeftXValue(final double value) {
			this.mLeftXValue = value;
		}

		public void setLeftYValue(final double value) {
			this.mLeftYValue = value;
		}

		public void setRightXValue(final double value) {
			this.mRightXValue = value;
		}

		public void setRightYValue(final double value) {
			this.mRightYValue = value;
		}

		public void setHorizontalYValue(final double value) {
			this.mHorizontalYValue = value;
		}

		public void setXAxis(SGAxis axis) {
			if (axis == null) {
				throw new IllegalArgumentException("axis==null");
			}
			this.mXAxis = axis;
		}

		public void setYAxis(SGAxis axis) {
			if (axis == null) {
				throw new IllegalArgumentException("axis==null");
			}
			this.mYAxis = axis;
		}

	}

}
