#include <u.h>
#include <errno.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <auth.h>
#include <9p.h>
#include <libsec.h>

#define APIKEY        "G9ANE2zvCozKEoLQ5qaR1AUtcE5YpuDj"
#define HOST          "api.smugmug.com"
#define UPLOAD_HOST   "upload.smugmug.com"
#define API_VERSION   "1.2.1"
#define PATH          "/services/api/json/" API_VERSION "/"
#define USER_AGENT    "smugfs (part of Plan 9 from User Space)"

void*	emalloc(int);
void*	erealloc(void*, int);
char*	estrdup(char*);
int	urlencodefmt(Fmt*);
int	timefmt(Fmt*);
int	writen(int, void*, int);


// Generic cache

typedef struct Cache Cache;
typedef struct CEntry CEntry;

struct CEntry
{
	char *name;
	struct {
		CEntry *next;
		CEntry *prev;
	} list;
	struct {
		CEntry *next;
	} hash;
};

Cache *newcache(int sizeofentry, int maxentry, void (*cefree)(CEntry*));
CEntry *cachelookup(Cache*, char*, int);
void cacheflush(Cache*, char*);

// JSON parser

typedef struct Json Json;

enum
{
	Jstring,
	Jnumber,
	Jobject,
	Jarray,
	Jtrue,
	Jfalse,
	Jnull
};

struct Json
{
	int ref;
	int type;
	char *string;
	double number;
	char **name;
	Json **value;
	int len;
};

void	jclose(Json*);
Json*	jincref(Json*);
vlong	jint(Json*);
Json*	jlookup(Json*, char*);
double	jnumber(Json*);
int	jsonfmt(Fmt*);
int	jstrcmp(Json*, char*);
char*	jstring(Json*);
Json*	jwalk(Json*, char*);
Json*	parsejson(char*);


// Wrapper to hide whether we're using OpenSSL for HTTPS.

typedef struct Protocol Protocol;
typedef struct Pfd Pfd;
struct Protocol
{
	Pfd *(*connect)(char *host);
	int (*read)(Pfd*, void*, int);
	int (*write)(Pfd*, void*, int);
	void (*close)(Pfd*);
};

Protocol http;
Protocol https;


// HTTP library

typedef struct HTTPHeader HTTPHeader;
struct HTTPHeader
{
	int code;
	char proto[100];
	char codedesc[100];
	vlong contentlength;
	char contenttype[100];
};

char *httpreq(Protocol *proto, char *host, char *request, HTTPHeader *hdr, int rfd, vlong rlength);
int httptofile(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int wfd);


// URL downloader - caches in files on disk

int download(char *url, HTTPHeader *hdr);
void downloadflush(char*);

// JSON RPC

enum
{
	MaxResponse = 1<<29,
};

Json*	jsonrpc(Protocol *proto, char *host, char *path, char *method, char *name1, va_list arg, int usecache);
Json*	jsonupload(Protocol *proto, char *host, char *req, int rfd, vlong rlength);
void	jcacheflush(char*);

extern int chattyhttp;


// SmugMug RPC

#ifdef __GNUC__
#define check_nil __attribute__((sentinel))
#else
#define check_nil
#endif

Json* smug(char *method, char *name1, ...) check_nil;  // cached, http
Json* ncsmug(char *method, char *name1, ...) check_nil;  // not cached, https


// Session information

extern Json *userinfo;
extern char *sessid;


// File system

extern Srv xsrv;
void xinit(void);
extern int nickindex(char*);

// Logging

typedef struct Logbuf Logbuf;
struct Logbuf
{
	Req *wait;
	Req **waitlast;
	int rp;
	int wp;
	char *msg[128];
};

extern void	lbkick(Logbuf*);
extern void	lbappend(Logbuf*, char*, ...);
extern void	lbvappend(Logbuf*, char*, va_list);
/* #pragma varargck argpos lbappend 2 */
extern void	lbread(Logbuf*, Req*);
extern void	lbflush(Logbuf*, Req*);
/* #pragma varargck argpos flog 1 */

extern void	rpclog(char*, ...);
extern void	rpclogflush(Req*);
extern void	rpclogread(Req*);
extern void	rpclogwrite(Req*);

enum
{
	STACKSIZE = 32768
};

extern int printerrors;