package Savage.Buildings.SecurityPerimeter;

import org.web3d.x3d.jsail.Core.*;
import org.web3d.x3d.jsail.EventUtilities.*;
import org.web3d.x3d.jsail.fields.*;
import org.web3d.x3d.jsail.Geometry3D.*;
import org.web3d.x3d.jsail.Grouping.*;
import org.web3d.x3d.jsail.Interpolation.*;
import org.web3d.x3d.jsail.Navigation.*;
import org.web3d.x3d.jsail.PointingDeviceSensor.*;
import org.web3d.x3d.jsail.Scripting.*;
import org.web3d.x3d.jsail.Shape.*;
import org.web3d.x3d.jsail.Text.*;
import org.web3d.x3d.jsail.Texturing.*;
import org.web3d.x3d.jsail.Time.*;

// Javadoc metadata annotations follow, see below for X3DJSAIL Java source code.
/**
 * <p> Rising/retractable security bollard. </p>
 <p> Related links: Catalog page <a href="../../../../Buildings/SecurityPerimeter/BollardHydraulicSecurityPrototypeIndex.html" target="_blank">BollardHydraulicSecurityPrototype</a>,  source <a href="../../../../Buildings/SecurityPerimeter/BollardHydraulicSecurityPrototype.java">BollardHydraulicSecurityPrototype.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="../../../../Buildings/SecurityPerimeter/BollardHydraulicSecurityPrototype.x3d">BollardHydraulicSecurityPrototype.x3d</a> </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> description </i> </td>
			<td> Rising/retractable security bollard </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> creator </i> </td>
			<td> Don Brutzman and MV4205 Advanced XML class </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> created </i> </td>
			<td> 30 May 2007 </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> modified </i> </td>
			<td> 20 October 2019 </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> reference </i> </td>
			<td> <a href="http://www.atgaccess.com" target="_blank">http://www.atgaccess.com</a> </td>
		</tr>
		<tr style="color:burntorange">
			<td style="text-align:right; vertical-align: text-top;"> <i> warning </i> </td>
			<td> under development, initial functionality completed. TODO: add SMALL metadata. TODO: how to string together multiple bollards - add fields for spacing and count? </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/Buildings/SecurityPerimeter/BollardHydraulicSecurityPrototype.x3d" target="_blank">https://www.web3d.org/x3d/content/examples/Savage/Buildings/SecurityPerimeter/BollardHydraulicSecurityPrototype.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="../../../../Buildings/SecurityPerimeter/../../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 and MV4205 Advanced XML class
 */

public class BollardHydraulicSecurityPrototype
{
	/** Default constructor to create this object. */
	public BollardHydraulicSecurityPrototype ()
	{
	  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_1)
  .setHead(new head()
    .addMeta(new meta().setName(meta.NAME_TITLE      ).setContent("BollardHydraulicSecurityPrototype.x3d"))
    .addMeta(new meta().setName(meta.NAME_DESCRIPTION).setContent("Rising/retractable security bollard"))
    .addMeta(new meta().setName(meta.NAME_CREATOR    ).setContent("Don Brutzman and MV4205 Advanced XML class"))
    .addMeta(new meta().setName(meta.NAME_CREATED    ).setContent("30 May 2007"))
    .addMeta(new meta().setName(meta.NAME_MODIFIED   ).setContent("20 October 2019"))
    .addMeta(new meta().setName(meta.NAME_REFERENCE  ).setContent("http://www.atgaccess.com"))
    .addMeta(new meta().setName(meta.NAME_WARNING    ).setContent("under development, initial functionality completed. TODO: add SMALL metadata. TODO: how to string together multiple bollards - add fields for spacing and count?"))
    .addMeta(new meta().setName(meta.NAME_IDENTIFIER ).setContent("https://www.web3d.org/x3d/content/examples/Savage/Buildings/SecurityPerimeter/BollardHydraulicSecurityPrototype.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("BollardHydraulicSecurityPrototype.x3d"))
    .addChild(new ProtoDeclare("BollardHydraulicSecurity").setName("BollardHydraulicSecurity").setAppinfo("A security bollard can be raised or lowered to prevent vehicle access by blocking a road. Usually multiple bollards are installed side by side raised and lowered together.")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("radius").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.2))
        .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(1))
        .addField(new field().setName("textureUrl").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INPUTOUTPUT))
        .addField(new field().setName("diffuseColor").setType(field.TYPE_SFCOLOR).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(new SFColor(1.0,1.0,0.0)))
        .addField(new field().setName("raise").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTONLY).setAppinfo("Command to raise the bollard."))
        .addField(new field().setName("lower").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTONLY).setAppinfo("Command to lower the bollard."))
        .addComments(" TODO: add TimeDelaySensor nodes to report completion by the following output fields ")
        .addField(new field().setName("isRaised").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Notification event sent when bollard is fully raised."))
        .addField(new field().setName("isLowered").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Notification event sent when bollard is fully lowered.")))
      .setProtoBody(new ProtoBody()
        .addChild(new Transform("BollardTransform")
          .addComments(" first Cylinder displays only the sides, with an optional texture applied ")
          .addChild(new Shape()
            .setGeometry(new Cylinder().setBottom(false).setTop(false)
              .setIS(new IS()
                .addConnect(new connect().setNodeField("radius").setProtoField("radius"))
                .addConnect(new connect().setNodeField("height").setProtoField("height"))))
            .setAppearance(new Appearance()
              .setMaterial(new Material("CylinderMaterial")
                .setIS(new IS()
                  .addConnect(new connect().setNodeField("diffuseColor").setProtoField("diffuseColor"))))
              .setTexture(new ImageTexture()
                .setIS(new IS()
                  .addConnect(new connect().setNodeField("url").setProtoField("textureUrl"))))))
          .addComments(" second Cylinder displays only the top and bottom, which do not have the optional texture applied ")
          .addChild(new Shape()
            .setGeometry(new Cylinder().setSide(false)
              .setIS(new IS()
                .addConnect(new connect().setNodeField("radius").setProtoField("radius"))
                .addConnect(new connect().setNodeField("height").setProtoField("height"))))
            .setAppearance(new Appearance()
              .setMaterial(new Material().setUSE("CylinderMaterial")))))
        .addComments(" only the first node in a prototype body is rendered, the others are carried along for the ride ")
        .addChild(new PositionInterpolator("HeightInterpolator").setKey(new double[] {0.0,1.0}).setKeyValue(new MFVec3f(new double[] {0.0,-0.5,0.0,0.0,0.5,0.0})))
        .addChild(new ROUTE().setFromNode("HeightInterpolator").setFromField("value_changed").setToNode("BollardTransform").setToField("set_translation"))
        .addComments(" ========= setup =========== ")
        .addComments(" this Script initializes our PositionInterpolator to proper start/stop heights. Also initializes BollardTransform translation to the correct height. ")
        .addChild(new Script("HeightTypeConversion").setDirectOutput(true).setSourceCode("""
ecmascript:

function initialize ()
{
	// set initial Transform translation value to the correct height
	initialTranslation = new SFVec3f (0, -(height / 2), 0); // output event
	finalTranslation   = new SFVec3f (0,  (height / 2), 0);
//	Browser.println ('initialTranslation=' + initialTranslation);

	// customize PositionInterpolator to move correct vertical distance
	PI.keyValue = new MFVec3f (initialTranslation, finalTranslation);
//	Browser.println ('PI.keyValue=' + PI.keyValue);
}
""")
          .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
          .addField(new field().setName("initialTranslation").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
          .addField(new field().setName("PI").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new PositionInterpolator().setUSE("HeightInterpolator")))
          .setIS(new IS()
            .addConnect(new connect().setNodeField("height").setProtoField("height"))))
        .addChild(new ROUTE().setFromNode("HeightTypeConversion").setFromField("initialTranslation").setToNode("BollardTransform").setToField("set_translation"))
        .addComments(" ========= raise =========== ")
        .addChild(new TimeSensor("RaiseBollardClock").setCycleInterval(5))
        .addComments(" alternative approach (shown below) replaces this script with a BooleanFilter plus TimeTrigger (to convert SFBool to SFTime) ")
        .addChild(new Script("ClockScript").setSourceCode("""
ecmascript:

function raise (value, timestamp)
{
	startRaising = timestamp;
}
""")
          .addField(new field().setName("raise").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("startRaising").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
          .setIS(new IS()
            .addConnect(new connect().setNodeField("raise").setProtoField("raise"))))
        .addChild(new ROUTE().setFromNode("RaiseBollardClock").setFromField("fraction_changed").setToNode("HeightInterpolator").setToField("set_fraction"))
        .addChild(new ROUTE().setFromNode("ClockScript").setFromField("startRaising").setToNode("RaiseBollardClock").setToField("startTime"))
        .addComments(" ========= lower =========== ")
        .addChild(new ScalarInterpolator("FractionReverser").setKey(new double[] {0.0,1.0}).setKeyValue(new double[] {1.0,0.0}))
        .addChild(new TimeSensor("LowerBollardClock").setCycleInterval(5))
        .addChild(new TimeTrigger("LowerTimeTrigger"))
        .addChild(new BooleanFilter("StartLoweringFilter")
          .setIS(new IS()
            .addConnect(new connect().setNodeField("set_boolean").setProtoField("lower"))))
        .addChild(new ROUTE().setFromNode("FractionReverser").setFromField("value_changed").setToNode("HeightInterpolator").setToField("set_fraction"))
        .addChild(new ROUTE().setFromNode("LowerBollardClock").setFromField("fraction_changed").setToNode("FractionReverser").setToField("set_fraction"))
        .addChild(new ROUTE().setFromNode("LowerTimeTrigger").setFromField("triggerTime").setToNode("LowerBollardClock").setToField("set_startTime"))
        .addChild(new ROUTE().setFromNode("StartLoweringFilter").setFromField("inputTrue").setToNode("LowerTimeTrigger").setToField("set_boolean"))))
    .addComments(" ==================== ")
    .addChild(new Viewpoint().setDescription("Bollard view").setPosition(0.0,0.0,6.0))
    .addComments(" test locally during development, once complete we split this out into a separate Example scene. ")
    .addChild(new ProtoInstance("BollardHydraulicSecurity", "Bollard").setContainerField("children")
      .addFieldValue(new fieldValue().setName("height").setValue(0.85))
      .addFieldValue(new fieldValue().setName("radius").setValue(0.2))
      .addFieldValue(new fieldValue().setName("textureUrl").setValue(new String[] {"fan.png"})))
    .addChild(new Shape("GroundLevel")
      .setGeometry(new Box().setSize(10.0,0.01,10.0)))
    .addChild(new Transform("RaiseInterface").setTranslation(-2.0,-1.0,0.0)
      .addChild(new Shape()
        .setGeometry(new Text().setString(new String[] {"Click to","raise"})
          .setFontStyle(new FontStyle().setJustify(FontStyle.JUSTIFY_MIDDLE_MIDDLE).setSize(0.3))))
      .addChild(new Shape()
        .setGeometry(new Box().setSize(3.0,2.0,0.01))
        .setAppearance(new Appearance()
          .setMaterial(new Material().setTransparency(1))))
      .addChild(new TouchSensor("ClickToRaiseBollard").setDescription("click to raise bollard"))
      .addChild(new ROUTE().setFromNode("ClickToRaiseBollard").setFromField("isActive").setToNode("Bollard").setToField("raise")))
    .addChild(new Transform("LowerInterface").setTranslation(2.0,-1.0,0.0)
      .addChild(new Shape()
        .setGeometry(new Text().setString(new String[] {"Click to","lower"})
          .setFontStyle(new FontStyle().setJustify(FontStyle.JUSTIFY_MIDDLE_MIDDLE).setSize(0.3))))
      .addChild(new Shape()
        .setGeometry(new Box().setSize(3.0,2.0,0.01))
        .setAppearance(new Appearance()
          .setMaterial(new Material().setTransparency(1))))
      .addChild(new TouchSensor("ClickToLowerBollard").setDescription("click tolower bollard"))
      .addChild(new ROUTE().setFromNode("ClickToLowerBollard").setFromField("isActive").setToNode("Bollard").setToField("lower"))));
            }
            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 BollardHydraulicSecurityPrototype 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 BollardHydraulicSecurityPrototype().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.Buildings.SecurityPerimeter.BollardHydraulicSecurityPrototype\" 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.Buildings.SecurityPerimeter.BollardHydraulicSecurityPrototype self-validation test confirmation: ");
                if (!validationResults.equals("success"))
                    System.out.println();
                System.out.println(validationResults.trim());

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