/*
 * BEGIN FLOCK GPL
 *
 * Copyright Flock Inc. 2005-2009
 * http://flock.com
 *
 * This file may be used under the terms of the
 * GNU General Public License Version 2 or later (the "GPL"),
 * http://www.gnu.org/licenses/gpl.html
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * END FLOCK GPL
 */

#include "flockCompressContent.h"

#include "nsIStringStream.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsNetUtil.h"

#include "zlib.h"

// This is the default when you just use deflateInit
#define DEFAULT_MEM_LEVEL 8

// Work around a bug in zlib's deflateBound function, it doesn't account
// for the gzip header
#define GZ_HEADER_SIZE 18

NS_IMPL_ISUPPORTS1(flockCompressContent, flockICompressContent)

flockCompressContent::flockCompressContent()
{
}

flockCompressContent::~flockCompressContent()
{
}

NS_IMETHODIMP flockCompressContent::CompressString(const nsACString & aData,
                                                   nsIInputStream **result)
{
  int ret;
  z_stream stream;

  stream.zalloc = Z_NULL;
  stream.zfree = Z_NULL;
  stream.opaque = Z_NULL;

  ret = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
                     MAX_WBITS + 16, // add 16 for gzip header, per zlib.h
                     DEFAULT_MEM_LEVEL,
                     Z_DEFAULT_STRATEGY);

  if (ret != Z_OK) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  PRInt32 inLength, outLength;
  inLength = aData.Length();

  outLength = deflateBound(&stream, inLength) + GZ_HEADER_SIZE;
  char *buffer = (char *) nsMemory::Alloc(outLength);
  
  stream.avail_in = inLength;
  stream.next_in = (unsigned char *) aData.BeginReading();
  stream.avail_out = outLength;
  stream.next_out = (unsigned char *) buffer;

  ret = deflate(&stream, Z_FINISH);
  deflateEnd(&stream);

  if (ret != Z_STREAM_END) {
    return NS_ERROR_UNEXPECTED;
  }

  PRInt32 actualLength = outLength - stream.avail_out;

  nsresult rv;
  nsCOMPtr<nsIStringInputStream> stringStream =
    do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = stringStream->AdoptData(buffer, actualLength);
  NS_ENSURE_SUCCESS(rv, rv);

  NS_ADDREF(*result = stringStream);
  return NS_OK;
}
