/******************************************************************************
CountedOutput extends the BufferedOutputStream by providing the features for
counting characters and lines of output, and addition methods to output
specific structures.

----------------------------------------------------
Copyright (c) Gunnar Gotshalks. All Rights Reserved.

Permission to use, copy, modify, and distribute this software
and its documentation for NON-COMMERCIAL purposes and
without fee is hereby granted. 
******************************************************************************/

package FlexOr.io;
import java.io.*;

/**
CountedOutput extends the BufferedOutputStream by providing the features for
counting characters and lines of output, and methods to output
specific structures.
<P>
@author Gunnar Gotshalks
@version 1.0 1999 Jan 10
*/

public class CountedOutput extends BufferedOutputStream {

/******************************************************************************
Creating an instance of CountedOutput opens the named file.
<P><PRE><B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   charChar = 0 and lineCount = 0
</PRE>
@exception IOException When the output file cannot be created.
*/

public CountedOutput (String fileName) throws IOException {
  super(new FileOutputStream(fileName));
}

/******************************************************************************
To help users of the output data type keep statistics within application
programs we provide: (1) a count, charCount of the total number of characters
emitted to the output file; and (2) the number of characters output, LineLength,
since the last new line character.
---------------------------*/

/** Number of characters output */

protected  int theCharCount = 0;

/**
Return the  number of data characters written to the file.
<P><PRE><B>Requires:</B>
&nbsp;   True</PRE>
@return charCount

*/

public int charCount() { return theCharCount; }

/** Number of end-of-line characters output. */

protected int theLineCount = 0;

/**
Return the number of lines written to the file.
<P><PRE><B>Requires:</B>
&nbsp;   True </PRE>
@return lineCount
*/

public int lineCount() { return theLineCount; }

/** Number of characters output on the current line.  Used by some methods to
decide when a new line is to be written. */

protected int theLineLength = 0;

/**
Return the number of characters written to the current line.
<P><PRE><B>Requires:</B>
&nbsp;   True </PRE>
@return lineCount
*/

public int lineLength() { return theLineLength; }

/******************************************************************************
The purpose of FlexOr is not to provide full typsetting functionality but it
does have to provide for some.  In place of a completely flexible tab rack
facility, FlexOr provides |tabstopDist| which is a uniform distance
between tab postions.  Tab position are be |1+Output~TabStopDist*n|.
---------------------------*/
/** The spacing between tabstops -- default is 4.*/

  protected int tabstopDist = 4;

/** Return the tabstop distance.
<P><PRE><B>Requires:</B>
&nbsp;   True </PRE>
@return tabstopDist
*/

  public int getTabstopDist() { return tabstopDist; }

/** Set the tabstop distance.
<P><PRE><B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   tabstopDist = newTabstop
</PRE> */

  public void setTabstopDist(int newTabstop){ tabstopDist = newTabstop; }
  
/******************************************************************************/
/** Output a single character
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^theChar
&nbsp;   charCount = 1 + oldCharCount
</PRE>
*/

public void write(int theChar) {
  if (theChar == Char.EOL) { writeNewline(); return; }
  theCharCount++;  theLineLength++;
  try { super.write(theChar);
  } catch (IOException e) { System.err.println("Cannot write character: " + e); }
}
  
/******************************************************************************
When a new line character is emitted we want to reset lineLength.
Again, having a special purpose parameterless call is more efficient and
descriptive in application programs.
---------------------------*/
/** Output a newline character
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^Character.EOL
&nbsp;   theCharCount = 1 + old CharCount  and  lineCount = 1 + old lineCount
</PRE>
*/

public void writeNewline() {
  theCharCount++; theLineLength = 0; theLineCount++;
  try { super.write(Char.Newline);
  } catch (IOException e) { System.out.println("Cannot write newline: " + e); }
}
  
/******************************************************************************/
/** Output a string.
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^string
&nbsp;   charCount = string.length + old CharCount
&nbsp;   lineCount = old lineCount + #(newLines in string)
</PRE>
*/
public void write(String string) {
  for (int c = 0 ; c < string.length() ; c++ ) write(string.charAt(c));
}
  
/******************************************************************************
Output a string of characters followed by a newline.
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^string^Character.EOL
&nbsp;   theCharCount = length(string) + 1 + old CharCount
&nbsp;   lineCount = 1 + old lineCount
</PRE>
*/

public void writeln(String string) {
  theCharCount++; theLineLength = 0;
  write(string);
  writeNewline();
}

/*****************************************************************************/
/** Output a string without adding to the lineLength.  Often used when markup
tags are output as they do not add to the effective line length.  The total
number of output characters is incremented.
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^string
&nbsp;   charCount = string.length() + old CharCount
&nbsp;   lineCount = old lineCount
</PRE>
*/

public void writeNoCount(String string) {
  byte[] buffer = string.getBytes();
  writeNoCount(buffer, 0, string.length());
}
  
/******************************************************************************/
/** Output a buffer of characters.
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^buffer[offset .. offset+count-1]
&nbsp;   charCount = count + old CharCount
&nbsp;   lineCount = old lineCount + #(newLines in buffer[offset .. offset+count-1])
</PRE>
*/
public void write(byte[] buffer, int offset, int count) {
  for (int c = 0 , i = offset ; c < count ; c++ , i++) write(buffer[i]);
}

/*****************************************************************************/
/** Output a buffer without adding to the lineLength.  Often used when markup
tags are output as they do not add to the effective line length.  The total
number of output characters is incremented.
<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^buffer[offset .. offset+count-1]
&nbsp;   charCount = count + old CharCount
&nbsp;   lineCount = old lineCount
</PRE>
*/

public void writeNoCount(byte[] buffer, int offset, int count) {
  theCharCount += count;
  try { super.write(buffer, offset, count);
  } catch (IOException e) { System.out.println("Cannot write buffer: " + e); }
}

/******************************************************************************
Output an integer in the minimum space.

<P><PRE<B>Requires:</B>
&nbsp;   True
<B>Ensures:</B>
&nbsp;   output = output^stringRep(integer)
&nbsp;   theCharCount = length(stringRep(integer)) + old CharCount
</PRE>
*/

public void writeInteger(int integer) {
  String intString = String.valueOf(integer);
  byte[] buffer = intString.getBytes();
  write(buffer, 0, intString.length());
}

/******************************************************************************
<P><PRE<B>Requires:</B>
&nbsp;   length(stringRep(integer)) <= width
<B>Ensures:</B>
&nbsp;   output = output^spaces^stringRep(integer)
&nbsp;   #spaces = width - length(stringRep(integer))
&nbsp;   charCount = width + old CharCount
</PRE>
*/

public void writeInteger(int integer, int width) {
  String intString = String.valueOf(integer);
  byte[] buffer = intString.getBytes();
  int length = intString.length();
  int pad = width - length;
  
  while (pad-- > 0) write(' ');
  for (int i = 0 ; i < buffer.length ; i++) write(buffer[i]);
}
}