/* gmediaserver.h - Common definitions
 *
 * Copyright (C) 2005, 2007  Oskar Liljeblad
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License along
 * with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef GMEDIASERVER_H
#define GMEDIASERVER_H

#include <errno.h>		/* C89; errno */
#include <stdarg.h>		/* C89; (variadict) */
#include <stdio.h>		/* C89; FILE */
#include <string.h>		/* C89 */
#include <stdbool.h>		/* Gnulib, C99; bool */
#include <sys/types.h>		/* POSIX: time_t */
#include <upnp/upnp.h>		/* libupnp */
#include "hmap.h"
#include "strbuf.h"

#define SPLIT_DURATION(a) (a)/3600, ((a)%3600)/60, (a)%60, 0

typedef struct _ServiceAction ServiceAction;
typedef struct _ServiceVariable ServiceVariable;
typedef struct _Service Service;
typedef struct _ActionEvent ActionEvent;
typedef struct _EntryChildren EntryChildren;
typedef struct _EntryTag EntryTag;
typedef struct _EntryDetail EntryDetail;
typedef struct _EntryFile EntryFile;
typedef struct _EntryURL EntryURL;
typedef struct _Entry Entry;
typedef struct _SortCriteria SortCriteria;
typedef struct _SortCriteriaEntry SortCriteriaEntry;
typedef struct _SearchExpr SearchExpr;
typedef struct _SearchCriteria SearchCriteria;
typedef struct _SearchCriteriaParseData SearchCriteriaParseData;
typedef struct _HTTPResult HTTPResult;
typedef struct _URL URL;

typedef enum {
    DETAIL_CHILDREN,	/* mutually exclusive with DETAIL_FILE, URL */
    DETAIL_TAG,		/* currently only available for DETAIL_FILE */
    DETAIL_FILE,	/* mutually exclusive with DETAIL_CHILDREN, URL */
    DETAIL_URL,		/* mutually exclusive with DETAIL_CHILDREN, FILE */
} EntryDetailType;

typedef enum {
    ITEM_IMAGE,		/* refers to imageItem */
    ITEM_AUDIO,		/* refers to audioItem */
    ITEM_VIDEO,		/* refers to videoItem */
    ITEM_PLAYLIST,	/* refers to playlistItem */
    ITEM_TEXT,		/* refers to textItem */
    ITEM_UNKNOWN,	/* Not mentioned in standard */
} ItemClass;

struct _ServiceAction {
    char *name;
    bool (*function)(ActionEvent *);
};

struct _ServiceVariable {
    char *name;
    char *value;
};

struct _Service {
    char *id;
    char *type;
    ServiceAction *actions;
    ServiceVariable *variables;
};

struct _ActionEvent {
    struct Upnp_Action_Request *request;
    bool status;
    Service *service;
};

struct _EntryChildren {
    uint32_t count;
    int32_t *list;
};

struct _EntryTag {
    char *title; /* if set and non-empty, title replaces entry->name in display */
    char *artist;
    char *album;
    char *genre;
    int32_t track_no; /* track number, -1 if not available */
    int32_t duration; /* duration in seconds, -1 if not available */
};

struct _EntryURL {
    char *url;
};

struct _EntryFile {
    ItemClass item_class;
    const char *mime_type;
    char *ext_info;
    mode_t mode;
    size_t size;
    char *filename;
    time_t mtime;
};

struct _EntryDetail {
    EntryDetail *next;
    /*EntryDetail *previous;*/
    EntryDetailType type;
    union {
	EntryTag tag;
	EntryChildren children;
	EntryFile file;
	EntryURL url;
    } data;
};

struct _Entry {
    int32_t id;
    int32_t parent;
    char *name; /* to display in control point */
    EntryDetail *details;
};

struct _SearchExpr {
    int type; /* token value from search-parser.h */
    union {
	struct {
	    SearchExpr *expr1;
	    SearchExpr *expr2;
	} logical;
	struct {
	    char *property;
	    char *value;
	} binary;
	struct {
	    char *property;
	    bool must_exist;
	} exists;
    } u;
};

struct _SearchCriteria {
    SearchExpr *expr; /* match any ("*") if NULL */
};

struct _SortCriteriaEntry {
    SortCriteriaEntry *next;
    char *property;
    bool ascending;
};

struct _SortCriteria {
    SortCriteriaEntry *first; /* NULL means arbitrary sorting */
};

/* Data required during lexing and parsing. This data could be placed
 * staticly in search-lexer.l or search-parser.y, but that will not work
 * because we are using a reentrant lexer and parser.
 */
struct _SearchCriteriaParseData {
    StrBuf *buf;
    SearchCriteria *criteria;
    const char *error;
};

struct _HTTPResult {
    bool icy_server;
    int result;
    HMap *headers;
    int fd;
    char *buf;
    size_t bufsize;
    size_t bufhead;
    size_t buftail;
};

struct _URL {
    /*char *protocol;*/
    char *hostname;
    uint16_t port;
    char *path;
};

/* logging.c */
#define DEFAULT_TIMESTAMP_FORMAT "%Y-%m-%d %H:%M"
#define MAX_VERBOSITY 4
#define errstr strerror(errno)
extern uint32_t verbosity;
void say(int level, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void warn(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void init_logging(const char *logfilename, const char *timestamp_format);
void finish_logging(bool success);

/* main.c */
char *convert_string_to_device(const char *str);
char *convert_string_to_log(const char *str);
char *conv_filename(const char *str);

/* interface.h */
char *get_ip_by_spec(char *spec);

/* metadata.c */
extern char *file_types;
extern bool tags_enabled;
bool init_metadata(void);
bool scan_entries(char **pathv, int pathc, int indent_size);
void clear_entries(void);
void finish_metadata(void);
void lock_metadata(void);
void unlock_metadata(void);
Entry *get_entry_by_id(uint32_t id);
EntryDetail *get_entry_detail(const Entry *entry, EntryDetailType type);
bool has_entry_detail(const Entry *entry, EntryDetailType type);

/* upnp.c */
/* The following errors are mentioned in the ContentDirectory specifications. */
#define UPNP_CONTENTDIR_E_NO_OBJECT		701
#define UPNP_CONTENTDIR_E_INVALID_CURRENT_TAG	702
#define UPNP_CONTENTDIR_E_INVALID_NEW_TAG	703
#define UPNP_CONTENTDIR_E_REQUIRED_TAG		704
#define UPNP_CONTENTDIR_E_READ_ONLY_TAG		705
#define UPNP_CONTENTDIR_E_PARAMETER_MISMATCH	706
#define UPNP_CONTENTDIR_E_BAD_SEARCH_CRITERIA	708
#define UPNP_CONTENTDIR_E_BAD_SORT_CRITERIA	709
#define UPNP_CONTENTDIR_E_NO_CONTAINER		710
#define UPNP_CONTENTDIR_E_RESTRICTED_OBJECT	711
#define UPNP_CONTENTDIR_E_BAD_METADATA		712
#define UPNP_CONTENTDIR_E_RESTRICTED_PARENT	713
#define UPNP_CONTENTDIR_E_NO_SRC_RESOURCE	714
#define UPNP_CONTENTDIR_E_NO_SRC_ACCESS		715
#define UPNP_CONTENTDIR_E_TRANSFER_BUSY		716
#define UPNP_CONTENTDIR_E_NO_FILE_TRANSFER	717
#define UPNP_CONTENTDIR_E_NO_DST_RESOURCE	718
#define UPNP_CONTENTDIR_E_NO_DST_ACCESS		719
#define UPNP_CONTENTDIR_E_CANNOT_PROCESS	720
extern char *friendly_name;
extern int ssdp_expire_time;
void init_upnp(const char *listenip, uint16_t listenport);
void finish_upnp(void);
void upnp_set_error(ActionEvent *event, int error_code, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
char *upnp_get_string(ActionEvent *event, const char *item);
uint32_t upnp_get_ui4(ActionEvent *event, const char *key);
bool upnp_add_response(ActionEvent *event, char *key, const char *value);
int32_t upnp_get_i4(ActionEvent *event, const char *key);
void notify_change(const char *service_id, ServiceVariable *var);

/* webserver.c */
extern struct UpnpVirtualDirCallbacks virtual_dir_callbacks;

/* webclient.c */
HTTPResult *http_query(const char *method, const char *url, bool keep_open);
void http_result_free(HTTPResult *result);
ssize_t http_skip(HTTPResult *result, size_t count);
ssize_t http_read(HTTPResult *result, void *buf, size_t count);
bool parse_http_date(const char *s, time_t *timeptr);

/* contentdir.c */
#define CONTENTDIR_SERVICE_ID "urn:upnp-org:serviceId:ContentDirectory"
extern ServiceAction contentdir_service_actions[];
extern ServiceVariable contentdir_service_variables[];
void bump_update_id(void);
void free_search_criteria(SearchCriteria *criteria);
void free_search_expr(SearchExpr *expr);
void init_contentdir(void);
void finish_contentdir(void);

/* connectmgr.c */
#define CONNECTMGR_SERVICE_ID "urn:upnp-org:serviceId:ConnectionManager"
extern ServiceAction connectmgr_service_actions[];
extern ServiceVariable connectmgr_service_variables[];

/* url.c */
void sgmlescape(const char *str, char *target, uint32_t *length);
char *xsgmlescape(const char *str);
void urlencode(const char *str, char *target, uint32_t *length);
char *xurlencode(const char *str);
URL *parse_simple_url(const char *url);
void free_url(URL *url);

#endif
