/*
 * Copyright (C) 2004-05  Mike Murray
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License (version 2)
 *  as published by the Free Software Foundation.
 *
 *  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 net.sf.j3d.threeD.raytracer.surfaceUI;

import java.awt.Graphics;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import net.sf.j3d.threeD.raytracer.camera.Camera;
import net.sf.j3d.threeD.raytracer.engine.AbstractSurface;
import net.sf.j3d.threeD.raytracer.engine.SurfaceGroup;
import net.sf.j3d.threeD.raytracer.primitives.Cone;
import net.sf.j3d.threeD.raytracer.primitives.Cylinder;
import net.sf.j3d.threeD.raytracer.primitives.Mesh;
import net.sf.j3d.threeD.raytracer.primitives.Plane;
import net.sf.j3d.threeD.raytracer.primitives.Polynomial;
import net.sf.j3d.threeD.raytracer.primitives.Sphere;
import net.sf.j3d.threeD.raytracer.primitives.Triangle;
import net.sf.j3d.threeD.ui.dialogs.Dialog;
import net.sf.j3d.threeD.ui.dialogs.EditPlaneDialog;
import net.sf.j3d.threeD.ui.dialogs.EditPolynomialDialog;
import net.sf.j3d.threeD.ui.dialogs.EditTriangleDialog;


// TODO  Add Mesh dialog that allows user to configure space partition.

/**
 * The SurfaceUIFactory class provides static methods for creating SurfaceUI instances.
 * 
 * @author Mike Murray
 */
public class SurfaceUIFactory {
	// TODO  Add getIcon method.
	public static class SurfaceUIImpl extends AbstractSurfaceUI {
		private String type;
		private Class dialog;
		
		public SurfaceUIImpl() { }
		
		public SurfaceUIImpl(AbstractSurface s, String type, Class dialog) {
			super(s, "Surface");
			
			this.type = type;
			this.dialog = dialog;
		}
		
		public void setType(String type) { this.type = type; }
		
		public void setDialogClass(Class dialog) { this.dialog = dialog; }
		
		public Class getDialogClass() { return this.dialog; }
		
		/**
		 * @see net.sf.j3d.threeD.raytracer.surfaceUI.SurfaceUI#hasDialog()
		 */
		public boolean hasDialog() { return (this.dialog != null); }
		
		public Dialog getDialog() {
		    try {
		        Constructor c = this.dialog.getConstructor(new Class[] {SurfaceUI.class});
		        return (Dialog)c.newInstance(new Object[] {this});
		    } catch (IllegalArgumentException iae) {
		        System.out.println("SurfaceUIImpl.getDialog: " + iae);
            } catch (InvocationTargetException ite) {
                System.out.println("SurfaceUIImpl.getDialog: " + ite);
            } catch (Exception e) {}
            
            try {
                return (Dialog)this.dialog.newInstance();
            } catch (Exception e) {
                return null;
            }
		}
		
		/**
		 * @see net.sf.j3d.threeD.raytracer.surfaceUI.SurfaceUI#getType()
		 */
		public String getType() { return this.type; }
		
		/**
		 * Does nothing.
		 * Perhaps someday this will be a useful method...
		 * 
		 * @see net.sf.j3d.threeD.raytracer.surfaceUI.SurfaceUI#draw(java.awt.Graphics, net.sf.j3d.threeD.raytracer.engine.Camera)
		 */
		public void draw(Graphics g, Camera camera) {}
	}
	
  private static final Class typeClasses[] = {Mesh.class,
  												Cone.class,
  												Cylinder.class,
												Plane.class,
												Polynomial.class,
												Sphere.class,
												Triangle.class,
												SurfaceGroup.class};
  private static final String typeNames[] = {"Mesh",
  												"Primitive Cone",
  												"Primitive Cylinder",
												"Primitive Plane",
												"Primitive Polynomial",
												"Primitive Sphere",
												"Primitive Triangle",
												"Group"};
  private static final Class dialogTypes[] = {null,
          										null,
          										null,
          										EditPlaneDialog.class,
          										EditPolynomialDialog.class,
          										null,
          										EditTriangleDialog.class,
          										null};
	
	/**
	 * Private constructor to insure that this class is not instanciated.
	 */
	private SurfaceUIFactory() {}
	
	/**
	 * @param s  AbstractSurface object to wrap.
	 * @return  An AbstractSurfaceUI implementation that wraps the AbstractSurface specified.
	 */
	public static AbstractSurfaceUI createSurfaceUI(AbstractSurface s) {
		String type = "Surface";
		Class dialog = null;
		
		i: for (int i = 0; i < SurfaceUIFactory.typeClasses.length; i++) {
			if (s.getClass().equals(SurfaceUIFactory.typeClasses[i])) {
				type = SurfaceUIFactory.typeNames[i];
				dialog = SurfaceUIFactory.dialogTypes[i];
				break i;
			}
		}
		
		return new SurfaceUIImpl(s, type, dialog);
	}
	
	/**
	 * Creates a new Surface implementation of the type given by the specified index
	 * into the array returned by the getSurfaceTypeNames method.
	 * 
	 * @param nameIndex  Index into array given by getSurfaceTypeNames that corresponds to the Surface object to construct.
	 * @return  An AbstractSurfaceUI implementation that wraps the surface specified.
	 */
	public static AbstractSurfaceUI createSurfaceUI(int nameIndex) {
		try {
			return new SurfaceUIImpl((AbstractSurface)SurfaceUIFactory.typeClasses[nameIndex].newInstance(),
										SurfaceUIFactory.typeNames[nameIndex], SurfaceUIFactory.dialogTypes[nameIndex]);
		} catch (InstantiationException ie) {
			System.out.println("SurfaceUIFactory: " + ie);
		} catch (IllegalAccessException iae) {
			System.out.println("SurfaceUIFactory: " + iae);
		}
		
		return null;
	}
	
	/**
	 * @return  An array containing the surface type names in order.
	 */
	public static String[] getSurfaceTypeNames() {
		return SurfaceUIFactory.typeNames;
	}
}
