// Version 15/08/2001/AM,OCL

package inf101;

import java.io.*;
import java.text.*;
import java.util.*;

/** Denne klassen er laget ved Ifi, UiO og inneholder metoder
 *  for ? skrive til terminal og fil, samt formattering av tall som String.
 *  Klassen st?tter b?de skriving
 *  linje for linje, tegn for tegn, og item for item (hvor et item
 *  kan v?re et heltall, et flyttall eller en tekststreng).  De tre
 *  typene skriving kan kombineres.  Eksempel p? bruk:
 *
 *  <pre>
 *    import inf101.*;
 *
 *    class TestUt {
 *      public static void main (String [] args) {
 *        double [] vekt = {10.6, 23.1, 16.2, 36.2, 8.2, 22.2, 33.1};
 *        double [] h?yde= {180.3, 170.2, 175.6, 165.3, 182.2, 160.2, 178.3};
 *        int n = 7;
 *        Ut utfil = new Ut("tekstfil.txt");
 *
 *        utfil.outStringln("   Individ      Vekt     H?yde");
 *        for (int i=0; i < n; i++) {
 *          utfil.outInt(i+1, 10);
 *          utfil.outDouble(vekt[i], 10, 1);
 *          utfil.outDouble(h?yde[i], 10, 1);
 *          utfil.outln();
 *        }
 *        utfil.close();
 *      }
 *    }
 *  </pre>
 * Merk: forel?pig kan en ikke benytte linker (slik som ~ eller /hom/)
 * i pathen n?r en oppretter et Ut-objekt.
 *
 *  Version 15/08/2001/AM og OCL
 **/
public class Ut {
  private static final int LEFT = 0;
  private static final int RIGHT = 1;
  private PrintWriter ut;
  private boolean terminal;

  /** Lager et Ut-objekt for skriving til skjerm. **/
  public Ut() {
    terminal = true;
  }

  /** Lager et Ut-objekt for skriving til spesifisert fil. **/
  public Ut(String filnavn) {
    terminal = false;
    try {
      ut = new PrintWriter(new FileWriter(filnavn));
    } catch (IOException e) {feil("Klarte ikke ? ?pne fil for skriving!");}
  }

  private static String blanks (int n) {
    String s = "";
    for (int i=0; i<n; i++) s = s + " ";
    return s;
  }

  private static String fillBlanks (String s, int n, int align) {
    String u;
    if (s.length() > n) {
      int N = s.length() + 3;
      u = (s + "...").substring(N-n, N);
    } else {
      if (align == LEFT) u = s + blanks(n-s.length());
      else u = blanks(n-s.length()) + s;
    }
    return u;
  }

  /** Skriv tegnet <CODE>c</CODE>. **/
  public void outChar(char c) {
    if (terminal) System.out.print(c);
    else ut.print(c);

  }

  /** Skriv tegnet <CODE>c</CODE> venstrejustert p? <CODE>width</CODE> plasser. **/
  public void outChar(char c, int width) {
    if (terminal) System.out.print(fillBlanks(c+"", width, LEFT));
    else ut.print(fillBlanks(c+"", width, LEFT));

  }

  /** Skriv heltallet <CODE>n</CODE>. **/
  public void outInt(int n) {
    if (terminal) System.out.print(n);
    else ut.print(n);
  }

  /** Skriv heltallet <CODE>n</CODE> h?yrejustert p? <CODE>width</CODE> plasser.
    * Dersom det ikke er plass til heltallet p? det spesifiserte antall plasser,
    * avsluttes tallet med ...
   **/
  public void outInt(int n, int width) {
    String s = fillBlanks(""+n, width, RIGHT);
    if (terminal) System.out.print(s);
    else ut.print(s);
  }

  /** Lag String av haltallet <CODE>n</CODE> h?yrejustert p? <CODE>width</CODE> plasser.
    * Dersom det ikke er plass til heltallet p? det spesifiserte antall plasser,
    * avsluttes tallet med ...
   **/
  public static String writeInt(int n, int width) {
    String s = fillBlanks(""+n, width, RIGHT);
    return s;
  }

  /** Lag String av long  <CODE>n</CODE> h?yrejustert p? <CODE>width</CODE> plasser.
  * Dersom det ikke er plass til heltallet p? det spesifiserte antall plasser,
  * avsluttes tallet med ...
  **/
  public static String writeLong(long n, int width) {
    String s = fillBlanks(""+n, width, RIGHT);
    return s;
  }


  private static String formatDouble(double x, int decimals) {
    NumberFormat df = DecimalFormat.getInstance(Locale.US);
    df.setGroupingUsed(false);
    df.setMaximumFractionDigits(decimals);
    df.setMinimumFractionDigits(decimals);

    return df.format(x);
  }

  /** Skriv flyttallet <CODE>x</CODE> med <CODE>decimals</CODE> desimaler. **/
  public void outDouble(double x, int decimals) {
    String s = formatDouble(x, decimals);

    if (terminal) System.out.print(s);
    else ut.print(s);
  }

  /** Lag String av flyttallet <CODE>x</CODE> h?yrejustert p? <CODE>width</CODE> plasser med <CODE>decimals</CODE> plasser etter komma.
    * Dersom det ikke er plass til heltallet p? det spesifiserte antall plasser,
    * avsluttes tallet med ...
   **/

  public static String writeDouble(double x, int width, int decimals) {
	 String s = formatDouble(x, decimals);

	    // legg p? prikker...
	    if (s.length() > width) {
	      s = s.substring(0, width);

	      StringBuffer sb = new StringBuffer(s);
	      int i = width > 3 ? 3 : width;
	      for (int pos = width - 1; i > 0; i--) {
		sb.setCharAt(pos--, '.');
	      }

	      s = sb.toString();
	    }

	    return fillBlanks(s, width, RIGHT);


  }



  /** Skriv flyttallet <CODE>x</CODE> med <CODE>decimals</CODE> desimaler, h?yrejustert
   *  og p? <CODE>width</CODE> plasser.
    * Dersom det ikke er plass til flyttallet p? det spesifiserte antall plasser,
    * avsluttes tallet med ...
  **/
  public void outDouble(double x, int width, int decimals) {

    String s = formatDouble(x, decimals);

    // legg p? prikker...
    if (s.length() > width) {
      s = s.substring(0, width);

      StringBuffer sb = new StringBuffer(s);
      int i = width > 3 ? 3 : width;
      for (int pos = width - 1; i > 0; i--) {
	sb.setCharAt(pos--, '.');
      }

      s = sb.toString();
    }

    s = fillBlanks(s, width, RIGHT);

    if (terminal) System.out.print(s);
    else ut.print(s);

  }



  /** Skriv tekststrengen <CODE>s</CODE>. **/
  public void outString(String s) {
    if (terminal) System.out.print(s);
    else ut.print(s);
  }

  /** Skriv tekststrengen <CODE>s</CODE> venstrejustert p? <CODE>width</CODE> plasser.
    * Dersom det ikke er plass til tekststrengen p? det spesifiserte antall plasser,
    * avsluttes tekststrengen med ...
   **/
  public void outString(String s, int width) {
    String u = fillBlanks(s, width, LEFT);
    if (terminal) System.out.print(u);
    else ut.print(u);
  }

  /** Skriv ut en tekststreng og avslutt med linjeskift. **/
  public void outStringLn(String s) {
    if (terminal) System.out.println(s);
    else ut.println(s);
  }

  /** Skriv ut et linjeskift. **/
  public void outLn() {
    if (terminal) System.out.println("");
    else ut.println("");
  }

  /** Lukk fil **/
  public void close() {
    if (!terminal) ut.close();
  }

  private void feil (String s) {
    System.out.println("*******************");
    System.out.println(s);
    System.out.println("*******************");
  }

}