package j3deditor.bin.editor.tools;

import j3deditor.bin.components.PopupDialog;

import j3deditor.bin.hierarchy.GeometryManipulator;

import j3deditor.bin.hierarchy.J3DeGeometryArray;

import j3deditor.bin.hierarchy.J3DeShape3D;

import j3deditor.bin.util.Utilities;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.media.j3d.GeometryArray;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;


/**
 * Dialog for changing the properties of a geometry.
 * 
 * @author Risto Seene
 */
public class ChangeGeometryDialog extends PopupDialog{

	private GeometryManipulator gm;
	
	private J3DeShape3D object;
	
	private J3DeGeometryArray ga;
	
	private int index;
	
	private JCheckBox byReference;
	
	private JCheckBox interleaved;
	
	private JCheckBox texture;
	
	private JComboBox texType;
	
	private JCheckBox color;
	
	private JComboBox clrType;
	
	private JCheckBox normals;
	
	private JTextField faceCount;
	
	private JLabel vertCount;
	
	private boolean ok;
	

	/**
	 * Creates a dialog for changing the various properties
	 * of the specified geometry.
	 * 
	 * @param object
	 * 	node which contains the geometry
	 * @param index
	 * 	index of the geometry
	 */
	public ChangeGeometryDialog(J3DeShape3D object, int index){
	          this.initDialog(Utilities.image.getImage("icons/geometry.png"), Utilities.translator.translate(this.getClass(), "title"), 400, 220);
		this.object = object;
		this.index = index;
	          this.ga = new J3DeGeometryArray((GeometryArray)(object.getGeometries()[index]));
		
		JPanel panel = new JPanel();
		panel.setLayout(null);
		this.add(panel);
		
	          this.byReference = new JCheckBox("BY REFERENCE", ga.getVertexMode() > 0);
	          byReference.setBounds(60, 20, (int)(byReference.getPreferredSize().getWidth()), (int)(byReference.getPreferredSize().getHeight()));
	          byReference.addActionListener(new ActionListener(){

	                              public void actionPerformed(ActionEvent e){
	                                        updateInterleaved();
	                              }
	                    });
	          panel.add(byReference);

	          this.interleaved = new JCheckBox("INTERLEAVED", ga.getVertexMode() > 1);
	          interleaved.setEnabled(ga.getVertexMode() > 0);
	          interleaved.setBounds(200, 20, (int)(interleaved.getPreferredSize().getWidth()), (int)(interleaved.getPreferredSize().getHeight()));
	          panel.add(interleaved);
		
	          String tex = Utilities.translator.translate(this.getClass(), "texture");
	          texture = new JCheckBox(tex, ga.getTexCoordType() > 0);
	          texture.setBounds(20, 50, 180, (int)(texture.getPreferredSize().getHeight()));
	          texture.addActionListener(new ActionListener(){

	                              public void actionPerformed(ActionEvent e){
	                                        updateTextype();
	                              }
	                    });
	          panel.add(texture);

	          texType = new JComboBox();
	          texType.addItem("2D " + tex);
	          texType.addItem("3D " + tex);
	          texType.addItem("4D " + tex);
	          texType.setSelectedIndex(0);
	          texType.setEnabled(false);
	          texType.setBounds(200, 50, 170, (int)(texture.getPreferredSize().getHeight()));
	          panel.add(texType);
		
		if(ga.getTexCoordType() > 1){
			texType.setEnabled(true);
			texType.setSelectedIndex(ga.getTexCoordType() - 2);
		}

	          String clr = Utilities.translator.translate(this.getClass(), "color");
	          color = new JCheckBox(clr, ga.hasColor());
	          color.setBounds(20, 80, 180, (int)(color.getPreferredSize().getHeight()));
	          color.addActionListener(new ActionListener(){

	                              public void actionPerformed(ActionEvent e){
	                                        updateClrtype();
	                              }
	                    });
	          panel.add(color);
	          
	          clrType = new JComboBox();
	          clrType.addItem(clr + " 3");
	          clrType.addItem(clr + " 4");
	          clrType.setSelectedIndex(0);
	          clrType.setEnabled(false);
	          clrType.setBounds(200, 80, 170, (int)(color.getPreferredSize().getHeight()));
	          panel.add(clrType);
		
		if(ga.hasColor()){
			clrType.setEnabled(true);
			clrType.setSelectedIndex(ga.getColorType() - 3);
		}

	          normals = new JCheckBox(Utilities.translator.translate(this.getClass(), "normals"), ga.hasNormals());
	          normals.setBounds(20, 110, 180, (int)(normals.getPreferredSize().getHeight()));
	          panel.add(normals);

	          JButton ok = new JButton(Utilities.translator.translate(this.getClass(), "ok"));
	          ok.setBounds(100, 160, 100, (int)(ok.getPreferredSize().getHeight()));
	          ok.addActionListener(new ActionListener(){

	                              public void actionPerformed(ActionEvent e){
	                                        setGeometry();
	                              }
	                    });
	          panel.add(ok);

	          JButton cancel = new JButton(Utilities.translator.translate(this.getClass(), "cancel"));
	          cancel.setBounds(205, 160, 100, (int)(cancel.getPreferredSize().getHeight()));
	          cancel.addActionListener(new ActionListener(){

	                              public void actionPerformed(ActionEvent e){
	                                        dispose();
	                              }
	                    });
	          panel.add(cancel);
		
		this.setVisible(true);
	}

	/**
	 * Creates a dialog for changing the size of the
	 * specified geometry.
	 * 
	 * @param gm
	 * 	<code>GeometryManipulator</code> which references the wanted geometry
	 */
	private ChangeGeometryDialog(GeometryManipulator gm){
		this.initDialog(Utilities.image.getImage("icons/geometry.png"), Utilities.translator.translate(this.getClass(), "gSize"), 400, 120);
		this.gm = gm;

		JPanel panel = new JPanel();
		panel.setLayout(null);
		this.add(panel);

		int fCount = gm.getAllVertCount() / gm.getGeometry().getVertexGroupMode();
		this.faceCount = new JTextField(fCount + "", 10);
		faceCount.setBounds(160, 20, 80, (int)(faceCount.getPreferredSize().getHeight()));
		JLabel pCount = new JLabel(Utilities.translator.translate(this.getClass(), "newPolys"), JLabel.RIGHT);
		faceCount.addCaretListener(new CaretListener(){

				public void caretUpdate(CaretEvent e){
					recalculateVertCount();
				}
			});
		pCount.setBounds(20, 20, 135, (int)(faceCount.getPreferredSize().getHeight()));
		panel.add(pCount);
		panel.add(faceCount);
		this.vertCount = new JLabel();
		vertCount.setBounds(245, 20, 125, (int)(faceCount.getPreferredSize().getHeight()));
		recalculateVertCount();
		panel.add(vertCount);

		JButton ok = new JButton(Utilities.translator.translate(this.getClass(), "ok"));
		ok.setBounds(145, 60, 100, (int)(ok.getPreferredSize().getHeight()));
		ok.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					okPressed();
				}
			});
		panel.add(ok);

		this.setVisible(true);
	}

	/**
	 * Updates UI.
	 */
	private void updateInterleaved(){
		if(this.byReference.isSelected()){
			this.interleaved.setEnabled(true);
		}
		else {
			this.interleaved.setSelected(false);
			this.interleaved.setEnabled(false);
		}
	}

	/**
	 * Updates UI.
	 */
	private void updateTextype(){
		if(this.texture.isSelected()){
			this.texType.setEnabled(true);
		}
		else {
			this.texType.setEnabled(false);
		}
	}

	/**
	 * Updates UI.
	 */
	private void updateClrtype(){
		if(this.color.isSelected()){
			this.clrType.setEnabled(true);
		}
		else {
			this.clrType.setEnabled(false);
		}
	}

	/**
	 * Changes the geometry of the specified SHape3D node.
	 */
	private void setGeometry(){
		try{
			int vertexFormat = GeometryArray.COORDINATES;
			
			if(this.byReference.isSelected()){
				vertexFormat = vertexFormat | GeometryArray.BY_REFERENCE;
				if(this.interleaved.isSelected()){
					vertexFormat = vertexFormat | GeometryArray.INTERLEAVED;
				}
			}
			
			if(this.texture.isSelected()){
				if(this.texType.getSelectedIndex() == 0){
					vertexFormat = vertexFormat | GeometryArray.TEXTURE_COORDINATE_2;
				}
			          else if(this.texType.getSelectedIndex() == 1){
			                    vertexFormat = vertexFormat | GeometryArray.TEXTURE_COORDINATE_3;
			          }
			          else if(this.texType.getSelectedIndex() == 2){
			                    vertexFormat = vertexFormat | GeometryArray.TEXTURE_COORDINATE_4;
			          }
			}
			
			if(this.color.isSelected()){
				if(this.clrType.getSelectedIndex() == 0){
					vertexFormat = vertexFormat | GeometryArray.COLOR_3;
				}
			          else if(this.clrType.getSelectedIndex() == 1){
			                    vertexFormat = vertexFormat | GeometryArray.COLOR_4;
			          }
			}
			if(this.normals.isSelected()){
				vertexFormat = vertexFormat | GeometryArray.NORMALS;
			}
			
			J3DeGeometryArray geometry = ga.changeGeometryType(vertexFormat);
			this.object.setGeometry(geometry, this.index);
			
			this.dispose();
		} catch(Throwable t){
			Utilities.out.throwError(t);
		}
	}

	/**
	 * Updates UI.
	 */
	private void recalculateVertCount(){
		int polyCount = 0;
		int faceSize = this.gm.getGeometry().getVertexGroupMode();

		try{
			polyCount = Integer.parseInt(this.faceCount.getText());
		} catch(Throwable t){
		}
		int vertCount = polyCount * faceSize;
		if(vertCount < 0){
			vertCount = 0;
		}
		this.vertCount.setText("(" + vertCount + " " + Utilities.translator.translate(this.getClass(), "verts") + ")");
	}

	/**
	 * Disposes this dialog.
	 */
	private void okPressed(){
		ok = true;
		dispose();
	}

	/**
	 * Returns the new size of the geometry.
	 * 
	 * @return the new size of the geometry
	 */
	private int getGSize(){
		if(ok){
			int faceCount = -1;
			try{
				faceCount = Integer.parseInt(this.faceCount.getText());
			} catch(Throwable t){
				String info = Utilities.translator.translate(this.getClass(), "invalidFC");
				Utilities.out.throwWarning(info);
			}
			return faceCount;
		}
		return -1;
	}

	/**
	 * Creates a dialog for changing vertex count of the
	 * specified geometry.
	 * 
	 * @param gm
	 * 	<code>GeometryManipulator</code> which references to the
	 *        geometry that will be changed
	 * @return new face count entered by user.<br/>
	 * 	face count = vertex count * face size
	 */
	public static int askNewFaceCount(GeometryManipulator gm){
		return new ChangeGeometryDialog(gm).getGSize();
	}
	
}
