/**
   * Set the fields of the sensor node that has the fields set based on the fields of the passed in
   * node. This will not copy any children nodes, only the local fields.
   *
   * @param node The sensor node to copy info from
   */
  protected void copy(VRMLPickingSensorNodeType node) {

    super.copy(node);

    try {
      int index = node.getFieldIndex("sortOrder");
      VRMLFieldData field = node.getFieldValue(index);
      vfSortOrder = field.stringValue;

      Integer i = (Integer) sortTypeMap.get(vfSortOrder);
      sortType = i.intValue();

      index = node.getFieldIndex("sortOrder");
      field = node.getFieldValue(index);
      vfIntersectionType = field.stringValue;

      i = (Integer) sortTypeMap.get(vfIntersectionType);
      intersectionType = i.intValue();

      index = node.getFieldIndex("objectType");
      field = node.getFieldValue(index);

      if (field.numElements != 0) {
        vfObjectType = new String[field.numElements];
        System.arraycopy(field.stringArrayValue, 0, vfObjectType, 0, field.numElements);
      }

    } catch (VRMLException ve) {
      throw new IllegalArgumentException(ve.getMessage());
    }
  }
  /**
   * Add a single child node to the list of available children. This auto matically deals with
   * DEF/USE and adds links and branchgroups where appropriate. When nodes are null, we do not add
   * them to the GL representation, only to the vfChildren list.
   *
   * @param node The node to view
   * @throws InvalidFieldValueException This is a bindable node shared
   */
  protected void addChildNode(VRMLNodeType node) throws InvalidFieldValueException {

    super.addChildNode(node);

    OGLVRMLNode n = (OGLVRMLNode) node;

    if (!inSetup) {
      Node ogl_node = (Node) n.getSceneGraphObject();
      oglChildMap.put(node, ogl_node);

      if (implGroup.isLive()) {
        addedChildren.add(ogl_node);
        implGroup.boundsChanged(this);
      } else implGroup.addChild(ogl_node);
    }

    // Finally check for sensors that we need to deal with.
    VRMLPointingDeviceSensorNodeType sensor = null;

    if (node instanceof VRMLPointingDeviceSensorNodeType)
      sensor = (VRMLPointingDeviceSensorNodeType) node;
    else if (node instanceof VRMLProtoInstance) {
      Object impl = ((VRMLProtoInstance) node).getImplementationNode();

      if (impl instanceof VRMLPointingDeviceSensorNodeType)
        sensor = (VRMLPointingDeviceSensorNodeType) impl;
    }

    if (sensor != null) {
      // So we have a valid sensor. Let's now add it to the
      // system. We only add the sensor itself, even if wrapped in a
      // proto. This is so that the processing of sensors doesn't need
      // to stuff around with the details of protos. As far as the proto
      // node is concerned it just wants the full events, not the
      // restricted view the outside of the proto would give.
      if (inSetup) sensorList.add(sensor);
      else {
        OGLUserData data = (OGLUserData) implGroup.getUserData();

        if (data == null) {
          data = new OGLUserData();
          implGroup.setUserData(data);
        }

        if (data.sensors == null) {
          data.sensors = new VRMLPointingDeviceSensorNodeType[1];
          data.sensors[0] = sensor;
        } else {
          int size = data.sensors.length;
          VRMLPointingDeviceSensorNodeType[] tmp = new VRMLPointingDeviceSensorNodeType[size + 1];

          System.arraycopy(data.sensors, 0, tmp, 0, size);
          tmp[size] = sensor;
          data.sensors = tmp;
        }
      }
    }
  }
  /**
   * Set the list of picking targets that this object corresponds to. These can be an array of
   * strings.
   *
   * @param types The list of object type strings to use
   * @param numValid The number of valid values to read from the array
   */
  public void setObjectType(String[] types, int numValid) {
    if (vfObjectType.length != numValid) vfObjectType = new String[numValid];

    System.arraycopy(types, 0, vfObjectType, 0, numValid);

    if (!inSetup) {
      hasChanged[FIELD_OBJECT_TYPE] = true;
      fireFieldChanged(FIELD_OBJECT_TYPE);
    }
  }
  /**
   * Process the picked geometry output.
   *
   * @param numPicks The number of items picked in the array
   * @param geom The geometry that was picked
   */
  private void processPickedGeometry(int numPicks, VRMLNodeType[] geom) {

    if ((vfPickedGeometry == null) || (vfPickedGeometry.length < numPicks))
      vfPickedGeometry = new VRMLNodeType[numPicks];

    System.arraycopy(geom, 0, vfPickedGeometry, 0, numPicks);
    numPickedGeometry = numPicks;

    hasChanged[FIELD_PICKED_GEOMETRY] = true;
    fireFieldChanged(FIELD_PICKED_GEOMETRY);
  }
  /**
   * Construct a new instance of this node based on the details from the given node. If the node is
   * not the same type, an exception will be thrown.
   *
   * @param node The node to copy
   * @throws IllegalArgumentException Incorrect Node Type
   */
  protected BaseMultiTexture(VRMLNodeType node) {
    this();

    checkNodeType(node);

    try {
      int index = node.getFieldIndex("mode");
      VRMLFieldData field = node.getFieldValue(index);
      if (field.numElements != 0) {
        vfMode = new String[field.numElements];
        System.arraycopy(field.stringArrayValue, 0, vfMode, 0, field.numElements);
      }

      index = node.getFieldIndex("function");
      field = node.getFieldValue(index);
      if (field.numElements != 0) {
        vfFunction = new String[field.numElements];
        System.arraycopy(field.stringArrayValue, 0, vfFunction, 0, field.numElements);
      }

      index = node.getFieldIndex("source");
      field = node.getFieldValue(index);
      if (field.numElements != 0) {
        vfSource = new String[field.numElements];
        System.arraycopy(field.stringArrayValue, 0, vfSource, 0, field.numElements);
      }

      index = node.getFieldIndex("color");
      field = node.getFieldValue(index);
      vfColor[0] = field.floatArrayValue[0];
      vfColor[1] = field.floatArrayValue[1];
      vfColor[2] = field.floatArrayValue[2];

      index = node.getFieldIndex("alpha");
      field = node.getFieldValue(index);
      vfAlpha = field.floatValue;

    } catch (VRMLException ve) {
      throw new IllegalArgumentException(ve.getMessage());
    }
  }
  /**
   * Remove the given node from this grouping node. If the node is not a child of this node, the
   * request is silently ignored.
   *
   * @param node The node to remove
   */
  protected void removeChildNode(VRMLNodeType node) {
    if (!oglChildMap.containsKey(node)) return;

    if (!inSetup) {
      Node ogl_node = (Node) oglChildMap.get(node);
      oglChildMap.remove(node);

      if (implGroup.isLive()) {
        removedChildren.add(ogl_node);
        implGroup.boundsChanged(this);
      } else implGroup.removeChild(ogl_node);
    }

    // Check to see if it is a sensor node and in therefore needs to be
    // removed from the current list.

    VRMLPointingDeviceSensorNodeType sensor = null;

    if (node instanceof VRMLPointingDeviceSensorNodeType)
      sensor = (VRMLPointingDeviceSensorNodeType) node;
    else if (node instanceof VRMLProtoInstance) {
      Object impl = ((VRMLProtoInstance) node).getImplementationNode();

      if (impl instanceof VRMLPointingDeviceSensorNodeType)
        sensor = (VRMLPointingDeviceSensorNodeType) impl;
    }

    if (sensor != null) {
      OGLUserData data = (OGLUserData) oglImplGroup.getUserData();

      int size = data.sensors.length;

      if (size == 1) {
        data.sensors = null;
      } else {
        int i;

        for (i = 0; i < size; i++) {
          if (data.sensors[i] == sensor) break;
        }

        for (; i < size - 1; i++) data.sensors[i] = data.sensors[i + 1];

        // now resize the array to suit
        VRMLPointingDeviceSensorNodeType[] tmp = new VRMLPointingDeviceSensorNodeType[size - 1];

        System.arraycopy(data.sensors, 0, tmp, 0, size - 1);
        data.sensors = tmp;
      }
    }

    super.removeChildNode(node);
  }
 /**
  * Fetch the number of object type values in use currently.
  *
  * @param val An array to copy the values to
  */
 public void getObjectType(String[] val) {
   System.arraycopy(vfObjectType, 0, val, 0, vfObjectType.length);
 }