#pragma once

#include "cryptoki.h"
#include "TokenInfo.h"
#include "ObjList.h"
#include "Communicator.h"
#include "P15CDF.h"
#include "P15PrKDF.h"
#include "P15PuKDF.h"
#include "P15DODF.h"
#include "P15EFUS.h"

// Flags para indicar si el tipo de usuario que se ha
// autenticado contra la tarjeta
#define TARJETA_NOT_USER_LOGGED		0x0000
#define TARJETA_SO_LOGGED			0x0001
#define TARJETA_USER_LOGGED			0x0002

class CMech;

class CSession
{
private:
	// Lista de handles de la sesión
	map<CK_SESSION_HANDLE, CK_FLAGS> m_maphSession; 

	// Puntero al Slot al que está asociada la sesión
	CSlot 	&		m_Slot;

	// Lista con los objetos PKCS#11 que se hayan leído de la tarjeta
	CObjList			m_ObjectList;

	//
	// Miembros para conocer la configuración específica de ASN1 que tiene esa tarjeta
	//
	int m_sessionASN1Type;			// Indicará si el fichero P15 está codificado en ASN1 ISO o CERES	
	int m_sessionASN1PathEncType;	// Indicará si el Path está codificado en binario o en ASCII

	//
	// Resultado de la última búsqueda
	//
	vector<CPKCS11Object *>		m_FindResult;	// Resultados pendientes de entregar
	bool						m_bFindOnGoing;	// Existe una búsqueda en curso

	//
	// Miembros para controlar el proceso de firma
	//
	bool					m_bSignOnGoing;			// Existe una firma en curso
	byteBuffer				m_Signature;			// Firma pendiente de entregar
	byteBuffer				m_SignatureUpdate;		// Datos pendientes de firmar (SignUpdate/SignFinal)
	CMech *					m_pSigningMechanism;	// Mecanismo para el proceso de firma

	//
	// Miembros para controlar el proceso de verificación
	//
	bool					m_bVerifyOnGoing;		// Existe una verificación en curso
	CMech *					m_pVerifyingMechanism;	// Mecanismo para el proceso de verificación

	//
	// Miembros para controlar el proceso de descifrado
	//
	bool					m_bDecryptOnGoing;		// Existe un descifrado en curso
	byteBuffer				m_DecryptedData;		// Datos pendiente de entregar
	CMech *					m_pDecryptingMechanism;	// Mecanismo para el proceso de descifrado

	//
	// Métodos internos
	//

	//
	// Comprueba si está logueado
	//
	bool IsLogged();

	//
	// Lee el atributo Value de la tarjeta
	//
	void ReadValue( CPKCS11Object * pObj );

	//
	// Comprime los datos de un atributo Value
	//
	void CompressValue( byteBuffer &data );

	//
	// Lee los componentes públicos de claves RSA
	//
	void ReadRSAPublicComponents( CPKCS11KeyObject * pObj );

	//
	// Comprobaciones de plantillas válidas y consistentes
	//
	CK_BBOOL TemplateGetBoolean( CK_ATTRIBUTE_TYPE attributeType,
								 CK_ATTRIBUTE_PTR pTemplate, 
							     CK_ULONG ulCount);

	CK_OBJECT_CLASS TemplateGetClass( CK_ATTRIBUTE_PTR pTemplate, 
									  CK_ULONG ulCount);
	CK_RV Verificar_Atributos( CK_ATTRIBUTE_PTR pTemplate, 
							   CK_ULONG ulCount);
	CK_RV Cargar_AtributosEspeciales( CPKCS11Object* pObject,
									  CK_ATTRIBUTE_PTR pTemplate, 
								      CK_ULONG ulCount);

	// Método para obtener un fichero elemental en el que almacenar los datos de los objetos
	void FindOrCreate( CPKCS11Object * pObject,
   					   CK_BBOOL		   isPrivate );

	// Método para crear un objeto de tipo clave, pública o privada
	void CreatePublicRSAKey ( CPKCS11Object	* pObject );
	void CreatePrivateRSAKey( CPKCS11Object	* pObject );

	//
	// Método auxiliar para forzar la lectura de los atributos CKA_VALUE, 
	// CKA_MODULUS y CKA_PUBLIC_EXPONENT cuando son necesarios para una búsqueda
	//
	CK_RV ReadAttributesForSearch( CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount );

	byte GetFreeKeyRef(void);

	// Método para actualizar el mapa de KeyReferences utilizados a partir de m_PrKDF y m_PuKDF
	void UpdateKeyRefsMap(void);

	// Lista de keyReferences utilizados
	map<byte, byte> m_mapKeyRefs;

public:
	CSession(CK_SLOT_ID slotID);
	~CSession(void);

	// Objeto para controlar las comunicaciones contra la tarjeta
	CCommunicator	*m_pComm;
	
	// Identificador del slot
	CK_SLOT_ID		m_slotID;
	
	// Flags de la sesión
	CK_FLAGS		m_sessionFlags;

	// Estado de la sesión
	CK_STATE		m_state;

	// Código de error
	CK_ULONG		m_ulDeviceError;

	// Punteros a los ficheros dedicados
	CP15CDF			m_CDF;
	CP15PrKDF		m_PrKDF;
	CP15PuKDF		m_PuKDF;
	CP15DODF		m_DODF;
	CP15EFUS		m_EFUS;

	ulong	GetNumberOfHandles( void );

	////////////////////////////////////////////////////////////////////////////////////////////
	// Métodos PKCS#11
	CK_RV OpenSession(   CK_FLAGS              flags, 
						 CK_VOID_PTR		   pApplication,
						 CK_NOTIFY             Notify,
						 CK_SESSION_HANDLE_PTR phSession);

	CK_RV CloseSession(	CK_SESSION_HANDLE	  hSession);

	CK_RV GetSessionInfo( CK_SESSION_INFO_PTR pInfo );

	CK_RV ResetSessionState( );
	
	//
	// Métodos de autenticación
	//
	CK_RV Login( CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen );
	CK_RV Logout( void );

	//
	// Métodos de gestión del PIN
	//
	CK_RV SetPIN  ( CK_UTF8CHAR_PTR   pOldPin, CK_ULONG ulOldLen,
					CK_UTF8CHAR_PTR   pNewPin, CK_ULONG ulNewLen);
	CK_RV UnblockPIN( CK_UTF8CHAR_PTR pUnblockCode, CK_ULONG ulUnblockCodeLen,
					  CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen );
	//
	// Métodos de búsqueda
	//
	CK_RV FindObjectsInit( CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount );
	CK_RV FindObjects( CK_OBJECT_HANDLE_PTR phObject, 
						CK_ULONG			ulMaxObjectCount, 
						CK_ULONG_PTR		pulObjectCount );
	CK_RV FindObjectsFinal( void );

	//
	// Gestión de Atributos
	//
	CK_RV GetAttributeValue( CK_OBJECT_HANDLE	hObject,
							 CK_ATTRIBUTE_PTR	pTemplate, 
							 CK_ULONG			ulCount );

	CK_RV SetAttributeValue( CK_SESSION_HANDLE hSession,  
							 CK_OBJECT_HANDLE  hObject,   
							 CK_ATTRIBUTE_PTR  pTemplate,  
							 CK_ULONG          ulCount);

	//
	// Firma
	//
	CK_RV SignInit(  CK_MECHANISM_PTR  pMechanism,
					 CK_OBJECT_HANDLE  hKey );

	CK_RV Sign(   CK_BYTE_PTR       pData,
				  CK_ULONG          ulDataLen,
				  CK_BYTE_PTR       pSignature,
				  CK_ULONG_PTR      pulSignatureLen );

	CK_RV SignUpdate( CK_BYTE_PTR       pPart,
					  CK_ULONG          ulPartLen);

	CK_RV SignFinal( CK_BYTE_PTR    pSignature,
					 CK_ULONG_PTR   pulSignatureLen );


	//
	// Verificación
	//
	CK_RV VerifyInit( CK_MECHANISM_PTR  pMechanism,
					  CK_OBJECT_HANDLE  hKey );

	CK_RV Verify( CK_BYTE_PTR       pData,
				  CK_ULONG          ulDataLen,
				  CK_BYTE_PTR       pSignature,
				  CK_ULONG			ulSignatureLen );

	CK_RV VerifyUpdate( CK_BYTE_PTR       pPart,
						CK_ULONG          ulPartLen);

	CK_RV VerifyFinal( CK_BYTE_PTR   pSignature,
					   CK_ULONG		 ulSignatureLen );

	//
	// Descifrado
	//
	CK_RV DecryptInit( CK_MECHANISM_PTR  pMechanism,
					   CK_OBJECT_HANDLE  hKey );

	CK_RV Decrypt (    CK_BYTE_PTR       pEncryptedData,     
					   CK_ULONG          ulEncryptedDataLen, 
					   CK_BYTE_PTR       pData,              
					   CK_ULONG_PTR      pulDataLen );

	// 
	// Gestión de objetos PKCS#11
	//
	CK_RV CreateObject( CK_ATTRIBUTE_PTR  pTemplate,  
					    CK_ULONG          ulCount,    
					    CK_OBJECT_HANDLE_PTR phObject  );

	CK_RV DestroyObject( CK_OBJECT_HANDLE  hObject );

	CK_RV GenerateKeyPair(  CK_MECHANISM_PTR     pMechanism,
							CK_ATTRIBUTE_PTR     pPublicKeyTemplate,
							CK_ULONG             ulPublicKeyAttributeCount,
							CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,
							CK_ULONG             ulPrivateKeyAttributeCount,
							CK_OBJECT_HANDLE_PTR phPublicKey,
							CK_OBJECT_HANDLE_PTR phPrivateKey);

	CK_RV GenerateRandom( CK_BYTE_PTR pRandomData,
						  CK_ULONG    ulRandomLen);

	// Método para el borrado de claves huérfanas y no-FAT
	void LimpiarClavesRSA( );

};
