/*
 * 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 PURPOUSE. See the GNU
 * General Public License for more details.
 *
 * You should have recieved a copy of the GNU General Public License
 * along with this program; if not write to the Free Software
 * Foundation, inc., 59 Temple Place, Suite 330, Boston MA 02111-1307
 * USA */

/*
 * Basis for this code was written by ocnus.com
 *
 * NurbsCurve.java
 *
 * author   Timothy F. Rohaly / Jonas Forssell, Yuriy Mikhaylovskiy
 */
package j3d;
import java.awt.*;
import java.io.*;
import javax.swing.tree.*;
import j3d.nurbs.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.table.*;
import gui.*;

/**
 * Implementing the NurbsCurve prototype.
 * @author   Timothy F. Rohaly / Jonas Forssell, Yuriy Mikhaylovskiy
 */
public class _NurbCurve implements _Object, Serializable{
  public Color color;
  protected String Id;
  protected int order;
  protected int div=5;
  protected boolean selected = false;
  protected int numKnots;
  public _Point[] mesh;
  public _CtrlPoint[] controlPoints;
  protected Nurbs curve;
  protected float[] knots;
  private Canvas3D J3D;
  private Object[][] dat;
  private String[] hdr;
  private TableModel tableModel;
  private JTable table;


  public _NurbCurve(_CtrlPoint[] cP, int d, Color cl) {
    color = cl;
    div = d;
    controlPoints = cP;
    reset();
  }

  private void writeObject(ObjectOutputStream out)  throws IOException{
    out.writeObject(controlPoints);
    out.writeInt(div);
    out.writeObject(color);
    out.writeObject(mesh);
  }
  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
    controlPoints = (_CtrlPoint[])in.readObject();
    div = in.readInt();
    color = (Color)in.readObject();
    mesh = (_Point[])in.readObject();
    selected = false;
  }


  public void reset(){
    order = 3;
    numKnots = controlPoints.length + order;
    knots = new float[numKnots];
    for (int i=0; i<numKnots; i++)  knots[i] = i;
    knots[0] = 0;
    knots[1] = 0;
    knots[2] = 0;
    knots[numKnots-3] = numKnots-1;
    knots[numKnots-2] = numKnots-1;
    knots[numKnots-1] = numKnots-1;
    generate(div);
  }

  public void generate(int div) {
    //
    // First create the Knots
    //
    int numControlPoints = controlPoints.length;
    int numKnots         = knots.length;
    order = numKnots - numControlPoints;
    Knot u = new Knot(order, numControlPoints);
    u.setKnots(knots);
    numControlPoints =  1;
    numKnots         =  1;
    order            =  0;  // constant
    knots = new float[numKnots];
    knots[0]  = 0.00f;
    Knot v = new Knot(order, numControlPoints);
    v.setKnots(knots);

    //
    // Second create the ControlNet
    //
    Point4[][] points = new Point4[u.getNumControlPoints()][v.getNumControlPoints()];
    for (int i=0; i<u.getNumControlPoints(); i++) {
      for (int j=0; j<v.getNumControlPoints(); j++) {
        // Creates the Point4 objects and initializes them
        int index = j + i*v.getNumControlPoints();
        points[i][j] = new Point4(controlPoints[index].x,controlPoints[index].y,controlPoints[index].z,controlPoints[index].w);
      }
    }
    ControlNet controlNet = new ControlNet(u.getNumControlPoints(), v.getNumControlPoints(), points);

    //
    // Finally we can construct the NURBS
    //
    Nurbs temp = new Nurbs(u, v, controlNet);

    //
    // Now tessellate to desired smoothness
    //
    curve = temp.tessellate(div,0);
    mesh = new _Point[curve.getNumUControlPoints()];
    for (int i=0; i<mesh.length; i++) {
      mesh[i] = curve.toCoordinateNode()[i][0];
    }
  }

  public Object[] get_Array(Canvas3D j3d){
    Object[] arr = new Object[mesh.length-1+controlPoints.length];
    for (int i=0; i<mesh.length-1; i++) {
      arr[i] = new shpLine(mesh[i].x,mesh[i].y,mesh[i].z,mesh[i+1].x,mesh[i+1].y,mesh[i+1].z, selected ? j3d.SELECTCOLOR : color);
    }
    for(int i=mesh.length-1; i<arr.length; i++){
      arr[i]=new shpPoint(controlPoints[i-(mesh.length-1)].x,controlPoints[i-(mesh.length-1)].y,controlPoints[i-(mesh.length-1)].z,controlPoints[i-(mesh.length-1)].selected ? j3d.SELECTCOLOR : color);
    }
    return arr;
  }

  public void mesh(int type, float size){}
  public boolean delete(){return selected;}
  public void Select(String st){ selected=st!=null; for(int i=0; i<controlPoints.length; i++) controlPoints[i].selected=st!=null;}
  public boolean isSelected(){return selected;}
  public String toString(){ return "Nurb Curve ID="+Id;}
  public void transform3D(Matrix3D t){
    if(!selected)return;
    for (int i=0; i<controlPoints.length; i++){
      controlPoints[i].Select("");
      controlPoints[i].transform3D(t);
      controlPoints[i].Select(null);
    }
    reset();
  }

  public MutableTreeNode get_TreeNode(){
    DefaultMutableTreeNode node = new DefaultMutableTreeNode(this);
    //node.add(new DefaultMutableTreeNode("Color"));
    for(int i=0; i<controlPoints.length; i++) node.add(new DefaultMutableTreeNode("X,Y,Z,W ("+controlPoints[i].x+","+controlPoints[i].y+","+controlPoints[i].z+","+controlPoints[i].w+")"));
    return node;
  }

  public String get_Id(){
    return Id;
  }
  public void set_Id(String id){
    Id=id;
  }
  public JPanel getEditPanel(Canvas3D j3d, PreProcessor pp){
    J3D=j3d;
    dat = new Object[100][4];
    hdr = new String[4];
    hdr[0]="X"; hdr[1]="Y"; hdr[2]="Z"; hdr[3]="W";
    tableModel = new AbstractTableModel() {
      public int getColumnCount() { return 4; }
      public int getRowCount() { return 100; }
      public Object getValueAt(int row, int col){ return dat[row][col];}
      public String getColumnName(int col) {return hdr[col];}
      public boolean isCellEditable(int row, int col) {return true;}
      public void setValueAt(Object aValue, int row, int col) { dat[row][col]=aValue;}
      public Class getColumnClass(int c) {return new Float(0).getClass();}
    };
    table = new JTable(tableModel);
    for(int i=0; i<controlPoints.length; i++){
      dat[i][0]=new Float(controlPoints[i].x+"");
      dat[i][1]=new Float(controlPoints[i].y+"");
      dat[i][2]=new Float(controlPoints[i].z+"");
      dat[i][3]=new Float(controlPoints[i].w+"");
    }
    JPanel p = new JPanel(new BorderLayout());
    JPanel p1 = new JPanel(new BorderLayout());
    JPanel p2 = new JPanel();
    JScrollPane sp = new JScrollPane();
    sp.setPreferredSize(new Dimension(180, 200));
    JButton b_up = new JButton("Update");
    b_up.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        int n = 0;
        for(n=0; (n<dat.length && dat[n][0]!=null && dat[n][1]!=null && dat[n][2]!=null && dat[n][3]!=null); n++){}
        controlPoints = new _CtrlPoint[n];
        for(int i=0; i<n; i++) controlPoints[i]=new _CtrlPoint(Float.parseFloat(""+dat[i][0]),Float.parseFloat(""+dat[i][1]),Float.parseFloat(""+dat[i][2]),Float.parseFloat(""+dat[i][3]),color);
        reset();
        J3D.tree_reset();
        J3D.view_reset();
      }
    });
    JLabel lb = new JLabel("Edit - "+toString());
    lb.setForeground(Color.blue);
    p.add(sp, BorderLayout.CENTER);
    p.add(p1, BorderLayout.SOUTH);
    p1.add(p2, BorderLayout.CENTER);
    p2.add(b_up, null);
    p.add(lb, BorderLayout.NORTH);
    sp.getViewport().add(table, null);
    p.validate();
    return p;
  }
  public _Node[] get_Nodes(){return null;}
  public _Object[] get_Elements(){return null;}

}

