/*
   * When generating (no) code for init routine, also generate File*
   * and close() for file.
   */
  private static void genFileWriterInit(
      SIRFileWriter fw,
      CType return_type,
      String function_name,
      int selfID,
      List /*String*/ cleanupCode,
      CodegenPrintWriter p) {

    int id = NodeEnumerator.getSIROperatorId(fw);

    String theType = "" + fw.getInputType();
    String bits_to_go = bitsToGoName(fw);
    String the_bits = theBitsName(fw);

    if (theType.equals("bit")) {
      p.println("FILE* " + fpName(fw) + ";");
    }

    if (theType.equals("bit")) {
      // the bit type is special since you can not just read or
      // write a bit.  It requires buffering in some larger
      // integer type.

      p.println(bits_type + " " + the_bits + " = 0;");
      p.println("int " + bits_to_go + " = 8 * sizeof(" + the_bits + ");");
    }
    p.newLine();

    startParameterlessFunction(CommonUtils.CTypeToStringA(return_type, true), function_name, p);

    if (theType.equals("bit")) {
      p.println(fpName(fw) + " = fopen(\"" + fw.getFileName() + "\", \"w\");");
      p.println("assert (" + fpName(fw) + ");");
    } else {
      p.print("__file_descr__" + id + " = FileWriter_open(\"" + fw.getFileName() + "\");");
      p.newLine();
      p.print("assert (__file_descr__" + id + ");");
      p.newLine();
    }

    endFunction(p);

    String closeName = ClusterUtils.getWorkName(fw, selfID) + "__close";

    startParameterlessFunction("void", closeName, p);
    if (theType.equals("bit")) {
      p.println("if (" + bits_to_go + " != 8 * sizeof(" + the_bits + ")) {");
      p.indent();
      p.println(the_bits + " = " + the_bits + " << " + bits_to_go + ";");
      p.println(
          "fwrite("
              + "&"
              + the_bits
              + ", "
              + "sizeof("
              + the_bits
              + "), "
              + "1, "
              + fpName(fw)
              + ");");
      p.outdent();
      p.println("}");
    }

    if (theType.equals("bit")) {
      p.println("fclose(" + fpName(fw) + ");");
    } else {
      p.println("FileWriter_flush(__file_descr__" + id + ");");
      p.println("FileWriter_close(__file_descr__" + id + ");");
    }

    endFunction(p);

    cleanupCode.add(closeName + "();\n");
  }
  /*
   * File writer code currently works by using fwrite.
   *
   * The File* is declared outside any function / method.
   *
   * There is special case code for FileReader<bit> since individual
   * bits can not be read in by any system routine that I know.
   * The current bits and the count of unprocessed bits are created
   * outside of
   */
  private static void genFileWriterWork(
      SIRFileWriter fw, Tape inputTape, int selfID, CodegenPrintWriter p) {

    if (KjcOptions.asciifileio) {
      System.err.println("Error: -asciifileio not supported in cluster backend.");
      System.err.println("Exiting...");
      System.exit(1);
    }

    String theType = "" + fw.getInputType();
    if (theType.equals("bit")) {
      // the bit type is special since you can not just read or
      // write a bit.  It requires buffering in some larger
      // integer type.
      String bits_to_go = bitsToGoName(fw);
      String the_bits = theBitsName(fw);

      p.println("unsigned char __buffer[____n/8+1];");
      p.println("int __index = 0;");
      p.println("for (; 0 < ____n; ____n--) {");
      p.indent();

      p.println(
          the_bits
              + " = ("
              + bits_type
              + ") (("
              + the_bits
              + " << 1) | ("
              + inputTape.getPopName()
              + "() & 1));");
      p.println(bits_to_go + "--;");
      p.println("if (" + bits_to_go + " == 0) {");
      p.indent();
      p.println("__buffer[__index++] = " + the_bits + ";");
      p.println(the_bits + " = 0;");
      p.println(bits_to_go + " = 8 * sizeof(" + the_bits + ");");
      p.outdent();
      p.println("}");
      p.outdent();
      p.println("}");
      p.println(
          "fwrite(__buffer, " + "sizeof(" + the_bits + "), " + "__index, " + fpName(fw) + ");");
    } else {
      // not a bit type.  write directly to file without needing to buffer bits.

      p.println("\n  int __index;");
      p.println("  for (__index=0; __index < ____n; __index++) {");
      if (KjcOptions.compressed) {
        Tape out = RegisterStreams.getFilterInStream(fw);
        int s = out.getSource();
        int d = out.getDest();

        String BUFFER = "BUFFER_" + s + "_" + d;
        String TAIL = "TAIL_" + s + "_" + d;

        String pop = inputTape.getPopName() + "()";
        p.println("    unsigned char __temp = " + pop + ";");
        p.println("    FileWriter_write<unsigned char>(__file_descr__" + selfID + ", __temp);");
        p.println("    unsigned int __frame_size = __temp;");

        p.println("    __temp = " + pop + ";");
        p.println("    FileWriter_write<unsigned char>(__file_descr__" + selfID + ", __temp);");
        p.println("    __frame_size <<= 8;");
        p.println("    __frame_size += __temp;");

        p.println("    __temp = " + pop + ";");
        p.println("    FileWriter_write<unsigned char>(__file_descr__" + selfID + ", __temp);");
        p.println("    __frame_size <<= 8;");
        p.println("    __frame_size += __temp;");

        p.println("    __temp = " + pop + ";");
        p.println("    FileWriter_write<unsigned char>(__file_descr__" + selfID + ", __temp);");
        p.println("    __frame_size <<= 8;");
        p.println("    __frame_size += __temp;");

        // the frame size includes the four bytes used to state the frame size
        p.println(
            "    FileWriter_write(__file_descr__"
                + selfID
                + ", (void *)("
                + BUFFER
                + " + "
                + TAIL
                + "), __frame_size - 4);");
        p.println("    " + TAIL + " += __frame_size - 4;");
      } else {
        p.println(
            "    FileWriter_write<"
                + theType
                + ">(__file_descr__"
                + selfID
                + ", "
                + inputTape.getPopName()
                + "());");
      }
      p.println("  }\n");

      /*
             NetStream in = RegisterStreams.getFilterInStream(fw);
             // source and destination of incoming stream
             int s = in.getSource();
             int d = in.getDest();

             p.println("#ifdef __FUSED_" + s + "_" + d);
             p.indent();
             {
                 p.println("fwrite(&(BUFFER_" + s + "_" + d + "[TAIL_" + s + "_" + d + "]), " +
                           "sizeof(BUFFER_" + s + "_" + d + "[TAIL_" + s + "_" + d + "]), " +
                           "____n, " + fpName(fw) + ");");
                 p.println("TAIL_" + s + "_" + d + "+=____n;");
             }
             p.outdent();
             p.println("#else");
             p.indent();
             {
                 p.println("fwrite(&(__pop_buf__" + selfID + "[__tail__" + selfID + "]), " +
                           "sizeof(__pop_buf__" + selfID + "[__tail__" + selfID + "]), " +
                           "____n, " + fpName(fw) + ");");
                 p.println("__tail__" + selfID + "+=____n;");
             }
             p.outdent();
             p.println("#endif");
      */

      if (KjcOptions.numbers > 0) {
        p.println("  stats_output_count++;");
      }
    }
  }