/*
 * File   : $Source: /usr/local/cvs/opencms/src/org/opencms/importexport/CmsImportHelper.java,v $
 * Date   : $Date: 2008-02-27 12:05:48 $
 * Version: $Revision: 1.3 $
 *
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software GmbH, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.importexport;

import org.opencms.i18n.CmsEncoder;
import org.opencms.i18n.CmsMessageContainer;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.util.CmsFileUtil;
import org.opencms.xml.CmsXmlEntityResolver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import org.apache.commons.logging.Log;

/**
 * Import helper.<p>
 * 
 * @author Michael Moossen
 * 
 * @version $Revision: 1.3 $ 
 * 
 * @since 7.0.4 
 */
public class CmsImportHelper {

    /** The log object for this class. */
    private static final Log LOG = CmsLog.getLog(CmsImport.class);

    /** The folder, or <code>null</code> if a zip file.*/
    private File m_folder;

    /** The import parameters to use. */
    private CmsImportParameters m_params;

    /** The zip file, or <code>null</code> if a folder.*/
    private ZipFile m_zipFile;

    /**
     * Constructor.<p>
     * 
     * @param parameters the import parameters to use
     */
    public CmsImportHelper(CmsImportParameters parameters) {

        m_params = parameters;
    }

    /**
     * Adds a new DTD system id prefix mapping for internal resolution 
     * of external URLs.<p>
     * 
     * @param dtdSystemLocation the internal system location of the DTD file, e.g. <code>org/opencms/configuration/</code>
     * @param dtdFilename the name of the DTD file, e.g. <code>opencms-configuration.dtd</code>
     * @param dtdUrlPrefix the external system id prefix of the DTD file, e.g. <code>http://www.opencms.org/dtd/6.0/</code>
     * 
     * @see org.opencms.configuration.I_CmsXmlConfiguration
     */
    public void cacheDtdSystemId(String dtdSystemLocation, String dtdFilename, String dtdUrlPrefix) {

        if (dtdSystemLocation != null) {
            try {
                String file = CmsFileUtil.readFile(dtdSystemLocation + dtdFilename, CmsEncoder.ENCODING_UTF_8);
                CmsXmlEntityResolver.cacheSystemId(dtdUrlPrefix + dtdFilename, file.getBytes(CmsEncoder.ENCODING_UTF_8));
                if (LOG.isDebugEnabled()) {
                    LOG.debug(org.opencms.configuration.Messages.get().getBundle().key(
                        org.opencms.configuration.Messages.LOG_CACHE_DTD_SYSTEM_ID_1,
                        new Object[] {dtdUrlPrefix + dtdFilename + " --> " + dtdSystemLocation + dtdFilename}));
                }
            } catch (IOException e) {
                LOG.error(org.opencms.configuration.Messages.get().getBundle().key(
                    org.opencms.configuration.Messages.LOG_CACHE_DTD_SYSTEM_ID_FAILURE_1,
                    new Object[] {dtdSystemLocation + dtdFilename}), e);
            }
        }
    }

    /**
     * Closes the zip file.<p>
     */
    public void closeFile() {

        if (getZipFile() != null) {
            try {
                getZipFile().close();
            } catch (IOException e) {
                CmsMessageContainer message = Messages.get().container(
                    Messages.ERR_IMPORTEXPORT_ERROR_CLOSING_ZIP_ARCHIVE_1,
                    getZipFile().getName());
                if (LOG.isDebugEnabled()) {
                    LOG.debug(message.key(), e);
                }
            }
        }
    }

    /**
     * Returns a byte array containing the content of the file.<p>
     *
     * @param filename the name of the file to read, relative to the folder or zip file
     * 
     * @return a byte array containing the content of the file
     * 
     * @throws CmsImportExportException if something goes wrong
     */
    public byte[] getFileBytes(String filename) throws CmsImportExportException {

        try {
            // is this a zip-file?
            if (getZipFile() != null) {
                // yes
                ZipEntry entry = getZipFile().getEntry(filename);
                // path to file might be relative, too
                if ((entry == null) && filename.startsWith("/")) {
                    entry = m_zipFile.getEntry(filename.substring(1));
                }
                if (entry == null) {
                    throw new ZipException(Messages.get().getBundle().key(
                        Messages.LOG_IMPORTEXPORT_FILE_NOT_FOUND_IN_ZIP_1,
                        filename));
                }

                InputStream stream = getZipFile().getInputStream(entry);
                int size = new Long(entry.getSize()).intValue();
                return CmsFileUtil.readFully(stream, size);
            } else {
                // no - use directory
                File file = new File(getFolder(), filename);
                return CmsFileUtil.readFile(file);
            }
        } catch (FileNotFoundException fnfe) {
            CmsMessageContainer msg = Messages.get().container(Messages.ERR_IMPORTEXPORT_FILE_NOT_FOUND_1, filename);
            if (LOG.isErrorEnabled()) {
                LOG.error(msg.key(), fnfe);
            }
            throw new CmsImportExportException(msg, fnfe);
        } catch (IOException ioe) {
            CmsMessageContainer msg = Messages.get().container(Messages.ERR_IMPORTEXPORT_ERROR_READING_FILE_1, filename);
            if (LOG.isErrorEnabled()) {
                LOG.error(msg.key(), ioe);
            }
            throw new CmsImportExportException(msg, ioe);
        }
    }

    /**
     * Returns the name of the import file, without zip extension.<p>
     * 
     * @return the name of the import file, without zip extension
     */
    public String getFileName() {

        String fileName = m_params.getPath().replace('\\', '/');
        String zipName = fileName.substring(fileName.lastIndexOf('/') + 1);
        String result;

        if (zipName.toLowerCase().endsWith(".zip")) {
            result = zipName.substring(0, zipName.lastIndexOf('.'));
            int pos = result.lastIndexOf('_');
            if (pos > 0) {
                result = result.substring(0, pos);
            }
        } else {
            result = zipName;
        }
        return result;
    }

    /**
     * Returns a stream for the content of the file.<p>
     *
     * @param fileName the name of the file to stream, relative to the folder or zip file
     * 
     * @return an input stream for the content of the file, remember to close it after using
     * 
     * @throws CmsImportExportException if something goes wrong
     */
    public InputStream getFileStream(String fileName) throws CmsImportExportException {

        try {
            InputStream stream = null;
            // is this a zip-file?
            if (getZipFile() != null) {
                // yes
                ZipEntry entry = getZipFile().getEntry(fileName);
                // path to file might be relative, too
                if ((entry == null) && fileName.startsWith("/")) {
                    entry = getZipFile().getEntry(fileName.substring(1));
                }
                if (entry == null) {
                    throw new ZipException(Messages.get().getBundle().key(
                        Messages.LOG_IMPORTEXPORT_FILE_NOT_FOUND_IN_ZIP_1,
                        fileName));
                }

                stream = getZipFile().getInputStream(entry);
            } else {
                // no - use directory
                File file = new File(getFolder(), CmsImportExportManager.EXPORT_MANIFEST);
                stream = new FileInputStream(file);
            }
            return stream;
        } catch (Exception ioe) {
            CmsMessageContainer msg = Messages.get().container(Messages.ERR_IMPORTEXPORT_ERROR_READING_FILE_1, fileName);
            if (LOG.isErrorEnabled()) {
                LOG.error(msg.key(), ioe);
            }
            throw new CmsImportExportException(msg, ioe);
        }
    }

    /**
     * Returns the RFS folder to import from.<p>
     *
     * @return the RFS folder to import from
     */
    public File getFolder() {

        return m_folder;
    }

    /**
     * Returns the class system location.<p>
     * 
     * i.e: <code>org/opencms/importexport</code><p>
     * 
     * @param clazz the class to get the location for
     *
     * @return the class system location
     */
    public String getLocation(Class clazz) {

        String filename = clazz.getName().replace('.', '/');
        int pos = filename.lastIndexOf('/') + 1;
        return (pos > 0 ? filename.substring(0, pos) : "");
    }

    /**
     * Returns the RFS zip file to import from.<p>
     *
     * @return the RFS zip file to import from
     */
    public ZipFile getZipFile() {

        return m_zipFile;
    }

    /**
     * Opens the import file.<p>
     * 
     * @throws IOException if the file could not be opened
     */
    public void openFile() throws IOException {

        // get the import resource
        m_folder = new File(OpenCms.getSystemInfo().getAbsoluteRfsPathRelativeToWebInf(m_params.getPath()));

        // if it is a file it must be a zip-file
        if (m_folder.isFile()) {
            m_zipFile = new ZipFile(m_params.getPath());
            m_folder = null;
        }
    }
}
