#ifndef METADATA_H
#define METADATA_H

#include <config.h>

#include <glib.h>

#include <libhrel/types.h>
#include <libhrel/tuple.h>
#include <libhrel/relation.h>

typedef enum {
    BMP_DATUM_LOCATION,

    BMP_DATUM_ARTIST,
    BMP_DATUM_ALBUM,
    BMP_DATUM_TITLE,
    BMP_DATUM_TRACK,
    BMP_DATUM_TIME,
    BMP_DATUM_GENRE,
    BMP_DATUM_COMMENT,
    BMP_DATUM_RATING,
    BMP_DATUM_DATE,
    BMP_DATUM_MTIME,
    BMP_DATUM_BITRATE,
    BMP_DATUM_SAMPLERATE,
    BMP_DATUM_COUNT,

    BMP_DATUM_HAL_VOLUME_UDI,
    BMP_DATUM_HAL_DEVICE_UDI,

    BMP_DATUM_NONE
} BmpMetadatumId;

#define BMP_METADATA_PKEY BMP_DATUM_LOCATION

gchar*
bmp_metadata_get_title		(BmpMetadatumId metadatum_id);

const gchar*
bmp_metadata_get_title_static	(BmpMetadatumId metadatum_id);

gchar*
bmp_metadata_get_title_plural	(BmpMetadatumId metadatum_id);

gint
bmp_metadata_get_id_by_name	(const gchar *id_string);
 
gchar*
bmp_metadata_get_id		(BmpMetadatumId metadatum_id);

const gchar*
bmp_metadata_get_id_static	(BmpMetadatumId metadatum_id);

const gchar*
bmp_metadata_get_default_char	(BmpMetadatumId metadatum_id);

gint
bmp_metadata_get_default_int	(BmpMetadatumId metadatum_id);

gboolean
bmp_metadata_get_filter		(BmpMetadatumId metadatum_id);
 

G_BEGIN_DECLS

GType
bmp_metadata_get_type		  (BmpMetadatumId metadatum_id);

HTuple*
bmp_metadata_tuple_create_default (const gchar *uri);


/* Metadata Cache Functions */
#define BMP_TYPE_METADATA_CACHE		   (bmp_metadata_cache_get_type ())
#define BMP_METADATA_CACHE(obj)		   (G_TYPE_CHECK_INSTANCE_CAST ((obj), BMP_TYPE_METADATA_CACHE, BmpMetadataCache))
#define BMP_METADATA_CACHE_CLASS(klass)	   (G_TYPE_CHECK_CLASS_CAST ((klass), BMP_TYPE_METADATA_CACHE, BmpMetadataCacheClass))
#define BMP_IS_METADATA_CACHE(obj)	   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BMP_TYPE_METADATA_CACHE))
#define BMP_IS_METADATA_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BMP_TYPE_METADATA_CACHE))
#define BMP_METADATA_CACHE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), BMP_TYPE_METADATA_CACHE, BmpMetadataCacheClass))

typedef struct _BmpMetadataCache BmpMetadataCache;
typedef struct _BmpMetadataCacheClass BmpMetadataCacheClass;
typedef struct _BmpMetadataCachePrivate BmpMetadataCachePrivate;

struct _BmpMetadataCache {
	GObject parent;

        BmpMetadataCachePrivate *private;
};

struct _BmpMetadataCacheClass {
	GObjectClass parent;

	void (*insert_tuple)		(BmpMetadataCache * self, HTuple *tuple); 
	void (*delete_tuple)		(BmpMetadataCache * self, HTuple *tuple); 

	void (*tag_added)		(BmpMetadataCache * self, const gchar *tagname); 
	void (*tag_deleted)		(BmpMetadataCache * self, const gchar *tagname);

	void (*tag_value_insert)	(BmpMetadataCache * self, const gchar *tagname, gint metadatum_tag_id, const gchar *value);
	void (*tag_value_remove)	(BmpMetadataCache * self, const gchar *tagname, gint metadatun_tag_id, const gchar *value);
};

extern BmpMetadataCache   *bmp_metadata_cache;

typedef enum {
    REALM_PERMANENT,
    REALM_TRANSIENT,

    N_REALMS
} MetadataRealm;

/* RowGUID */
typedef struct _RowGUID RowGUID;
struct _RowGUID {
    guint   counter;
    guint   hash;
};
#define ROW_GUID(guid) ((RowGUID*)(guid))
gboolean
row_guid_equal_func (RowGUID *guid_a, RowGUID *guid_b);

guint
row_guid_hash_func (RowGUID *guid);

/* BmpFileItem */
typedef struct _BmpFileItem BmpFileItem;
struct _BmpFileItem {
	gchar		  *uri;
	RowGUID		  *guid;
	MetadataRealm	   realm;
};
#define BMP_FILE_ITEM(item) ((BmpFileItem*)(item))

BmpFileItem*
bmp_file_item_copy (BmpFileItem *item);

void
bmp_file_item_free (BmpFileItem *item);

BmpFileItem*
bmp_file_item_new (const gchar	    *uri,
		   MetadataRealm     realm);
 
GType
bmp_file_item_get_type (void);
#define BMP_TYPE_FILE_ITEM		    (bmp_file_item_get_type ())


GType
bmp_metadata_cache_get_type		    (void);

BmpMetadataCache*
bmp_metadata_cache_new			    (void);

HTuple*
bmp_metadata_cache_metadata_get		    (BmpMetadataCache	*self,
					     BmpFileItem	*item); 

void
bmp_metadata_cache_metadata_remove	    (BmpMetadataCache	*self,
					     const gchar	*uri); 

void
bmp_metadata_cache_metadata_cache	    (BmpMetadataCache *self,
					     const gchar      *uri); 

gboolean
bmp_metadata_cache_cache_audiocd	    (BmpMetadataCache *self);


HTuple*
bmp_metadata_cache_get_cached		    (BmpMetadataCache	*self,
					     const gchar	*uri); //This function returns cached items ONLY and ONLY from the PERMANENT realm
 
void
bmp_metadata_cache_load_rtfs		    (BmpMetadataCache *self);

void
bmp_metadata_cache_load_tags		    (BmpMetadataCache *self);

void
bmp_metadata_cache_for_each_tuple	    (BmpMetadataCache *self, HTupleFunc func, gpointer data);
 
gchar*
bmp_metadata_cache_get_titlestring	    (BmpMetadataCache *self, BmpFileItem *item); 

GHashTable*
bmp_metadata_cache_get_hash_value_table	    (BmpMetadataCache *self, BmpFileItem *item); 

/* Query API */
typedef struct _QueryAtom QueryAtom;
struct _QueryAtom {
    BmpMetadatumId    metadatum_id;
    GValue	     *match_value;
    gboolean	      exact_match;
};

typedef struct _Query Query;
struct _Query {
    GList *query_atoms;
};

Query*
bmp_metadata_cache_query_initialize	(BmpMetadataCache     *self);

gboolean
bmp_metadata_cache_query_append_int	(BmpMetadataCache     *self,
					 Query		      *query,
					 BmpMetadatumId	       metadatum_id,
					 gboolean	       exact_match,
					 gint		       datum); 

gboolean
bmp_metadata_cache_query_append_string	(BmpMetadataCache     *self,
					 Query		      *query,
					 BmpMetadatumId	       metadatum_id,
					 gboolean	       exact_match,
					 gchar		      *datum); 

HRelation*
bmp_metadata_cache_query_run		(BmpMetadataCache     *self, 
					 Query		      *query); 

void
bmp_metadata_cache_query_free		(BmpMetadataCache     *self,
					 Query		      *query);

HRelation*
bmp_metadata_cache_query_list_datum	(BmpMetadataCache     *self,
					 gint		      metadatum_id,
					 gint                 metadatum_id_predicate,
					 gchar		      *predicate_value);
 
/* Query convenience API */ 
Query*
bmp_metadata_cache_query_construct	(BmpMetadataCache     *self, gint n_atoms, ...);

/* Tags stuff */
typedef enum {
    BMP_TAGS_EEXISTS,
    BMP_TAGS_ENOEXIST
} BmpTagsErrorCode;

typedef enum {
    BMP_TAG_ARTIST,
    BMP_TAG_ALBUM,
    BMP_TAG_TITLE,

    BMP_N_TAGS
} BmpMetadatumTagId;

//FIXME: This does completely suck as we have to extend it each time we add a new metadatum to tag
typedef struct _TagDataTuple TagDataTuple;

struct _TagDataTuple {
    gchar* tag[BMP_N_TAGS];
};

#ifdef HAVE_GUI
#ifdef USE_AMAZON
#include <gtk/gtk.h>
GdkPixbuf*
bmp_metadata_cache_get_cover_from_tuple (BmpMetadataCache      *self,
					 HTuple		       *tuple);
#endif
#endif

gint
bmp_metadata_datum_to_tag_id	(gint n);

gint
bmp_metadata_tag_id_to_datum	(gint n);
 
const gchar*
bmp_metadata_get_tag_define	(gint n);
 
GList*
bmp_metadata_cache_tags_list	(BmpMetadataCache *self);

gboolean
bmp_metadata_cache_tag_new    (BmpMetadataCache *self, 
			       const gchar	*tagname, 
			       GError	       **error);

gboolean
bmp_metadata_cache_tag_delete (BmpMetadataCache *self, 
			       const gchar      *tagname, 
			       GError	       **error);
 
gboolean
bmp_metadata_cache_tag_insert (BmpMetadataCache	  *self,
			       const gchar	  *tagname,
			       BmpMetadatumTagId   metadatum_tag_id,
			       TagDataTuple	  *tuple, 
			       GError		 **error);

gboolean
bmp_metadata_cache_tag_remove (BmpMetadataCache	  *self,
			       const gchar	  *tagname,
			       BmpMetadatumTagId   metadatum_tag_id,
			       TagDataTuple	  *tuple, 
			       GError	         **error);
 
gboolean
bmp_metadata_cache_tag_check  (BmpMetadataCache	    *self,
			       const gchar	    *tagname,
			       BmpMetadatumTagId      metadatum_tag_id,
			       const gchar	    *value,
			       gboolean		    *exists,
			       GError		   **error);

/* Higher-level API */
gboolean
bmp_metadata_cache_tuple_matches_tag (BmpMetadataCache	    *self,
				      HTuple		    *tuple,
				      BmpMetadatumTagId	     metadatum_tag_id,
				      const gchar	    *tagname);

GList*
bmp_metadata_cache_tuple_get_tags     (BmpMetadataCache	    *self,
				       HTuple		    *tuple,
				       BmpMetadatumTagId     metadatum_tag_id);


gboolean
bmp_metadata_cache_tag_tuple (BmpMetadataCache	    *self,
			      HTuple		    *tuple,
			      BmpMetadatumTagId	     metadatum_tag_id,
			      const gchar	    *tagname,
			      GError		   **error);

gboolean
bmp_metadata_cache_untag_tuple (BmpMetadataCache    *self,
			        HTuple		    *tuple,
			        BmpMetadatumTagId    metadatum_tag_id,
			        const gchar	    *tagname,
			        GError		   **error);

/* Tags END */

#ifdef HAVE_HAL
gboolean
bmp_metadata_cache_check_tuple_volume	(BmpMetadataCache     *self,
					 HTuple		      *tuple,
					 gboolean	      *is_present);
#endif

#endif /* METADATA_H */
