/**
 * @file libcomprex/module.h Module API
 * 
 * $Id: module.h,v 1.23 2002/05/25 19:55:36 chipx86 Exp $
 *
 * @Copyright (C) 2001-2002 The GNUpdate Project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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.
 */
#ifndef _LIBCOMPREX_MODULE_H_
#define _LIBCOMPREX_MODULE_H_

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef enum   _CxModuleType CxModuleType;  /**< Module types.          */
typedef struct _CxArchiveOps CxArchiveOps;  /**< File operations.       */
typedef struct _CxSchemeOps  CxSchemeOps;   /**< URI scheme operations. */
typedef struct _CxModule     CxModule;      /**< A loadable module.     */

#include <libcomprex/types.h>
#include <libcomprex/file.h>
#include <libcomprex/fp.h>
#include <libcomprex/directory.h>

/**
 * Handles the initialization of modules.
 */
#ifdef STATIC_MODULE
# define CX_INIT_ARCHIVE_MODULE(modname, initfunc, archiveops) \
	CxModule *init_##modname##_archive_module(void) { \
		initfunc(CX_MODULE_ARCHIVE); \
		return cxRegisterModule(#modname, &(archiveops), CX_MODULE_ARCHIVE); \
	}
# define CX_INIT_SCHEME_MODULE(modname, initfunc, schemeops) \
	CxModule *init_##modname##_scheme_module(void) { \
		initfunc(CX_MODULE_SCHEME); \
		return cxRegisterModule(#modname, &(schemeops), CX_MODULE_SCHEME); \
	}
#else /* if !STATIC_MODULE */
# define CX_INIT_ARCHIVE_MODULE(modname, initfunc, archiveops) \
	CxModule *initComprexModule(void) { \
		initfunc(CX_MODULE_ARCHIVE); \
		return cxRegisterModule(#modname, &(archiveops), CX_MODULE_ARCHIVE); \
	}
# define CX_INIT_SCHEME_MODULE(modname, initfunc, schemeops) \
	CxModule *initComprexModule(void) { \
		initfunc(CX_MODULE_SCHEME); \
		return cxRegisterModule(#modname, &(schemeops), CX_MODULE_SCHEME); \
	}
#endif

/**
 * A module type.
 *
 * These are the types of modules that libcomprex can dynamically load.
 */
enum _CxModuleType
{
	CX_MODULE_ARCHIVE, /**< File handler module. */
	CX_MODULE_SCHEME   /**< URI scheme module.   */
};

/**
 * @struct _CxArchiveOps module.h libcomprex/module.h
 *
 * File operations structure.
 *
 * This structure is to be filled out by all modules that handle
 * comression/decompression of files.
 *
 * @see CxModuleType
 * @see CxSchemeOps
 */
struct _CxArchiveOps
{
	/**
	 * Reads an archive and returns information on it.
	 *
	 * This is similar to openDir(), but reports information on
	 * the archive file itself, as well as all of the files stored
	 * inside it.
	 *
	 * @param archive The archive structure, which will contain the
	 *                archive information.
	 * @param fp      The file pointer to the archive file.
	 *
	 * @return The status of the operation.
	 */
	CxStatus (*readArchive)(CxArchive *archive, CxFP *fp);

	/**
	 * Saves an archive to a file.
	 *
	 * @param archive  The archive structure.
	 * @param fp       The file pointer to the archive file.
	 *
	 * @return The status of the operation.
	 */
	CxStatus (*saveArchive)(CxArchive *archive, CxFP *fp);

	/**
	 * Closes an archive.
	 *
	 * @param archive The archive structure.
	 */
	void (*closeArchive)(CxArchive *archive);

	/**
	 * Opens a contained file for reading, writing, or appending.
	 *
	 * @param file The file structure.
	 * @param mode The access mode.
	 *
	 * @return The file pointer to this file.
	 */
	CxFP *(*openFile)(CxFile *file, CxAccessMode mode);

	/**
	 * Destroys the module-specific data in a contained file.
	 *
	 * @param file The file to destroy.
	 */
	void (*destroyFile)(CxFile *file);

	/**
	 * Determines if the module supports the specified file extension.
	 *
	 * This should just give a best guess. All string comparisons should
	 * be case-insensitive.
	 * 
	 * @param ext The extension (without the leading '.')
	 * 
	 * @return 1 if the extension is supported; 0 otherwise.
	 */
	char (*supportsExtension)(const char *ext);
};

/**
 * @struct _CxSchemeOps module.h libcomprex/module.h
 *
 * Scheme operations structure.
 *
 * This structure is to be filled out by all modules that handle
 * the retrieval of files from non-local locations.
 *
 * @see CxModuleType
 * @see CxArchiveOps
 */
struct _CxSchemeOps
{
	/**
	 * Retrieves a file from a non-local source.
	 *
	 * @param scheme      The scheme part of the URI.
	 * @param path        The path part of the URI.
	 * @param outFilename The destination filename.
	 *
	 * @return The status of the operation.
	 */
	CxStatus (*get)(const char *scheme, const char *path,
					const char *outFilename);
	
	/**
	 * Determines if the module supports the specified scheme.
	 *
	 * @param scheme The URI scheme to check.
	 * 
	 * @return 1 if the scheme is supported; 0 otherwise.
	 */
	char (*supports)(const char *scheme);
};

/**
 * @struct _CxModule module.h libcomprex/module.h
 * 
 * A file or scheme module.
 *
 * @see CxModuleType
 * @see CxArchiveOps
 * @see CxSchemeOps
 */
struct _CxModule
{
	CxModuleType type;          /**< The type of module.              */

	char *filename;             /**< The filename of the module.      */
	char *name;                 /**< The name of the module.          */
	void *handle;               /**< The libtool handle.              */

	unsigned int refCount;      /**< The module's reference count.    */

	union
	{
		CxArchiveOps *archive;  /**< File operations.                 */
		CxSchemeOps  *scheme;   /**< Scheme operations.               */

	} ops;                      /**< Operations.                      */

	CxModule *prev;             /**< The previous module in the list. */
	CxModule *next;             /**< The next module in the list.     */
};

/**
 * Registers a module.
 *
 * @param name The name of the module.
 * @param ops  The operations structure.
 * @param type The type of module.
 *
 * @return The module structure, or @c NULL on failure.
 */
CxModule *cxRegisterModule(const char *name, void *ops, CxModuleType type);

/**
 * Loads the module of the specified name and type.
 *
 * @param name The name of the module (without ".so")
 * @param type The type of module.
 * 
 * @return A CxModule structure representing the module.
 *
 * @see cxUnloadModule()
 * @see cxGetModule()
 */
CxModule *cxLoadModule(const char *name, CxModuleType type);

/**
 * Unloads the specified module.
 *
 * @param module The module to unload.
 *
 * @see cxLoadModule()
 */
void cxUnloadModule(CxModule *module);

/**
 * Returns the specified module.
 *
 * The module
 *
 * @param name The name of the module.
 * @param type The type of the module.
 *
 * @return A CxModule structure representing the module.
 *
 * @see cxLoadModule()
 */
CxModule *cxGetModule(const char *name, CxModuleType type);

/**
 * Notifies libcomprex that the module is being used.
 *
 * This is used to increment the module's reference count.
 *
 * @param ptr The module.
 *
 * @see cxUnlinkModule()
 */
void cxLinkModule(CxModule **ptr);

/**
 * Notifies libcomprex that the module is no longer being used.
 *
 * This is used to decrement the module's reference count.
 *
 * @see ptr The module.
 *
 * @see cxLinkModule()
 */
void cxUnlinkModule(CxModule **ptr);

/**
 * Returns the first module in the list.
 *
 * This will probably only be useful inside libcomprex.
 *
 * @param type The type of module.
 * 
 * @return The first module in the list.
 *
 * @see cxGetModule()
 */
CxModule *cxGetFirstModule(CxModuleType type);

/**
 * Unloads all modules.
 *
 * This should only be called when you are absolutely done with
 * this library.
 *
 * This will be automatically called by cxCleanup().
 *
 * @see cxCleanup()
 */
void cxCleanupModules();

/**
 * Cleans up the entire library.
 *
 * This should only be called when you are absolutely done with
 * this library.
 *
 * This will call cxCleanupModules() automatically.
 *
 * @see cxCleanupModules()
 */
void cxCleanup(void);

#ifdef __cplusplus
}
#endif

#endif /* _LIBCOMPREX_MODULE_H_ */

