package Savage.Buildings.UHRB;

import org.web3d.x3d.jsail.Core.*;
import org.web3d.x3d.jsail.EnvironmentalEffects.*;
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.Navigation.*;
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.*;
import org.web3d.x3d.jsail.Time.*;

// Javadoc metadata annotations follow, see below for X3DJSAIL Java source code.
/**
 * <p> Prototypes for simple building construction: Floor, Wall, Level and Building. </p>
 <p> Related links: Catalog page <a href="../../../../Buildings/UHRB/SimpleBuildingConstructionPrototypesIndex.html" target="_blank">SimpleBuildingConstructionPrototypes</a>,  source <a href="../../../../Buildings/UHRB/SimpleBuildingConstructionPrototypes.java">SimpleBuildingConstructionPrototypes.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/UHRB/SimpleBuildingConstructionPrototypes.x3d">SimpleBuildingConstructionPrototypes.x3d</a> </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> creator </i> </td>
			<td> Don Brutzman </td>
		</tr>
		<tr>
			<td style="text-align:right; vertical-align: text-top;"> <i> created </i> </td>
			<td> 17 October 2001 </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> description </i> </td>
			<td> Prototypes for simple building construction: Floor, Wall, Level and Building. </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/UHRB/SimpleBuildingConstructionPrototypes.x3d" target="_blank">https://www.web3d.org/x3d/content/examples/Savage/Buildings/UHRB/SimpleBuildingConstructionPrototypes.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/UHRB/../../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
 */

public class SimpleBuildingConstructionPrototypes
{
	/** Default constructor to create this object. */
	public SimpleBuildingConstructionPrototypes ()
	{
	  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("SimpleBuildingConstructionPrototypes.x3d"))
    .addMeta(new meta().setName(meta.NAME_CREATOR    ).setContent("Don Brutzman"))
    .addMeta(new meta().setName(meta.NAME_CREATED    ).setContent("17 October 2001"))
    .addMeta(new meta().setName(meta.NAME_MODIFIED   ).setContent("20 October 2019"))
    .addMeta(new meta().setName(meta.NAME_DESCRIPTION).setContent("Prototypes for simple building construction: Floor, Wall, Level and Building."))
    .addMeta(new meta().setName(meta.NAME_IDENTIFIER ).setContent("https://www.web3d.org/x3d/content/examples/Savage/Buildings/UHRB/SimpleBuildingConstructionPrototypes.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("SimpleBuildingConstructionPrototypes.x3d"))
    .addChild(new ProtoDeclare("Floor").setName("Floor").setAppinfo("Each Floor cantains the current floor surface plus a ceiling surface for the floor immediately underneath. A Floor does not include exterior or interior wall polygons.")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Identifying name for this Floor."))
        .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Description info for this construction."))
        .addField(new field().setName("size").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("single-value Coordinate node with dimension x=width y=height z=depth in meters")
          .addChild(new Coordinate()))
        .addField(new field().setName("floorAppearance").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Appearance node with Material colors ImageTexture etc. for this construction.")
          .addChild(new Appearance("DefaultFloorAppearance")
            .setMaterial(new Material().setDiffuseColor(0.2,0.2,0.2))))
        .addField(new field().setName("ceilingAppearance").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Appearance node with Material colors ImageTexture etc. for this construction.")
          .addChild(new Appearance("DefaultCeilingAppearance")
            .setMaterial(new Material())))
        .addField(new field().setName("showSides").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(false).setAppinfo("Whether sides are visible."))
        .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("width of front side of floor aligned with local X axis."))
        .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("height of vertical distance between floor and ceiling directly underneath aligned with local Y axis."))
        .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("depth of horizontal side of floor aligned with local -Z axis."))
        .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Indicate whether initialization complete.")))
      .setProtoBody(new ProtoBody()
        .addChild(new Group("FloorRoot")
          .addChild(new Transform("LowerLeftOutsideCornerLocation")
            .addChild(new Shape("Floor")
              .setIS(new IS()
                .addConnect(new connect().setNodeField("appearance").setProtoField("floorAppearance")))
              .setGeometry(new IndexedFaceSet().setCoordIndex(new int[] {0,1,2,3,0,-1})
                .setCoord(new Coordinate("FloorCoordinate"))))
            .addChild(new Shape("Ceiling")
              .setIS(new IS()
                .addConnect(new connect().setNodeField("appearance").setProtoField("ceilingAppearance")))
              .setGeometry(new IndexedFaceSet().setCoordIndex(new int[] {4,7,6,5,4,-1})
                .setCoord(new Coordinate().setUSE("FloorCoordinate"))))
            .addChild(new Switch("FloorSidesSwitch").setWhichChoice(-1)
              .addChild(new Shape("FloorSides")
                .setIS(new IS()
                  .addConnect(new connect().setNodeField("appearance").setProtoField("floorAppearance")))
                .setGeometry(new IndexedFaceSet().setSolid(false).setCoordIndex(new int[] {0,3,7,4,-1,3,2,6,7,-1,1,5,6,2,-1,0,4,5,1,-1})
                  .setCoord(new Coordinate().setUSE("FloorCoordinate"))))))
          .addChild(new Script("FloorConstructionScript").setDirectOutput(true).setSourceCode("""
ecmascript:

function tracePrint (outputString)
{
	if (traceEnabled) Browser.println ('[Floor' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.println ('[Floor' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	tracePrint ('description=' + description);
	tracePrint ('showSides=' + showSides);
	if (showSides == true) wallsVisible = 0; // goes to Switch whichChoice
	tracePrint ('wallsVisible=' + wallsVisible);
	if ((size.point.length == 0) || (size.point.length > 1))
		alwaysPrint ('** warning, size.point.length =' + size.point.length + ' rather than 1');
	width  = size.point[0].x;
	height = size.point[0].y;
	depth  = size.point[0].z;
	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');
	// floor is immediately above ceiling
	floorPoints = new MFVec3f (
		new SFVec3f (0, 0, 0),
		new SFVec3f (width, 0, 0),
		new SFVec3f (width, 0, -depth),
		new SFVec3f (0, 0, -depth),
		new SFVec3f (0, -height, 0),
		new SFVec3f (width, -height, 0),
		new SFVec3f (width, -height, -depth),
		new SFVec3f (0, -height, -depth));
	tracePrint ('floorPoints=' + floorPoints);
	built = true;
	tracePrint ('built=' + built);
}
""")
            .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("size").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("showSides").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("wallsVisible").setType(field.TYPE_SFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("floorPoints").setType(field.TYPE_MFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("traceEnabled").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
            .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .setIS(new IS()
              .addConnect(new connect().setNodeField("name").setProtoField("name"))
              .addConnect(new connect().setNodeField("description").setProtoField("description"))
              .addConnect(new connect().setNodeField("size").setProtoField("size"))
              .addConnect(new connect().setNodeField("showSides").setProtoField("showSides"))
              .addConnect(new connect().setNodeField("width").setProtoField("width"))
              .addConnect(new connect().setNodeField("height").setProtoField("height"))
              .addConnect(new connect().setNodeField("depth").setProtoField("depth"))
              .addConnect(new connect().setNodeField("built").setProtoField("built"))))
          .addChild(new ROUTE().setFromNode("FloorConstructionScript").setFromField("floorPoints").setToNode("FloorCoordinate").setToField("point"))
          .addChild(new ROUTE().setFromNode("FloorConstructionScript").setFromField("wallsVisible").setToNode("FloorSidesSwitch").setToField("whichChoice")))))
    .addChild(new ProtoDeclare("Wall").setName("Wall").setAppinfo("Each Wall contains exterior and interior walls.")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Identifying name for this Wall."))
        .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Description info for this construction."))
        .addField(new field().setName("size").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("single-value Coordinate node with dimension x=width y=height z=depth in meters")
          .addChild(new Coordinate().setPoint(new MFVec3f(new double[] {0.0,0.0,0.0}))))
        .addField(new field().setName("interiorAppearance").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Appearance node with Material colors ImageTexture etc. for this construction.")
          .addChild(new Appearance("DefaultInteriorAppearance")
            .setMaterial(new Material().setDiffuseColor(0.4,0.4,0.4))))
        .addField(new field().setName("exteriorAppearance").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Appearance node with Material colors ImageTexture etc. for this construction.")
          .addChild(new Appearance("DefaultExteriorAppearance")
            .setMaterial(new Material().setDiffuseColor(0.6,0.6,0.6))))
        .addField(new field().setName("showSides").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(false).setAppinfo("Whether sides are visible."))
        .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("width of horizontal side of wall aligned with local X axis."))
        .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("height of Wall aligned with local Y axis."))
        .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("depth of horizontal thickness of Wall aligned with local -Z axis."))
        .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Indicate whether initialization complete.")))
      .setProtoBody(new ProtoBody()
        .addChild(new Group("WallRoot")
          .addChild(new Transform("LowerLeftOutsideCornerLocationWall")
            .addChild(new Shape("InteriorWall")
              .setIS(new IS()
                .addConnect(new connect().setNodeField("appearance").setProtoField("interiorAppearance")))
              .addComments(" only draw interior-facing side for efficiency, and also so that view piercing external wall immediately sees interior ")
              .setGeometry(new IndexedFaceSet().setCoordIndex(new int[] {4,7,6,5,4,-1})
                .setCoord(new Coordinate("WallCoordinate"))))
            .addChild(new Shape("ExteriorWall")
              .setIS(new IS()
                .addConnect(new connect().setNodeField("appearance").setProtoField("exteriorAppearance")))
              .setGeometry(new IndexedFaceSet().setCoordIndex(new int[] {0,1,2,3,0,-1})
                .setCoord(new Coordinate().setUSE("WallCoordinate"))))
            .addChild(new Switch("WallSidesSwitch").setWhichChoice(-1)
              .addChild(new Shape("WallSides")
                .setIS(new IS()
                  .addConnect(new connect().setNodeField("appearance").setProtoField("exteriorAppearance")))
                .setGeometry(new IndexedFaceSet().setCoordIndex(new int[] {0,3,7,4,-1,3,2,6,7,-1,1,5,6,2,-1,0,4,5,1,-1})
                  .setCoord(new Coordinate().setUSE("WallCoordinate"))))))
          .addChild(new Script("WallConstructionScript").setDirectOutput(true).setSourceCode("""
ecmascript:

function tracePrint (outputString)
{
	if (traceEnabled) Browser.println ('[Wall' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.println ('[Wall' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	tracePrint ('description=' + description);
	tracePrint ('showSides=' + showSides);
	if (showSides == true) wallsVisible = 0; // goes to Switch whichChoice
	tracePrint ('wallsVisible=' + wallsVisible);
	if ((size.point.length == 0) || (size.point.length > 1))
		alwaysPrint ('** warning, size.point.length =' + size.point.length + ' rather than 1');
	width  = size.point[0].x;
	height = size.point[0].y;
	depth  = size.point[0].z;
	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');
	coordinatePoints = new MFVec3f (
		new SFVec3f (0, 0, 0),
		new SFVec3f (width, 0, 0),
		new SFVec3f (width, height, 0),
		new SFVec3f (0, height, 0),
		new SFVec3f (0, 0, -depth),
		new SFVec3f (width, 0, -depth),
		new SFVec3f (width, height, -depth),
		new SFVec3f (0, height, -depth));
	tracePrint ('coordinatePoints=' + coordinatePoints);
	built = true;
	tracePrint ('built=' + built);
}
""")
            .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("size").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("showSides").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("wallsVisible").setType(field.TYPE_SFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("coordinatePoints").setType(field.TYPE_MFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("traceEnabled").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
            .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .setIS(new IS()
              .addConnect(new connect().setNodeField("name").setProtoField("name"))
              .addConnect(new connect().setNodeField("description").setProtoField("description"))
              .addConnect(new connect().setNodeField("size").setProtoField("size"))
              .addConnect(new connect().setNodeField("showSides").setProtoField("showSides"))
              .addConnect(new connect().setNodeField("width").setProtoField("width"))
              .addConnect(new connect().setNodeField("height").setProtoField("height"))
              .addConnect(new connect().setNodeField("depth").setProtoField("depth"))
              .addConnect(new connect().setNodeField("built").setProtoField("built"))))
          .addChild(new ROUTE().setFromNode("WallConstructionScript").setFromField("coordinatePoints").setToNode("WallCoordinate").setToField("point"))
          .addChild(new ROUTE().setFromNode("WallConstructionScript").setFromField("wallsVisible").setToNode("WallSidesSwitch").setToField("whichChoice")))))
    .addChild(new ProtoDeclare("Level").setName("Level").setAppinfo("collection of a Floor and four Walls working in order up from lowest level (i.e. story) of the Building")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Identifying name for this Level."))
        .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Description info for this construction."))
        .addField(new field().setName("floor").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("contains single Floor node")
          .addChild(new Group()))
        .addField(new field().setName("frontWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("contains single front Wall node")
          .addChild(new ProtoInstance("Wall").setContainerField("children")))
        .addField(new field().setName("rightWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("contains single right-side Wall node")
          .addChild(new ProtoInstance("Wall").setContainerField("children")))
        .addField(new field().setName("rearWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("contains single rear Wall node")
          .addChild(new ProtoInstance("Wall").setContainerField("children")))
        .addField(new field().setName("leftWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("contains single left-side Wall node")
          .addChild(new ProtoInstance("Wall").setContainerField("children")))
        .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Calculated width of horizontal side of Level aligned with local X axis."))
        .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Calculated height of Level aligned with local Y axis."))
        .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Calculated depth of horizontal thickness of Level aligned with local -Z axis."))
        .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Indicate whether initialization complete.")))
      .setProtoBody(new ProtoBody()
        .addChild(new Group("LevelRoot")
          .addChild(new Transform("FloorTransform")
            .setIS(new IS()
              .addConnect(new connect().setNodeField("children").setProtoField("floor"))))
          .addChild(new Transform("FrontWallTransform")
            .setIS(new IS()
              .addConnect(new connect().setNodeField("children").setProtoField("frontWall"))))
          .addChild(new Transform("RightWallTransform").setRotation(0.0,1.0,0.0,1.57079)
            .setIS(new IS()
              .addConnect(new connect().setNodeField("children").setProtoField("rightWall"))))
          .addChild(new Transform("RearWallTransform").setRotation(0.0,1.0,0.0,3.1416)
            .setIS(new IS()
              .addConnect(new connect().setNodeField("children").setProtoField("rearWall"))))
          .addChild(new Transform("LeftWallTransform").setRotation(0.0,1.0,0.0,4.7124)
            .setIS(new IS()
              .addConnect(new connect().setNodeField("children").setProtoField("leftWall"))))
          .addChild(new Script("LevelConstructionScript").setDirectOutput(true).setSourceCode("""
ecmascript:

var firstLoopWhileTrueCompleted;

function tracePrint (outputString)
{
	if (traceEnabled) Browser.println ('[Level' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.println ('[Level' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	firstLoopWhileTrueCompleted = false;
	alwaysPrint ('initialize, built=' + built);
}
function recheckUntilBuilt (value)
{
	if      (built == true)
	{
		built = true; // resend to trigger cancellation event for TimeSensor
		if (firstLoopWhileTrueCompleted)
			alwaysPrint ('recheckUntilBuilt() continuous built=true indicates internal error');
		else firstLoopWhileTrueCompleted = true;
		return;  // done
	}
	alwaysPrint ('recheckUntilBuilt testing...');
	// following are single nodes, cast as MFNode type for IS/connect matchups
	if      (floor[0].built == false)	return;  // not yet ready
	else if (frontWall[0].built == false)	return;
	else if (rightWall[0].built == false)	return;
	else if (rearWall[0].built == false)	return;
	else if (leftWall[0].built == false)	return;
	alwaysPrint ('recheckUntilBuilt ready, initializing Level...');

	alwaysPrint ('description=' + description);
	if (floor)
	{
	//	tracePrint ('floor found');
		if (floor.length > 1)
			alwaysPrint ('** warning, more than one floor found (' +
				floor.length + ' nodes total)');
		tracePrint ('floor (width, height, depth)=(' +
			floor[0].width + ',' + floor[0].height + ',' +  floor[0].depth + ')');
	}
	else	tracePrint ('floor not found');

	if (frontWall)
	{
	//	tracePrint ('frontWall found');
		if (frontWall > 1)
			alwaysPrint ('** warning, more than one frontWall found (' +
				frontWall.length + ' nodes total)');
		tracePrint ('frontWall (width, height, depth)=(' +
			frontWall[0].width + ',' + frontWall[0].height + ',' +  frontWall[0].depth + ')');
	}
	else	tracePrint ('frontWall not found');

	if (rightWall)
	{
	//	tracePrint ('rightWall found');
		if (rightWall > 1)
			alwaysPrint ('** warning, more than one rightWall found (' +
				frontWall.length + ' nodes total)');
		tracePrint ('rightWall (width, height, depth)=(' +
			rightWall[0].width + ',' + rightWall[0].height + ',' +  rightWall[0].depth + ')');
	}

	else	tracePrint ('rightWall not found');

	if (rearWall)
	{
	//	tracePrint ('rearWall found');
		if (frontWall > 1)
			alwaysPrint ('** warning, more than one rearWall found (' +
				rearWall + ' nodes total)');
		tracePrint ('rearWall (width, height, depth)=(' +
			rearWall[0].width + ',' + rearWall[0].height + ',' +  rearWall[0].depth + ')');
	}
	else	tracePrint ('rearWall not found');

	if (leftWall)
	{
	//	tracePrint ('leftWall found');
		if (frontWall > 1)
			alwaysPrint ('** warning, more than one leftWall found (' +
				leftWall.length + ' nodes total)');
		tracePrint ('leftWall (width, height, depth)=(' +
			leftWall[0].width + ',' + leftWall[0].height + ',' +  leftWall[0].depth + ')');
	}
	else	tracePrint ('leftWall not found');

	if (floor && frontWall)
	{
		if ((floor[0].width != frontWall[0].width) && (floor[0].width != 0) && (frontWall[0].width != 0))
			alwaysPrint ('** warning, floor/frontWall width mismatch');
	}
	if (floor && rearWall)
	{
		if ((floor[0].width != rearWall[0].width) && (floor[0].width != 0) && (rearWall[0].width != 0))
			alwaysPrint ('** warning, floor/rearWall width mismatch');
	}
	if (floor && rightWall)
	{
		if ((floor[0].depth != rightWall[0].width) && (floor[0].depth != 0) && (rightWall[0].width != 0))
			alwaysPrint ('** warning, floor.depth/rightWall.width mismatch');
	}
	if (floor && leftWall)
	{
		if ((floor[0].depth != leftWall[0].width) && (floor[0].depth != 0) && (leftWall[0].width != 0))
			alwaysPrint ('** warning, floor.depth/leftWall.width mismatch');
	}
	if (frontWall && rearWall)
	{
		if ((frontWall[0].width != rearWall[0].width) && (frontWall[0].width != 0) && (rearWall[0].width != 0))
			alwaysPrint ('** warning, frontWall/rearWall width mismatch');
	}
	if (leftWall && rightWall)
	{
		if ((leftWall[0].width != rightWall[0].width) && (leftWall[0].width != 0) && (rightWall[0].width != 0))
			alwaysPrint ('** warning, leftWall/rightWall width mismatch');
	}

	// find first nonzero values
	width = 0;
	if (floor)                     width = floor[0].width;
	if (frontWall && (width == 0)) width = frontWall[0].width;
	if (rearWall  && (width == 0)) width = rearWall[0].width;

	height = 0;
	if      (frontWall)                  height = frontWall[0].height;
	if      (rightWall && (height == 0)) height = rightWall[0].height;
	else if (rearWall  && (height == 0)) height = rearWall[0].height;
	else if (leftWall  && (height == 0)) height = leftWall[0].height;

	depth = 0;
	if (floor)                     depth = floor[0].depth;
	if (rightWall && (depth == 0)) depth = rightWall[0].depth;
	if (leftWall  && (depth == 0)) depth = leftWall[0].depth;

	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');

	// translate wall centers (not corners)
	rightTranslation = new SFVec3f (width, 0, 0);
	tracePrint ('rightTranslation=' + rightTranslation);
	rearTranslation = new SFVec3f  (width, 0, -depth);
	tracePrint ('rearTranslation=' + rearTranslation);
	leftTranslation = new SFVec3f  (0, 0, -width/2);
	tracePrint ('leftTranslation=' + leftTranslation);
	built = true;
	tracePrint ('built=' + built);
}
""")
            .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("floor").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("frontWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("rightWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("rearWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("leftWall").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
            .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("rightTranslation").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("rearTranslation").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("leftTranslation").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .addField(new field().setName("traceEnabled").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
            .addField(new field().setName("recheckUntilBuilt").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INPUTONLY).setAppinfo("New floor or wall initialization may be complete check and recalculate until built"))
            .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
            .setIS(new IS()
              .addConnect(new connect().setNodeField("name").setProtoField("name"))
              .addConnect(new connect().setNodeField("description").setProtoField("description"))
              .addConnect(new connect().setNodeField("floor").setProtoField("floor"))
              .addConnect(new connect().setNodeField("frontWall").setProtoField("frontWall"))
              .addConnect(new connect().setNodeField("rightWall").setProtoField("rightWall"))
              .addConnect(new connect().setNodeField("rearWall").setProtoField("rearWall"))
              .addConnect(new connect().setNodeField("leftWall").setProtoField("leftWall"))
              .addConnect(new connect().setNodeField("width").setProtoField("width"))
              .addConnect(new connect().setNodeField("height").setProtoField("height"))
              .addConnect(new connect().setNodeField("depth").setProtoField("depth"))
              .addConnect(new connect().setNodeField("built").setProtoField("built"))))
          .addChild(new ROUTE().setFromNode("LevelConstructionScript").setFromField("rightTranslation").setToNode("RightWallTransform").setToField("translation"))
          .addChild(new ROUTE().setFromNode("LevelConstructionScript").setFromField("rearTranslation").setToNode("RearWallTransform").setToField("translation"))
          .addChild(new ROUTE().setFromNode("LevelConstructionScript").setFromField("leftTranslation").setToNode("LeftWallTransform").setToField("translation"))
          .addChild(new Group("LevelInitializeAfterChildrenReady")
            .addChild(new BooleanFilter("LevelBuiltFilter"))
            .addChild(new BooleanFilter("LevelBuiltNegation"))
            .addChild(new TimeSensor("LevelRecalculateUntilBuilt").setCycleInterval(0.1).setLoop(true))
            .addChild(new ROUTE().setFromNode("LevelConstructionScript").setFromField("built").setToNode("LevelBuiltFilter").setToField("set_boolean"))
            .addChild(new ROUTE().setFromNode("LevelBuiltFilter").setFromField("inputTrue").setToNode("LevelBuiltNegation").setToField("set_boolean"))
            .addChild(new ROUTE().setFromNode("LevelBuiltNegation").setFromField("inputNegate").setToNode("LevelRecalculateUntilBuilt").setToField("enabled"))
            .addChild(new ROUTE().setFromNode("LevelRecalculateUntilBuilt").setFromField("cycleTime").setToNode("LevelConstructionScript").setToField("recheckUntilBuilt"))))))
    .addChild(new ProtoDeclare("Building").setName("Building").setAppinfo("Collect prototypes for levels floors and walls to create a simple Building.")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Identifying name of this Building."))
        .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Description info for this construction."))
        .addField(new field().setName("authorAssist").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true).setAppinfo("whether or not to display author assist tools such as coordinate axes measuring grids etc."))
        .addField(new field().setName("xHeading").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0).setAppinfo("compass direction in degrees of building X axis as seen when regarding front face of building pointing from left side to right side."))
        .addField(new field().setName("orientation").setType(field.TYPE_SFROTATION).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("output rotation value calculated from xHeading as (0 1 0 xHeading * 2pi / 360)"))
        .addField(new field().setName("latitude").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("example value: 120.30 E"))
        .addField(new field().setName("longitude").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("example value: 20.45 N"))
        .addField(new field().setName("levels").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("contains array of Level nodes")
          .addChild(new ProtoInstance("Level").setContainerField("children")))
        .addField(new field().setName("roof").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setAppinfo("Geometry for Roof positioned above topmost Level")
          .addChild(new Group()))
        .addField(new field().setName("roofHeight").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0).setAppinfo("height value for provided Roof geometry."))
        .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Calculated width of horizontal side of Building aligned with local X axis."))
        .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Calculated height of Building aligned with local Y axis."))
        .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Calculated depth of horizontal thickness of Building aligned with local -Z axis."))
        .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY).setAppinfo("Indicate whether initialization complete.")))
      .setProtoBody(new ProtoBody()
        .addChild(new Group()
          .addChild(new Switch("AuthorAssist1").setWhichChoice(-1)
            .addChild(new Transform("CoordinateAxesTransform")
              .addChild(new Inline("CoordinateAxes").setUrl(new String[] {"../../X3dForWebAuthors/Chapter03Grouping/CoordinateAxes.x3d","https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter03Grouping/CoordinateAxes.x3d","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/CoordinateAxes.x3d","../../X3dForWebAuthors/Chapter03Grouping/CoordinateAxes.wrl","https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter03Grouping/CoordinateAxes.wrl","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/CoordinateAxes.wrl"}))))
          .addChild(new Group("BuildingRoot")
            .addChild(new Transform("LevelsRoot")
              .addChild(new Switch("AuthorAssist2").setWhichChoice(-1)
                .addChild(new Transform("AuthorAssistTransform2")
                  .addChild(new Inline().setUrl(new String[] {"GridXY_20x20Movable.wrl","https://www.web3d.org/x3d/content/examples/Basic/course/GridXY_20x20Movable.wrl","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/GridXY_20x20Movable.wrl","GridXY_20x20Movable.x3d","https://www.web3d.org/x3d/content/examples/Basic/course/GridXY_20x20Movable.x3d","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/GridXY_20x20Movable.x3d"}))
                  .addChild(new Inline().setUrl(new String[] {"GridXZ_20x20Movable.wrl","https://www.web3d.org/x3d/content/examples/Basic/course/GridXZ_20x20Movable.wrl","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/GridXZ_20x20Movable.wrl","GridXZ_20x20Movable.x3d","https://www.web3d.org/x3d/content/examples/Basic/course/GridXZ_20x20Movable.x3d","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/GridXZ_20x20Movable.x3d"}))
                  .addChild(new Inline().setUrl(new String[] {"GridYZ_20x20Movable.wrl","https://www.web3d.org/x3d/content/examples/Basic/course/GridYZ_20x20Movable.wrl","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/GridYZ_20x20Movable.wrl","GridYZ_20x20Movable.x3d","https://www.web3d.org/x3d/content/examples/Basic/course/GridYZ_20x20Movable.x3d","https://www.web3d.org/x3d/content/examples/Savage/Tools/Authoring/GridYZ_20x20Movable.x3d"})))))
            .addChild(new Script("BuildingConstructionScript").setDirectOutput(true).setSourceCode("""
ecmascript:

var firstLoopWhileTrueCompleted;

function tracePrint (outputString)
{
	if (traceEnabled) Browser.println ('[Building' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.println ('[Building' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	firstLoopWhileTrueCompleted = false;
	alwaysPrint ('initialize, built=' + built);
}
function recheckUntilBuilt (value)
{
	if      (built == true)
	{
		built = true; // resend to trigger cancellation event for TimeSensor
		if (firstLoopWhileTrueCompleted)
			alwaysPrint ('recheckUntilBuilt() continuous built=true indicates internal error');
		else firstLoopWhileTrueCompleted = true;
		return;  // done
	}
	tracePrint ('recheckUntilBuilt testing...');
	if      (built == true)			return;  // done
	for (i=0; i < levels.length; i++)
	{
		if (levels[i].built == false)	return;  // not yet ready
	}
	tracePrint ('recheckUntilBuilt ready!');

	alwaysPrint ('description=' + description);
	if (levels.length == 0)
	{
		alwaysPrint ('** warning, no levels found');
		return;
	}
	orientation = new SFRotation (0, 1, 0, -xHeading * 3.14159 / 180.0);
	LevelsRoot.rotation = orientation;
	tracePrint ('xHeading=' + xHeading + ' degrees,' + 'orientation=' + orientation);

	width  = 0;
	depth  = 0;
	incrementalHeight = 0;
	// first child of LevelsRoot is oriented AuthorAssist2 Switch
	for (i=0; i < levels.length; i++)
	{
		tracePrint ('level[' + i + ']');
		// compute max values for width, height, depth
		if (width  < levels[i].width)  width   = levels[i].width;
		if (depth  < levels[i].depth)  depth   = levels[i].depth;

		newTransform ='Transform {' +
		'translation 0' + incrementalHeight + ' 0' +
		'}';
		tracePrint ('newTransform=' + newTransform);
		newTransformNode = Browser.createVrmlFromString (newTransform); // returns MFNode
		// append newTransformNode to LevelsRoot.children
		LevelsRoot.children[i+1] = newTransformNode[0];
		// append current Level to current newTransformNode
		newTransformNode[0].children[0] = levels[i];

		incrementalHeight += levels[i].height;
		tracePrint ('incrementalHeight=' + incrementalHeight);
	}
	childCount = levels.length + 1;
	if (roof)
	{
		tracePrint ('roof');
		newTransform ='Transform {' +
		'translation 0' + incrementalHeight + ' 0' +
		'}';
		tracePrint ('newTransform=' + newTransform);
		newTransformNode = Browser.createVrmlFromString (newTransform); // returns MFNode
		// append newTransformNode to LevelsRoot.children
		LevelsRoot.children[childCount] = newTransformNode[0];
		childCount++;
		// append roof to current newTransformNode
		newTransformNode[0].children[0] = roof;
		incrementalHeight += roofHeight;
	}
	else alwaysPrint ('** warning, no roof found');

	height = incrementalHeight;
	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');
	maxDimension = width;
	if (maxDimension < height) maxDimension = height;
	if (maxDimension < depth)  maxDimension = depth;
	scale = new SFVec3f (maxDimension * 1.1, maxDimension * 1.1, maxDimension * 1.1);

	newView ='Viewpoint {' +
	'description \"' + name + ' (' + latitude + ',' + longitude + ')\"' +
	'position' + (width/2) + ' ' + (height*2.0/3.0) + ' ' + (depth*3) + ' ' +
	'}';
	tracePrint ('newView=' + newView);
	newViewNode = Browser.createVrmlFromString (newView); // returns MFNode
	// append newViewNode to LevelsRoot.children
	LevelsRoot.children[childCount] = newViewNode[0];
	childCount++;

	newView ='Viewpoint {' +
	'description \"' + name + ' (above)\"' +
	'position' + (width/2) + ' ' + (height*3.0) + ' ' + (-depth/2) + ' ' +
	'orientation 1 0 0 -1.57' +
	'}';
	tracePrint ('newView=' + newView);
	newViewNode = Browser.createVrmlFromString (newView); // returns MFNode
	// append newViewNode to LevelsRoot.children
	LevelsRoot.children[childCount] = newViewNode[0];
	childCount++;

	if (authorAssist)
	{
		tracePrint ('authorAssist');
		authorAssistChoice = 0;
	}
	else	authorAssistChoice = -1;

	tracePrint ('LevelsRoot childCount=' + childCount + ' (Switch + # levels + [roof] + Viewpoint*2)');
	built = true;
	tracePrint ('built=' + built);
}
""")
              .addField(new field().setName("name").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("description").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("xHeading").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("orientation").setType(field.TYPE_SFROTATION).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("latitude").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("longitude").setType(field.TYPE_SFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("authorAssist").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("levels").setType(field.TYPE_MFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("roof").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("roofHeight").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
              .addField(new field().setName("LevelsRoot").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
                .addChild(new Transform().setUSE("LevelsRoot")))
              .addField(new field().setName("width").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("depth").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("scale").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("authorAssistChoice").setType(field.TYPE_SFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .addField(new field().setName("traceEnabled").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
              .addField(new field().setName("recheckUntilBuilt").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INPUTONLY).setAppinfo("New floor or wall initialization may be complete check and recalculate until built"))
              .addField(new field().setName("built").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
              .setIS(new IS()
                .addConnect(new connect().setNodeField("name").setProtoField("name"))
                .addConnect(new connect().setNodeField("description").setProtoField("description"))
                .addConnect(new connect().setNodeField("authorAssist").setProtoField("authorAssist"))
                .addConnect(new connect().setNodeField("xHeading").setProtoField("xHeading"))
                .addConnect(new connect().setNodeField("orientation").setProtoField("orientation"))
                .addConnect(new connect().setNodeField("latitude").setProtoField("latitude"))
                .addConnect(new connect().setNodeField("longitude").setProtoField("longitude"))
                .addConnect(new connect().setNodeField("levels").setProtoField("levels"))
                .addConnect(new connect().setNodeField("roof").setProtoField("roof"))
                .addConnect(new connect().setNodeField("roofHeight").setProtoField("roofHeight"))
                .addConnect(new connect().setNodeField("width").setProtoField("width"))
                .addConnect(new connect().setNodeField("height").setProtoField("height"))
                .addConnect(new connect().setNodeField("depth").setProtoField("depth"))
                .addConnect(new connect().setNodeField("built").setProtoField("built"))))
            .addChild(new ROUTE().setFromNode("BuildingConstructionScript").setFromField("authorAssistChoice").setToNode("AuthorAssist1").setToField("whichChoice"))
            .addChild(new ROUTE().setFromNode("BuildingConstructionScript").setFromField("authorAssistChoice").setToNode("AuthorAssist2").setToField("whichChoice"))
            .addChild(new ROUTE().setFromNode("BuildingConstructionScript").setFromField("scale").setToNode("CoordinateAxesTransform").setToField("scale"))
            .addChild(new Group("BuildingInitializeAfterChildrenReady")
              .addChild(new BooleanFilter("BuildingBuiltFilter"))
              .addChild(new BooleanFilter("BuildingBuiltNegation"))
              .addChild(new TimeSensor("BuildingRecalculateUntilBuilt").setCycleInterval(0.1).setLoop(true))
              .addChild(new ROUTE().setFromNode("BuildingConstructionScript").setFromField("built").setToNode("BuildingBuiltFilter").setToField("set_boolean"))
              .addChild(new ROUTE().setFromNode("BuildingBuiltFilter").setFromField("inputTrue").setToNode("BuildingBuiltNegation").setToField("set_boolean"))
              .addChild(new ROUTE().setFromNode("BuildingBuiltNegation").setFromField("inputNegate").setToNode("BuildingRecalculateUntilBuilt").setToField("enabled"))
              .addChild(new ROUTE().setFromNode("BuildingRecalculateUntilBuilt").setFromField("cycleTime").setToNode("BuildingConstructionScript").setToField("recheckUntilBuilt")))))))
    .addComments(" ============================ ")
    .addChild(new Viewpoint().setDescription("SimpleBuildingConstructionPrototypes").setPosition(0.0,0.0,12.0))
    .addChild(new Background().setGroundAngle(new double[] {1.57}).setGroundColor(new MFColor(new double[] {0.6,0.9,0.6,0.6,0.9,0.6})).setSkyColor(new MFColor(new double[] {0.6,0.6,0.9})))
    .addChild(new Anchor().setDescription("SimpleBuildingConstructionExample").setParameter(new String[] {"target=_blank"}).setUrl(new String[] {"SimpleBuildingConstructionExample.wrl","https://www.web3d.org/x3d/content/examples/Savage/Buildings/UHRB/SimpleBuildingConstructionExample.wrl","SimpleBuildingConstructionExample.x3d","https://www.web3d.org/x3d/content/examples/Savage/Buildings/UHRB/SimpleBuildingConstructionExample.x3d"})
      .addChild(new Shape()
        .setGeometry(new Text().setString(new String[] {"SimpleBuildingConstructionPrototypes","is a prototype definition file","","Click this text to see","SimpleBuildingConstructionExample"})
          .setFontStyle(new FontStyle().setJustify(FontStyle.JUSTIFY_MIDDLE_MIDDLE)))
        .setAppearance(new Appearance()
          .setMaterial(new Material().setDiffuseColor(0.2,0.2,0.8))))));
            }
            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 SimpleBuildingConstructionPrototypes 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 SimpleBuildingConstructionPrototypes().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.UHRB.SimpleBuildingConstructionPrototypes\" 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.UHRB.SimpleBuildingConstructionPrototypes self-validation test confirmation: ");
                if (!validationResults.equals("success"))
                    System.out.println();
                System.out.println(validationResults.trim());

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