package at.gv.egovernment.moa.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

import iaik.utils.Base64InputStream;
import iaik.utils.Base64OutputStream;

/**
 * Utitility functions for encoding/decoding Base64 strings.
 * 
 * @author Patrick Peck
 * @version $Id$
 */
public class Base64Utils {

  /**
   * Read the bytes encoded in a Base64 encoded <code>String</code>. 
   * 
   * @param base64String The <code>String</code> containing the Base64 encoded
   * bytes.
   * @param ignoreInvalidChars Whether to ignore invalid Base64 characters.
   * @return byte[] The raw bytes contained in the <code>base64String</code>.
   * @throws IOException Failed to read the Base64 data.
   */
  public static byte[] decode(String base64String, boolean ignoreInvalidChars)
    throws IOException {

    Base64InputStream in =
      new Base64InputStream(
        new ByteArrayInputStream(base64String.getBytes("UTF-8")),
        ignoreInvalidChars);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] bytes = new byte[256];
    int bytesRead;

    while ((bytesRead = in.read(bytes)) > 0) {
      out.write(bytes, 0, bytesRead);
    }

    return out.toByteArray();
  }

  /**
   * Read the bytes encoded in a Base64 encoded <code>String</code> and provide
   * them via an <code>InputStream</code>.
   * 
   * @param base64String The <code>String</code> containing the Base64 encoded
   * bytes.
   * @param ignoreInvalidChars Whether to ignore invalid Base64 characters.
   * @return The <code>InputStream</code> from which the binary content of the
   * <code>base64String</code> can be read.
   */
  public static InputStream decodeToStream(
    String base64String,
    boolean ignoreInvalidChars) {

    try {
      ByteArrayInputStream bin = 
        new ByteArrayInputStream(base64String.getBytes("UTF-8"));
      Base64InputStream in = new Base64InputStream(bin, ignoreInvalidChars);
      
      return in;
    } catch (UnsupportedEncodingException e) {
      // cannot occur, since UTF-8 is required to be supported by every JRE
      return null; 
    }
  }

  /**
   * Convert a byte array to a Base64 encoded <code>String</code>.
   * 
   * @param bytes The bytes to encode.
   * @return String The Base64 encoded representation of the <code>bytes</code>.
   * @throws IOException Failed to write the bytes as Base64 data.
   */
  public static String encode(byte[] bytes) throws IOException {
    return encode(new ByteArrayInputStream(bytes));
  }

  /**
   * Convert the data contained in the given stream to a Base64 encoded
   * <code>String</code>.
   * 
   * @param inputStream The stream containing the data to encode.
   * @return The Base64 encoded data of <code>inputStream</code>, as a 
   * <code>String</code>.
   * @throws IOException Failed to convert the data in the stream.
   */
  public static String encode(InputStream inputStream) throws IOException {
    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    Base64OutputStream base64Stream = new Base64OutputStream(byteStream);
    byte[] bytes = new byte[256];
    int bytesRead;

    while ((bytesRead = inputStream.read(bytes)) > 0) {
      base64Stream.write(bytes, 0, bytesRead);
    }
    base64Stream.flush();
    base64Stream.close();
    inputStream.close();

    return byteStream.toString("UTF-8");
  }

}