package pbl2011.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;

import pbl2011.common.Util;
import pbl2011.model.AssociationArc;
import pbl2011.model.Attribute;
import pbl2011.model.ClassModel;
import pbl2011.model.ClassNode;
import pbl2011.model.Method;
import pbl2011.mvc.Controller;
import pbl2011.mvc.Model;
import pbl2011.mvc.View;

/**
 * UMLキャンバス
 * <p>
 *
 * @author 10745104 Y.Ishii
 *
 */
public class UMLCanvas extends View {

	int scale; // 倍率（メインウィンドウを１として何分の１にするか）
	BufferedImage img = null; // 編集中のイメージ

	boolean mainCanvas; // メインキャンバスかどうか

	/**
	 * コンストラクタ
	 * @param x ウィンド幅
	 * @param y ウィンド高さ
	 * @param z 縮尺
	 * @param m モデル
	 */
	public UMLCanvas(int z, Model m) {
		super(m);
		scale = z;

		if (z == 1)
			mainCanvas = true;

		addMouseListener((UMLCanvasController) myController);
		addMouseMotionListener(myController);
		initialize();
	}

	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (img == null) {
			img = ( BufferedImage )createImage(scaledown(State.width), scaledown(State.height));
		}
		Graphics2D g2 =img.createGraphics();
		Graphics2D paramG = (Graphics2D)g;

		if(State.font!= null) {
			g2.setFont(State.font);
		}
		State.fm = g2.getFontMetrics(g2.getFont());

		g2.setColor(Color.WHITE);
		g2.fillRect(0, 0, scaledown(State.width), scaledown(State.height));

		if (State.gridlineFlag) {
			grawGridLine(g2);
		}

		ArrayList<ClassNode> cn = myModel.getAllActiveClassData();
		ArrayList<AssociationArc> arclist = myModel
				.getAllActiveAssociationArc();

		ClassNode current = cuMgr.getCurrentNode();
		ArrayList<ClassNode> currentList = cuMgr.getCurrentNodeList();

		if (current != null && State.gridFlag) {
			drawCurrentGridLine(g2, current);
		}

		BasicStroke stroke = new BasicStroke(getLineSize()); // 線の太さを変更
		g2.setStroke(stroke); // 線の種類を設定
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

		for (AssociationArc arc : arclist) {
			drawArcLine(g2, arc);
		}

		for (ClassNode node : cn) {
			if (!node.equals(current) && !currentList.contains(node)) {
				drawClass(g2, node);
			}
		}

		if (State.arcSelect != null) {
			dragNewArc(g2);
		}

		// 移動中の描画を自然にするため、一番最後
		if (currentList.size() > 0) {
			for (ClassNode node : currentList) {
				drawClass(g2, node);
				drawKnobs(g2, node);
			}
		}

		drowArcPoint(g2);

		// マウスによる選択時の矩形描画
		g2.setColor(Color.magenta);
		Rectangle rect = cuMgr.getSelectRect();
		if(rect != null) {
			drawRect(g2, rect);
		}
		paramG.drawImage(img, 0, 0, null);

	}

	 public BufferedImage getCanvasImg(){
  	   return img;
     }

	@Override
	protected Controller makeController() {
		return new UMLCanvasController(this);
	}

	@Override
	protected void initialize() {
		assert Util.debug("initialize");
		setPreferredSize(new Dimension(scaledown(State.width), scaledown(State.height)));
		img = ( BufferedImage )createImage(scaledown(State.width), scaledown(State.height));
		revalidate();
	}

	@Override
	protected void draw() {
		repaint();
	}

	/**
	 * キャンバスのグリッド線を引く
	 * @param g
	 */
	protected void grawGridLine(Graphics g) {
		int gridline = GRID_SIZE * scale;
		g.setColor(Color.YELLOW);
		for (int i = gridline; i < State.width; i += gridline) {
			drawLine(g, i, 0, i, State.height);
		}

		for (int i = gridline; i < State.height; i += gridline) {
			drawLine(g, 0, i, State.width, i);
		}
	}

	/**
	 * 目印のグリッド線を引く
	 * @param g
	 */
	protected void drawCurrentGridLine(Graphics2D g2, ClassNode current) {
		float dash[] = { 3.0f, 2.0f };
		BasicStroke dashStroke = new BasicStroke(getLineSize(), BasicStroke.CAP_BUTT,
				BasicStroke.JOIN_ROUND, 2.0f, dash, 0.0f);
		g2.setStroke(dashStroke);
		g2.setColor(Color.GREEN);
		drawLine(g2, current.p.x, 0, current.p.x, State.height);
		drawLine(g2, current.p.x+current.width, 0, current.p.x+current.width, State.height);
		drawLine(g2, 0, current.p.y, State.width, current.p.y);
		drawLine(g2, 0, current.p.y+current.height(), State.width, current.p.y+current.height());

	}

	/**
	 * クラスを描画する
	 * @param g
	 */
	protected void drawClass(Graphics g, ClassNode c) {

		if (!c.isBuiltInClass) {
			int x = c.p.x;
			int y = c.p.y;
			g.setColor(new Color(c.colorRed, c.colorGreen, c.colorBlue));
			fillRect(g, x, y, c.width, c.height());

			g.setColor(Color.BLACK);
			drawRect(g, x, y, c.width, c.height());
			drawLine(g, x, y + c.height1, x + c.width, y + c.height1);
			drawLine(g, x, y + c.height1 + c.height2, x + c.width, y + c.height1
					+ c.height2);

			g.setColor(Color.BLACK);

			if (mainCanvas) {

				g.drawString(c.visibilityMark() + c.typeMark() + " " + c.className,
						c.p.x + SIDE_MARGINE, c.p.y + getLineHight());
				int i = 0;
				for (Attribute a : c.attributeList) {
					if(a.visibility.level() <= State.attributeVisibility) {
						g.drawString(a.visibilityMark() + a.attributeName, c.p.x + SIDE_MARGINE,
								c.p.y + c.height1 + i * getLineHight() + getLineHight());
						i++;
					}
				}

				i = 0;
				for (Method m : c.methodList) {
					if(m.visibility.level() <= State.methodVisibility) {
						g.drawString(m.visibilityMark() + m.methodName, c.p.x + SIDE_MARGINE,
								c.p.y + c.height1 + c.height2 + i * getLineHight() + getLineHight());
						i++;
					}
				}
			}
		}

	}

	/**
	 * 行間を含んだ文字の高さを求める
	 * @return
	 */
	private int getLineHight() {
		return State.fm.getHeight()+ LINE_SPACE;
	}

	/**
	 * 関連の線を引く
	 * @param g
	 * @param arc
	 */
	protected void drawArcLine(Graphics g, AssociationArc arc) {

		Point[] pList = getArcPointList(arc);
		drawArcLine(g, pList, arc);
	}

	/**
	 * 関連の線を引く
	 * @param g
	 * @param pList
	 * @param arc
	 * @param target
	 * @param source
	 */
	private void drawArcLine(Graphics g, Point[] pList,AssociationArc arc) {
		ClassNode target = myModel.getClassData(arc.classIdTarget);
		ClassNode source = myModel.getClassData(arc.classIdSource);

		if (pList != null) {
			int len = pList.length;
			g.setColor(getArcColor(arc));

			// クラスからインタフェースへの線・依存関係は破線
			if (isBrokenLine(target, source, arc)) {
				for(int i = 0; i < len-1; i++) {
					drawBrokenLine(g, pList[i], pList[i+1]);
				}
			} else {
				for(int i = 0; i < len-1; i++) {
					drawLine(g, pList[i], pList[i+1]);
				}
			}

			if (arc.getKind().isASSOC() || arc.getKind().isDEPENDS()) {
				if (arc.naviTarget)
					drawArrow(g, pList[0], pList[1]);
				if (arc.naviSource)
					drawArrow(g, pList[len-1], pList[len-2]);

			} else if (arc.getKind().isEXTENDS()) {
				if (arc.naviTarget)
					drawExtendArrow(g, getArcColor(arc), pList[0], pList[1]);
				if (arc.naviSource)
					drawExtendArrow(g, getArcColor(arc), pList[len-1], pList[len-2]);
			} else if (arc.getKind().isINNER()) {
				drawInner(g, getArcColor(arc), pList[0], pList[1]);
			}

			drawMultiplicity(g, arc, pList[0], pList[1]);
		}
	}

	/**
	 * 関連線のポイントを描く
	 * @param g
	 */
	protected void drowArcPoint(Graphics g) {
		if(cuMgr.getCurrentArc() != null && mainCanvas && cuMgr.getCurrentArc().lineStyle.isFREE_LINE()) {
			drowPoint(g, getArcPointList(cuMgr.getCurrentArc()));
		}
	}

	/**
	 * 関連線のポイントを描く
	 * @param g
	 * @param pList
	 */
	private void drowPoint(Graphics g, Point[] pList) {
		for (Point p : pList) {
			g.setColor(Color.RED);
			fillOval(g, p.x, p.y, POINT_SIZE);
		}
	}

	// 110806, CA
	private boolean isBrokenLine(ClassNode target, ClassNode source,
								 AssociationArc arc) {
		if(arc.getKind().isEXTENDS())
			return target.isInterfaceNode() && source.isClassNode();
		return arc.getKind().isDEPENDS();
	}

	// 110806, CA
	private void drawInner(Graphics g, Color color, Point p1, Point p2) {
		double theta = Math.atan2(p2.y - p1.y, p2.x - p1.x);
		int x = p1.x + (int)((INNER_SIZE+2) * Math.cos(theta));
		int y = p1.y + (int)((INNER_SIZE+2) * Math.sin(theta));
		int r = INNER_SIZE;
		int w = INNER_SIZE*2;
		g.setColor(Color.WHITE);
		fillOval(g, x, y, w);
		g.setColor(color);
		drawOval(g, x, y, w);
		drawLine(g, x - r, y, x + r, y);
		drawLine(g, x, y - r, x, y + r);
	}

	// 110806, CA
	private void drawMultiplicity(Graphics g, AssociationArc arc,
								  Point p1, Point p2) {
		if(!mainCanvas) {
			return;
		}
		String m = arc.multiplTarget;
		if(m.equals("null")) return;
		if(m.equals("0..1")) m = "1";
		double theta = Math.atan2(p2.y - p1.y, p2.x - p1.x) + Math.PI / 6.0;
		int x = p1.x + (int)(16 * Math.cos(theta));
		int y = p1.y + (int)(16 * Math.sin(theta));
		g.drawString(m, x-3, y+6);
	}

	private void drawArrow(Graphics g, Point p1, Point p2) {
		int[] arrow = Util.calcArrowPoint(p1, p2);
		drawLine(g, p1.x, p1.y, arrow[0], arrow[1]);
		drawLine(g, p1.x, p1.y, arrow[2], arrow[3]);
	}

	private void drawExtendArrow(Graphics g, Color color, Point p1, Point p2) {
		int[] arrow = Util.calcTrianglePoint(p1, p2);
		int[] arrowPoints = { p1.x, arrow[0], arrow[2],
							  p1.y, arrow[1], arrow[3] };
		g.setColor(Color.WHITE);
		fillPolygon(g, arrowPoints);
		g.setColor(color);
		drawPolygon(g, arrowPoints);
	}

	private void drawBrokenLine(Graphics g, Point cross1, Point cross2) {

		Graphics2D g2 = (Graphics2D) g;
		Stroke solidLine = g2.getStroke(); //元々の線のスタイルを保持

		float dash[] = { 5.0f, 3.0f };
		BasicStroke dashStroke = new BasicStroke(getLineSize(), BasicStroke.CAP_BUTT,
				BasicStroke.JOIN_ROUND, 3.0f, dash, 0.0f);
		g2.setStroke(dashStroke);
		drawLine(g, cross1, cross2);
		g2.setStroke(solidLine);

	}

	protected float getLineSize() {
		if (mainCanvas)
			return MAIN_LINE_SIZE;
		return SUB_LINE_SIZE;
	}

	protected Color getArcColor(AssociationArc arc) {
		if (arc == cuMgr.getCurrentArc()) {
			return Color.MAGENTA;

		}
		return Color.BLACK;
	}

	protected void dragNewArc(Graphics g) {

		if (startPt == null || endPt == null)
			return;
		g.setColor(Color.MAGENTA);
		drawLine(g, startPt, endPt);
	}

	protected void drawKnobs(Graphics g, ClassNode c) {

		int x = c.p.x;
		int y = c.p.y;
		if (mainCanvas) {
			g.setColor(Color.BLACK);
			drawKnob(g, x, y);
			drawKnob(g, x, y + c.height1);
			drawKnob(g, x + c.width, y);
			drawKnob(g, x + c.width, y + c.height1);
			drawKnob(g, x, y + c.height1 + c.height2);
			drawKnob(g, x, y + c.height());
			drawKnob(g, x + c.width, y + c.height1 + c.height2);
			drawKnob(g, x + c.width, y + c.height());
		} else {
			// g.setColor(Color.BLUE);
			g.setColor(Color.MAGENTA);
			drawRect(g, x, y, c.width, c.height());
			drawLine(g, x, y + c.height1, x + c.width, y + c.height1);
			drawLine(g, x, y + c.height1 + c.height2, x + c.width, y
					+ c.height1 + c.height2);
		}
	}

	void moveFrame(int dx, int dy) {
		assert Util.debug("moveFrame");
		dx = multiply(dx);
		dy = multiply(dy);
		int w = multiply(State.width);
		int h = multiply(State.height);

		ArrayList<ClassNode> currentList = cuMgr.getCurrentNodeList();
		ArrayList<Integer> list = new ArrayList<Integer>();
		for (ClassNode cu: currentList) {
			list.add(cu.classId);
			cu.moveDelta(dx, dy, w, h);
		}

		// Source Target 共に移動する場合、自由に描いた関連もコピー
		for (AssociationArc arc : myModel.getAllActiveAssociationArc()) {
			if (arc.lineStyle.isFREE_LINE()) {
				if (list.contains(arc.classIdSource)  &&
					list.contains(arc.classIdTarget)) {

					for( Point p : arc.pointList ) {
						p.x  += dx;
						p.y  += dy;
					}

				} else if (list.contains(arc.classIdSource)) {
					arc.pointList[arc.pointList.length -1].x += dx;
					arc.pointList[arc.pointList.length -1].y += dy;

				} else if (list.contains(arc.classIdTarget)) {
					arc.pointList[0].x += dx;
					arc.pointList[0].y += dy;
				}
			}
		}

		repaint();
	}

	void dragFrame(Point orgPt, Point ordPt, Point newPt, int poz, int side) {
		ClassNode current = cuMgr.getCurrentNode();

		if (current == null) {
			return;
		}
		int x = current.p.x;
		int y = current.p.y;
		int width = current.calcMinWidth();

		// 右側のノブ
		if (side == 2 && newPt.x - orgPt.x > width) {
			width = newPt.x - orgPt.x;

		// 左側のノブ
		} else if (side == 1 && orgPt.x - newPt.x > width) {
			x = newPt.x;
			width = orgPt.x - newPt.x;
		}

		int height1 = current.height1;
		int height2 = current.height2;
		int height3 = current.height3;
		switch (poz) {
		case 1:
			height1 = current.calcMinHeigh1();
			if (newPt.y > orgPt.y && newPt.y - orgPt.y > height1) {
				height1 = newPt.y - orgPt.y;
			} else if (orgPt.y > newPt.y && orgPt.y - newPt.y > height1) {
				y = newPt.y;
				height1 = orgPt.y - newPt.y;
			}
			break;
		case 2:
			height2 = current.calcMinHeigh2();
			if (newPt.y - orgPt.y > height2) {
				height2 = newPt.y - orgPt.y;
			}
			break;
		case 3:
			height3 = current.calcMinHeigh3();
			if (newPt.y - orgPt.y > height3) {
				height3 = newPt.y - orgPt.y;
			}
			break;

		}

		current.resize(x, y, width, height1, height2, height3);
		moveFreeArc(current);
		repaint();
	}

	/**
	 * 関連線の自由の線のポイントを再算出する
	 */
	private void moveFreeArc(ClassNode current) {
		Point cross;
		for (AssociationArc arc : myModel.getAllActiveAssociationArc()) {
			if (arc.lineStyle.isFREE_LINE()) {
				if (current.classId == arc.classIdSource ) {

					cross = Util.calcCrossPoint(
						current.getRectangle(),arc.pointList[arc.pointList.length -2]);

					if(cross!= null) {
						arc.pointList[arc.pointList.length -1] = cross;
					} else {
						arc.delPoint(arc.pointList.length -1);
					}

				} else if (current.classId == arc.classIdTarget) {
					cross = Util.calcCrossPoint(current.getRectangle(),arc.pointList[1]);

					if(cross!= null) {
						arc.pointList[0] = cross;
					} else {
						arc.delPoint(0);
					}
				}
			}
		}
	}

	/**
	 * 関連線のポイントを移動する
	 * @param pt ポイント
	 * @param no 移動対象
	 */
	void moveArcPoint(Point pt, int no) {
		if (cuMgr.getCurrentArc() != null) {
			Point[] pList = cuMgr.getCurrentArc().pointList;

			// 最初と最後のポイントの場合には、クラスから離れない位置を求める
			if(no == 0) {
				calcPoint(pt, myModel.getClassData(cuMgr.getCurrentArc().classIdTarget));

			} else if ( no == pList.length -1 ) {
				calcPoint(pt, myModel.getClassData(cuMgr.getCurrentArc().classIdSource));
			}
			pList[no] = pt;
		}
		repaint();
	}

	/**
	 * クラスから離れないポイントの位置を算出する
	 * @param pt
	 * @param cn
	 */
	protected void calcPoint(Point pt, ClassNode cn) {
		if (pt.x < cn.p.x ) {
			pt.x = cn.p.x;
		} else if (pt.x > cn.p.x + cn.width ) {
			pt.x = cn.p.x + cn.width;
		}
		if (pt.y < cn.p.y ) {
			pt.y = cn.p.y;
		} else if (pt.y > cn.p.y + cn.height() ) {
			pt.y = cn.p.y + cn.height();
		}
	}

	@SuppressWarnings("unchecked")
	ClassNode selectClass(Point pt) {

		// 描画の逆順にソート
		ArrayList<ClassNode> cn =
			(ArrayList<ClassNode>)myModel.getAllActiveClassData().clone();
		Collections.reverse(cn);
		//選択中のクラスが最優先
		if (cuMgr.getCurrentNode() != null) {
			cn.add(0, cuMgr.getCurrentNode());
		}
		return selectClass(pt, cn);
	}

	ClassNode selectClass(Point pt, ArrayList<ClassNode> cn) {
		int z = KNOB_SIZE / 2;
		for (ClassNode c : cn) {
			if (!c.isBuiltInClass) {
				int x = multiply(pt.x);
				int y = multiply(pt.y);
				if ((x > c.p.x - z && (c.p.x + c.width + z) > x) &&
						(y > c.p.y - z && (c.p.y + c.height() + z) > y)) {
					assert Util.debug("in");
					return c;
				}
			}
		}
		assert Util.debug("out");
		return null;
	}

	// クリックされた関連線を返す
	AssociationArc selectArc(Point pt) {

		ArrayList<AssociationArc> list = myModel.getAllActiveAssociationArc();
		for (AssociationArc arc : list) {

			Point[] pList = getArcPointList(arc);

			if (pList !=null) {
				int len = pList.length;
				Stroke stroke = new BasicStroke(8);
				for (int i = 0; i< len -1; i++) {

					Line2D line = new Line2D.Double(pList[i].x, pList[i].y,
							pList[i+1].x, pList[i+1].y);
					Shape shape = stroke.createStrokedShape(line);

					if (shape.contains(pt)) {
						return arc;
					}
				}
			}
		}
		return null;
	}

	/**
	 * 関連線のポイントを追加する
	 * @param p ポイント
	 */
	void addArcPoint(Point p) {
		AssociationArc a = cuMgr.getCurrentArc();
		Point[] pList = getArcPointList(a);
		int poz = getArcClickPoint(pList, p);
		if (poz > -1) {
			a.addPoint(poz+1, p); //取得したポジションの１つ後ろに追加。
		}
	}

	/**
	 * クリックされたポイントの前のポイントを取得する
	 * @param p ポイント
	 * @return int (取得できない場合 -1)
	 */
	protected int getArcClickPoint(Point[] pList, Point pt) {

		if (pList != null) {
			int len = pList.length;
			Stroke stroke = new BasicStroke(8);
			for (int i = 0; i < len - 1; i++) {

				Line2D line = new Line2D.Double(pList[i].x, pList[i].y,
						pList[i + 1].x, pList[i + 1].y);
				Shape shape = stroke.createStrokedShape(line);

				if (shape.contains(pt)) {
					return i;
				}
			}
		}
		return -1;
	}

	/**
	 * 関連線のポイントを削除する
	 * @param poz 削除対象
	 */
	void delArcPoint(int poz) {
		AssociationArc a = cuMgr.getCurrentArc();
		a.delPoint(poz);
	}

	// 関連線のポイントリストを返す
	protected Point[] getArcPointList(AssociationArc arc) {
		ClassNode target = myModel.getClassData(arc.classIdTarget);
		ClassNode source = myModel.getClassData(arc.classIdSource);
		Point[] pList = null;
		if (arc.lineStyle.isSTRAIGHT_LINE()) {
			Point cross1 = Util.calcCrossPoint(target.getRectangle(),
					source.getCenter());
			Point cross2 = Util.calcCrossPoint(source.getRectangle(),
					target.getCenter());

			if (cross1 != null && cross2 != null) {
				pList = new Point[]{cross1, cross2};
			}

		} else if (arc.lineStyle.isRIGHT_ANGLE()) {
			pList = Util.calcRightAngleVPoint(target.getRectangle(), source.getRectangle());
		} else if (arc.lineStyle.isRIGHT_ANGLE_H()) {
			pList = Util.calcRightAngleHPoint(target.getRectangle(), source.getRectangle());

		} else if (arc.lineStyle.isFREE_LINE()) {
			pList = arc.pointList;
		}

		return pList;
	}

	ClassNode addNewClass(Point pt) {

		int id = myModel.getNextClassId();
		ClassNode node = new ClassModel(id, pt);
		myModel.addClass(node);
		return node;
	}

	AssociationArc addNewArc(ClassNode orgNode, ClassNode node, AssocType kind) {
		int id = myModel.getNewAssocId();
		AssociationArc arc = new AssociationArc(id, orgNode.classId, node.classId,
				kind);
		myModel.addAssociation(arc);
		return arc;
	}

	protected Point startPt;
	protected Point endPt;

	void setCurrPoint(Point startPt, Point endPt) {
		this.startPt = startPt;
		this.endPt = endPt;
		myModel.changeModel();
	}

	protected void drawLine(Graphics g, Point p1, Point p2) {
		drawLine(g, p1.x, p1.y, p2.x, p2.y);
	}

	protected void drawLine(Graphics g, int x1, int y1, int x2, int y2) {
		g.drawLine(scaledown(x1), scaledown(y1), scaledown(x2), scaledown(y2));
	}


	protected void drawRect(Graphics g, Rectangle rect) {
		drawRect(g, rect.x, rect.y, rect.width, rect.height);
	}

	protected void drawRect(Graphics g, int x, int y, int w, int h) {
		x = scaledown(x);
		y = scaledown(y);
		w = scaledown(w);
		h = scaledown(h);
		g.drawRect(x, y, w, h);
	}

	private void fillRect(Graphics g, int x, int y, int w, int h) {
		x = scaledown(x);
		y = scaledown(y);
		w = scaledown(w);
		h = scaledown(h);
		g.fillRect(x, y, w, h);
	}

	protected void drawKnob(Graphics g, int x, int y) {
		x = scaledown(x);
		y = scaledown(y);
		int z = KNOB_SIZE;
		g.fillRect(x - z / 2, y - z / 2, z, z);

	}

	private void fillOval(Graphics g, int x, int y, int z) {
		x = scaledown(x);
		y = scaledown(y);
		z = scaledown(z);
		g.fillOval(x - z / 2, y - z / 2, z, z);
	}

	private void drawOval(Graphics g, int x, int y, int z) {
		x = scaledown(x);
		y = scaledown(y);
		z = scaledown(z);
		g.drawOval(x - z / 2, y - z / 2, z, z);
	}

	private void fillPolygon(Graphics g, int[] x) {
		g.fillPolygon(new int[] { scaledown(x[0]), scaledown(x[1]),
								  scaledown(x[2]) },
					  new int[] { scaledown(x[3]), scaledown(x[4]),
								  scaledown(x[5]) }, 3);
	}

	private void drawPolygon(Graphics g, int[] x) {
		g.drawPolygon(new int[] { scaledown(x[0]), scaledown(x[1]),
								  scaledown(x[2]) },
					  new int[] { scaledown(x[3]), scaledown(x[4]),
								  scaledown(x[5]) }, 3);
	}

	protected int scaledown(int i) {

		return i / scale;
	}

	protected int multiply(int i) {

		return i * scale;
	}

	/**
	 * 自動サイズ調整
	 * 自由な線は、直線へ変更する。
	 */
	public void autoAdjust() {

		for (ClassNode cn : myModel.getAllActiveClassData()) {
			cn.autoAdjust();
		}

		for (AssociationArc a : myModel.getAllActiveAssociationArc()) {
			if (a.lineStyle.isFREE_LINE()) {
				a.lineStyle = AssocLineType.STRAIGHT_LINE;
				a.pointList = null;
			}

		}
	}

	public void setStartPoint(Point pt) {
		pt.x = multiply(pt.x);
		pt.y = multiply(pt.y);
		cuMgr.setStartPoint(pt);
	}

	public void setEndPoint(Point pt) {
		pt.x = multiply(pt.x);
		pt.y = multiply(pt.y);
		cuMgr.setEndPoint(pt);
	}
}
