/*
 * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *   Free SoftwareFoundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Charles Reich
 */

package com.caucho.quercus.lib.zip;

import com.caucho.quercus.QuercusModuleException;
import com.caucho.quercus.env.BooleanValue;
import com.caucho.quercus.env.Env;
import com.caucho.quercus.env.LongValue;
import com.caucho.quercus.env.NullValue;
import com.caucho.quercus.env.StringValueImpl;
import com.caucho.quercus.env.Value;

import com.caucho.quercus.lib.file.BinaryInput;
import com.caucho.quercus.lib.file.BinaryStream;
import com.caucho.quercus.lib.file.FileModule;

import com.caucho.quercus.module.AbstractQuercusModule;
import com.caucho.quercus.module.NotNull;
import com.caucho.quercus.module.Optional;
import com.caucho.quercus.module.ReturnNullAsFalse;
import com.caucho.util.L10N;
import com.caucho.util.Log;
import com.caucho.vfs.Path;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * PHP Zip
 */
public class ZipModule extends AbstractQuercusModule {
  private static final Logger log =
                                Logger.getLogger(ZipModule.class.getName());
  private static final L10N L = new L10N(ZipModule.class);

  public String []getLoadedExtensions()
  {
    return new String[] {  "zip" };
  }

  /**
   * Opens stream to read zip entries.
   * Since we're only reading, fopen mode is always "rb".
   */
  @ReturnNullAsFalse
  public ZipDirectory zip_open(Env env,
                                String filename)
  {
    if (filename == null || filename == "")
      return null;

    BinaryStream s = FileModule.fopen(env, filename, "rb", false, null);

    if (s == null)
      return null;

    return new ZipDirectory((BinaryInput)s);
  }

  /**
   * Reads an entry's metadata from the zip stream.
   * It appears PHP's zip_read also does a zip_entry_open.
   */
  @ReturnNullAsFalse
  public QuercusZipEntry zip_read(Env env,
                        @NotNull ZipDirectory directory)
  {
    try {
      if (directory == null)
        return null;

      QuercusZipEntry qze = directory.zip_read();
      zip_entry_open(env, directory, qze, "rb");

      return qze;

    } catch (IOException e) {
      throw new QuercusModuleException(e);
    }
  }

  /**
   * Returns the file name.
   *
   * @param env
   * @param zipEntry
   * @return false if zipEntry is null
   */
  public Value zip_entry_name(Env env,
                                @NotNull QuercusZipEntry entry)
  {
    if (entry == null)
      return BooleanValue.FALSE;

    return new StringValueImpl(entry.zip_entry_name());
  }

  /**
   * Returns the file's uncompressed size.
   *
   * @param zipEntry
   * @return false if zipEntry is null
   */
  public Value zip_entry_filesize(@NotNull QuercusZipEntry entry)
  {
    if (entry == null)
      return BooleanValue.FALSE;

    return new LongValue(entry.zip_entry_filesize());
  }

  /**
   * Closes the file.
   */
  public boolean zip_close(@NotNull ZipDirectory directory)
  {
    if (directory == null)
      return false;
    return directory.zip_close();
  }

  /**
   * Opens entry for decompression.
   *
   * @param file
   * @param entry
   * @param mode ignored - always "rb" from fopen()
   * @return true on success or false on failure
   */
  public boolean zip_entry_open(Env env,
                                @NotNull ZipDirectory directory,
                                @NotNull QuercusZipEntry entry,
                                @Optional String mode)
  {
    if ((directory == null) || (entry == null))
      return false;

    return entry.zip_entry_open(env, directory);
  }

  /**
   * Closes this entry's stream.
   *
   * @param entry
   * @return true if successful, else false;
   */
  public boolean zip_entry_close(Env env,
                              @NotNull QuercusZipEntry entry)
  {
    try {
      if (entry == null)
        return false;
      return entry.zip_entry_close();

    } catch (IOException e) {
        env.warning(L.l(e.toString()));
        log.log(Level.FINE, e.toString(), e);
        return false;
    }
  }

  /**
   * Reads and decompresses entry's compressed data.
   *
   * @param entry
   * @param length
   * @return false or decompressed BinaryValue
   */
  public Value zip_entry_read(Env env,
                              @NotNull QuercusZipEntry entry,
                              @Optional("1024") int length)
  {
    if (entry == null)
      return BooleanValue.FALSE;

    return entry.zip_entry_read(env, length);
  }

  /**
   * Returns the compression method used for this entry.
   * Only "deflate" and "store" are supported.
   *
   * @param entry
   * @return empty string, stored or deflated
   */
  public String zip_entry_compressionmethod(@NotNull QuercusZipEntry entry)
  {
    if (entry == null)
      return "";

    return entry.zip_entry_compressionmethod();
  }

  /**
   * Returns the size of the compressed data.
   *
   * @param entry
   * @return -1, or compressed size
   */
  public Value zip_entry_compressedsize(@NotNull QuercusZipEntry entry)
  {
    if (entry == null)
      return new LongValue(-1);

    return entry.zip_entry_compressedsize();
  }
}
