/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/
/**
 * Storage Management for Workspace Manager API. <BR>
 * MS Windows version.
 *
 * @version  @label
 *
 */



/*************************************************************************/
/*  Definitions                                                          */
/*************************************************************************/

#include "wsm_sm.h"

#include <stdlib.h>
#include <string.h>
#include "libmem.h"
#include "smldef.h"
#include "smlerr.h"


/* Global Vars */
/* =========== */

/** root of buffer list */

#include "mgr.h"
#define root (mgrGetSyncMLAnchor())->wsmGlobals->wsmSm

/* private functions prototypes */
static Byte_t newListEle(const char *name, smWinList_t **newEle, MemHandle_t *newHandle);
static Byte_t locateEle(const char *eleName, smWinList_t **p);
static Byte_t locateH(MemHandle_t memH, smWinList_t **p);
static void removeEle(const char *eleName);


/*************************************************************************/
/*  Internal Functions                                                   */
/*************************************************************************/

/** create new buffer element and assign name to it
 * return pointer to new element and handle of new element
 */

/* 
SCTSTK - 16/03/2002 : fixed so that it works even if the sequence of buffer termination
is not in the reverse order of buffer creation
*/

static Byte_t newListEle(const char *name, 
		  smWinList_t **newEle, 
		  MemHandle_t *newHandle) {
  smWinList_t *p;
  int i;
  for ( i=0; *newHandle < MAX_WSM_BUFFERS && (mgrGetSyncMLAnchor())->wsmGlobals->wsmBuf[i].memH != -1; ++i );
  if (i == MAX_WSM_BUFFERS) return 0;
  *newHandle=i+1;
 
  if ( ((*newEle) = smlLibMalloc(sizeof(smWinList_t))) == 0 )
    return 0;  // no more memory
  if ( ((*newEle)->memName = smlLibMalloc(strlen(name)+1)) == 0 ){
    smlLibFree(*newEle);
    return 0;  // no more memory
    }
  memcpy((*newEle)->memName, name, strlen(name));
  (*newEle)->memName[strlen(name)] = '\0';
  if ( root == 0 )
    root = *newEle;
  else
  {
	p=root;
	while ( p->next != NULL) p = p->next;
    p->next = *newEle;
  }
  return 1;
}


/**
 * search for buffer with name eleName and return pointer to it in p.
 * return == 0 if not found; 1 if found
 */
static Byte_t locateEle(const char *eleName, smWinList_t **p) {
  *p = root;
  while ( (*p != NULL) && (strcmp((*p)->memName, eleName) != 0) )  {
    *p = (*p)->next;
  }
  if ( *p == NULL ) 
    return 0;
  else 
    return 1;
}

/**
 * search for buffer with memHandle memH and return pointer to it in p.
 * return == 0 if not found; 1 if found
 */
static Byte_t locateH(MemHandle_t memH, smWinList_t **p) {
  *p = root;
  while ( (*p != NULL) && ((*p)->memH != memH) )  {
    *p = (*p)->next;
  }
  if ( *p == NULL ) 
    return 0;
  else 
    return 1;
}

/**
 * remove buffer with name eleName from smWinList.
 */
static void removeEle(const char *eleName) {
  smWinList_t *act, *old;

  old = act = root;
  while ( (act != NULL) && (strcmp(act->memName, eleName) != 0) )  {
    old = act;
    act = act->next;
  }
  if ( act != NULL ) {
    if ( old == act )   // delete first list ele
      root = act->next;
    else
      old->next = act->next;
    smlLibFree(act->memName);
	smlLibFree(act);
  }
}




/*************************************************************************/
/*  External Functions                                                   */
/*************************************************************************/


/**
 * FUNCTION: smCreate
 *
 * Creates a new memory block with name memName and size memSize.
 *
 * PRE-Condition:   OS does not know memName; memSize > 0
 *
 * POST-Condition:  memName exists with size memSize; 
 *                  memH refers to new memory block.
 *
 * IN:      memName
 *          Name of new memory block
 * IN:      memSize
 *          Size of new memory block
 * 
 * OUT:     memH
 *          Handle to new memory block
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_USAGE, if memName is already known to the OS
 *          SML_ERR_INVALID_SIZE, if memSize <= 0
 *          SML_ERR_NOT_ENOUGH_SPACE, if available memory < memSize
 *
 * @see  smDestroy
 */
Ret_t smCreate (String_t memName, MemSize_t memSize, MemHandle_t *memH) {
  smWinList_t *pEle;     // pointer to new buffer

  if ( memSize <= 0 ) {
    return SML_ERR_INVALID_SIZE;
  }
  if ( locateEle(memName, &pEle) ) {
    return SML_ERR_WRONG_USAGE;
  }
  
  // create new element in buffer list
  if ( ! newListEle(memName, &pEle, memH) ) {
    return SML_ERR_NOT_ENOUGH_SPACE;
  }
    
  // create memory
  if ( (pEle->winH=smlLibMalloc(memSize)) == 0 ) {
    smlLibFree(pEle->memName);
 	smlLibFree(pEle);
    return SML_ERR_NOT_ENOUGH_SPACE;
  }

  // set new values
  pEle->locked = 0;
  pEle->memH = *memH;
  pEle->memSize = memSize;
  pEle->next = NULL;

  return SML_ERR_OK;
}


/**
 * FUNCTION: smOpen
 *
 * Open connection to memory block with name memName.
 *
 * PRE-Condition:   OS does know memName
 *
 * POST-Condition:  memH refers to memory block memName
 *
 * IN:      memName
 *          Name of memory block to open<BR>
 *          Windows version: Name is ignored
 * 
 * OUT:     memH
 *          Handle to opened memory block
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_PARAM, if memName is unknown
 *
 * @see  smClose
 */
Ret_t smOpen (String_t memName, MemHandle_t *memH) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateEle(memName, &pEle) ) {
    return SML_ERR_WRONG_PARAM;
  }

  *memH = pEle->memH;
  return SML_ERR_OK;
}


/**
 * FUNCTION: smClose
 *
 * Close link to memory block.
 *
 * PRE-Condition:   memH is a valid memory block handle; memH is unlocked;
 *                  no pointers to records are in use
 *
 * POST-Condition:  memH is not valid anymore
 *
 * IN:      memH
 *          Handle to close
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_USAGE, if memH is locked or unknown
 *
 * @see  smOpen
 */
Ret_t smClose (MemHandle_t memH) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateH(memH, &pEle) ) {
    return SML_ERR_WRONG_USAGE;
  }

  // reset handle  
  smlLibFree(pEle->winH);
  pEle->memH = 0;
  pEle->locked = 0;
  pEle->memSize = 0;

  return SML_ERR_OK;
}


/**
 * FUNCTION: smDestroy
 *
 * Remove memory block memName within OS.
 *
 * PRE-Condition:   memName is a valid memory block name; 
 *                  memory block is not in use (i.e. no handles and 
 *                  pointers to this memory block are in use)
 *
 * POST-Condition:  memName is not a valid memory block name anymore
 *
 * IN:      memName
 *          Name of memory block to remove
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_PARAM, if memName is unknown
 *          SML_ERR_WRONG_USAGE, if memory block is still locked
 *
 * @see  smCreate
 */
Ret_t smDestroy (String_t memName) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateEle(memName, &pEle) ) {
    return SML_ERR_WRONG_PARAM;
  }
  if ( pEle->locked ) {
    return SML_ERR_WRONG_USAGE;
  }

  // remove memory buffer
  removeEle(memName);

  return SML_ERR_OK;
}


/**
 * FUNCTION: smLock
 *
 * Map memory block memH to local address space.
 *
 * PRE-Condition:   memH is a valid handle; memory block is not locked
 *
 * POST-Condition:  pMem points to memory block memH; 
 *                  memory block is locked
 *
 * IN:      memH
 *          Handle to memory block
 * 
 * OUT:     pMem
 *          Pointer to memory block memH mapped in local address space
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_PARAM, if memH is unknown
 *          SML_ERR_WRONG_USAGE, if memH was already locked
 *          SML_ERR_UNSPECIFIC, if lock failed
 *
 * @see  smUnlock
 */
Ret_t smLock (MemHandle_t memH, MemPtr_t *pMem) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateH(memH, &pEle) ) {
    return SML_ERR_WRONG_PARAM;
  }
  if ( pEle->locked ) {
    return SML_ERR_WRONG_USAGE;
  }

  *pMem = (MemPtr_t)pEle->winH;
  pEle->locked = 1;

  return SML_ERR_OK;
}


/**
 * FUNCTION: smUnlock
 *
 * Free pointer mapped to memH memory block.
 *
 * PRE-Condition:   memH is a valid handle; memory block is locked
 *
 * POST-Condition:  memory block is unlocked
 *
 * IN:      memH
 *          Handle to memory block
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_PARAM, if memH is unknown
 *          SML_ERR_WRONG_USAGE, if memH was already unlocked
 *          SML_ERR_UNSPECIFIC, if unlock failed
 *
 * @see  smLock
 */
Ret_t smUnlock (MemHandle_t memH) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateH(memH, &pEle) ) {
    return SML_ERR_WRONG_PARAM;
  }
  if ( ! pEle->locked ) {
    return SML_ERR_WRONG_USAGE;
  }

  pEle->locked = 0;

  return SML_ERR_OK;
}


/**
 * FUNCTION: smSetSize
 *
 * Set size of memory block memH to newSize.
 *
 * PRE-Condition:   memH is a valid handle; newSize > 0; 
 *                  memory block is unlocked
 *
 * POST-Condition:  memory block size = newSize
 *
 * IN:      memH
 *          Handle to memory block
 * IN:      newSize
 *          New size of memory block
 * 
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_PARAM, if memH is unknown
 *          SML_ERR_WRONG_USAGE, if memH is locked
 *          SML_ERR_INVALID_SIZE, if newSize <= 0
 *          SML_ERR_NOT_ENOUGH_SPACE, if available memory < newSize
 *
 * @see  smGetSize
 */
Ret_t smSetSize (MemHandle_t memH, MemSize_t newSize) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateH(memH, &pEle) ) {
    return SML_ERR_WRONG_PARAM;
  }
  if ( pEle->locked ) {
    return SML_ERR_WRONG_USAGE;
  }
  if ( newSize <= 0 ) {
    return SML_ERR_INVALID_SIZE;
  }

  smlLibFree(pEle->winH);
  if ( (pEle->winH=smlLibMalloc(newSize)) == 0 ) {
    return SML_ERR_NOT_ENOUGH_SPACE;
  }
  pEle->memSize = newSize;

  return SML_ERR_OK;
}


/**
 * FUNCTION: smGetSize
 *
 * Get size of memory block memH.
 *
 * PRE-Condition:   memH is a valid handle
 *
 * POST-Condition:  actSize = memory block size
 *
 * IN:      memH
 *          Handle to memory block
 * 
 * OUT:     actSize
 *          Actual size of memory block
 *
 * RETURN:  SML_ERR_OK, if O.K.
 *          SML_ERR_WRONG_PARAM, if memH is unknown
 *
 * @see  smSetSize
 */
Ret_t smGetSize (MemHandle_t memH, MemSize_t *actSize) {
  smWinList_t *pEle;     // pointer to buffer element

  if ( ! locateH(memH, &pEle) ) {
    return SML_ERR_WRONG_PARAM;
  }

  *actSize = pEle->memSize;

  return SML_ERR_OK;
}




