/* Copyright (C) 1999-2004 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY 
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */

package artofillusion;

import artofillusion.animation.*;
import artofillusion.math.*;
import artofillusion.object.*;
import artofillusion.ui.*;
import buoy.event.*;
import java.awt.*;
import java.util.Vector;

/** CreateCurveTool is an EditingTool used for creating Curve objects. */

public class CreateCurveTool extends EditingTool
{
  Image icon, selectedIcon;
  static int counter = 1;
  Point lastPoint;
  Vector clickPoint, smoothness;
  int smoothing;
  Curve theCurve;
  CoordinateSystem coords;

  public static final int HANDLE_SIZE = 3;

  public CreateCurveTool(EditingWindow fr, int smoothingMethod)
  {
    super(fr);
    if (smoothingMethod == Curve.INTERPOLATING)
      {
        icon = loadImage("interpCurve.gif");
        selectedIcon = loadImage("selected/interpCurve.gif");
      }
    else
      {
        icon = loadImage("approxCurve.gif");
        selectedIcon = loadImage("selected/approxCurve.gif");
      }
    smoothing = smoothingMethod;
  }

  public void activate()
  {
    super.activate();
    theWindow.setHelpText(Translate.text("createCurveTool.helpText"));
  }

  public void deactivate()
  {
    addToScene();
  }

  public int whichClicks()
  {
    return ALL_CLICKS;
  }

  public Image getIcon()
  {
    return icon;
  }

  public Image getSelectedIcon()
  {
    return selectedIcon;
  }

  public String getToolTipText()
  {
    if (smoothing == Curve.INTERPOLATING)
      return Translate.text("createCurveTool.tipText.interpolating");
    else
      return Translate.text("createCurveTool.tipText.approximating");
  }

  public boolean hilightSelection()
  {
    return (clickPoint == null);
  }
  
  public void drawOverlay(Graphics g, ViewerCanvas view)
  {
    Scene theScene = ((LayoutWindow) theWindow).getScene();
    Camera cam = view.getCamera();
    Point p1, p2;
    int i;

    if (clickPoint == null)
      return;
    g.setPaintMode();
    g.setColor(Color.black);
    if (theCurve != null)
      Object3D.draw(g, cam, theCurve.getWireframeMesh(), theCurve.getBounds());
    g.setColor(Color.red);
    for (i = 0; i < clickPoint.size(); i++)
      {
	p1 = (Point) clickPoint.elementAt(i);
	g.fillRect(p1.x-HANDLE_SIZE/2, p1.y-HANDLE_SIZE/2, HANDLE_SIZE, HANDLE_SIZE);
      }
  }
  
  public void mousePressed(WidgetMouseEvent e, ViewerCanvas view)
  {
    Graphics g = view.getComponent().getGraphics();
    Point p;
    
    lastPoint = e.getPoint();
    if (clickPoint == null)
      {
	clickPoint = new Vector();
	smoothness = new Vector();
	((SceneViewer) view).drawImage(g);
      }
    else
      {
	g.setXORMode(Color.white);
	p = (Point) clickPoint.lastElement();
	g.drawLine(p.x, p.y, lastPoint.x, lastPoint.y);
      }
    g.dispose();
  }
  
  public void mouseDragged(WidgetMouseEvent e, ViewerCanvas view)
  {
    Graphics g;
    Point p, dragPoint = e.getPoint();

    if (clickPoint.size() == 0)
      return;
    g = view.getComponent().getGraphics();
    g.setXORMode(Color.white);
    p = (Point) clickPoint.lastElement();
    g.drawLine(p.x, p.y, lastPoint.x, lastPoint.y);
    g.drawLine(p.x, p.y, dragPoint.x, dragPoint.y);
    lastPoint = dragPoint;
    g.dispose();
  }

  public void mouseReleased(WidgetMouseEvent e, ViewerCanvas view)
  {
    Graphics g = view.getComponent().getGraphics();
    Camera cam = view.getCamera();
    Point p, dragPoint = e.getPoint();
    Vec3 vertex[], orig, ydir, zdir;
    float s[];
    int i;

    if (e.getClickCount() != 2)
      {
	clickPoint.addElement(dragPoint);
	smoothness.addElement(new Float(e.isShiftDown() ? 0.0f : 1.0f));
      }
    if (clickPoint.size() > 1)
      {
	// Create a new line object.  First, find all the points in world coordinates.
	    
	vertex = new Vec3 [clickPoint.size()];
	s = new float [clickPoint.size()];
	orig = new Vec3();
	for (i = 0; i < vertex.length; i++)
	  {
	    vertex[i] = cam.convertScreenToWorld((Point) clickPoint.elementAt(i), ModellingApp.DIST_TO_SCREEN);
	    s[i] = ((Float) smoothness.elementAt(i)).floatValue();
	    orig = orig.plus(vertex[i]);
	  }
	orig = orig.times(1.0/vertex.length);

	// Find the object's coordinate system.

        ydir = cam.getViewToWorld().timesDirection(Vec3.vy());
        zdir = cam.getViewToWorld().timesDirection(new Vec3(0.0, 0.0, -1.0));
        coords = new CoordinateSystem(orig, zdir, ydir);
	    
	// Transform all of the vertices into the object's coordinate system.
	    
	for (i = 0; i < vertex.length; i++)
	  {
	    vertex[i] = coords.toLocal().times(vertex[i]);
	    vertex[i].z = 0.0;  // Prevent round-off error.
	  }
	theCurve = new Curve(vertex, s, smoothing, false);
	if (e.getClickCount() == 2)
	  {
	    theCurve.setClosed(e.isControlDown());
	    addToScene();
	    g.dispose();
	    return;
	  }
	cam.setObjectTransform(coords.fromLocal());
      }
    view.drawImage(g);
    drawOverlay(g, view);
    g.dispose();
  }
  
  /** When the user presses Enter, add the curve to the scene. */
  
  public void keyPressed(KeyPressedEvent e, ViewerCanvas view)
  {
    if (e.getKeyCode() == KeyPressedEvent.VK_ENTER)
      {
        theCurve.setClosed(e.isControlDown());
        addToScene();
      }
  }

  /** Add the curve to the scene. */
  
  private void addToScene()
  {
    if (theCurve != null)
      {
	ObjectInfo info = new ObjectInfo(theCurve, coords, "Curve "+(counter++));
	info.addTrack(new PositionTrack(info), 0);
	info.addTrack(new RotationTrack(info), 1);
	UndoRecord undo = new UndoRecord(theWindow, false);
	((LayoutWindow) theWindow).addObject(info, undo);
	theWindow.setUndoRecord(undo);
	((LayoutWindow) theWindow).setSelection(((LayoutWindow) theWindow).getScene().getNumObjects()-1);
      }
    clickPoint = null;
    smoothness = null;
    theCurve = null;
    coords = null;
    theWindow.updateImage();
  }
}