/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  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.
 *
 *  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
 *  Library 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, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *
 ***********************************************************************/


//===[ Include files ]=====================================================

#include "internal.h"

//===[ Type definitions ]==================================================

//
// Config Interface instance data
// 
typedef struct _PrincipalIfInstance
{
   int            refCount;
   IdenTokenIf    *pIdenTokenIf;
   PrincipalIf    principalIf;

} PrincipalIfInstance, *PPrincipalIfInstance;

//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

// PrincipalIf variables
static
int               g_numPrincipalIfObjs = 0;

// Synchronization mutex
static
HANDLE            g_principalIfMutex = NULL;


//++=======================================================================
static
int SSCS_CALL
AddReference(
   IN       const void  *pIfInstance)
//
// Arguments:  
//    pIfInstance -
//       Pointer to interface object.
//   
// Returns:
//    Interface reference count.
//                           
// Description:
//    Increases interface reference count.
//
// L2
//=======================================================================--
{
   int                  refCount;
   PrincipalIfInstance  *pPrincipalIfInstance = CONTAINING_RECORD(pIfInstance, PrincipalIfInstance, principalIf);

   DbgTrace(2, "-AddReference- Start\n", 0);

   // Increment the reference count on the object
   PlatAcquireMutex(g_principalIfMutex);
   pPrincipalIfInstance->refCount ++;
   refCount = pPrincipalIfInstance->refCount;
   PlatReleaseMutex(g_principalIfMutex);

   DbgTrace(2, "-AddReference- End, refCount = %08X\n", refCount);

   return refCount;
}


//++=======================================================================
static
void SSCS_CALL
ReleaseReference(
   IN       const void  *pIfInstance)
//
// Arguments:  
//    pIfInstance -
//       Pointer to interface object.
//   
// Returns:
//    Nothing.
//                           
// Description:
//    Decreases interface reference count. The interface is deallocated if
//    the reference count becomes zero.
//
// L2
//=======================================================================--
{
   bool                 freeObj = false;
   PrincipalIfInstance  *pPrincipalIfInstance = CONTAINING_RECORD(pIfInstance, PrincipalIfInstance, principalIf);

   DbgTrace(2, "-ReleaseReference- Start\n", 0);

   // Decrement the reference count on the object and determine if it needs to
   // be released.
   PlatAcquireMutex(g_principalIfMutex);
   pPrincipalIfInstance->refCount --;
   if (pPrincipalIfInstance->refCount == 0)
   {
      // The object needs to be released, forget about it.
      freeObj = true;
      g_numPrincipalIfObjs --;
   }
   PlatReleaseMutex(g_principalIfMutex);

   // Free object if necessary
   if (freeObj)
   {
      // Release the identity token interface associated with our instance
      pPrincipalIfInstance->pIdenTokenIf->releaseReference(pPrincipalIfInstance->pIdenTokenIf);

      // Free our instance data
      free(pPrincipalIfInstance);
   }

   DbgTrace(2, "-ReleaseReference- End\n", 0);
}


//++=======================================================================
static
CasaStatus SSCS_CALL
GetIdentityId(
   IN       const void  *pIfInstance,
   INOUT    char        *pIdentIdBuf,
   INOUT    int         *pIdentIdLen)
//
// Arguments:  
//    pIfInstance -
//       Pointer to interface object.
//   
//    pIdentIdBuf -
//       Pointer to buffer that will receive the identity id. The returned
//       id will be in the form of a NULL terminated string.
//
//    pIdentIdBufLen -
//       Pointer to variable with the length of the buffer pointed by
//       pIdentIdBuf. On exit it contains the length of the returned id
//       (including the NULL terminator).
//
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Get the identity id associated with the identity token.
//
// L2
//=======================================================================--
{
   CasaStatus           retStatus;
   PrincipalIfInstance  *pPrincipalIfInstance = CONTAINING_RECORD(pIfInstance, PrincipalIfInstance, principalIf);

   DbgTrace(2, "-GetIdentityId- Start\n", 0);

   // Just call into the identity token
   retStatus = pPrincipalIfInstance->pIdenTokenIf->getIdentityId(pPrincipalIfInstance->pIdenTokenIf,
                                                                 pIdentIdBuf,
                                                                 pIdentIdLen);

   DbgTrace(2, "-GetIdentityId- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
static
CasaStatus SSCS_CALL
GetSourceName(
   IN       const void  *pIfInstance,
   INOUT    char        *pSourceNameBuf,
   INOUT    int         *pSourceNameLen)
//
// Arguments:  
//    pIfInstance -
//       Pointer to interface object.
//   
//    pSourceNameBuf -
//       Pointer to buffer that will receive the name associated with the
//       identity information source. The returned name will be in the form
//       of a NULL terminated string.
//
//    pSourceNameBufLen -
//       Pointer to variable with the length of the buffer pointed by
//       pSourceNameBuf. On exit it contains the length of the returned
//       name (including the NULL terminator).
//
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Get the name of the identity source associated with the identity token.
//
// L2
//=======================================================================--
{
   CasaStatus           retStatus;
   PrincipalIfInstance  *pPrincipalIfInstance = CONTAINING_RECORD(pIfInstance, PrincipalIfInstance, principalIf);

   DbgTrace(2, "-GetSourceName- Start\n", 0);

   // Just call into the identity token
   retStatus = pPrincipalIfInstance->pIdenTokenIf->getSourceName(pPrincipalIfInstance->pIdenTokenIf,
                                                                 pSourceNameBuf,
                                                                 pSourceNameLen);

   DbgTrace(2, "-GetSourceName- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
static
CasaStatus SSCS_CALL
GetSourceUrl(
   IN       const void  *pIfInstance,
   INOUT    char        *pSourceUrlBuf,
   INOUT    int         *pSourceUrlLen)
//
// Arguments:  
//    pIfInstance -
//       Pointer to interface object.
//   
//    pSourceUrlBuf -
//       Pointer to buffer that will receive the URL associated with the
//       identity information source. The returned URL will be in the form
//       of a NULL terminated string.
//
//    pSourceUrlBufLen -
//       Pointer to variable with the length of the buffer pointed by
//       pSourceUrlBuf. On exit it contains the length of the returned
//       URL (including the NULL terminator).
//
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Get the URL to the identity source associated with the identity token.
//
// L2
//=======================================================================--
{
   CasaStatus           retStatus;
   PrincipalIfInstance  *pPrincipalIfInstance = CONTAINING_RECORD(pIfInstance, PrincipalIfInstance, principalIf);

   DbgTrace(2, "-GetSourceUrl- Start\n", 0);

   // Just call into the identity token
   retStatus = pPrincipalIfInstance->pIdenTokenIf->getSourceUrl(pPrincipalIfInstance->pIdenTokenIf,
                                                                pSourceUrlBuf,
                                                                pSourceUrlLen);

   DbgTrace(2, "-GetSourceUrl- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
static
CasaStatus SSCS_CALL
AttributeEnumerate(
   IN       const void  *pIfInstance,
   INOUT    int         *pEnumHandle,       
   INOUT    char        *pAttribNameBuf,
   INOUT    int         *pAttribNameLen,
   INOUT    char        *pAttribValueBuf,
   INOUT    int         *pAttribValueLen)
//
// Arguments:  
//    pIfInstance -
//       Pointer to interface object.
//   
//    pEnumHandle -
//       Pointer to enumeration handle. Must be set to 0 to start an
//       enumeration.
//
//    pAttribNameBuf -
//       Pointer to buffer that will receive the identity attribute name. The
//       returned name will be in the form of a NULL terminated string.
//
//    pAttribNameLen -
//       Pointer to variable with the length of the buffer pointed by
//       pAttribNameBuf. On exit it contains the length of the returned
//       name (including the NULL terminator).
//
//    pAttribValueBuf -
//       Pointer to buffer that will receive the identity attribute value. The
//       returned value will be in the form of a NULL terminated string.
//
//    pAttribValueLen -
//       Pointer to variable with the length of the buffer pointed by
//       pAttribValueBuf. On exit it contains the length of the returned
//       value (including the NULL terminator).
//
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Enumerates through the attributes associated with the identity token.
//
// L2
//=======================================================================--
{
   CasaStatus           retStatus;
   PrincipalIfInstance  *pPrincipalIfInstance = CONTAINING_RECORD(pIfInstance, PrincipalIfInstance, principalIf);

   DbgTrace(2, "-AttributeEnumerate- Start\n", 0);

   // Just call into the identity token
   retStatus = pPrincipalIfInstance->pIdenTokenIf->attributeEnumerate(pPrincipalIfInstance->pIdenTokenIf,
                                                                      pEnumHandle,
                                                                      pAttribNameBuf,
                                                                      pAttribNameLen,
                                                                      pAttribValueBuf,
                                                                      pAttribValueLen);

   DbgTrace(2, "-AttributeEnumerate- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
CasaStatus
GetPrincipalInterface(
   IN       IdenTokenIf  *pIdenTokenIf,
   INOUT    PrincipalIf  **ppPrincipalIf)
//
// Arguments:  
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Get principal interface instanced for the identity associated
//    with specified identity token.
//
// L2
//=======================================================================--
{
   PrincipalIfInstance  *pPrincipalIfInstance;
   CasaStatus           retStatus;

   DbgTrace(2, "-GetPrincipalInterface- Start\n", 0);

   // Create a PrincipalIfInstance object for it.
   pPrincipalIfInstance = malloc(sizeof(*pPrincipalIfInstance));
   if (pPrincipalIfInstance)
   {
      // Initialize the PrincipalIf within the instance data
      pPrincipalIfInstance->principalIf.addReference = AddReference;
      pPrincipalIfInstance->principalIf.releaseReference = ReleaseReference;
      pPrincipalIfInstance->principalIf.getIdentityId = GetIdentityId;
      pPrincipalIfInstance->principalIf.getSourceName = GetSourceName;
      pPrincipalIfInstance->principalIf.getSourceUrl = GetSourceUrl;
      pPrincipalIfInstance->principalIf.attributeEnumerate = AttributeEnumerate;

      // Keep reference to the identity token interface instance
      pPrincipalIfInstance->pIdenTokenIf = pIdenTokenIf;
      pIdenTokenIf->addReference(pIdenTokenIf);

      // Return the PrincipalIf associated with the instance data after
      // incrementing its reference count.
      pPrincipalIfInstance->refCount ++;
      *ppPrincipalIf = &pPrincipalIfInstance->principalIf;

      // Bump up our interface instance count
      PlatAcquireMutex(g_principalIfMutex);
      g_numPrincipalIfObjs ++;
      PlatReleaseMutex(g_principalIfMutex);

      // Success
      retStatus = CASA_STATUS_SUCCESS;
   }
   else
   {
      DbgTrace(0, "-GetPrincipalInterface- Buffer allocation failure\n", 0);
      retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INSUFFICIENT_RESOURCES);
   }

   DbgTrace(2, "-GetPrincipalInterface- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
CasaStatus
PrincipalIfInit(void)
//
// Arguments:  
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Initializes the principal interface complex.
//
// L2
//=======================================================================--
{
   CasaStatus        retStatus;

   DbgTrace(1, "-PrincipalIfInit- Start\n", 0);

   // Allocate mutex
   if ((g_principalIfMutex = PlatAllocMutex()) != NULL)
      retStatus = CASA_STATUS_SUCCESS;
   else
      retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INSUFFICIENT_RESOURCES);

   DbgTrace(1, "-PrincipalIfInit- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
void
PrincipalIfUninit(void)
//
// Arguments:  
//   
// Returns:
//    Casa Status
//                           
// Description:
//    Uninitializes the configuration interface complex.
//
// L2
//=======================================================================--
{
   DbgTrace(1, "-PrincipalIfUninit- Start\n", 0);

   // Free mutex if necessary
   if (g_principalIfMutex)
   {
      PlatDestroyMutex(g_principalIfMutex);
      g_principalIfMutex = NULL;
   }

   DbgTrace(1, "-PrincipalIfUninit- End\n", 0);
}


//++=======================================================================
//++=======================================================================
//++=======================================================================