/**
 * @file llappcorehttp.h
 * @brief Singleton initialization/shutdown class for llcorehttp library
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012-2014, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef	_LL_APP_COREHTTP_H_
#define	_LL_APP_COREHTTP_H_


#include "httprequest.h"
#include "httphandler.h"
#include "httpresponse.h"


// This class manages the lifecyle of the core http library.
// Slightly different style than traditional code but reflects
// the use of handler classes and light-weight interface
// object instances of the new libraries.  To be used
// as a singleton and static construction is fine.
class LLAppCoreHttp : public LLCore::HttpHandler
{
public:
	static const long			PIPELINING_DEPTH;

	typedef LLCore::HttpRequest::policy_t policy_t;

	enum EAppPolicy
	{
		/// Catchall policy class.  Not used yet
		/// but will have a generous concurrency
		/// limit.  Deep queueing possible by having
		/// a chatty HTTP user.
		///
		/// Destination:     anywhere
		/// Protocol:        http: or https:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     high 
		/// Request rate:    unknown
		/// Pipelined:       no
		AP_DEFAULT,

		// <FS:Beq> Avoid stall in texture fetch due to asset fetching. [Drake]
		/// Asset fetching policy class.  Used to
		/// download assets via capability.
		/// Deep queueing of requests.
		/// Do not share.  GET requests only.
		///
		/// Destination:     cdn:80
		/// Protocol:        http:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     high
		/// Request rate:    high
		/// Pipelined:       yes
		AP_ASSET,
		// </FS:Beq>

		/// Texture fetching policy class.  Used to
		/// download textures via capability or SSA
		/// baking service.  Deep queueing of requests.
		/// Do not share.  GET requests only.
		///
		/// Destination:     simhost:12046 & {bake-texture,cdn}:80
		/// Protocol:        http:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     high
		/// Request rate:    high
		/// Pipelined:       yes
		AP_TEXTURE,

		/// Legacy mesh fetching policy class.  Used to
		/// download textures via 'GetMesh' capability.
		/// To be deprecated.  Do not share.
		///
		/// Destination:     simhost:12046
		/// Protocol:        http:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     dangerously high
		/// Request rate:    high
		/// Pipelined:       no
		AP_MESH1,

		/// New mesh fetching policy class.  Used to
		/// download textures via 'GetMesh2' capability.
		/// Used when fetch request (typically one LOD)
		/// is 'small', currently defined as 2MB.
		/// Very deeply queued.  Do not share.  GET
		/// requests only.
		///
		/// Destination:     simhost:12046 & cdn:80
		/// Protocol:        http:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     high
		/// Request rate:    high
		/// Pipelined:       yes
		AP_MESH2,

		/// Large mesh fetching policy class.  Used to
		/// download textures via 'GetMesh' or 'GetMesh2'
		/// capability.  Used when fetch request
		/// is not small to avoid head-of-line problem
		/// when large requests block a sequence of small,
		/// fast requests.  Can be shared with similar
		/// traffic that can wait for longish stalls
		/// (default timeout 600S).
		///
		/// Destination:     simhost:12046 & cdn:80
		/// Protocol:        http:
		/// Transfer size:   MB
		/// Long poll:       no
		/// Concurrency:     low
		/// Request rate:    low
		/// Pipelined:       no
		AP_LARGE_MESH,

		/// Asset upload policy class.  Used to store
		/// assets (mesh only at the moment) via
		/// changeable URL.  Responses may take some
		/// time (default timeout 240S).
		///
		/// Destination:     simhost:12043
		/// Protocol:        https:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     low
		/// Request rate:    low
		/// Pipelined:       no
		AP_UPLOADS,

		/// Long-poll-type HTTP requests.  Not
		/// bound by a connection limit.  Requests
		/// will typically hang around for a long
		/// time (~30S).  Only shareable with other
		/// long-poll requests.
		///
		/// Destination:     simhost:12043
		/// Protocol:        https:
		/// Transfer size:   KB
		/// Long poll:       yes
		/// Concurrency:     unlimited but low in practice
		/// Request rate:    low
		/// Pipelined:       no
		AP_LONG_POLL,

		/// Inventory operations (really Capabilities-
		/// related operations).  Mix of high-priority
		/// and low-priority operations.
		///
		/// Destination:     simhost:12043
		/// Protocol:        https:
		/// Transfer size:   KB-MB
		/// Long poll:       no
		/// Concurrency:     high
		/// Request rate:    high
		/// Pipelined:       no
		AP_INVENTORY,
		AP_REPORTING = AP_INVENTORY,	// Piggy-back on inventory

		/// Material resource requests and puts.  
		///
		/// Destination:     simhost:12043
		/// Protocol:        https:
		/// Transfer size:   KB
		/// Long poll:       no
		/// Concurrency:     low
		/// Request rate:    low
		/// Pipelined:       no
		AP_MATERIALS,

		/// Appearance resource requests and puts.  
		///
		/// Destination:     simhost:12043
		/// Protocol:        https:
		/// Transfer size:   KB
		/// Long poll:       no
		/// Concurrency:     mid
		/// Request rate:    low
		/// Pipelined:       yes
		AP_AGENT,

		AP_COUNT						// Must be last
	};
	
public:
	LLAppCoreHttp();
	~LLAppCoreHttp();
	
	// Initialize the LLCore::HTTP library creating service classes
	// and starting the servicing thread.  Caller is expected to do
	// other initializations (SSL mutex, thread hash function) appropriate
	// for the application.
	void init();

	// Request that the servicing thread stop servicing requests,
	// release resource references and stop.  Request is asynchronous
	// and @see cleanup() will perform a limited wait loop for this
	// request to stop the thread.
	void requestStop();
	
	// Terminate LLCore::HTTP library services.  Caller is expected
	// to have made a best-effort to shutdown the servicing thread
	// by issuing a requestThreadStop() and waiting for completion
	// notification that the stop has completed.
	void cleanup();

	// Notification when the stop request is complete.
	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);

	// Retrieve a policy class identifier for desired
	// application function.
	policy_t getPolicy(EAppPolicy policy) const
		{
			return mHttpClasses[policy].mPolicy;
		}

	// Return whether a policy is using pipelined operations.
	bool isPipelined(EAppPolicy policy) const
		{
			return mHttpClasses[policy].mPipelined;
		}

	// Apply initial or new settings from the environment.
	void refreshSettings(bool initial);
	
private:
	static const F64			MAX_THREAD_WAIT_TIME;
	
private:

	// PODish container for per-class settings and state.
	struct HttpClass
	{
	public:
		HttpClass();

	public:
		policy_t					mPolicy;			// Policy class id for the class
		U32							mConnLimit;
		bool						mPipelined;
		boost::signals2::connection mSettingsSignal;	// Signal to global setting that affect this class (if any)
	};
		
	LLCore::HttpRequest *		mRequest;				// Request queue to issue shutdowns
	LLCore::HttpHandle			mStopHandle;
	F64							mStopRequested;
	bool						mStopped;
	HttpClass					mHttpClasses[AP_COUNT];
	bool						mPipelined;				// Global setting
	boost::signals2::connection	mPipelinedSignal;		// Signal for 'HttpPipelining' setting
	boost::signals2::connection	mSSLNoVerifySignal;		// Signal for 'NoVerifySSLCert' setting

	static LLCore::HttpStatus	sslVerify(const std::string &uri, const LLCore::HttpHandler::ptr_t &handler, void *appdata);
};


#endif	// _LL_APP_COREHTTP_H_
