/**
{file:
	{name: LmiAuthenticator.h}
	{description: Interface for LmiAuthenticator. }
	{copyright:
		(c) 2019 Vidyo, Inc.,
		433 Hackensack Avenue,
		Hackensack, NJ  07601.

		All rights reserved.

		The information contained herein is proprietary to Vidyo, Inc.
		and shall not be reproduced, copied (in whole or in part), adapted,
		modified, disseminated, transmitted, transcribed, stored in a retrieval
		system, or translated into any language in any form by any means
		without the express written consent of Vidyo, Inc.
		                  ***** CONFIDENTIAL *****
	}
}
*/
#ifndef LMI_AUTHENTICATOR_H_
#define LMI_AUTHENTICATOR_H_

#include <Lmi/Os/LmiTime.h>
#include <Lmi/Os/LmiMutex.h>
#include <Lmi/Utils/LmiUnordered.h>
#include <Lmi/Utils/LmiString.h>
#include <Lmi/Utils/LmiTypes.h>

typedef struct {
	LmiTime time;
	LmiUint attemptsRemaining;
} LmiAuthenticationWindow;

LMI_BEGIN_EXTERN_C

LmiAuthenticationWindow* LmiAuthenticationWindowConstruct(LmiAuthenticationWindow* x, LmiTime timeWindow, LmiUint attemptsMax);
LmiAuthenticationWindow* LmiAuthenticationWindowConstructCopy(LmiAuthenticationWindow* x, const LmiAuthenticationWindow* y);
void LmiAuthenticationWindowDestruct(LmiAuthenticationWindow* x);
LmiAuthenticationWindow* LmiAuthenticationWindowAssign(LmiAuthenticationWindow* x, const LmiAuthenticationWindow* y);
LmiBool LmiAuthenticationWindowIsExpired(const LmiAuthenticationWindow* x);
LmiBool LmiAuthenticationWindowAttemptAuthentication(const LmiAuthenticationWindow* x);
LmiUint LmiAuthenticationWindowsGetAttemptsRemaining(const LmiAuthenticationWindow* x);
LmiTime LmiAuthenticationWindowsGetTimeRemaining(const LmiAuthenticationWindow* x);

Declare_LmiUnorderedMap(LmiString, LmiAuthenticationWindow);

struct LmiAuthenticator_;

/**
{callback visibility="private":
	{name: LmiAuthenticatorAuthenticateCallback}
	{parent: LmiAuthenticator}
	{description: A callback used by LmiAuthenticator to request authentication of a user/password.}
	{prototype: typedef LmiBool (*LmiAuthenticatorAuthenticateCallback)(const LmiAuthenticator* x, const LmiString* user, const LmiString* password, void* userData)}
	{parameter:
		{name: x}
		{description: The authenticator object which called this callback.}
	}
	{parameter:
		{name: user}
		{description: A unique string identifying the user to authenticate.}
	}
 	{parameter:
		{name: password}
		{description: A string containing the password to validate against the user\'s credentials.}
	}
 	{parameter:
		{name: userData}
		{description: A user-defined data pointer passed to LmiAuthenticatorConstruct.}
	}
 	{return: The application returns LMI_TRUE if the user/password is authentic or LMI_FALSE otherwise.}
}
*/
typedef LmiBool (*LmiAuthenticatorAuthenticateCallback)(const struct LmiAuthenticator_* x, const LmiString* user, const LmiString* password, void* userData);

/**
{type visibility="private":
	{name: LmiAuthenticator}
	{parent: Os}
	{include: Lmi/Os/LmiAuthenticator.h}
	{library: LmiOs}
	{description: A class for tracking the authentication of users/passwords. The authenticator tracks failed authentication
 	  attempts and limits the number of attempts allowed in a given time window.}
}
*/
typedef struct LmiAuthenticator_ {
	LmiMutex mutex;
	LmiTime timeWindow;
	LmiUint attemptsMax;
	LmiAuthenticatorAuthenticateCallback authenticateCallback;
	LmiTime lastSweep;	/* Last time we swept through the authentication window table to remove expired windows */
	LmiUnorderedMap(LmiString, LmiAuthenticationWindow) table;
} LmiAuthenticator;

/**
{function visibility="private":
	{name: LmiAuthenticatorConstruct}
	{parent: LmiAuthenticator}
	{description: Construct an authenticator.}
 	{prototype: LmiAuthenticator* LmiAuthenticatorConstruct(LmiAuthenticator* x, LmiTime timeWindow, LmiUint attemptsMax,
 LmiAuthenticatorAuthenticateCallback authenticateCallback, LmiAllocator* a)}
	{parameter:
		{name: x}
		{description: Tthe authenticator object to construct.}
	}
	{parameter:
		{name: timeWindow}
 		{description: The interval of time in which the authenticator will track authentication attempts after an initial failed attempt.  During this time interval the authenticator will only allow {code:attemptsMax - 1} authentication attempts.}
	}
 	{parameter:
		{name: attemptsMax}
 		{description: The maximum number of attempts in the {code: timeWindow} that the authenticator will allow. If
 		  {code:attemptsMax} is less then 1, it will be forced to 1.}
	}
  	{parameter:
		{name: authenticateCallback}
 		{description: A callback called by the authenticator to perform the actual authentication.}
	}

  	{parameter:
		{name: a}
 		{description: An allocator.}
 	}
	{return: Returns a pointer to the authenticator object, or NULL on failure.}
	{note: The newly-constructed authenticator uses the same allocator as the source string did.}
}
*/
LmiAuthenticator* LmiAuthenticatorConstruct(LmiAuthenticator* x, LmiTime timeWindow, LmiUint attemptsMax,
  LmiAuthenticatorAuthenticateCallback authenticateCallback, LmiAllocator* a);

/**
{function visibility="private":
	{name: LmiAuthenticatorConstructCopy}
	{parent: LmiAuthenticator}
	{description: Construct a copy of an authenticator.}
	{prototype: LmiAuthenticator* LmiAuthenticatorConstructCopy(LmiAuthenticator* x, const LmiAuthenticator* y)}
	{parameter:
		{name: x}
		{description: The authenticator object to construct.}
	}
	{parameter:
		{name: y}
		{description: The authenticator object to copy.}
	}
	{return: Returns a pointer to the authenticator object, or NULL on failure.}
	{note: The newly-constructed authenticator uses the same allocator as the source string did.}
}
*/
LmiAuthenticator* LmiAuthenticatorConstructCopy(LmiAuthenticator* x, const LmiAuthenticator* y);

/**
{function visibility="private":
	{name: LmiAuthenticatorDestruct}
	{parent: LmiAuthenticator}
	{description: Destruct an authenticator, freeing all associated storage.}
	{prototype: void LmiAuthenticatorDestruct(LmiAuthenticator* x)}
	{parameter:
		{name: x}
		{description: The authenticator object to destruct.}
 	}
}
*/
void LmiAuthenticatorDestruct(LmiAuthenticator* x);

/**
{function visibility="private":
	{name: LmiAuthenticatorAssign}
	{parent: LmiAuthenticator}
	{description: Assign the value of one string to another.  The previous data stored in the destination is overwritten.}
	{prototype: LmiAuthenticator* LmiAuthenticatorAssign(LmiAuthenticator* x, const LmiAuthenticator* y)}
	{parameter:
		{name: x}
		{description: The authenticator object to assign to.}
	}
	{parameter:
		{name: y}
		{description: The authenticator object to copy.}
	}
	{return: Returns a pointer to the authenticator object, or NULL on failure.}
}
*/
LmiAuthenticator* LmiAuthenticatorAssign(LmiAuthenticator* x, const LmiAuthenticator* y);

/**
{function visibility="private":
	{name: LmiAuthenticatorAuthenticate}
	{parent: LmiAuthenticator}
	{description: Authenticates a user/password.}
	{prototype: LmiBool LmiAuthenticatorAuthenticate(const LmiAuthenticator* x, const LmiString* user, const LmiString* password, void* userData)}
	{parameter:
		{name: x}
		{description: The authenticator object.}
	}
	{parameter:
		{name: user}
		{description: A string containing the users unique identifier.}
	}
 	{parameter:
		{name: password}
		{description: A string containing the password to authenticate.}
	}
   	{parameter:
		{name: userData}
 		{description: A user-defined data pointer.}
	}
	{return: Returns LMI_TRUE if the user/password were authenticated, or LMI_FALSE otherwise.}
}
*/
LmiBool LmiAuthenticatorAuthenticate(const LmiAuthenticator* x, const LmiString* user, const LmiString* password, void* userData);

/**
{function visibility="private":
	{name: LmiAuthenticatorGetAttemptsRemaining}
	{parent: LmiAuthenticator}
	{description: Get the number of attempts remaining in the current authentication window of a user.}
	{prototype: LmiUint LmiAuthenticatorGetAttemptsRemaining(const LmiAuthenticator* x, const LmiString* user)}
	{parameter:
		{name: x}
		{description: The authenticator object.}
	}
	{parameter:
		{name: user}
		{description: A string containing the users unique identifier.}
	}
	{return: Returns the number of attempts remaining in the current authentication window.}
}
*/
LmiUint LmiAuthenticatorGetAttemptsRemaining(const LmiAuthenticator* x, const LmiString* user);

/**
{function visibility="private":
	{name: LmiAuthenticatorGetTimeRemaining}
	{parent: LmiAuthenticator}
	{description: Get the remaining time in the current authentication window of a user.}
	{prototype: LmiTime LmiAuthenticatorGetTimeRemaining(const LmiAuthenticator* x, const LmiString* user)}
	{parameter:
		{name: x}
		{description: The authenticator object.}
	}
	{parameter:
		{name: user}
		{description: A string containing the users unique identifier.}
	}
	{return: Returns the remaining time in the current authentication window.}
}
*/
LmiTime LmiAuthenticatorGetTimeRemaining(const LmiAuthenticator* x, const LmiString* user);

/**
{function visibility="private":
	{name: LmiAuthenticatorResetUser}
	{parent: LmiAuthenticator}
	{description: Reset the authentication window of a user.}
	{prototype: LmiBool LmiAuthenticatorResetUser(LmiAuthenticator* x, const LmiString* user)}
	{parameter:
		{name: x}
		{description: The authenticator object.}
	}
	{parameter:
		{name: user}
		{description: A string containing the users unique identifier.}
	}
	{return: Returns LMI_TRUE on success or LMI_FALSE otherwise.}
}
*/
LmiBool LmiAuthenticatorResetUser(LmiAuthenticator* x, const LmiString* user);

/**
 {function visibility="private":
 {name: LmiAuthenticatorReset}
 {parent: LmiAuthenticator}
 {description: Reset all authentication windows.}
 {prototype: void LmiAuthenticatorReset(LmiAuthenticator* x)}
 {parameter:
 {name: x}
 {description: The authenticator object.}
 }
 }
 */
void LmiAuthenticatorReset(LmiAuthenticator* x);

LMI_END_EXTERN_C

#endif	/* LmiAuthenticator.h */

