package ro.isdc.wro.http;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ro.isdc.wro.http.support.DelegatingServletOutputStream;
import ro.isdc.wro.http.support.HttpHeader;
import ro.isdc.wro.model.resource.locator.support.DispatcherStreamLocator;
import ro.isdc.wro.util.WroUtil;


/**
 * A filter responsible for gzipping all content served through this filter.
 *
 * @author Alex Objelean
 * @created 11 Apr 2013
 * @since 1.6.4
 */
public class GzipFilter
    implements Filter {
  private static final Logger LOG = LoggerFactory.getLogger(GzipFilter.class);

  /**
   * {@inheritDoc}
   */
  public void init(final FilterConfig filterConfig)
      throws ServletException {
  }

  /**
   * {@inheritDoc}
   */
  public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
      throws IOException, ServletException {
    final HttpServletRequest request = (HttpServletRequest) req;
    final HttpServletResponse response = (HttpServletResponse) res;

    final ServletResponseWrapper responseWrapper = decorateResponse(request, response);
    chain.doFilter(req, responseWrapper);
    responseWrapper.flushBuffer();
    IOUtils.closeQuietly(response.getOutputStream());
    //chain.doFilter(request, response);
  }

  /**
   * Decorates the provided {@link HttpServletResponse} which handles gzip if it is allowed.
   */
  private HttpServletResponseWrapper decorateResponse(final HttpServletRequest request, final HttpServletResponse response)
      throws IOException {
    HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(response);
    if (isGzipAllowed(request)) {
      LOG.debug("setting gzip header");
      response.setHeader(HttpHeader.CONTENT_ENCODING.toString(), "gzip");
      // Create a gzip stream
      final GZIPOutputStream gzout = new GZIPOutputStream(new ByteArrayOutputStream());
      // Handle the request

      wrappedResponse = new HttpServletResponseWrapper(wrappedResponse) {
        @Override
        public ServletOutputStream getOutputStream()
            throws IOException {
          return new DelegatingServletOutputStream(gzout);
        }
      };
    }
    return wrappedResponse;
  }

  /**
   * Checks if the request supports gzip and is not a include request (these cannot be gzipped)
   */
  private boolean isGzipAllowed(final HttpServletRequest request) {
    return !DispatcherStreamLocator.isIncludedRequest(request) && WroUtil.isGzipSupported(request);
  }

  /**
   * {@inheritDoc}
   */
  public void destroy() {
  }

}

@@ -20,16 +20,53 @@
 .http;%0A%0A
+import java.io.BufferedOutputStream;%0A
 import j
@@ -304,50 +304,8 @@
 on;%0A
-import javax.servlet.ServletOutputStream;%0A
 impo
@@ -379,53 +379,8 @@
 se;%0A
-import javax.servlet.ServletResponseWrapper;%0A
 impo
@@ -655,37 +655,18 @@
 ort.
-DelegatingServletOutputStream
+HttpHeader
 ;%0Aim
@@ -691,32 +691,60 @@
 ttp.support.
-HttpHead
+RedirectedStreamServletResponseWrapp
 er;%0Aimport r
@@ -1565,229 +1565,105 @@
     
-final ServletResponseWrapper responseWrapper = decorateResponse(request, response);%0A    chain.doFilter(req, responseWrapper);%0A    responseWrapper.flushBuffer();%0A    IOUtils.closeQuietly(response.getOutputStream());%0A    //
+if (isGzipAllowed(request)) %7B%0A      doGzipResponse(request, response, chain);%0A    %7D else %7B%0A      
 chai
@@ -1693,16 +1693,22 @@
 ponse);%0A
+    %7D%0A
   %7D%0A%0A  /
@@ -1719,147 +1719,81 @@
   * 
-Decorates the provided %7B@link HttpServletResponse%7D which handles
+Performs actual
  gzip 
-if it is allowed.%0A   */%0A  private HttpServletResponseWrapper decorate
+of the filtered content.%0A   */%0A  private void doGzip
 Resp
@@ -1825,20 +1825,16 @@
 uest req
-uest
 , final 
@@ -1861,16 +1861,41 @@
 response
+, final FilterChain chain
 )%0A      
@@ -1916,138 +1916,29 @@
 tion
- %7B%0A    HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(response);%0A    if (isGzipAllowed(request))
+, ServletException
  %7B%0A
-  
     
@@ -1952,12 +1952,13 @@
 ug(%22
-sett
+Apply
 ing 
@@ -1966,20 +1966,47 @@
 zip 
-header%22
+on resource: %22 + req.getRequestURI()
 );%0A
-  
     
@@ -2081,36 +2081,72 @@
     
-  // Create a gzip s
+final ByteArrayOutputStream baos = new ByteArrayOutputS
 tream
-%0A  
+();%0A
     
@@ -2198,32 +2198,31 @@
 Stream(new B
-yteArray
+uffered
 OutputStream
@@ -2226,68 +2226,88 @@
 eam(
+baos
 ));%0A
-  
     //
- Handle the request%0A%0A      wrappedResponse = new
+Perform gzip operation in-memory before sending response%0A    final
  Htt
@@ -2329,17 +2329,17 @@
 eWrapper
-(
+ 
 wrappedR
@@ -2349,226 +2349,272 @@
 onse
-) %7B%0A        @Override%0A        public ServletOutputStream getOutputStream()%0A            throws IOException %7B%0A          return new DelegatingServletOutputStream(gzout);%0A        %7D%0A      %7D;%0A    %7D%0A    return wrappedResponse
+ = new RedirectedStreamServletResponseWrapper(gzout, response);%0A    chain.doFilter(req, wrappedResponse);%0A    //close underlying stream%0A    gzout.close();%0A    response.setContentLength(baos.size());%0A    IOUtils.write(baos.toByteArray(), response.getOutputStream())
 ;%0A  

make GzipFilter functional. Still have to write unit tests