package FDATI;

import java.awt.*;
import java.util.Vector;
import SModeling.*;

/**
 * Panel which contains the displayed model and controls for adding/removing
 * fixture points, specifying analysis options and submitting the added fixture
 * points for stability analysis.<p>
 * 
 * <hr>
 * Copyright (c) 1995, H. Robert Frost, Stanford University.
 * All rights reserved.<p>
 * Copyright (c) 1996, H. Robert Frost, Enterprise Integration Technologies,
 * Inc. All rights reserved.<p>
 *
 * RESTRICTED RIGHTS LEGEND: Use, duplication or disclosure by the 
 * Government is subject to restrictions as set forth in 
 * subparagraph(c)(1)(ii) of the Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 and in similar clauses in the
 * FAR and NASA FAR supplement.<p>
 * 
 * This software is bound by the terms and conditions listed in the
 * attached <a href="../LICENSE">LICENSE file</A>.
 * <hr>
 * @author <A HREF="http://cdr.stanford.edu/html/people/frost-bio.html"> Rob Frost</A>
 * @version 0.3 5/21/96 for Java(tm) Language Version 1.0.2
 */

public class ModelPanel extends Panel{
  
  Panel ModelDisplayPanel = new Panel();
  Panel XTranslationPanel = new Panel();
  Panel YTranslationPanel = new Panel();
  Panel ZoomModePanel = new Panel();
  Panel FixelPanel = new Panel();
  Panel ActionPanel = new Panel();

  Label NumFixels = new Label("# Fixels: 0");
  Label FixelNum = new Label("Current Fixel: 0");
  Button ModeButton =  new Button("Rotation Mode");
  Label DimLabel = new Label("Dim: 3D");
  Label DirLabel = new Label("Dir: Form Closure");
  Label DirVecLabel = new Label("i: NA, j: NA, k: NA");
  Label ModeInstructions = new Label("Shift-click to add fixels.");
  Label XYZ = new Label("x: y: z: ");
  Label IJK = new Label("i: j: k: ");

  Button ZoomIn = new Button("Zoom In");
  Button ZoomOut = new Button("Zoom Out");
  Button UpFixel = new Button("Up Fixel");
  Button DownFixel = new Button("Down Fixel");
  Button RemoveFixel = new Button("Remove");
  Button UpY = new Button("+ Y");
  Button DownY = new Button("- Y");
  Button UpX = new Button("+ X");
  Button DownX = new Button("- X");
  Button AnalysisOptions = new Button("Analysis Options");
  Button DisplayOptions = new Button("Display Options");
  Button Submit= new Button("Submit");
  Button Quit= new Button("Quit");


  static final int md_width = 400;
  static final int md_height = 450;
  static final int fx_width = 100;
  static final int fx_height = 450;
  static final int ac_width = 400;
  static final int ac_height = 100;
  static final int ap_width = 300;
  static final int ap_height = 150;
  static final int dp_width = 425;
  static final int dp_height = 150;
  static final int rp_width = 300;
  static final int rp_height = 400;

  boolean mode = true; // true for rotation, false for fixel selection
  public FDATI parent;
  model M;
  Vector fixels = new Vector();
  ModelViewer viewer;
  String dimensionality = "3D";
  String directionality = "Form Closure";
  hpoint direction_vector = new hpoint(1,0,0,1);
  Color bg_color;
  Color button_color;
  String name;

  /**
   * Holds a reference to all top level frames created by this frame.
   * (AnalysisOptions, DisplayOptions, etc.).
   */
  
  Vector frames = new Vector();


  /**
   * Creates a new ModelPanel from the specified FDATIapplet for the specified
   * model.
   * @param p FDATI from which this ModelPanel was created
   * @param m Model to be displayed
   * @param name Name of the model
   */

  public ModelPanel( FDATI p, model m, String name, Color bg, Color button) {
    
    super();
    bg_color = bg;
    button_color = button;
    parent = p;
    M = m;
    this.name = name;
    viewer = new ModelViewer(M,this, bg_color);
    
    setLayout(new BorderLayout());  
    
    setBackground(bg_color);
    
    ZoomIn.setBackground(button_color);
    ZoomOut.setBackground(button_color);
    UpFixel.setBackground(button_color);
    DownFixel.setBackground(button_color);
    RemoveFixel.setBackground(button_color);
    UpY.setBackground(button_color);
    DownY.setBackground(button_color);
    UpX.setBackground(button_color);
    DownX.setBackground(button_color);
    AnalysisOptions.setBackground(button_color);
    DisplayOptions.setBackground(button_color);
    Submit.setBackground(button_color);
    Quit.setBackground(button_color);

    ActionPanel.setLayout(new BorderLayout());
    Panel ButtonPanel = new Panel();
    ButtonPanel.setLayout(new FlowLayout());
    ButtonPanel.add(AnalysisOptions);
    ButtonPanel.add(DisplayOptions);
    ButtonPanel.add(Submit);    
    ButtonPanel.add(Quit);
    ActionPanel.add("North", ButtonPanel);
    
    FixelPanel.setLayout(new GridLayout(10,1));
    FixelPanel.add(UpFixel);
    FixelPanel.add(DownFixel);
    FixelPanel.add(RemoveFixel);
    FixelPanel.add(NumFixels);
    FixelPanel.add(FixelNum);
    FixelPanel.add(XYZ);
    FixelPanel.add(IJK);
    FixelPanel.add(DimLabel);
    FixelPanel.add(DirLabel);
    FixelPanel.add(DirVecLabel);
    
    ModelDisplayPanel.setLayout(new BorderLayout());
    ModelDisplayPanel.add("North", ZoomModePanel);
    //md.resize(200,200);
    ModelDisplayPanel.add("Center", viewer);
    ModelDisplayPanel.add("South", XTranslationPanel);
    ModelDisplayPanel.add("East", YTranslationPanel);
    
    ZoomModePanel.setLayout(new FlowLayout());
    ZoomModePanel.add(ZoomOut);
    ZoomModePanel.add(ZoomIn);
    
    XTranslationPanel.setLayout(new FlowLayout());
    XTranslationPanel.add(ModeInstructions);
    XTranslationPanel.add(DownX);
    XTranslationPanel.add(UpX);
    
    YTranslationPanel.setLayout(new GridLayout(2,1));
    YTranslationPanel.add(DownY);
    YTranslationPanel.add(UpY);
    
    add("Center", ModelDisplayPanel);
    add("East", FixelPanel);
    add("South", ActionPanel);
    
  }

  /**
   * Adds a string message to the ModelPanel's TextArea.
   * @param message Message to display.
   */

  public void addSystemMessage(String message){
    parent.addSystemMessage(message);
  }
  
  
  public boolean action(Event evt, Object arg) {
    
    if("Quit".equals(arg)) {
      stop();
    } else if("Submit".equals(arg)) {
      SubmitAction();
    } else if("Analysis Options".equals(arg)) {
      AnalysisAction();
    } else if("Display Options".equals(arg)) {
      DisplayOptionsAction();
    } else if("Up Fixel".equals(arg)) {
      UpAction();
    } else if("Down Fixel".equals(arg)) {
      DownAction();
    } else if("Remove".equals(arg)) {
      RemoveAction();
    } else if("Zoom Out".equals(arg)) {
      ZoomOutAction();
    } else if("Zoom In".equals(arg)) {
      ZoomInAction();
    } else if(evt.target == ModeButton){
      ModeAction();
    } else if("- X".equals(arg)) {
      MinusXAction();
    } else if("+ X".equals(arg)) {
      PlusXAction();
    } else if("- Y".equals(arg)) {
      MinusYAction();
    } else if("+ Y".equals(arg)) {
      PlusYAction();
    } else {
      addSystemMessage(evt.toString() + (String)arg);
    }
 
    
    return true;
  }

  void ModeAction(){
    if(mode){ /* change to fixel selection */
      mode = false;
      ModeButton.setLabel("Fixel Selection");
    } else { /* change to rotation mode */
      mode = true;
      ModeButton.setLabel("Rotation");
    }
    viewer.changeMode(mode);
  }

  protected void stop(){
    Frame f = (Frame)getParent();
    f.dispose();
    for(int i = 0; i < frames.size(); i++){
      ((Frame)frames.elementAt(i)).dispose();
    }
    M.reset();
  }

  /**
   * Called by a child frame to remove itself from the frames list.
   */
  public void removeFrame(Frame child){
    if(frames.contains(child)){
      frames.removeElement(child);
    }
  }

  void AnalysisAction(){
    Frame f = new Frame("Analysis Options");
    frames.addElement(f);
    AnalysisPanel ap = new AnalysisPanel(this, bg_color, button_color);
    ap.resize(ap_width, ap_height);
    f.add("Center", ap);
    f.resize(ap_width, ap_height);
    f.show();
  }
    
  /**
   * Sets the dimensionality analysis option.
   * @param dim String representing the dimensionality, either "3D" or
   * "planar"
   */

  public void setDim(String dim){
    dimensionality = dim;
    DimLabel.setText("Dim: " +dim);
  }

  /**
   * Sets the directionality analysis option.
   * @param dim String representing the directionality, either "Form Closure"
   * or "Directional"
   */

  public void setDir(String dir){
    directionality = dir;
    DirLabel.setText("Dir: " +dir);
    if(dir.equals("Directional")){
      viewer.MD.setDirection(true, direction_vector);
    } else {
      viewer.MD.setDirection(false, direction_vector);
    }
  }

  /**
   * Sets the direction vector for directional analysis.
   * @param vec An hpoint vector.
   */

  public void setDirVec(hpoint vec){
    direction_vector = vec;
    DirVecLabel.setText("i: " + (int)vec.getx() + "j: " + (int)vec.gety() +
		     "k: " + (int)vec.getz());
  }

  void DisplayOptionsAction(){
    Frame f = new Frame("Display Options");
    frames.addElement(f);
    DisplayPanel dp = new DisplayPanel(this, bg_color, button_color);
    dp.resize(dp_width, dp_height);
    f.add("Center", dp);
    f.resize(dp_width, dp_height);
    f.show();
  }
  
  /**
   * Changes the display options. If both edge and render are false, the 
   * model will be rendered.
   * @param edge Should edges be shown?
   * @param render Should faces be rendered?
   * @param light Direction of light vector, one of "north", "south", "east"
   * or "west".
   */

  public void setDisplayOptions(boolean edge, boolean render, String light){
    //viewer.change_culling(Culling.getState());
    viewer.set_edge(edge);
    viewer.set_render(render || (!edge && !render));
    viewer.MD.set_light(light.equals("north"),light.equals("south"),light.equals("east"),light.equals("west"));
    viewer.repaint();
  }
  
  void SubmitAction(){
    parent.submit_fixels(name,directionality,dimensionality,
			 direction_vector,M);
  }
  
  void UpAction(){
    if (viewer.M.current_point < viewer.numPoints()) {
      viewer.M.current_point++;
      viewer.repaint();
      UpdatePoints();
    }
  }
  
  void DownAction(){
    if (viewer.M.current_point > 1) {
      viewer.M.current_point--;
      viewer.repaint();
      UpdatePoints();
    }
  } 
  
  void RemoveAction(){
    if( viewer.M.current_point > 0) {
      viewer.modifyPoint();
      viewer.M.current_point--;
      if(viewer.numPoints() > 0 && viewer.M.current_point == 0) {
	viewer.M.current_point = 1;
      }
      viewer.repaint();
      UpdatePoints();
    } else { 
      addSystemMessage("No fixels to modify!");
    }
  }
        
  void UpdatePoints () {
    int l = 4;

    FixelNum.setText("Fixel #" + viewer.M.current_point);
    NumFixels.setText("# Fixels: " + viewer.numPoints());

    if(viewer.numPoints() > 0){
      fix_point fixel =
	(fix_point)viewer.M.fix_points.elementAt(viewer.M.current_point -1);
      XYZ.setText("x: " + getFloatString(fixel.x(),l) +
		  "y: " + getFloatString(fixel.y(),l) +
		  "z: " + getFloatString(fixel.z(),l));
      IJK.setText("i: " + getFloatString(viewer.M.get_dircos(fixel, 1),l) +
		  "j: " + getFloatString(viewer.M.get_dircos(fixel, 2),l) +
		  "k: " + getFloatString(viewer.M.get_dircos(fixel, 3),l));
    } else {
      XYZ.setText("x: y: z: ");
      IJK.setText("i: j: k: ");
    }
  }

  String getFloatString(float f, int max_length){
    String answer = String.valueOf(f);
    if(answer.length() > max_length){
      answer = answer.substring(0,max_length);
    }
    return answer;
  }


  void ZoomOutAction(){
    float sf = (float).7;
    viewer.MD.Mat.scale(sf,sf,sf,true);
    viewer.repaint();
  }
  
  void ZoomInAction(){
    float sf = (float)1.3;
    viewer.MD.Mat.scale(sf,sf,sf,true);
    viewer.repaint();
  }

  void MinusXAction(){
    viewer.MD.deltax -= 30;
    viewer.repaint();
  }
  
  void PlusXAction(){
    viewer.MD.deltax += 30;
    viewer.repaint();
  }
  
  void MinusYAction(){
    viewer.MD.deltay -= 30;
    viewer.repaint();
  }
  
  void PlusYAction(){
    viewer.MD.deltay += 30;
    viewer.repaint();
  }
  
  /**
   * Called by ModelViewer when fixture points have been added or another
   * message event has occured (usually debugging event).
   * @param viewer AppModelViewer which has called the action method
   * @param message Message being sent by viewer
   */
  
  public void action(ModelViewer viewer, String message) {
    
    if( message.startsWith("Fixture")) { /* Fixture point has been added */
      
	 viewer.M.current_point = viewer.numPoints();
	 UpdatePoints();
	 	
    }
    addSystemMessage(message);
  }

}












