// ZipFileResource.java
// $Id: ZipFileResource.java,v 1.2 1998/06/15 15:43:26 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1998.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.zip;

import java.util.zip.*;
import java.util.*;
import java.io.*;

import org.w3c.util.*;
import org.w3c.tools.resources.*;


/**
 * @version $Revision: 1.2 $
 * @author  Benoît Mahé (bmahe@w3.org)
 */
public class ZipFileResource extends FileResource {

    /**
     * Attributes index - The filename attribute.
     */
    protected static int ATTR_ZIPFILE = -1 ;
    /**
     * Attribute index - The index for our entry path.
     */
    protected static int ATTR_ENTRYPATH = -1 ;

    static {
	Attribute a   = null ;
	Class     cls = null ;
	try {
	    cls = Class.forName("org.w3c.jigsaw.zip.ZipFileResource") ;
	} catch (Exception ex) {
	    ex.printStackTrace();
	    System.exit(0);
	}
	// The zip file attribute.
	a = new FileAttribute("zipfile"
			      , null
			      , Attribute.COMPUTED) ;
	ATTR_ZIPFILE = AttributeRegistry.registerAttribute(cls, a) ;
	// the entry path attribute
	a = new StringAttribute("entrypath"
				, null
				, Attribute.COMPUTED) ;
	ATTR_ENTRYPATH = AttributeRegistry.registerAttribute(cls, a) ;
    }

    protected ZipFile zipfile = null;

    /**
     * Get this zip file.
     */
    public synchronized File getFile() {
	return (File) getValue(ATTR_ZIPFILE, null);
    }

    public String getEntryPath() {
	return getString(ATTR_ENTRYPATH, null);
    }

    protected synchronized InputStream getInputStream() {
	try {
	    if (zipfile == null) {
		zipfile = new ZipFile(getFile());
	    }
	    ZipEntry zentry = zipfile.getEntry(getEntryPath());
	    return zipfile.getInputStream(zentry);
	} catch (IOException ex) {
	    ex.printStackTrace();
	    return null;
	}
    }

    protected synchronized ZipEntry getEntry() {
	try {
	    if (zipfile == null) {
		zipfile = new ZipFile(getFile());
	    }
	    return zipfile.getEntry(getEntryPath());
	} catch (IOException ex) {
	    ex.printStackTrace();
	    return null;
	}
    }

    /**
     * Update the file related attributes.
     * The file we serve has changed since the last time we checked it, if
     * any of the attribute values depend on the file content, this is the
     * appropriate place to recompute them.
     */
    
    public void updateFileAttributes() {
	File file = getFile() ;
	setValue(ATTR_FILESTAMP, new Long(file.lastModified()));
	setValue(ATTR_FILE_LENGTH, new Integer((int)getEntry().getSize()));
	return ;
    }

    /**
     * Is that resource still wrapping an existing file ?
     * If the underlying file has disappeared <string> and if</strong> the
     * container directory is extensible, remove the resource.
     */
    
    public synchronized boolean verify() 
	throws MultipleLockException
    {
	File file = getFile();
	if ( ! file.exists() ) 
	    return false;
	return (getEntry() != null);
    }

    /**
     * Save the given stream as the underlying file content.
     * This method preserve the old file version in a <code>~</code> file.
     * @param in The input stream to use as the resource entity.
     * @return A boolean, <strong>true</strong> if the resource was just
     * created, <strong>false</strong> otherwise.
     * @exception IOException If dumping the content failed.
     */

    public synchronized boolean newContent(InputStream in) 
	throws IOException
    {
	throw new IOException("Can't modify the content of ZipFile");
    }

    /**
     * Delete this Resource instance, and remove it from its store.
     * This method will erase definitely this resource, for ever, by removing
     * it from its resource store (when doable).
     */
    public synchronized void delete() 
	throws MultipleLockException 
    {
	if (zipfile != null) {
	    try {
		zipfile.close();
	    } catch (IOException ex) {
		// nothing
	    }
	}
	super.delete();
    }

    /**
     * This resource is being unloaded.
     * The resource is being unloaded from memory, perform any additional
     * cleanup required.
     */
    public void notifyUnload() {
	if (zipfile != null) {
	    try {
		zipfile.close();
	    } catch (IOException ex) {
		// nothing
	    }
	}
	super.notifyUnload();
    }

}
