/**
   * find the definiton from this statement (loads it if necessary)
   *
   * @param statement the statement being read
   * @return the definition
   * @throws IOException
   */
  public ShaderNodeDefinition findDefinition(Statement statement) throws IOException {
    String defLine[] = statement.getLine().split(":");
    String defName = defLine[1].trim();

    ShaderNodeDefinition def = getNodeDefinitions().get(defName);
    if (def == null) {
      if (defLine.length == 3) {
        List<ShaderNodeDefinition> defs = null;
        try {
          defs = assetManager.loadAsset(new ShaderNodeDefinitionKey(defLine[2].trim()));
        } catch (AssetNotFoundException e) {
          throw new MatParseException("Couldn't find " + defLine[2].trim(), statement, e);
        }

        for (ShaderNodeDefinition definition : defs) {
          definition.setPath(defLine[2].trim());
          if (defName.equals(definition.getName())) {
            def = definition;
          }
          if (!(getNodeDefinitions().containsKey(definition.getName()))) {
            getNodeDefinitions().put(definition.getName(), definition);
          }
        }
      }
      if (def == null) {
        throw new MatParseException(
            defName + " is not a declared as Shader Node Definition", statement);
      }
    }
    return def;
  }
 /**
  * reads a list of ShaderNode{} blocks
  *
  * @param statements the list of statements to parse
  * @throws IOException
  */
 protected void readShaderNode(List<Statement> statements) throws IOException {
   for (Statement statement : statements) {
     String line = statement.getLine();
     String[] split = statement.getLine().split("[ \\{]");
     if (line.startsWith("Definition")) {
       ShaderNodeDefinition def = findDefinition(statement);
       shaderNode.setDefinition(def);
       if (def.isNoOutput()) {
         techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName());
       }
     } else if (line.startsWith("Condition")) {
       String condition = line.substring(line.lastIndexOf(":") + 1).trim();
       extractCondition(condition, statement);
       shaderNode.setCondition(conditionParser.getFormattedExpression());
     } else if (line.startsWith("InputMapping")) {
       for (Statement statement1 : statement.getContents()) {
         VariableMapping mapping = readInputMapping(statement1);
         techniqueDef
             .getShaderGenerationInfo()
             .getUnusedNodes()
             .remove(mapping.getRightVariable().getNameSpace());
         shaderNode.getInputMapping().add(mapping);
       }
     } else if (line.startsWith("OutputMapping")) {
       for (Statement statement1 : statement.getContents()) {
         VariableMapping mapping = readOutputMapping(statement1);
         techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName());
         shaderNode.getOutputMapping().add(mapping);
       }
     } else {
       throw new MatParseException("ShaderNodeDefinition", split[0], statement);
     }
   }
 }
  /**
   * effectiveliy reads the ShaderNodesDefinitions block
   *
   * @param statements the list of statements to parse
   * @param key the ShaderNodeDefinitionKey
   * @throws IOException
   */
  protected void readShaderNodeDefinition(List<Statement> statements, ShaderNodeDefinitionKey key)
      throws IOException {
    boolean isLoadDoc =
        key instanceof ShaderNodeDefinitionKey
            && ((ShaderNodeDefinitionKey) key).isLoadDocumentation();
    for (Statement statement : statements) {
      String[] split = statement.getLine().split("[ \\{]");
      String line = statement.getLine();

      if (line.startsWith("Type")) {
        String type = line.substring(line.lastIndexOf(':') + 1).trim();
        shaderNodeDefinition.setType(Shader.ShaderType.valueOf(type));
      } else if (line.startsWith("Shader ")) {
        readShaderStatement(statement);
        shaderNodeDefinition.getShadersLanguage().add(shaderLanguage);
        shaderNodeDefinition.getShadersPath().add(shaderName);
      } else if (line.startsWith("Documentation")) {
        if (isLoadDoc) {
          String doc = "";
          for (Statement statement1 : statement.getContents()) {
            doc += "\n" + statement1.getLine();
          }
          shaderNodeDefinition.setDocumentation(doc);
        }
      } else if (line.startsWith("Input")) {
        varNames = "";
        for (Statement statement1 : statement.getContents()) {
          shaderNodeDefinition.getInputs().add(readVariable(statement1));
        }
      } else if (line.startsWith("Output")) {
        varNames = "";
        for (Statement statement1 : statement.getContents()) {
          if (statement1.getLine().trim().equals("None")) {
            shaderNodeDefinition.setNoOutput(true);
          } else {
            shaderNodeDefinition.getOutputs().add(readVariable(statement1));
          }
        }
      } else {
        throw new MatParseException(
            "one of Type, Shader, Documentation, Input, Output", split[0], statement);
      }
    }
  }
  /**
   * Read the ShaderNodesDefinitions block and returns a list of ShaderNodesDefinition This method
   * is used by the j3sn loader
   *
   * <p>note that the order of the definitions in the list is not guaranteed.
   *
   * @param statements the list statements to parse
   * @param key the ShaderNodeDefinitionKey
   * @return a list of ShaderNodesDefinition
   * @throws IOException
   */
  public List<ShaderNodeDefinition> readNodesDefinitions(
      List<Statement> statements, ShaderNodeDefinitionKey key) throws IOException {

    for (Statement statement : statements) {
      String[] split = statement.getLine().split("[ \\{]");
      if (statement.getLine().startsWith("ShaderNodeDefinition")) {
        String name = statement.getLine().substring("ShaderNodeDefinition".length()).trim();

        if (!getNodeDefinitions().containsKey(name)) {
          shaderNodeDefinition = new ShaderNodeDefinition();
          getNodeDefinitions().put(name, shaderNodeDefinition);
          shaderNodeDefinition.setName(name);
          readShaderNodeDefinition(statement.getContents(), key);
        }
      } else {
        throw new MatParseException("ShaderNodeDefinition", split[0], statement);
      }
    }

    return new ArrayList<ShaderNodeDefinition>(getNodeDefinitions().values());
  }