/**
   * Send a routed value from this node to the given destination node. The route should use the
   * appropriate setValue() method of the destination node. It should not attempt to cast the node
   * up to a higher level. Routing should also follow the standard rules for the loop breaking and
   * other appropriate rules for the specification.
   *
   * @param time The time that this route occurred (not necessarily epoch time. Should be treated as
   *     a relative value only)
   * @param srcIndex The index of the field in this node that the value should be sent from
   * @param destNode The node reference that we will be sending the value to
   * @param destIndex The index of the field in the destination node that the value should be sent
   *     to.
   */
  public void sendRoute(double time, int srcIndex, VRMLNodeType destNode, int destIndex) {

    // Simple impl for now.  ignores time and looping

    try {
      switch (srcIndex) {
        case FIELD_PICKING_GEOMETRY:
          destNode.setValue(destIndex, vfPickingGeometry);
          break;

        case FIELD_PICK_TARGET:
          destNode.setValue(destIndex, vfPickTarget, vfPickTarget.length);
          break;

        case FIELD_PICKED_GEOMETRY:
          destNode.setValue(destIndex, vfPickedGeometry, numPickedGeometry);
          break;

        case FIELD_OBJECT_TYPE:
          destNode.setValue(destIndex, vfObjectType, vfObjectType.length);
          break;

        default:
          super.sendRoute(time, srcIndex, destNode, destIndex);
      }
    } catch (InvalidFieldException ife) {
      System.err.println("BasePickingNode.sendRoute: No field! " + srcIndex);
      ife.printStackTrace();
    } catch (InvalidFieldValueException ifve) {
      System.err.println("BasePickingNode.sendRoute: Invalid field value: " + ifve.getMessage());
    }
  }
  /**
   * Get the value of a field. If the field is a primitive type, it will return a class representing
   * the value. For arrays or nodes it will return the instance directly.
   *
   * @param index The index of the field to change.
   * @return The class representing the field value
   * @throws InvalidFieldException The field index is not known
   */
  public VRMLFieldData getFieldValue(int index) throws InvalidFieldException {
    VRMLFieldData fieldData = fieldLocalData.get();

    switch (index) {
      case FIELD_SPEED:
        fieldData.clear();
        fieldData.floatValue = vfSpeed;
        fieldData.dataType = VRMLFieldData.FLOAT_DATA;
        break;

      case FIELD_REPEAT_S:
        fieldData.clear();
        fieldData.booleanValue = vfRepeatS;
        fieldData.dataType = VRMLFieldData.BOOLEAN_DATA;
        break;

      case FIELD_REPEAT_T:
        fieldData.clear();
        fieldData.booleanValue = vfRepeatT;
        fieldData.dataType = VRMLFieldData.BOOLEAN_DATA;
        break;

      case FIELD_URL:
        fieldData.clear();
        fieldData.stringArrayValue = vfURL;
        fieldData.dataType = VRMLFieldData.STRING_ARRAY_DATA;
        fieldData.numElements = vfURL.length;
        break;

      case FIELD_DURATION:
        fieldData.clear();
        fieldData.doubleValue = vfDuration;
        fieldData.dataType = VRMLFieldData.DOUBLE_DATA;
        break;

      case FIELD_IS_ACTIVE:
        fieldData.clear();
        fieldData.booleanValue = vfIsActive;
        fieldData.dataType = VRMLFieldData.BOOLEAN_DATA;
        break;

      case FIELD_TEXTURE_PROPERTIES:
        if (vrmlMajorVersion <= 3 && vrmlMinorVersion < 2) {
          InvalidFieldException ife = new InvalidFieldException(TEXPROPS_VERSION_MSG);
          ife.setFieldName("TextureProperties");
          throw ife;
        }

        fieldData.clear();
        if (pTextureProperties != null) fieldData.nodeValue = pTextureProperties;
        else fieldData.nodeValue = vfTextureProperties;
        fieldData.dataType = VRMLFieldData.NODE_DATA;
        break;

      default:
        super.getFieldValue(index);
    }

    return fieldData;
  }
  /**
   * Send a routed value from this node to the given destination node. The route should use the
   * appropriate setValue() method of the destination node. It should not attempt to cast the node
   * up to a higher level. Routing should also follow the standard rules for the loop breaking and
   * other appropriate rules for the specification.
   *
   * @param time The time that this route occurred (not necessarily epoch time. Should be treated as
   *     a relative value only)
   * @param srcIndex The index of the field in this node that the value should be sent from
   * @param destNode The node reference that we will be sending the value to
   * @param destIndex The index of the field in the destination node that the value should be sent
   *     to.
   */
  public void sendRoute(double time, int srcIndex, VRMLNodeType destNode, int destIndex) {

    // Simple impl for now.  ignores time and looping. Note that for a
    // couple of the fields, if the array size is greater than the number
    // of components in it, we create a temporary array to send. This is
    // a negative hit, but it is very rare that someone will route out of
    // these fields, so we don't consider it to be a major impact compared
    // to the performance of having to reallocate the arrays every time
    // someone sets the values, which will happen much, much more often.

    try {
      switch (srcIndex) {
        case FIELD_BOUNDARY_COLOR:
          destNode.setValue(destIndex, vfBoundaryColor, 4);
          break;

        case FIELD_BOUNDARY_WIDTH:
          destNode.setValue(destIndex, vfBoundaryWidth);
          break;

        case FIELD_BOUNDARY_MODE_S:
          destNode.setValue(destIndex, vfBoundaryModeS);
          break;

        case FIELD_BOUNDARY_MODE_T:
          destNode.setValue(destIndex, vfBoundaryModeT);
          break;

        case FIELD_MAGNIFICATION_FILTER:
          destNode.setValue(destIndex, vfMagnificationFilter);
          break;

        case FIELD_MINIFICATION_FILTER:
          destNode.setValue(destIndex, vfMinificationFilter);
          break;

        case FIELD_GENERATE_MIPMAPS:
          destNode.setValue(destIndex, vfGenerateMipMaps);
          break;

        case FIELD_ANISOTROPIC_MODE:
          destNode.setValue(destIndex, vfAnisotropicMode);
          break;

        case FIELD_ANISOTROPIC_FILTER_DEGREE:
          destNode.setValue(destIndex, vfAnisotropicFilterDegree);
          break;

        default:
          super.sendRoute(time, srcIndex, destNode, destIndex);
      }
    } catch (InvalidFieldException ife) {
      System.err.println("sendRoute: No field!" + ife.getFieldName());
    } catch (InvalidFieldValueException ifve) {
      System.err.println("sendRoute: Invalid field Value: " + ifve.getMessage());
    }
  }
  /**
   * Get node content for the textureProperties field. This field is only available for X3D 3.2 or
   * later.
   *
   * @return The current field value
   * @throws InvalidFieldException This field was request in a field with spec version < 3.2
   */
  public VRMLNodeType getTextureProperties() throws InvalidFieldException {

    if (vrmlMajorVersion <= 3 && vrmlMinorVersion < 2) {
      InvalidFieldException ife = new InvalidFieldException(TEXPROPS_VERSION_MSG);
      ife.setFieldName("TextureProperties");
      throw ife;
    }

    if (pTextureProperties != null) {
      return pTextureProperties;
    } else {
      return vfTextureProperties;
    }
  }
  /**
   * Set node content as replacement for the textureProperties field. This field is only available
   * for X3D 3.2 or later.
   *
   * @param props The new value for geometry. Null will act like delete
   * @throws InvalidFieldValueException The node does not match the required type.
   * @throws InvalidFieldException This field was request in a field with spec version < 3.2
   */
  public void setTextureProperties(VRMLNodeType props)
      throws InvalidFieldValueException, InvalidFieldException {

    if (vrmlMajorVersion <= 3 && vrmlMinorVersion < 2) {
      InvalidFieldException ife = new InvalidFieldException(TEXPROPS_VERSION_MSG);
      ife.setFieldName("TextureProperties");
      throw ife;
    }

    VRMLNodeType old_node;

    if (pTextureProperties != null) old_node = pTextureProperties;
    else old_node = vfTextureProperties;

    if (props instanceof VRMLProtoInstance) {
      VRMLNodeType impl = ((VRMLProtoInstance) props).getImplementationNode();

      // Walk down the proto impl looking for the real node to check it
      // is the right type.
      while ((impl != null) && (impl instanceof VRMLProtoInstance))
        impl = ((VRMLProtoInstance) impl).getImplementationNode();

      if ((impl != null) && !(impl instanceof VRMLTextureProperties2DNodeType))
        throw new InvalidFieldValueException(TEXTURE_PROPS_PROTO_MSG);

      pTextureProperties = (VRMLProtoInstance) props;
      vfTextureProperties = (VRMLTextureProperties2DNodeType) impl;

    } else if (props != null && !(props instanceof VRMLTextureProperties2DNodeType)) {
      throw new InvalidFieldValueException(TEXTURE_PROPS_NODE_MSG);
    } else {
      pTextureProperties = null;
      vfTextureProperties = (VRMLTextureProperties2DNodeType) props;
    }

    if (props != null) updateRefs(props, true);

    if (old_node != null) updateRefs(old_node, false);

    if (!inSetup) {
      if (old_node != null) stateManager.registerRemovedNode(old_node);

      if (props != null) stateManager.registerAddedNode(props);

      hasChanged[FIELD_TEXTURE_PROPERTIES] = true;
      fireFieldChanged(FIELD_TEXTURE_PROPERTIES);
    }
  }
  /**
   * Send a routed value from this node to the given destination node. The route should use the
   * appropriate setValue() method of the destination node. It should not attempt to cast the node
   * up to a higher level. Routing should also follow the standard rules for the loop breaking and
   * other appropriate rules for the specification.
   *
   * @param time The time that this route occurred (not necessarily epoch time. Should be treated as
   *     a relative value only)
   * @param srcIndex The index of the field in this node that the value should be sent from
   * @param destNode The node reference that we will be sending the value to
   * @param destIndex The index of the field in the destination node that the value should be sent
   *     to.
   */
  public void sendRoute(double time, int srcIndex, VRMLNodeType destNode, int destIndex) {

    // Simple impl for now.  ignores time and looping

    try {
      switch (srcIndex) {
        case FIELD_TEXTURE_PROPERTIES:
          if (pTextureProperties != null) destNode.setValue(destIndex, pTextureProperties);
          else destNode.setValue(destIndex, vfTextureProperties);
          break;

        default:
          super.sendRoute(time, srcIndex, destNode, destIndex);
      }
    } catch (InvalidFieldException ife) {
      System.err.println("sendRoute: No field!" + ife.getFieldName());
    } catch (InvalidFieldValueException ifve) {
      System.err.println("sendRoute: Invalid field Value: " + ifve.getMessage());
    }
  }
  /**
   * Send a routed value from this node to the given destination node. The route should use the
   * appropriate setValue() method of the destination node. It should not attempt to cast the node
   * up to a higher level. Routing should also follow the standard rules for the loop breaking and
   * other appropriate rules for the specification.
   *
   * @param time The time that this route occurred (not necessarily epoch time. Should be treated as
   *     a relative value only)
   * @param srcIndex The index of the field in this node that the value should be sent from
   * @param destNode The node reference that we will be sending the value to
   * @param destIndex The index of the field in the destination node that the value should be sent
   *     to.
   */
  public void sendRoute(double time, int srcIndex, VRMLNodeType destNode, int destIndex) {

    // Simple impl for now.  ignores time and looping

    try {
      switch (srcIndex) {
        case FIELD_MODE:
          destNode.setValue(destIndex, vfMode, vfMode.length);
          break;

        case FIELD_FUNCTION:
          destNode.setValue(destIndex, vfFunction, vfFunction.length);
          break;

        case FIELD_SOURCE:
          destNode.setValue(destIndex, vfSource, vfSource.length);
          break;

        case FIELD_COLOR:
          destNode.setValue(destIndex, vfColor, 3);
          break;

        case FIELD_TEXTURE:
          VRMLNodeType kids[] = new VRMLNodeType[vfTexture.size()];
          vfTexture.toArray(kids);
          destNode.setValue(destIndex, kids, kids.length);
          break;

        case FIELD_ALPHA:
          destNode.setValue(destIndex, vfAlpha);
          break;

        default:
          super.sendRoute(time, srcIndex, destNode, destIndex);
      }
    } catch (InvalidFieldException ife) {
      System.err.println("sendRoute: No field!" + ife.getFieldName());
    } catch (InvalidFieldValueException ifve) {
      System.err.println("sendRoute: Invalid field Value: " + ifve.getMessage());
    }
  }
  /**
   * Send a routed value from this node to the given destination node. The route should use the
   * appropriate setValue() method of the destination node. It should not attempt to cast the node
   * up to a higher level. Routing should also follow the standard rules for the loop breaking and
   * other appropriate rules for the specification.
   *
   * @param time The time that this route occurred (not necessarily epoch time. Should be treated as
   *     a relative value only)
   * @param srcIndex The index of the field in this node that the value should be sent from
   * @param destNode The node reference that we will be sending the value to
   * @param destIndex The index of the field in the destination node that the value should be sent
   *     to.
   */
  public void sendRoute(double time, int srcIndex, VRMLNodeType destNode, int destIndex) {

    // Simple impl for now.  ignores time and looping

    try {
      switch (srcIndex) {
        case FIELD_NAME:
          destNode.setValue(destIndex, vfName);
          break;
        case FIELD_SHAPE:
          if (pShape != null) destNode.setValue(destIndex, pShape);
          else destNode.setValue(destIndex, vfShape);
          break;

        default:
          super.sendRoute(time, srcIndex, destNode, destIndex);
      }
    } catch (InvalidFieldException ife) {
      System.err.println("sendRoute: No field!" + ife.getFieldName());
    } catch (InvalidFieldValueException ifve) {
      System.err.println("sendRoute: Invalid fieldValue: " + ifve.getMessage());
    }
  }