/**
 * Removes the mapping for this key from this map if it is present.
 *
 * More formally, if this map contains a mapping from a key k to a value v such that
 * (key==null ? k==null : memcmp( key, k, keyLength ) == 0,
 * that mapping is removed.
 * (The map can contain at most one such mapping.)
 *
 * Returns the previous value associated with key,
 * NULL if there was no mapping for key
 * or (void*)-1 in case of an error.
 *
 * Note: If a valid pointer to a value is returned, the value returned is
 * malloced on the heap. It is the caller's responsibility to free that memory
 * once it is no longer needed.
 *
 * For hash maps this method has a time complexity of O(1).
 * For tree maps this method has a time complexity of O(Log N).
 *
 * @return void * retptr != (void*)-1: The previously associated value.
 * @return void * retptr == (void*)-1: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY - Out of memory.
 */
void * pblMapRemove( /*                                             */
PblMap * map, /**                            The map to remove from */
void * key, /**                    Key whose association is removed */
size_t keyLength, /**                             Length of the key */
size_t * valueLengthPtr /**       Out: Length of the value returned */
)
{
    PblMapEntry * mapEntry;
    void * retptr = NULL;
    PblMapKey mapKey;

    mapKey.tag = PBL_MAP_KEY_TAG;
    mapKey.keyLength = keyLength;
    mapKey.key = key;

    mapEntry = (PblMapEntry *)pblSetGetElement( map->entrySet, &mapKey );
    if( !mapEntry )
    {
        if( valueLengthPtr )
        {
            *valueLengthPtr = 0;
        }
        return NULL;
    }

    if( mapEntry->valueLength > 0 )
    {
        retptr = pbl_memdup( "pblMapRemove", mapEntry->buffer
                + mapEntry->keyLength, mapEntry->valueLength );
    }
    else
    {
        retptr = pbl_malloc0( "pblMapRemove0", 1 );
    }
    if( !retptr )
    {
        if( valueLengthPtr )
        {
            *valueLengthPtr = 0;
        }
        return (void*)-1;
    }

    if( valueLengthPtr )
    {
        *valueLengthPtr = mapEntry->valueLength;
    }

    pblSetRemoveElement( map->entrySet, mapEntry );

    PBL_FREE( mapEntry );

    return retptr;
}
/**
 * Removes from the underlying list or tree set the last element returned by the iterator.
 *
 * This method can be called only once per call to next or previous.
 * It can be made only if pblIteratorAdd() has not been called after the last call to next or previous.
 *
 * For array lists this method has a time complexity of O(N),
 * with N being the number of elements in the underlying list.
 *
 * For linked lists and hash sets this method has a time complexity of O(1).
 *
 * For tree sets this method has a time complexity of O(Log N),
 * with N being the number of elements in the underlying collection.
 *
 * @return int rc >= 0: The size of the collection.
 * @return int rc <  0: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_NOT_ALLOWED - The the next or previous method has not yet been called,
 *                         or the remove method has already been called after the last call to the next or previous method.
 *
 * <BR>PBL_ERROR_CONCURRENT_MODIFICATION - The underlying list or tree set was modified concurrently.
 * <BR>PBL_ERROR_PARAM_LIST              - The underlying collection is neither a list nor a tree set.
 */
int pblIteratorRemove(
PblIterator * iterator /** The iterator to remove the next element from */
)
{
    if( iterator->changeCounter != iterator->collection->changeCounter )
    {
        pbl_errno = PBL_ERROR_CONCURRENT_MODIFICATION;
        return -1;
    }

    if( PBL_SET_IS_TREE_SET( iterator->collection ) )
    {
        PblTreeIterator * treeIterator = (PblTreeIterator *)iterator;

        if( !treeIterator->current )
        {
            pbl_errno = PBL_ERROR_NOT_ALLOWED;
            return -1;
        }
        else
        {
            if( treeIterator->next == treeIterator->current )
            {
                treeIterator->next = pblTreeNodeNext( treeIterator->next );
            }
            else if( treeIterator->prev == treeIterator->current )
            {
                treeIterator->prev = pblTreeNodePrevious( treeIterator->prev );
            }

            pblSetRemoveElement( (PblSet*)treeIterator->collection,
                                 treeIterator->current->element );
        }
    }
    else if( PBL_LIST_IS_LINKED_LIST( iterator->collection ) )
    {
        if( !iterator->current )
        {
            pbl_errno = PBL_ERROR_NOT_ALLOWED;
            return -1;
        }
        else
        {
            PblLinkedList * linkedList = (PblLinkedList *)iterator->collection;
            PblLinkedNode * nodeToFree = iterator->current;

            if( iterator->next == iterator->current )
            {
                iterator->next = iterator->next->next;
            }
            else if( iterator->prev == iterator->current )
            {
                iterator->prev = iterator->prev->prev;
            }

            PBL_LIST_UNLINK( linkedList->head, linkedList->tail, nodeToFree, next, prev );
            linkedList->genericList.size--;
            linkedList->genericList.changeCounter++;

            PBL_FREE( nodeToFree );
        }
    }
    else if( PBL_LIST_IS_ARRAY_LIST( iterator->collection ) )
    {
        if( iterator->lastIndexReturned < 0 )
        {
            pbl_errno = PBL_ERROR_NOT_ALLOWED;
            return -1;
        }

        if( pblArrayListRemoveAt( (PblArrayList*)iterator->collection,
                                  iterator->lastIndexReturned ) == (void*)-1 )
        {
            return -1;
        }
    }
    else
    {
        pbl_errno = PBL_ERROR_PARAM_LIST;
        return -1;
    }

    if( iterator->lastIndexReturned < iterator->index )
    {
        iterator->index--;
    }

    iterator->current = NULL;
    iterator->lastIndexReturned = -1;

    iterator->changeCounter = iterator->collection->changeCounter;

    return iterator->collection->size;
}