package com.FitBank.web.filtro;

import java.io.*;

import java.util.zip.GZIPOutputStream;

import javax.servlet.*;
import javax.servlet.http.*;


/**
 * Clase que implementa un ResponseStream comprimido
 * @author Fit-Bank
 */
public class GZIPResponseStream extends ServletOutputStream {
  protected ByteArrayOutputStream baos    = null;
  protected GZIPOutputStream gzipstream   = null;
  protected boolean cerrado               = false;
  protected HttpServletResponse respuesta = null;
  protected ServletOutputStream salida    = null;

  /**
   * Crea un GZIPResponseStream
   * @param respuesta
   * @throws java.io.IOException
   */
  public GZIPResponseStream(HttpServletResponse respuesta)
    throws IOException {
    super();
    cerrado          = false;
    this.respuesta   = respuesta;
    this.salida      = respuesta.getOutputStream();
    baos             = new ByteArrayOutputStream();
    gzipstream       = new GZIPOutputStream(baos);
  }

  /**
   * Cierra el stream
   * @throws java.io.IOException
   */
  public void close() throws IOException {
    if(cerrado) {
      throw new IOException("Este stream está cerrado");
    }

    gzipstream.finish();

    byte[] bytes = baos.toByteArray();

    respuesta.addHeader("Content-Length", Integer.toString(bytes.length));
    respuesta.addHeader("Content-Encoding", "gzip");
    salida.write(bytes);
    salida.flush();
    salida.close();
    cerrado = true;
  }

  /**
   * Limpia el stream enviando los datos
   * @throws java.io.IOException
   */
  public void flush() throws IOException {
    if(cerrado) {
      throw new IOException("No se puede hacer flush sobre un stream cerrado");
    }

    gzipstream.flush();
  }

  /**
   * Sobreescribe el metodo definido en ServletOutputStream
   * @param b
   * @throws java.io.IOException
   */
  public void write(int b) throws IOException {
    if(cerrado) {
      throw new IOException("No se puede escribir en un stream cerrado");
    }

    gzipstream.write((byte)b);
  }

  /**
   * Sobreescribe el metodo definido en ServletOutputStream
   * @param b
   * @throws java.io.IOException
   */
  public void write(byte[] b) throws IOException {
    write(b, 0, b.length);
  }

  /**
   * Sobreescribe el metodo definido en ServletOutputStream
   * @param b
   * @param off
   * @param len
   * @throws java.io.IOException
   */
  public void write(byte[] b, int off, int len) throws IOException {
    if(cerrado) {
      throw new IOException("No se puede escribir en un stream cerrado");
    }

    gzipstream.write(b, off, len);
  }

  /**
   * Permite saber si este stream ha sido cerrado
   * @return boolean con el estado
   */
  public boolean closed() {
    return (this.cerrado);
  }

  /**
   * Sobreescribe el metodo definido en ServletOutputStream
   */
  public void reset() {
    // no hacer nada
  }
}
