/*************************************************************************
	File:	pcld_plugin.c

	FormZ unstructured translator sample.  Imports and exports point cloud data.

	COPYRIGHT (C) 2001.  All Rights Reserved.
	auto*des*sys, Inc., Columbus, Ohio, USA.
*************************************************************************/

#include "pcld_prvt.h"

/* This include file must be included in only the plugins source file which contains 
	the implementation of fz_plugin_entry */
#include "fz_plugin_glue_api.h"



	/* application provided function sets to hold on to */
const fzpl_fset_glue_fset	*_fset_glue = NULL;
fz_syst_fset					_syst_funcs;
fz_ffmt_fset					_ffmt_funcs;
fz_fuim_fset					_fuim_funcs;
fz_type_fset					_type_funcs;
fz_iost_fset					_iost_funcs;
fz_model_fset					_model_funcs;
fz_objt_attr_fset				_model_attr_funcs;
fz_rmtl_fset					_rmtl_funcs;
fz_fzrt_base_fset				_fzrt_base_funcs;
fz_fzrt_mem_fset				_fzrt_mem_funcs;
fz_fzrt_file_fset				_fzrt_file_funcs;
fz_fzrt_graf_fset				_fzrt_graf_funcs;

	/* plugin's runtime id */
fzrt_unsigned_int					_pcld_plugin_runtime_id = FZ_FFMT_NONE;

	/* translator's format reference id */
fz_ffmt_ref_td					_pcld_ref = -1;

	/* translator's resource file id */
fzrt_fzr_ref_td					_fz_rsrc_ref = -1;
	
	/* export custom options */
double							_export_scale = 1.0;

	/* import custom options */
double							_import_scale = 1.0;


/************************************************************************
	Acquires all application provided function sets.
*************************************************************************/
static fzrt_error_td pcld_acquire_fsets ( void )
{
	fzrt_error_td err;

	err = _fset_glue->fzpl_fset_acquire( FZ_SYST_FSET_TYPE, FZ_SYST_FSET_VERSION, FZRT_UUID_NULL,
								 FZPL_TYPE_STRING(fz_syst_fset), sizeof(_syst_funcs),
								 (fzpl_fset_td *)&_syst_funcs );
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FFMT_FSET_TYPE, FZ_FFMT_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_ffmt_fset), sizeof(_ffmt_funcs),
									 (fzpl_fset_td *)&_ffmt_funcs );
	}
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_TYPE_FSET_TYPE, FZ_TYPE_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_type_fset), sizeof(_type_funcs),
									 (fzpl_fset_td *)&_type_funcs );
	}
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FUIM_FSET_TYPE, FZ_FUIM_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_fuim_fset), sizeof(_fuim_funcs),
									 (fzpl_fset_td *)&_fuim_funcs );
	}
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_MODEL_FSET_TYPE, FZ_MODEL_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_model_fset), sizeof(_model_funcs),
									 (fzpl_fset_td *)&_model_funcs );
	}
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_OBJT_ATTR_FSET_TYPE, FZ_OBJT_ATTR_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_objt_attr_fset), sizeof(_model_attr_funcs),
									 (fzpl_fset_td *)&_model_attr_funcs );
	}
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_RMTL_FSET_TYPE, FZ_RMTL_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_rmtl_fset), sizeof(_rmtl_funcs),
									 (fzpl_fset_td *)&_rmtl_funcs );
	}
	
	if ( err == FZRT_NOERR )
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_IOST_FSET_TYPE, FZ_IOST_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_iost_fset), sizeof(_iost_funcs),
									 (fzpl_fset_td *)&_iost_funcs );
	}
	
	if(err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_MEM_FSET_TYPE, FZ_FZRT_MEM_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_fzrt_mem_fset), sizeof(_fzrt_mem_funcs),
									 (fzpl_fset_td *)&_fzrt_mem_funcs );
	}
	
	if(err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_FILE_FSET_TYPE, FZ_FZRT_FILE_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_fzrt_file_fset), sizeof(_fzrt_file_funcs),
									 (fzpl_fset_td *)&_fzrt_file_funcs );
	}
	
	if(err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_BASE_FSET_TYPE, FZ_FZRT_BASE_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_fzrt_base_fset), sizeof(_fzrt_base_funcs),
									 (fzpl_fset_td *)&_fzrt_base_funcs );
	}

	if(err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_GRAF_FSET_TYPE, FZ_FZRT_GRAF_FSET_VERSION, FZRT_UUID_NULL,
									 FZPL_TYPE_STRING(fz_fzrt_graf_fset), sizeof(_fzrt_graf_funcs),
									 (fzpl_fset_td *)&_fzrt_graf_funcs );
	}


	return(err);
}

/************************************************************************
	Releases all application provided function sets.
*************************************************************************/
static void pcld_release_fsets ( void )
{
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_fzrt_base_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_fzrt_mem_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_fzrt_file_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_fzrt_graf_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_iost_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_rmtl_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_model_attr_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_model_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_fuim_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_type_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_ffmt_funcs);
	_fset_glue->fzpl_fset_release((fzpl_fset_td *)&_syst_funcs);
}

/************************************************************************
	Fills the function set structure with the file translator info
	callback functions.
*************************************************************************/
static fzrt_error_td pcld_translator_info_get_fset ( const fzpl_fset_def_ptr fset_def, fzpl_fset_td * const fset )
{
	fzrt_error_td					err = FZRT_NOERR;
	fz_ffmt_cbak_info_fset		*info_struct;

	if ( fset_def && fset )
	{
			/* Check the version and size of the function set structure */
		_fset_glue->fzpl_fset_def_check ( fset_def, FZ_FFMT_CBAK_INFO_FSET_VERSION, FZPL_TYPE_STRING(fz_ffmt_cbak_info_fset), sizeof ( fz_ffmt_cbak_info_fset ), FZPL_VERSION_OP_NEWER );
		if ( err == FZRT_NOERR )
		{
			info_struct = (fz_ffmt_cbak_info_fset *)fset;

				/* Assign functions to the function set. */
			info_struct->fz_ffmt_cbak_name			= pcld_get_name;
			info_struct->fz_ffmt_cbak_uuid			= pcld_get_id;
			info_struct->fz_ffmt_cbak_info			= pcld_get_info;
			info_struct->fz_ffmt_cbak_ftype			= pcld_get_ftype;
			info_struct->fz_ffmt_cbak_icon_rsrc		= NULL;
			info_struct->fz_ffmt_cbak_icon_file		= pcld_get_icon;
			info_struct->fz_ffmt_cbak_opts_io		= pcld_opts_io;
			info_struct->fz_ffmt_cbak_is_file		= NULL;
		}
	}
	else
	{
		err = _fzrt_base_funcs.fzrt_error_set_with_detail ( FZRT_BAD_PARAM_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0, 3001 );
	}

	return(err);
}

/************************************************************************
	Fills the function set structure with the unstructured translator
	callback functions.
*************************************************************************/
static fzrt_error_td pcld_get_basic_cbak_fset ( const fzpl_fset_def_ptr fset_def, fzpl_fset_td * const fset )
{
	fzrt_error_td					err = FZRT_NOERR;
	fz_ffmt_cbak_basic_fset		*basic_struct;

	if ( fset_def && fset )
	{
			/* Check the version and size of the function set structure */
		_fset_glue->fzpl_fset_def_check ( fset_def, FZ_FFMT_CBAK_BASIC_FSET_VERSION, FZPL_TYPE_STRING(fz_ffmt_cbak_basic_fset), sizeof ( fz_ffmt_cbak_basic_fset ), FZPL_VERSION_OP_NEWER );
		if ( err == FZRT_NOERR )
		{
			basic_struct = (fz_ffmt_cbak_basic_fset *)fset;

				/* Assign functions to the function set. */
			basic_struct->fz_ffmt_cbak_basic_type					= pcld_type;
			basic_struct->fz_ffmt_cbak_basic_read_opts_dlog			= pcld_read_opts;
			basic_struct->fz_ffmt_cbak_basic_read_opts_default		= pcld_read_opts_default;
			basic_struct->fz_ffmt_cbak_basic_read					= pcld_read;
			basic_struct->fz_ffmt_cbak_basic_write_opts_dlog		= pcld_write_opts;
			basic_struct->fz_ffmt_cbak_basic_write_opts_default		= pcld_write_opts_default;
			basic_struct->fz_ffmt_cbak_basic_write					= pcld_write;
		}
	}
	else
	{
		err = _fzrt_base_funcs.fzrt_error_set_with_detail ( FZRT_BAD_PARAM_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0, 3001 );
	}

	return(err);
}


/************************************************************************
		A first pass check to see if the plugin can be loaded.
		- Checks licensing if needed.
		- Acquires the application defined function sets which are
			needed by the plugin.
		- Verifies that plugin and application are compatible if needed.
		- Loads the plugin's resource file.
*************************************************************************/
static fzrt_error_td pcld_check_config ( const fzpl_fset_glue_fset * const fset_glue, const fzpl_host_config_td * const hostConfig )
{
	fzrt_error_td					err = FZRT_NOERR;
	fzrt_floc_ptr					floc;

	_fset_glue = fset_glue;

	/*	IF NEEDED : Check the application's version and api version */

	/*  Make sure required application defined function sets are available */
	/*  Release the function sets at unload. */

	err = pcld_acquire_fsets();

	// IF NEEDED : Check License

	/* Make sure the plugin's resource file is available and load it */
	if ( err == FZRT_NOERR )
	{
		_fzrt_file_funcs.fzrt_file_floc_init(&floc);
		err = fset_glue->fzpl_plugin_file_get_floc(floc);
		if(err == FZRT_NOERR)
		{
			err = _fzrt_base_funcs.fzrt_fzr_open(floc, "pcld", &_fz_rsrc_ref);
		}
		_fzrt_file_funcs.fzrt_file_floc_finit(&floc);
	}	

	if ( err != FZRT_NOERR )
	{
		pcld_release_fsets();
	}

	return(err);
}

/************************************************************************
	Registers plugins and their assocoated function sets.
*************************************************************************/
static fzrt_error_td pcld_register_plugins ( const fzpl_fset_glue_fset * const fset_glue, const fzpl_host_config_td * const hostConfig )
{
	fzrt_error_td					err = FZRT_NOERR;
	fzrt_int								num_failed = 0;
	char							desc[FZPL_DESC_SIZE];
	char							pname[FZPL_NAME_SIZE];

		/* Make sure the plugin can run. */
	err = pcld_check_config ( fset_glue, hostConfig );

	if(err == FZRT_NOERR)
	{
		/* Register the plugin */
		_fzrt_base_funcs.fzrt_fzr_get_string(_fz_rsrc_ref, PCLD_STRINGS, PCLD_NAME_STR, pname);
		err = fset_glue->fzpl_plugin_register( PCLD_FMT_PLUGIN_ID, pname, PCLD_FMT_PLUGIN_VERSION,
											PCLD_FMT_PLUGIN_VENDOR,
											PCLD_FMT_PLUGIN_URL,
											FZ_FILE_IMAGE_EXTS_TYPE, FZ_FILE_IMAGE_EXTS_VERSION,
											pcld_error_str_func, 0, NULL,
											&_pcld_plugin_runtime_id);
		if ( err != FZRT_NOERR )
		{
			err = FZRT_NOERR;
			num_failed++;
		}
		else
		{
			/* Add the function sets implemented by the plugin */
			err = fset_glue->fzpl_plugin_add_fset( _pcld_plugin_runtime_id, FZ_FFMT_CBAK_INFO_FSET_TYPE,
								 				FZ_FFMT_CBAK_INFO_FSET_VERSION, FZ_FFMT_CBAK_INFO_FSET_NAME,
												FZPL_TYPE_STRING(fz_ffmt_cbak_info_fset), sizeof ( fz_ffmt_cbak_info_fset ),
												pcld_translator_info_get_fset, FALSE);
			if(err == FZRT_NOERR)
			{
				err = fset_glue->fzpl_plugin_add_fset( _pcld_plugin_runtime_id, FZ_FFMT_CBAK_BASIC_FSET_TYPE,
													FZ_FFMT_CBAK_BASIC_FSET_VERSION, FZ_FFMT_CBAK_BASIC_FSET_NAME,
													FZPL_TYPE_STRING(fz_ffmt_cbak_basic_fset), sizeof(fz_ffmt_cbak_basic_fset),
													pcld_get_basic_cbak_fset, FALSE);
			}
		}

		/* If registering more than one plugin, and some of the plugins fail to register, return an err with severity
			set to FZRT_ERROR_SEVERITY_WARNING and do not release application implemented function sets.
			If all plugins fail to register return an err with severity set to FZRT_ERROR_SEVERITY_ERROR. and
			release application implemented function sets */
		if ( num_failed == 1 )
		{
			/* Release application implemented function sets */
			pcld_release_fsets();
			err = _fzrt_base_funcs.fzrt_error_set_with_detail ( FZRT_UNKNOWN_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0, 3002 );
		}
		if ( num_failed == 0 )
		{
			_fzrt_base_funcs.fzrt_fzr_get_string(_fz_rsrc_ref, PCLD_STRINGS, PCLD_DESC_STR, desc);

			err = fset_glue->fzpl_plugin_set_desc(_pcld_plugin_runtime_id, desc);
		}
	}

	return(err);
}

/************************************************************************
	Unregisters plugins.
*************************************************************************/
static fzrt_error_td pcld_unregister_plugins ( const fzpl_fset_glue_fset * const fset_glue )
{
	fzrt_error_td					err = FZRT_NOERR;

	/* Unregister the plugin */
	err = fset_glue->fzpl_plugin_unregister( _pcld_plugin_runtime_id );

	/* Release application implemented function sets */
	pcld_release_fsets();

	return(err);
}

/************************************************************************
	The main plugin file entry point.  Plugin initialization and uninitialization
		happens via this function.
*************************************************************************/
FZPL_PLUGIN_FUNC(fzrt_error_td) fz_plugin_entry( const fzpl_fset_glue_fset * const fset_glue, fzpl_command_td cmd, const fzpl_host_config_td * const hostConfig )
{
	fzrt_error_td	err = FZRT_NOERR;
	
	switch ( cmd )
	{
		case FZPL_PLUGIN_INITIALIZE:
			err = pcld_register_plugins(fset_glue, hostConfig);
		break;
		
		case FZPL_PLUGIN_EXIT:
			err = pcld_unregister_plugins(fset_glue);
			break;
			
		default:
			break;
	}

	return(err);
}

