/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.wizards.datatransfer;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;

/**
 * This class provides information regarding the context structure and
 * content of specified zip file entry objects.
 */
public class ZipFileStructureProvider implements IImportStructureProvider {
    private ZipFile zipFile;

    private ZipEntry root = new ZipEntry("/");//$NON-NLS-1$

    private Map children;

    private Map directoryEntryCache = new HashMap();

    /**
     * Creates a <code>ZipFileStructureProvider</code>, which will operate
     * on the passed zip file.
     * 
     * @param sourceFile the zip file used to create this structure provider
     */
    public ZipFileStructureProvider(ZipFile sourceFile) {
        super();
        zipFile = sourceFile;
    }

    /**
     * Adds the specified child to the internal collection of the parent's children.
     */
    protected void addToChildren(ZipEntry parent, ZipEntry child) {
        List childList = (List) children.get(parent);
        if (childList == null) {
            childList = new ArrayList();
            children.put(parent, childList);
        }

        childList.add(child);
    }

    /**
     * Creates a new container zip entry with the specified name, iff
     * it has not already been created.
     */
    protected void createContainer(IPath pathname) {
        if (directoryEntryCache.containsKey(pathname)) {
			return;
		}

        ZipEntry parent;
        if (pathname.segmentCount() == 1) {
			parent = root;
		} else {
			parent = (ZipEntry) directoryEntryCache.get(pathname
                    .removeLastSegments(1));
		}

        ZipEntry newEntry = new ZipEntry(pathname.toString());
        directoryEntryCache.put(pathname, newEntry);
        addToChildren(parent, newEntry);
    }

    /**
     * Creates a new file zip entry with the specified name.
     */
    protected void createFile(ZipEntry entry) {
        IPath pathname = new Path(entry.getName());
        ZipEntry parent;
        if (pathname.segmentCount() == 1) {
			parent = root;
		} else {
			parent = (ZipEntry) directoryEntryCache.get(pathname
                    .removeLastSegments(1));
		}

        addToChildren(parent, entry);
    }

    /* (non-Javadoc)
     * Method declared on IImportStructureProvider
     */
    public List getChildren(Object element) {
        if (children == null) {
			initialize();
		}

        return ((List) children.get(element));
    }

    /* (non-Javadoc)
     * Method declared on IImportStructureProvider
     */
    public InputStream getContents(Object element) {
        try {
            return zipFile.getInputStream((ZipEntry) element);
        } catch (IOException e) {
        	IDEWorkbenchPlugin.log(e.getLocalizedMessage(), e);
            return null;
        }
    }

    /* (non-Javadoc)
     * Method declared on IImportStructureProvider
     */
    public String getFullPath(Object element) {
        return ((ZipEntry) element).getName();
    }

    /* (non-Javadoc)
     * Method declared on IImportStructureProvider
     */
    public String getLabel(Object element) {
        if (element.equals(root)) {
			return ((ZipEntry) element).getName();
		}

        return new Path(((ZipEntry) element).getName()).lastSegment();
    }

    /**
     * Returns the entry that this importer uses as the root sentinel.
     *
     * @return java.util.zip.ZipEntry
     */
    public ZipEntry getRoot() {
        return root;
    }

    /**
     * Returns the zip file that this provider provides structure for.
     * 
     * @return the zip file this provider provides structure for
     */
    public ZipFile getZipFile() {
        return zipFile;
    }

    /**
     * Initializes this object's children table based on the contents of
     * the specified source file.
     */
    protected void initialize() {
        children = new HashMap(1000);

        Enumeration entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
            if (!entry.isDirectory()) {
                IPath path = new Path(entry.getName()).addTrailingSeparator();
                int pathSegmentCount = path.segmentCount();

                for (int i = 1; i < pathSegmentCount; i++) {
					createContainer(path.uptoSegment(i));
				}
                createFile(entry);
            }
        }
    }

    /* (non-Javadoc)
     * Method declared on IImportStructureProvider
     */
    public boolean isFolder(Object element) {
        return ((ZipEntry) element).isDirectory();
    }
}
