/** Name: RLE <BR>
    Autor: Martin Klossek und Fabian Wleklinski<BR>
    Sprache: JAVA 1.1+ <BR> <BR>
    Die Klasse RLE enthält Routinen zur Lauflängenkompression (RLE). */
public class RLE {

  /** Komprimiert das übergebenen Array und liefert ein komprimiertes Array zurück.
  @param src Das Eingabearray */
  public byte[] compress( byte[] src ) {

    // Einen Array für die Ausgabe 
    byte [] dest = new byte[ 0 ];

    // Wenn ein Leerstring übergeben wurde -> raus
    if (src.length == 0) { return dest; }
  
    // Hält jeweils das letzte Zeichen
    byte lastChar = src[ 0 ];
    // Hält das aktuelle Zeichen
    byte curChar = 0;
    // Hält die Anzahl der Wiederholungen des aktuellen Zeichens
    int n = 0;

    // Den Eingabestring Zeichen für Zeichen abarbeiten
    for (int pos = 1; pos <= src.length+1; pos++) {

      // Den Zeichencode holen
      if (pos <= src.length) {
        curChar = src[ pos-1 ];
      }

      // Wiederholungszähler ggf. zurücksetzen
      if ((curChar == lastChar) && (pos <= src.length)) { 
        n++;
      }

      // Wenn hier die Wiederholungskette abbricht -> In den Ausgabestring schreiben
      if ((curChar != lastChar) || (pos > src.length ) ) {

        if ((n > 3) || (lastChar == -1)) {

          // Eine Kodierung in den String schreiben
          dest = add( dest, (byte) -1 );
          dest = add( dest, lastChar );
          dest = add( dest, (byte) n );

        } else {
          // die entsprechende Anzahl Zeichen in den Ausgabestring schreiben
          dest = add( dest, lastChar );
          if (n >= 2) { 
            dest = add( dest, lastChar );
          }
          if (n == 3) { 
            dest = add( dest, lastChar );
          }
        }
        n = 1;
      }
      

      // Den Zeichencode merken
      lastChar = curChar;
    }

    return dest;
  }

  /** Dekomprimiert das übergebene Array und liefert das dekomprimierten Array zurück.
  @param src Das Eingabearray */
  public byte[] decompress( byte[] src ) {

    // Ein Array für die Ausgabe allokieren
    byte[] dest = new byte[0];

    // Wenn ein Leerstring übergeben wurde -> raus
    if (src.length == 0) { return dest; }

    // Hält das aktuelle Zeichen
    byte curChar = 0;
  
    // Den Eingabestring Zeichen für Zeichen abarbeiten
    for (int pos = 1; pos <= src.length; pos++) {

      // Den Zeichencode holen
      curChar = src[pos-1];

      // Wenn es ein normales Zeichen ist -> ausgeben
      if (curChar != -1) {
        dest = add( dest, curChar );
      } else {
        // Steuerzeichen gefunden
        // Um welches Zeichen handelt es sich?
        byte c = src[ pos ];
        int n = (int) src[ pos+1 ];

        // n mal einfügen
        for (int i = 1; i<=n; i++) {
          dest = add( dest, c );
        }
        pos = pos + 2;
        
      }
    }

    return dest;
  }

  // Fügt dem übergebenen Array das übergebene Zeichen hinzu
  private byte[] add( byte[] src, byte c ) {
    byte [] result = new byte[ src.length+1 ];
    System.arraycopy( src, 0, result, 0, src.length );
    result[ src.length ] = c;
    return result;
  }

}