code: package org.sunflow;
  
  import java.util.Locale;
  
  import org.sunflow.core.Display;
  import org.sunflow.core.ParameterList.InterpolationType;
  import org.sunflow.core.parser.SCAbstractParser.Keyword;
  import org.sunflow.image.ColorFactory;
  import org.sunflow.math.Matrix4;
  import org.sunflow.math.Point2;
  import org.sunflow.math.Point3;
  import org.sunflow.math.Vector3;
  import org.sunflow.system.UI;
  import org.sunflow.system.UI.Module;
  
  abstract class FileSunflowAPI implements SunflowAPIInterface {
      private int frame;
  
      protected FileSunflowAPI() {
          frame = 1;
          reset();
      }
  
      public void camera(String name, String lensType) {
          writeKeyword(Keyword.CAMERA);
          writeString(name);
          writeString(lensType);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void geometry(String name, String typeName) {
          writeKeyword(Keyword.GEOMETRY);
          writeString(name);
          writeString(typeName);
          writeNewline(0);
          writeNewline(0);
      }
  
      public int getCurrentFrame() {
          return frame;
      }
  
      public void instance(String name, String geoname) {
          writeKeyword(Keyword.INSTANCE);
          writeString(name);
          writeString(geoname);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void light(String name, String lightType) {
          writeKeyword(Keyword.LIGHT);
          writeString(name);
          writeString(lightType);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void modifier(String name, String modifierType) {
          writeKeyword(Keyword.MODIFIER);
          writeString(name);
          writeString(modifierType);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void options(String name) {
          writeKeyword(Keyword.OPTIONS);
          writeString(name);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void parameter(String name, String value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.STRING);
          writeString(value);
          writeNewline(0);
      }
  
      public void parameter(String name, boolean value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.BOOL);
          writeBoolean(value);
          writeNewline(0);
      }
  
      public void parameter(String name, int value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.INT);
          writeInt(value);
          writeNewline(0);
      }
  
      public void parameter(String name, float value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.FLOAT);
          writeFloat(value);
          writeNewline(0);
      }
  
      public void parameter(String name, String colorspace, float... data) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.COLOR);
          if (colorspace == null)
              writeString(colorspace = ColorFactory.getInternalColorspace());
          else
              writeString(colorspace);
          if (ColorFactory.getRequiredDataValues(colorspace) == -1)
              writeInt(data.length);
          int idx = 0;
          int step = 9;
          for (float f : data) {
              if (data.length > step && idx % step == 0)
                  writeNewline(1);
              writeFloat(f);
              idx++;
          }
          writeNewline(0);
      }
  
      public void parameter(String name, Point3 value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.POINT);
          writeFloat(value.x);
          writeFloat(value.y);
          writeFloat(value.z);
          writeNewline(0);
      }
  
      public void parameter(String name, Vector3 value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.VECTOR);
          writeFloat(value.x);
          writeFloat(value.y);
          writeFloat(value.z);
          writeNewline(0);
      }
  
      public void parameter(String name, Point2 value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.TEXCOORD);
          writeFloat(value.x);
          writeFloat(value.y);
          writeNewline(0);
      }
  
      public void parameter(String name, Matrix4 value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.MATRIX);
          writeMatrix(value);
          writeNewline(0);
      }
  
      public void parameter(String name, int[] value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.INT_ARRAY);
          writeInt(value.length);
          int idx = 0;
          int step = 9;
          for (int v : value) {
              if (idx % step == 0)
                  writeNewline(1);
              writeInt(v);
              idx++;
          }
          writeNewline(0);
      }
  
      public void parameter(String name, String[] value) {
          writeKeyword(Keyword.PARAMETER);
          writeString(name);
          writeKeyword(Keyword.STRING_ARRAY);
          writeInt(value.length);
          for (String v : value) {
              writeNewline(1);
              writeString(v);
          }
          writeNewline(0);
      }
  
      public void parameter(String name, String type, String interpolation, float[] data) {
          InterpolationType interp;
          try {
              interp = InterpolationType.valueOf(interpolation.toUpperCase(Locale.ENGLISH));
          } catch (IllegalArgumentException e) {
              UI.printError(Module.API, "Unknown interpolation type: %s -- ignoring parameter \"%s\"", interpolation, name);
              return;
          }
          Keyword typeKeyword;
          int lengthFactor;
          if (type.equals("float")) {
              typeKeyword = Keyword.FLOAT_ARRAY;
              lengthFactor = 1;
          } else if (type.equals("point")) {
              typeKeyword = Keyword.POINT_ARRAY;
              lengthFactor = 3;
          } else if (type.equals("vector")) {
              typeKeyword = Keyword.VECTOR_ARRAY;
              lengthFactor = 3;
          } else if (type.equals("texcoord")) {
              typeKeyword = Keyword.TEXCOORD_ARRAY;
              lengthFactor = 2;
          } else if (type.equals("matrix")) {
              typeKeyword = Keyword.MATRIX_ARRAY;
              lengthFactor = 16;
          } else {
              UI.printError(Module.API, "Unknown parameter type: %s -- ignoring parameter \"%s\"", type, name);
              return;
          }
          writeKeyword(Keyword.PARAMETER);
  
          writeString(name);
          writeKeyword(typeKeyword);
          writeInterpolationType(interp);
          writeInt(data.length / lengthFactor);
          int idx = 0;
          if (data.length > 16)
              lengthFactor *= 8;
          for (float v : data) {
              if (lengthFactor > 1 && idx % lengthFactor == 0)
                  writeNewline(1);
              writeFloat(v);
              idx++;
          }
          writeNewline(0);
      }
  
      public boolean include(String filename) {
          writeKeyword(Keyword.INCLUDE);
          writeString(filename);
          writeNewline(0);
          writeNewline(0);
          return true;
      }
  
      public void plugin(String type, String name, String code) {
          writeKeyword(Keyword.PLUGIN);
          writeString(type);
          writeString(name);
          writeVerbatimString(code);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void remove(String name) {
          writeKeyword(Keyword.REMOVE);
          writeString(name);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void render(String optionsName, Display display) {
          UI.printWarning(Module.API, "Unable to render file stream");
      }
  
      public void reset() {
          frame = 1;
      }
  
      public void searchpath(String type, String path) {
          writeKeyword(Keyword.SEARCHPATH);
          writeString(type);
          writeString(path);
          writeNewline(0);
          writeNewline(0);
  
      }
  
      public void currentFrame(int currentFrame) {
          writeKeyword(Keyword.FRAME);
          writeInt(frame = currentFrame);
          writeNewline(0);
          writeNewline(0);
      }
  
      public void shader(String name, String shaderType) {
          writeKeyword(Keyword.SHADER);
          writeString(name);
          writeString(shaderType);
          writeNewline(0);
          writeNewline(0);
      }
  
      protected abstract void writeKeyword(Keyword keyword);
  
      protected abstract void writeInterpolationType(InterpolationType interp);
  
      protected abstract void writeBoolean(boolean value);
  
      protected abstract void writeInt(int value);
  
      protected abstract void writeFloat(float value);
  
      protected abstract void writeString(String string);
  
      protected abstract void writeVerbatimString(String string);
  
      protected abstract void writeMatrix(Matrix4 value);
  
      protected abstract void writeNewline(int indentNext);
      
      public abstract void close();
  }