/*

  FreeWRL support library.
  Resources handling: URL, files, ...

*/

/****************************************************************************
    This file is part of the FreeWRL/FreeX3D Distribution.

    Copyright 2009 CRC Canada. (http://www.crc.gc.ca)

    FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    FreeWRL/FreeX3D 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with FreeWRL/FreeX3D.  If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/

#ifndef __LIBFREEWRL_RESOURCES_H__
#define __LIBFREEWRL_RESOURCES_H__

#include "list.h"

#ifdef AQUA
#include <system_threads.h>
#endif

#ifdef _MSC_VER
#include <system_threads.h>
#endif

#ifdef _ANDROID
#include <system_threads.h>
#endif

/* is this file name relative to another path, or is it really, really, a direct file name? */
#if defined(_MSC_VER)
#define IF_cleanedURL_IS_ABSOLUTE if(strchr(cleanedURL,':')) // if(cleanedURL[0] != '\0' && cleanedURL[1]== ':')

#else

#define IF_cleanedURL_IS_ABSOLUTE \
	DEBUG_RES("resource_identify = we have base cleanedurl = %s\n", cleanedURL); \
	if (cleanedURL[0] == '/')
#endif

typedef enum resource_type {
	rest_invalid,
	rest_url,
	rest_file,
	rest_multi,
	rest_string /* inline VRML/X3D code */
} resource_type_t;

typedef enum resource_status {
	ress_none,        /* never processed */
	ress_starts_good, /* path/url identification succeeded */
	ress_invalid,     /* path/url identification failed */
	ress_downloaded,  /* download succeeded (or local file available) */
	ress_failed,      /* download failed */
	ress_loaded,      /* loader succeeded */
	ress_not_loaded,  /* loader failed */
	ress_parsed,      /* parser succeeded */
	ress_not_parsed   /* parser failed */
} resource_status_t;

typedef enum resource_media_type {
	resm_unknown,
	resm_vrml,
	resm_x3d,
	resm_image,
	resm_movie,
	resm_script,
	resm_pshader,
	resm_fshader,
	resm_audio,
	resm_x3z
} resource_media_type_t;

typedef enum resource_actions {
	resa_default = 0, //all by default: download, load, parse/process: not using actions
	resa_identify = 1,
	resa_download = 2, //will & and | as bit flags so declare 1,2,4,8.. power of 2 or 1<<n
	resa_load = 4,
	resa_process = 8,
	//resa_place,
	//resa_ remove, delete ?? ... see parser_process_res()
} resource_actions_t;

typedef struct resource_item {

	/* Parent */
	struct resource_item *parent;
	s_list_t *children;

	bool network;
	bool new_root;

	/* Request */
	resource_type_t type;
	resource_status_t status;
	resource_actions_t actions; //if 0, do default which is all actions: download, load, parse, 
		//else do specific requested actions (which are bitwise |= resource_actions_t's)
	//resource_actions_t successful;  //you could have more bitwise flags to track what steps succeeded, which were attempted etc.
	//resource_actions_t attempted; 

	/* Resource has passed all the steps */
	//July30,2014 dug9: clarification (and possible change) of the meaning of complete: 
	//  work thread (and FE/ML download/load threads) has attempted all requested actions which are possible,
	//  and is finished with the resitem (some actions may have failed - test with last status ie ress_failed etc)
	bool complete;  
	//for vrml/x3d media types:
	void *ectx; //for parsing brotos - the X3D_Proto executionContext to put __ROUTES, __nodes, __subContext
	void *whereToPlaceData;  // usually X3D_Node*, except for Scripts and Shaders, it's Shader_Script* (which is a sub-struct)
	int offsetFromWhereToPlaceData; //usually field offset (not used for Scripts/Shaders)
	int textureNumber; //Dec 2014 textures don't use wheretoplacedata now, because the *tti might be zapped during inline unload before the image is downloaded ie Mars dataset
	/* We can be feed with a Multi_String list of requests */
	s_list_t *m_request;

	/* Verbatim request : requested path/url */
	char *URLrequest;

	/* Base:
	   (base url or base path of the main world)
	   - if parent != NULL, use parent's base, 
	   - else use own's base 

	   MUST be complete: either have a trailing '/'
	   either be the end of a valid URI that can
	   be appended with a file:
	   'http://host/cgi?request_file='

	   This last example requires that we can
	   parse the main url and extract that 'base'.
	   Is there a 'base' declaration in X3D spec ?
	*/
	char *URLbase; 

	/* Temporary directory:
	   (each main file/world has its own temp dir)
	   - if parent != NULL, use parent's dir,
	   - else use own's dir
	*/
	char *temp_dir; 

	/* if we have a # character in it (eg, proto, Anchor) we'll have a mallocd bit of 
	   memory here */
	char *afterPoundCharacters;


/*
 *   Note on temp dir: to improve user experience, each time a temporary
 *                     file is created to mirror a network resource, we
 *                     use the temporary directory created specificaly
 *                     for this main file/world : this way the user (or
 *                     a future menu in FreeWRL) can pack all that stuff
 *                     more easily.
 */

	/* Parsed request:
	   - complete url to network file
	   - complete path to local file
	*/
	char *parsed_request;

	/* Cached files: first is actual file to read,
	   other are intermediate: zipped file, 
	   file not in good format, ...
	*/
	char *actual_file;
	void *cached_files;

	/* Openned files: to be able to close them. */
	void *openned_files;

	/* Convenient */
	char four_first_bytes[4];

	resource_media_type_t media_type;
	int treat_as_root; //bandaid for .x3z doc.x3d to be seen as root res equivalent
	pthread_t *_loadThread; //pthread_t * used for async_loading in middleLayer ML
	void *tg; //gglobal context
	int (*_loadFunc)(void *); //used for some experiments where the backend loads, but the frontend injects a load function
} resource_item_t;

extern resource_item_t *root_res;

bool resource_init_base(resource_item_t *root_res);

resource_item_t* resource_create_single(const char *request);

/* Quick hack to not be forced to include Structs.h */
typedef struct Multi_String s_Multi_String_t;
resource_item_t* resource_create_multi(s_Multi_String_t *request);
resource_item_t* resource_create_multi0(s_Multi_String_t *request);

resource_item_t* resource_create_from_string(const char *string);

void push_resource_request(const char *request);
void resource_identify(resource_item_t *base, resource_item_t *resresource_identify);
bool resource_fetch(resource_item_t *res);
void resitem_enqueue(s_list_t *resitem);
bool resource_load(resource_item_t *res);
void resource_identify_type(resource_item_t *res);
bool resource_fetch(resource_item_t *res);
void resource_destroy(resource_item_t *res);
void destroy_root_res();

void resource_remove_child(resource_item_t *parent, resource_item_t *child);

void send_resource_to_parser(resource_item_t *res);
void send_resource_to_parser_async(resource_item_t *res);

bool send_resource_to_parser_if_available(resource_item_t *res);

/*
void resource_push_single_request(const char *request);
*/
void resource_push_multi_request(struct Multi_String *request);
void resource_wait(resource_item_t *res);

void resource_get_valid_url_from_multi(resource_item_t *parentPath, resource_item_t *res);

void resource_dump(resource_item_t *res);
void resource_tree_dump(int level, resource_item_t *root);
void resource_tree_list_files(int level, resource_item_t *root);
void resource_tree_destroy();

char *resourceStatusToString(int status);
char *resourceTypeToString(int type);
char *resourceMediaTypeToString(int type);

/* Initial URL loaded : replace IS_WORLD_LOADED */
extern bool resource_is_root_loaded();
void frontenditem_enqueue(s_list_t *item);

void popInputResource();
void pushInputResource(resource_item_t *url);
resource_item_t *getInputResource();

bool imagery_load(resource_item_t *res);

#endif /* __LIBFREEWRL_RESOURCES_H__ */
