/**
   * 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;
  }
  /**
   * 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);
    }
  }