/* Web Polygraph       http://www.web-polygraph.org/
 * (C) 2003-2006 The Measurement Factory
 * Licensed under the Apache License, Version 2.0 */

#ifndef POLYGRAPH__CLIENT_CLIENT_H
#define POLYGRAPH__CLIENT_CLIENT_H

#include "xstd/AlarmClock.h"
#include "xstd/Ring.h"
#include "runtime/XactFarm.h"
#include "runtime/Agent.h"
#include "runtime/BcastRcver.h"
#include "client/MembershipMap.h"
#include "client/IcpCltXact.h"
#include "client/PrivWorld.h"

class BitMask;
class Connection;
class CltConnMgr;
class DnsMgr;
class SessionMgr;
class CltCfg;
class CltSharedCfgs;
class PortMgr;
class ServerRep;
class ObjId;
class UserCred;
class PrivCache;
class DistrPoint;
class RobotSym;
class SslWrap;
class PrivWorldIterator;

class Client: public Agent, public AlarmUser, public BcastRcver {
	friend class PrivWorldIterator;

	public:
		enum CltReqTypes { rqtBasic = 1, rqtIms200, rqtIms304, rqtReload };
		enum CltReqMethods { rqmGet = 1, rqmHead, rqmPost, rqmPut };

	public:
		static void ReportWss(int commentLvl);
		static void Farm(XactFarm<CltXact> *aFarm);
		static void LogState(OLog &log);

	public:
		Client();
		virtual ~Client();

		virtual void configure(const RobotSym *cfg, const NetAddr &aHost);
		void icpClient(IcpClient *anIcpClient);

		virtual void start();
		virtual void stop();

		// called by the Cache on a miss
		CltXact *fetch(const ObjId &oid, DistrPoint *dp);

		CltCfg *cfg() { return theCfg; }
		const Memberships &memberships() const { return theMemberships; }

		bool hasCredentials() const { return theCredentials; }
		bool credsForOrigin(const ObjId &oid, UserCred &cred) const;
		bool credsForProxy(const ObjId &, UserCred &cred) const;
		bool genCredentials(UserCred &cred) const;
		bool doCookies(int &limit) const;

		void noteOriginAuthReq(CltXact *cause);
		void noteProxyAuthReq(CltXact *cause);
		virtual void noteEmbedded(CltXact *x, const ObjId &embedOid);
		virtual void noteRedirect(CltXact *x, const ObjId &destOid);
		virtual void notePeerAsked(IcpCltXact *q);
		virtual void noteAddrLookup(const NetAddr &addr, CltXact *x);
		void noteXactDone(CltXact *x);

		void selectTarget(ObjId &oid); // embedded objs and redirects need it

		const String &credentials() const { return theCredentials; }
		IcpClient *icpClient() { return theIcpClient; }
		PrivCache *privCache() { return thePrivCache; }
		const NetAddr &proxy() const { return theProxyAddr; }

		virtual void becomeBusy();
		virtual void continueSession();
		virtual void becomeIdle();

		virtual void loadWorkingSet(IBStream &is);
		virtual void storeWorkingSet(OBStream &os);
		virtual void missWorkingSet();

		virtual int logCat() const;

		virtual void describe(ostream &os) const;

	protected:
		static void FreezeSrvWss();

		PortMgr *getPortMgr(bool bind2iface);

		bool shouldRetry(const CltXact *x) const;

		bool tryLaunch();
		bool tryLaunch(CltXact *x);
		bool suspendXact(CltXact *x);
		void resumeXact();
		CltXact *dequeSuspXact();
		virtual void loneXactFollowup();

		void putXact(CltXact *x);

		CltXact *genXact();
		CltXact *genXact(const ObjId &oid, CltXact *cause);
		void genOid(ObjId &oid);
		void selectViserv(ObjId &oid);
		void selectAnyTarget(ObjId &oid, int niamIdx);
		void selectTypedTarget(ObjId &oid, int niamIdx);
		void selectObj(ObjId &oid, int world);
		void selectForeignObj(ObjId &oid);
		void selectContType(ObjId &oid);
		void selectReqType(ObjId &oid);
		void selectReqMethod(ObjId &oid);

		bool setNextHopAddr(CltXact *x) const;
		void askPeer(const NetAddr &addr, CltXact *x);
		bool lookupAddr(CltXact *x);

		virtual void scheduleLaunch(Time lastLaunch) = 0;
		virtual bool launchCanceled(CltXact *x) = 0; // with body
		bool launchFailed(CltXact *x);

		virtual void noteInfoEvent(BcastChannel *ch, InfoEvent ev);
		virtual void noteLogEvent(BcastChannel *ch, OLog &log);

		void configurePrivWorlds();

	private:
		bool launch(CltXact *x);

	protected:
		static XactFarm<CltXact> *TheXacts;
		static ObjFarm<IcpCltXact> TheIcpXacts;

		static CltSharedCfgs *TheSharedCfgs;
		static Array<PortMgr*> ThePortMgrs;  // port managers for all aliases

		Array<PrivWorld> thePrivWorlds; // per-origin private worlds
		PrivCache *thePrivCache;        // private cache for this agent
		BitMask *theAuthOrigins;        // origins that need our credentials

		Array<CltXact*> theLaunchDebts; // postponed requests

		CltCfg *theCfg;         // client configuration (maybe shared)
		CltConnMgr *theConnMgr; // one for all servers
		DnsMgr *theDnsMgr;      // DNS client, cache, etc.
		SessionMgr *theSessionMgr; // manages busy/idle periods

		NetAddr theProxyAddr;
		IcpClient *theIcpClient;

		// XXX: group all per-session objects into one struct and reset
		String theCredentials; // per-session username and password
		Memberships theMemberships; // per-session user membership

		int theCcXactLvl;      // outstanding concurrent xactions level
		int theExtraLaunchLvl; // uncompensated out-of-order launches

		int theCookiesKeepLimit; // maximum number of cookies/server to keep

		bool authProxy;        // proxy needs our credentials
		bool isIdle;
};

#endif


syntax highlighted by Code2HTML, v. 0.9.1