
// WebAdmin.h

// Declares the cWebAdmin class representing the admin interface over http protocol, and related services (API)

#pragma once

#include "Bindings/LuaState.h"
#include "IniFile.h"
#include "HTTP/HTTPServer.h"
#include "HTTP/HTTPMessage.h"





// Disable MSVC warnings:
#if defined(_MSC_VER)
	#pragma warning(push)
	#pragma warning(disable:4355)  // 'this' : used in base member initializer list
#endif





// tolua_begin
struct HTTPFormData
{
	std::string Name;
	std::string Value;
	std::string Type;
} ;
// tolua_end




// tolua_begin
struct HTTPRequest
{
	typedef std::map< std::string, std::string > StringStringMap;
	typedef std::map< std::string, HTTPFormData > FormDataMap;

	/** The entire URL presented to the HTTP server. */
	AString URL;

	/** HTTP method used for the request ("GET", "POST" etc.) */
	AString Method;

	/** The Path part of the request's URL (excluding GET params). */
	AString Path;

	/** Name of the logged-in user. Empty if not logged in. */
	AString Username;

	// tolua_end

	/** Parameters given in the URL, after the questionmark */
	StringStringMap Params;     // >> EXPORTED IN MANUALBINDINGS <<

	/** Parameters posted as a part of a form - either in the URL (GET method) or in the body (POST method) */
	StringStringMap PostParams;  // >> EXPORTED IN MANUALBINDINGS <<

	/** Same as PostParams */
	FormDataMap FormData;       // >> EXPORTED IN MANUALBINDINGS <<
} ;  // tolua_export





// tolua_begin
struct HTTPTemplateRequest
{
	HTTPRequest Request;
} ;
// tolua_end





struct sWebAdminPage
{
	AString Content;
	AString PluginName;
	AString TabTitle;
	AString TabUrlPath;
	AString ContentType;
};





// tolua_begin
class cWebAdmin :
	// tolua_end
	public cHTTPServer::cCallbacks
	// tolua_begin
{
public:
	// tolua_end

	/** Interface for getting the content of a single WebTab. */
	class cWebTabCallback abstract
	{
	public:
		// Force a virtual destructor in descendants
		virtual ~cWebTabCallback() {}

		/** Returns the contents for the specified request.
		Returns true if the call was successful, false on an error.
		a_Request is the full HTTP request object, as received from the client.
		a_UrlPath is the UrlPath of the WebTab registered for this request, as parsed from a_Request.
		Descendants should fill a_Content with the page contents
		and optionally set a_ContentType [defaults to "text/html"] */
		virtual bool Call(
			const HTTPRequest & a_Request,
			const AString & a_UrlPath,
			AString & a_Content,
			AString & a_ContentType
		) = 0;
	};


	/** Container for a single web tab.
	Each web tab has a title, URL path and an associated plugin's name.
	Each web tab is registered with a callback to provide the content. */
	class cWebTab
	{
	public:
		AString m_Title;
		AString m_UrlPath;
		AString m_PluginName;
		std::shared_ptr<cWebTabCallback> m_Callback;

		cWebTab(const AString & a_Title, const AString & a_UrlPath, const AString & a_PluginName, std::shared_ptr<cWebTabCallback> a_Callback):
			m_Title(a_Title),
			m_UrlPath(a_UrlPath),
			m_PluginName(a_PluginName),
			m_Callback(std::move(a_Callback))
		{
		}
	};
	typedef std::shared_ptr<cWebTab> cWebTabPtr;
	typedef std::vector<cWebTabPtr> cWebTabPtrs;


	cWebAdmin(void);
	virtual ~cWebAdmin() override;

	/** Initializes the object. Returns true if successfully initialized and ready to start */
	bool Init(void);

	/** Starts the HTTP server taking care of the webadmin. Returns true if successful */
	bool Start(void);

	/** Stops the HTTP server, if it was started. */
	void Stop(void);

	/** Loads the login template into m_LoginPage.
	Returns true if the loading succeeds, false if not. */
	bool LoadLoginPage(void);

	/** Returns a copy of all the registered web tabs.
	Exported to Lua in ManualBindings.cpp. */
	cWebTabPtrs GetAllWebTabs(void) { return m_WebTabs; }

	/** Removes all WebTabs registered by the specified plugin. */
	void RemoveAllPluginWebTabs(const AString & a_PluginName);

	/** Returns the (inner) page contents for the specified request.
	Calls the appropriate WebTab handler to get the contents.
	Exported to Lua in ManualBindings.cpp. */
	sWebAdminPage GetPage(const HTTPRequest & a_Request);

	// tolua_begin

	/** Reloads m_IniFile, m_LoginPage and m_TemplateScript.
	Note that reloading will not change the "enabled" state of the server, and it will not update listening ports. */
	void Reload(void);

	/** Returns the list of ports on which the webadmin is configured to listen. */
	AString GetPorts(void) const { return StringsConcat(m_Ports, ','); }

	/** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style). */
	static AString GetBaseURL(const AString & a_URL);

	/** Returns the content type from the file extension.
	If the extension isn't in the list, the function returns an empty string. */
	static AString GetContentTypeFromFileExt(const AString & a_FileExtension);

	/** Escapes text passed into it, so it can be embedded into html. */
	static AString GetHTMLEscapedString(const AString & a_Input);
	// tolua_end

	/** Adds a new WebTab handler.
	a_Title is the display title of the tab
	a_UrlPath is the part of the URL that uniquely identifies this tab.
	a_PluginName is the display name of the plugin creating this tab.
	a_Callback is used to provide the actual WebTab contents, when requested.
	Exported in ManualBindings.cpp. */
	void AddWebTab(
		const AString & a_Title,
		const AString & a_UrlPath,
		const AString & a_PluginName,
		std::shared_ptr<cWebTabCallback> a_Callback
	);

	/** Removes the WebTab with the specified URL path.
	Returns true if WebTab was found and removed, false if not found.
	Exported in ManualBindings.cpp */
	bool DelWebTab(const AString & a_UrlPath);

	/** Escapes the string for use in an URL
	Exported to Lua in ManualBindings.cpp. */
	static AString GetURLEncodedString(const AString & a_Input);

	/** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
	static AString GetBaseURL(const AStringVector & a_URLSplit);

protected:

	/** Protects m_WebTabs, m_TemplateScript, m_LoginTemplate and m_IniFile against multithreaded access. */
	cCriticalSection m_CS;

	/** All registered WebTab handlers.
	Protected against multithreaded access by m_CS. */
	cWebTabPtrs m_WebTabs;

	/** The Lua template script to provide templates.
	Protected against multithreaded access by m_CS. */
	cLuaState m_TemplateScript;

	/** The HTML page that provides the login.
	Protected against multithreaded access by m_CS. */
	AString m_LoginPage;

	/** The webadmin.ini file, used for the settings and allowed logins.
	Protected against multithreaded access by m_CS. */
	cIniFile m_IniFile;

	/** Set to true if Init() succeeds and the webadmin isn't to be disabled */
	bool m_IsInitialized;

	/** Set to true if Start() succeeds in starting the server, reset back to false in Stop(). */
	bool m_IsRunning;

	/** The ports on which the webadmin is running. */
	AStringVector m_Ports;

	/** The HTTP server which provides the underlying HTTP parsing, serialization and events */
	cHTTPServer m_HTTPServer;


	/** Loads webadmin.ini into m_IniFile.
	Creates a default file if it doesn't exist.
	Returns true if webadmin is enabled, false if disabled. */
	bool LoadIniFile(void);

	/** Checks inside the webadmin.ini file if there are users configured. */
	bool HasUsers();

	/** Handles requests coming to the "/webadmin" or "/~webadmin" URLs */
	void HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request);

	/** Handles requests for the root page */
	void HandleRootRequest(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request);

	/** Handles requests for a file */
	void HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request);

	// cHTTPServer::cCallbacks overrides:
	virtual void OnRequestBegun   (cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request) override;
	virtual void OnRequestBody    (cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request, const char * a_Data, size_t a_Size) override;
	virtual void OnRequestFinished(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request) override;
} ;  // tolua_export





// Revert MSVC warnings back to orignal state:
#if defined(_MSC_VER)
	#pragma warning(pop)
#endif




