//  hey, emacs, treat this like -*- C++ -*- file

//  ------------------------------------------------------------------
//  The Goldware Library.
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 2000 Alex. S. Aganichev
//  ------------------------------------------------------------------
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License as
//  published by the Free Software Foundation; either version 2 of the
//  License, or (at your option) any later version.
//
//  This program 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
//  General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  Group/Random System.
//  ------------------------------------------------------------------

#ifdef __GNUG__
    #pragma implementation "gutlgrp.h"
#endif

#include <cstdlib>
#include <gmemdbg.h>
#include <string>
#include <gwildmat.h>
#include <gutlgrp.h>


//  ------------------------------------------------------------------
//  Constructor

Grp::Grp()
{

    currgrp = container.end();
    currgrpno = -1;
}


//  ------------------------------------------------------------------
//  Destructors

Grp::~Grp()
{

    std::multimap<int, grp_stock>::iterator i;
    for(currgrp = container.begin(); currgrp != container.end(); currgrp++)
        for(i = currgrp->second.begin(); i != currgrp->second.end(); i++)
        {
            if(i->second.type == grp_stock::TYPE_OBJECT)
                throw_free(i->second.data.object_item);
            else if(i->second.type == grp_stock::TYPE_STRING)
                throw_delete(i->second.data.string_item);
        }
}


//  ------------------------------------------------------------------
//  Add a new group

void Grp::AddGrp(const char* id)
{

    std::string sid(id);
    std::multimap<int, grp_stock> m;
    m.insert(std::pair<int, grp_stock>(GRP_MEMBER, sid));
    container.push_back(std::pair<std::string, std::multimap<int, grp_stock> >(sid, m));
    currgrp = container.end()-1;
    currgrpno = container.size()-1;
}


//  ------------------------------------------------------------------
//  Add a new group member

void Grp::AddMbr(const char* id)
{

    currgrp->second.insert(std::pair<int, grp_stock>(GRP_MEMBER, std::string(id)));
}


//  ------------------------------------------------------------------

const char* Grp::SetGrp(const char* id)
{

    std::multimap<int, grp_stock>::iterator i;
    for(currgrp = container.begin(), currgrpno = 0; currgrp != container.end(); currgrp++, currgrpno++)
        for(i = currgrp->second.find(GRP_MEMBER); (i != currgrp->second.end()) and (i->first == GRP_MEMBER); i++)
            if(strwild(id, i->second.data.string_item->c_str()))
                return i->second.data.string_item->c_str();
    currgrpno = -1;
    return NULL;
}


//  ------------------------------------------------------------------

void Grp::AddItm(int __type, bool __data)
{

    currgrp->second.insert(std::pair<int, grp_stock>(__type, __data));
}


//  ------------------------------------------------------------------

void Grp::AddItm(int __type, char __data)
{

    currgrp->second.insert(std::pair<int, grp_stock>(__type, __data));
}


//  ------------------------------------------------------------------

void Grp::AddItm(int __type, int __data)
{

    currgrp->second.insert(std::pair<int, grp_stock>(__type, __data));
}


//  ------------------------------------------------------------------

void Grp::AddItm(int __type, const std::string& __data)
{

    currgrp->second.insert(std::pair<int, grp_stock>(__type, __data));
}


//  ------------------------------------------------------------------

void Grp::AddItm(int __type, void* __data, int __size)
{

    void *data = throw_malloc(__size+sizeof(int));
    *((int *)data) = __size;
    memcpy((char *)data+sizeof(int), __data, __size);
    currgrp->second.insert(std::pair<int, grp_stock>(__type, data));
}


//  ------------------------------------------------------------------

int Grp::GetItm(int __type, bool& __data, int __no)
{

    // Return error if a current group is not set
    if(currgrpno == -1)
        return -1;

    // Pointer to item type index for this group and type
    int rv = currgrp->second.count(__type);

    if(rv)
    {
        if((__no >= rv) or (__no == -1))
            __no = rand() % rv;
        std::multimap<int, grp_stock>::iterator i = currgrp->second.find(__type);
        while(__no--) i++;
        __data = i->second.data.bool_item;
    }

    // Return number of items of this type in the group
    return rv;
}


//  ------------------------------------------------------------------

int Grp::GetItm(int __type, char& __data, int __no)
{

    // Return error if a current group is not set
    if(currgrpno == -1)
        return -1;

    // Pointer to item type index for this group and type
    int rv = currgrp->second.count(__type);

    if(rv)
    {
        if((__no >= rv) or (__no == -1))
            __no = rand() % rv;
        std::multimap<int, grp_stock>::iterator i = currgrp->second.find(__type);
        while(__no--) i++;
        __data = i->second.data.char_item;
    }

    // Return number of items of this type in the group
    return rv;
}


//  ------------------------------------------------------------------

int Grp::GetItm(int __type, int& __data, int __no)
{

    // Return error if a current group is not set
    if(currgrpno == -1)
        return -1;

    // Pointer to item type index for this group and type
    int rv = currgrp->second.count(__type);

    if(rv)
    {
        if((__no >= rv) or (__no == -1))
            __no = rand() % rv;
        std::multimap<int, grp_stock>::iterator i = currgrp->second.find(__type);
        while(__no--) i++;
        __data = i->second.data.int_item;
    }

    // Return number of items of this type in the group
    return rv;
}


//  ------------------------------------------------------------------

int Grp::GetItm(int __type, std::string& __data, int __no)
{

    // Return error if a current group is not set
    if(currgrpno == -1)
        return -1;

    // Pointer to item type index for this group and type
    int rv = currgrp->second.count(__type);

    if(rv)
    {
        if((__no >= rv) or (__no == -1))
            __no = rand() % rv;
        std::multimap<int, grp_stock>::iterator i = currgrp->second.find(__type);
        while(__no--) i++;
        __data = *(i->second.data.string_item);
    }

    // Return number of items of this type in the group
    return rv;
}


//  ------------------------------------------------------------------

int Grp::GetItm(int __type, void* __data, int __size, int __no)
{

    // Return error if a current group is not set
    if(currgrpno == -1)
        return -1;

    // Pointer to item type index for this group and type
    int rv = currgrp->second.count(__type);

    if(rv)
    {
        if((__no >= rv) or (__no == -1))
            __no = rand() % rv;
        std::multimap<int, grp_stock>::iterator i = currgrp->second.find(__type);
        while(__no--) i++;
        void *data = i->second.data.object_item;
        int local_size = *((int *)data);
        __size = minimum_of_two (local_size, __size);
        memcpy(__data, (char *)data+sizeof(int), __size);
    }

    // Return number of items of this type in the group
    return rv;
}


//  ------------------------------------------------------------------
