package Savage.Tools.Animation;

import org.web3d.x3d.jsail.Core.*;
import org.web3d.x3d.jsail.fields.*;
import org.web3d.x3d.jsail.Geometry3D.*;
import org.web3d.x3d.jsail.Grouping.*;
import org.web3d.x3d.jsail.Networking.*;
import org.web3d.x3d.jsail.Rendering.*;
import org.web3d.x3d.jsail.Scripting.*;
import org.web3d.x3d.jsail.Shape.*;
import org.web3d.x3d.jsail.Text.*;

// Javadoc metadata annotations follow, see below for X3DJSAIL Java source code.
/**
 * <p> This prototype generates bathymetry based on the input data using IndexedFaceSet. </p>
 <p> Related links: Catalog page <a href="../../../../Tools/Animation/BathymetryGeneratorPrototypeIndex.html" target="_blank">BathymetryGeneratorPrototype</a>,  source <a href="../../../../Tools/Animation/BathymetryGeneratorPrototype.java">BathymetryGeneratorPrototype.java</a>, <a href="https://www.web3d.org/x3d/content/examples/X3dResources.html" target="_blank">X3D Resources</a>, <a href="https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html" target="_blank">X3D Scene Authoring Hints</a>, and <a href="https://www.web3d.org/x3d/content/X3dTooltips.html" target="_blank">X3D Tooltips</a>. </p>
	<table style="color:black; border:0px solid; border-spacing:10px 0px;">
        <caption>Scene Meta Information</caption>
		<tr style="background-color:silver; border-color:silver;">
			<td style="text-align:center; padding:10px 0px;"><i>meta tags</i></td>
			<td style="text-align:left;   padding:10px 0px;">&nbsp; Document Metadata </td>
		</tr>

		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> title </i> </td>
			<td> <a href="../../../../Tools/Animation/BathymetryGeneratorPrototype.x3d">BathymetryGeneratorPrototype.x3d</a> </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> description </i> </td>
			<td> This prototype generates bathymetry based on the input data using IndexedFaceSet. </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> creator </i> </td>
			<td> Don Brutzman, Jane Wu </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> created </i> </td>
			<td> 8 February 2002 </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> modified </i> </td>
			<td> 28 November 2019 </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> subject </i> </td>
			<td> bathymetry </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> identifier </i> </td>
			<td> <a href="https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorPrototype.x3d" target="_blank">https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorPrototype.x3d</a> </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> generator </i> </td>
			<td> X3D-Edit 3.2, <a href="https://www.web3d.org/x3d/tools/X3D-Edit" target="_blank">https://www.web3d.org/x3d/tools/X3D-Edit</a> </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> license </i> </td>
			<td> <a href="../../../../Tools/Animation/../../license.html">../../license.html</a> </td>
		</tr>
		<tr style="background-color:silver; border-color:silver;">
			<td style="text-align:center;" colspan="2">  &nbsp; </td>
		</tr>
	</table>

	<p>
		This program uses the
		<a href="https://www.web3d.org/specifications/java/X3DJSAIL.html" target="_blank">X3D Java Scene Access Interface Library (X3DJSAIL)</a>.
		It has been produced using the 
		<a href="https://www.web3d.org/x3d/stylesheets/X3dToJava.xslt" target="_blank">X3dToJava.xslt</a>
		stylesheet
	       (<a href="https://sourceforge.net/p/x3d/code/HEAD/tree/www.web3d.org/x3d/stylesheets/X3dToJava.xslt" target="_blank">version control</a>)
                which is used to create Java source code from an original <code>.x3d</code> model.
	</p>

	* @author Don Brutzman, Jane Wu
 */

public class BathymetryGeneratorPrototype
{
	/** Default constructor to create this object. */
	public BathymetryGeneratorPrototype ()
	{
	  initialize();
	}

	/** Create and initialize the X3D model for this object. */
	public final void initialize()
	{
            try { // catch-all
  x3dModel = new X3D().setProfile(X3D.PROFILE_IMMERSIVE).setVersion(X3D.VERSION_3_0)
  .setHead(new head()
    .addMeta(new meta().setName(meta.NAME_TITLE      ).setContent("BathymetryGeneratorPrototype.x3d"))
    .addMeta(new meta().setName(meta.NAME_DESCRIPTION).setContent("This prototype generates bathymetry based on the input data using IndexedFaceSet."))
    .addMeta(new meta().setName(meta.NAME_CREATOR    ).setContent("Don Brutzman, Jane Wu"))
    .addMeta(new meta().setName(meta.NAME_CREATED    ).setContent("8 February 2002"))
    .addMeta(new meta().setName(meta.NAME_MODIFIED   ).setContent("28 November 2019"))
    .addMeta(new meta().setName(meta.NAME_SUBJECT    ).setContent("bathymetry"))
    .addMeta(new meta().setName(meta.NAME_IDENTIFIER ).setContent("https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorPrototype.x3d"))
    .addMeta(new meta().setName(meta.NAME_GENERATOR  ).setContent("X3D-Edit 3.2, https://www.web3d.org/x3d/tools/X3D-Edit"))
    .addMeta(new meta().setName(meta.NAME_LICENSE    ).setContent("../../license.html")))
  .setScene(new Scene()
    .addChild(new WorldInfo().setTitle("BathymetryGeneratorPrototype.x3d"))
    .addChild(new ProtoDeclare("BathymetryGenerator").setName("BathymetryGenerator").setAppinfo("BathymetryGenerator creates bottom topography")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("positionArray").setType(field.TYPE_MFVEC3F).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new MFVec3f(new MFVec3f(new double[] {0.0,0.0,0.0,10.0,-4.0,0.0,25.0,-6.0,0.0,30.0,-8.0,5.0,38.0,-15.0,5.0,45.0,-18.0,5.0,55.0,-22.0,5.0,60.0,-25.0,15.0,60.0,-27.0,22.0,55.0,-30.0,35.0,48.0,-35.0,35.0,35.0,-35.0,35.0,25.0,-45.0,35.0,20.0,-55.0,35.0,15.0,-70.0,35.0,3.0,-70.0,35.0,-5.0,-72.0,40.0,-5.0,-75.0,50.0,0.0,-80.0,55.0,15.0,-75.0,55.0,30.0,-70.0,55.0,35.0,-60.0,55.0,40.0,-50.0,55.0,50.0,-34.0,55.0,65.0,-23.0,70.0}))))
        .addField(new field().setName("colorSchemeDepthRangeArray").setType(field.TYPE_MFVEC2F).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new MFVec2f(new MFVec2f(new double[] {0.0,-10.0,-10.0,-20.0,-20.0,-30.0,-30.0,-40.0,-40.0,-50.0,-50.0,-60.0,-60.0,-70.0,-70.0,-999999.0}))))
        .addField(new field().setName("colorSchemeColorArray").setType(field.TYPE_MFCOLOR).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new MFColor(new MFColor(new double[] {1.0,1.0,0.2,0.6,1.0,1.0,0.0,1.0,1.0,0.2,0.6,0.2,1.0,0.0,1.0,0.56,0.0,0.32,0.2,0.3,0.7,0.0,0.0,1.0}))))
        .addField(new field().setName("beamWidth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(2))
        .addField(new field().setName("traceEnabled").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(false)))
      .setProtoBody(new ProtoBody()
        .addChild(new Group()
          .addChild(new Transform("Bathymetry")
            .addChild(new Shape()
              .setGeometry(new IndexedFaceSet("BathymetryFaceSet").setDEF("BathymetryFaceSet").setCcw(false)
                .setColor(new Color("BathymetryFaceColor"))
                .setCoord(new Coordinate("BathymetryFaceCoord"))))
            .addChild(new Script("BathymetryScript").setSourceCode("""
ecmascript:

function initialize()
{
	dataValid = true;
	checkDataValidity();
	if (!dataValid)
		return;

	tracePrint('positionArray.length = ' + positionArray.length);

	coordIndex = 0;
	colorIndex = 0;
	for (i = 0; i < positionArray.length; i++)
	{
		//determine the color for every position
		determineFaceColor(positionArray[i].y)
		bathyFaceColorArray[colorIndex++] = color;

		//determine the 'leftPoint' for every poistion -- For the first
		//position, use the first and second position.
		if (i == 0)
		{
			determineLeftPoint(positionArray[0], positionArray[1]);
			bathyFaceCoordPoints[coordIndex++] = leftPoint;
			determineRightPoint(positionArray[0], positionArray[1]);
			bathyFaceCoordPoints[coordIndex++] = rightPoint;
		}
		else
		{
			determineLeftPoint(positionArray[i], positionArray[i-1]);
			bathyFaceCoordPoints[coordIndex++] = leftPoint;
			determineRightPoint(positionArray[i], positionArray[i-1]);
			bathyFaceCoordPoints[coordIndex++] = rightPoint;
		}
	}

	tracePrint('bathyFaceCoordPoints = ' + bathyFaceCoordPoints);

	j = 0;
	for (i = 0; i < (positionArray.length - 1); i++)
	{
		bathyCoordIndex[j++] = i * 2;
		bathyCoordIndex[j++] = i * 2 + 1;
		bathyCoordIndex[j++] = i * 2 + 2;
		bathyCoordIndex[j++] = i * 2 + 3;
		bathyCoordIndex[j++] = -1;

		bathyCoordIndex[j++] = i * 2 + 3;
		bathyCoordIndex[j++] = i * 2 + 2;
		bathyCoordIndex[j++] = i * 2 + 1;
		bathyCoordIndex[j++] = i * 2;
		bathyCoordIndex[j++] = -1;
	}

	tracePrint('bathyCoordIndex = ' + bathyCoordIndex);
}

function checkDataValidity()
{
	if (depthRangeArray.length != depthColorArray.length)
	{
		alwaysPrint('<Error> colorSchemeDepthRangeArray must be the same length as colorSchemeColorArray');
		dataValid = false;
		return;
	}
}

function determineFaceColor(depth)
{
	for (j = 0; j < depthColorArray.length; j++)
        {
		if (depth <= depthRangeArray[j].x && depth >= depthRangeArray[j].y)
		{
			color = depthColorArray[j]
			return;
		}
        }
	color = null;
	return;
}

function determineLeftPoint(currPosition, prevPosition)
{
	deltaX = currPosition.x - prevPosition.x;
	deltaZ = currPosition.z - prevPosition.z;

	theta = Math.atan2(deltaX, deltaZ);
	tracePrint('theta = ' + theta);

	leftPoint = new SFVec3f(currPosition.x + Math.cos(theta),
	                        currPosition.y,
	                        currPosition.z - Math.sin(theta) * (beamWidth / 2));
}

function determineRightPoint(currPosition, prevPosition)
{
	deltaX = currPosition.x - prevPosition.x;
	deltaZ = currPosition.z - prevPosition.z;

	theta = Math.atan2(deltaX, deltaZ);

	rightPoint = new SFVec3f(currPosition.x - Math.cos(theta),
	                         currPosition.y,
	                         currPosition.z + Math.sin(theta) * (beamWidth / 2));
}

function alwaysPrint(string)
{
	Browser.println ('[BathymetryGeneratorPrototype] ' + string);
}

function tracePrint(string)
{
	if (traceEnabled)
		Browser.println ('[BathymetryGeneratorPrototype] ' + string);
}
""")
              .addField(new field().setName("positionArray").setType(field.TYPE_MFVEC3F).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("depthRangeArray").setType(field.TYPE_MFVEC2F).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("depthColorArray").setType(field.TYPE_MFCOLOR).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("beamWidth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("bathyFaceCoordPoints").setType(field.TYPE_MFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("bathyCoordIndex").setType(field.TYPE_MFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("bathyFaceColorArray").setType(field.TYPE_MFCOLOR).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("bathyColorIndex").setType(field.TYPE_MFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("traceEnabled").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("dataValid").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(false).setAppinfo("local variable"))
              .addField(new field().setName("color").setType(field.TYPE_SFCOLOR).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new SFColor(1.0,1.0,1.0)).setAppinfo("local variable"))
              .addField(new field().setName("leftPoint").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new SFVec3f(0.0,0.0,0.0)).setAppinfo("local variable"))
              .addField(new field().setName("rightPoint").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new SFVec3f(0.0,0.0,0.0)).setAppinfo("local variable"))
              .setIS(new IS()
                .addConnect(new connect().setNodeField("positionArray").setProtoField("positionArray"))
                .addConnect(new connect().setNodeField("depthRangeArray").setProtoField("colorSchemeDepthRangeArray"))
                .addConnect(new connect().setNodeField("depthColorArray").setProtoField("colorSchemeColorArray"))
                .addConnect(new connect().setNodeField("beamWidth").setProtoField("beamWidth"))
                .addConnect(new connect().setNodeField("traceEnabled").setProtoField("traceEnabled"))))
            .addChild(new ROUTE().setFromNode("BathymetryScript").setFromField("bathyFaceCoordPoints").setToNode("BathymetryFaceCoord").setToField("point"))
            .addChild(new ROUTE().setFromNode("BathymetryScript").setFromField("bathyCoordIndex").setToNode("BathymetryFaceSet").setToField("set_coordIndex"))
            .addChild(new ROUTE().setFromNode("BathymetryScript").setFromField("bathyFaceColorArray").setToNode("BathymetryFaceColor").setToField("color"))
            .addChild(new ROUTE().setFromNode("BathymetryScript").setFromField("bathyColorIndex").setToNode("BathymetryFaceSet").setToField("set_colorIndex"))))))
    .addComments(" ==================== ")
    .addComments(" Example scene starts here, in case this prototype is examined. ")
    .addChild(new Anchor().setDescription("BathymetryGeneratorExample").setParameter(new String[] {"target=_blank"}).setUrl(new String[] {"BathymetryGeneratorExample.x3d","https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorExample.x3d","BathymetryGeneratorExample.wrl","https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorExample.wrl"})
      .addChild(new Shape()
        .setGeometry(new Text().setString(new String[] {"BathymetryGeneratorPrototype","is a prototype definition file","","Click this text to see","BathymetryGeneratorExample"})
          .setFontStyle(new FontStyle().setJustify(FontStyle.JUSTIFY_MIDDLE_MIDDLE)))
        .setAppearance(new Appearance()
          .setMaterial(new Material().setDiffuseColor(0.6,0.8,0.4))))));
            }
            catch (Exception ex)
            {       
                System.err.println ("*** Further hints on X3DJSAIL errors and exceptions at");
                System.err.println ("*** https://www.web3d.org/specifications/java/X3DJSAIL.html");
                throw (ex);
            }
	}
	// end of initialize() method

	/** The initialized model object, created within initialize() method. */
	private X3D x3dModel;

	/** 
	 * Provide a 
	 * <a href="https://dzone.com/articles/java-copy-shallow-vs-deep-in-which-you-will-swim" target="_blank">shallow copy</a>
	 * of the X3D model.
	 * @see <a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/Core/X3D.html">X3D</a>
	 * @return BathymetryGeneratorPrototype model
	 */
	public X3D getX3dModel()
	{	  
		return x3dModel;
	}
	   
    /** 
     * Default main() method provided for test purposes, uses CommandLine to set global ConfigurationProperties for this object.
     * @param args array of input parameters, provided as arguments
     * @see <a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/Core/X3D.html#handleArguments-java.lang.String:A-">X3D.handleArguments(args)</a>
     * @see <a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/Core/X3D.html#validationReport--">X3D.validationReport()</a>
     * @see <a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/CommandLine.html">CommandLine</a>
     * @see <a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/CommandLine.html#USAGE">CommandLine.USAGE</a>
     * @see <a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/ConfigurationProperties.html">ConfigurationProperties</a>
     */
    public static void main(String args[])
    {
        System.out.println("Build this X3D model, showing validation diagnostics...");
        X3D thisExampleX3dModel = new BathymetryGeneratorPrototype().getX3dModel();
//      System.out.println("X3D model construction complete.");
	
        // next handle command line arguments
        boolean hasArguments = (args != null) && (args.length > 0);
        boolean validate = true; // default
        boolean argumentsLoadNewModel = false;
        String  fileName = new String();

        if (args != null)
        {
                for (String arg : args)
                {
                        if (arg.toLowerCase().startsWith("-v") || arg.toLowerCase().contains("validate"))
                        {
                                validate = true; // making sure
                        }
                        if (arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_X3D) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_CLASSICVRML) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_X3DB) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_VRML97) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_EXI) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_GZIP) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_ZIP) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_HTML) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_XHTML))
                        {
                                argumentsLoadNewModel = true;
                                fileName = arg;
                        }
                }
        }
        if      (argumentsLoadNewModel)
                System.out.println("WARNING: \"Savage.Tools.Animation.BathymetryGeneratorPrototype\" model invocation is attempting to load file \"" + fileName + "\" instead of simply validating itself... file loading ignored.");
        else if (hasArguments) // if no arguments provided, this method produces usage warning
                thisExampleX3dModel.handleArguments(args);
	
        if (validate)
        {
            //  System.out.println("--- TODO fix duplicated outputs ---"); // omit when duplicated outputs problem is solved/refactored
		String validationResults = thisExampleX3dModel.validationReport();
            //  System.out.println("-----------------------------------"); // omit when duplicated outputs problem is solved/refactored
                System.out.print("Savage.Tools.Animation.BathymetryGeneratorPrototype self-validation test confirmation: ");
                if (!validationResults.equals("success"))
                    System.out.println();
                System.out.println(validationResults.trim());

                // experimental: test X3DJSAIL output files
                // Tools/Animation/BathymetryGeneratorPrototype_JavaExport.* file validation is checked when building X3D Example Archives
                String filenameX3D  = "Tools/Animation/BathymetryGeneratorPrototype_JavaExport.x3d"; 
                String filenameX3DV = "Tools/Animation/BathymetryGeneratorPrototype_JavaExport.x3dv"; 
                String filenameJSON = "Tools/Animation/BathymetryGeneratorPrototype_JavaExport.json";
                thisExampleX3dModel.toFileX3D        (filenameX3D);
                thisExampleX3dModel.toFileClassicVRML(filenameX3DV);
// TODO         thisExampleX3dModel.toFileJSON       (filenameJSON);
        }
    }
}
