#ifndef _URL_H
#define _URL_H

#include <OS.h>
#include <String.h>
#include "BArray.h"

struct entry_ref;
struct URLData;
class StringBuffer;

namespace Wagner {

enum QueryMethod {
	GET_QUERY,
	POST_QUERY
};

class URL {
public:
	URL();
	URL(const URL&);
	URL(const char *urlString);					// xxx Remove me
	URL(const char *urlString, bool escape);
	URL(const char *scheme, const char *hostname, const char *path, int port,
		const char *fragment, const char *username = "", const char *password = "",
		const char *query = "", QueryMethod method = GET_QUERY, const char *uploadQuery = "");
	URL(const URL& baseURL, const char *relativePath);
	URL(const char *name, const BMessage *message);
	URL(const entry_ref&);
	~URL();
	
	void Reset();
	bool IsValid() const;

	// Note: Equals does *not* consider the fragment, username, password, or query method.
	// The resource cache depends on this so it doesn't store multiple
	// copies of the same resource.
	bool Equals(const char*) const;
	bool Equals(const URL& url) const;
	bool operator==(const URL& url) const;
	bool operator==(const char *urlString) const;
	bool operator!=(const URL& url) const;

	URL& operator=(const URL& url);
	URL& operator=(const char*);
	URL& operator=(const entry_ref&);

	URL& SetTo(const char *scheme, const char *hostname, const char *path, int port,
		const char *fragment, const char *username = "", const char *password = "",
		const char *query = "", QueryMethod method = GET_QUERY, const char *uploadQuery = "");
	URL& SetTo(const char *urlString, bool escape);
	URL& SetTo(const URL& url);
	URL& SetTo(const URL& baseURL, const char *relativePath);
	URL& SetTo(const entry_ref&);

	URL& SetTo(const char *urlString);	// xxx Remove Me
	
	const char* GetScheme() const;
	const char* GetUserName() const;
	const char* GetPassword() const;
	const char* GetHostName() const;
	ushort GetPort() const;
	const char* GetPath() const;
	const char* GetExtension() const;
	const char* GetQuery() const;
	const char* GetUploadQuery() const;
	const char* GetFragment() const;
	QueryMethod GetQueryMethod() const;
	void GetUnescapedFileName(char *out, int size) const;

	void GetUnescapedPath(char *out, int size);
	
	void SetFragment(const char *fragment);
	void SetQuery(const char *query);
	void SetQueryMethod(QueryMethod method, bool compressIfPost=false);
	void AddQueryParameter(const char *name, const char *value);
	status_t GetQueryParameter(const char* name, BString* out_value) const;
	status_t RemoveQueryParameter(const char* name);
	status_t ReplaceQueryParameter(const char* name, const char* value, bool addIfNotPresent=true);

	void SetUploadQuery(const char *uploadQuery);
	void AddUploadQueryParameter(const char *name, const char *value);
	status_t GetUploadQueryParameter(const char* name, BString* out_value) const;
	status_t RemoveUploadQueryParameter(const char* name);
	status_t ReplaceUploadQueryParameter(const char* name, const char* value, bool addIfNotPresent=true);

	void GetString(char *buffer, size_t maxSize) const;
	void AppendTo(StringBuffer&) const;
	status_t GetRef(entry_ref &outRef) const;

	void AddToMessage(const char *name, BMessage *message) const;
	void ExtractFromMessage(const char *name, const BMessage *message);

	uint GenerateHash() const;

	void GetMinimalString(StringBuffer&) const;

	void PrintToStream() const;

private:
	URL& SetToInternal(const URL &base, const char *relativePath);
	void AppendToInternal(StringBuffer&, bool minimal) const;
	int LookupScheme(const char *scheme);
	int LookupScheme(const char *scheme, int len);
	char* NormalizePath();
	void ParsePathURL(const char *url, bool escape);
	void ParseMailToURL(const char *url);
	void ParseJavaScriptURL(const char *url);
	status_t GetQueryParameterInternal(const char *query, const char *name, BString *out_value) const;

	URLData *fData;
};

}

#endif
