package jazz.io;

///////////////////////////////////////////////////////////////////////////////
//
//                                 Writers
//
// Output operations are imperative operations that must be explicitly
// serialized in order to guarantee the order in which they are performed.
//
///////////////////////////////////////////////////////////////////////////////

public abstract class Writer {
  // Underlying native writer
  writer: native;

  // Write methods returning a new object that can be used to
  // perform further writes with a guarantee of sequentiality
  public writeChar(b: int): alike;
  public writeString(s: String): alike;

  // Same thing, but on arrays
  public writeCharArray(n: int)(b: int[n]): alike;
  public writeStringArray(n: int)(s: String[n]): alike;

  // Flushes the writer
  public flush(): alike;
  
  // Flushes and closes the writer
  public close(): alike;
}

///////////////////////////////////////////////////////////////////////////////
//
//                               Implementation
//
///////////////////////////////////////////////////////////////////////////////

writeChar@Writer(b) =
  (native("void java.io.Writer.write(int)", writer, b)
   ; flush()
   ; this);

writeString@Writer(s) =
  (native("void java.io.Writer.write(java.lang.String)", writer, s)
   ; flush()
   ; this);

flush@Writer() = (native("void java.io.Writer.flush()", writer)
                  ; this);
  
close@Writer() = (native("void java.io.Writer.close()", writer)
                  ; this);
  
writeCharArray@Writer(n)(b) = fw[n]
{
  fw = [this, i -> fw[i-1].writeChar(b[i-1])];
}

writeStringArray@Writer(n)(b) = fw[n]
{
  fw = [this, i -> fw[i-1].writeString(b[i-1])];
}