// $Id: JGInfoManager.cpp,v 1.8 2003/03/22 16:41:44 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGInfoManager.cpp
 *
 *  @author  Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 2001-2003 BEE Co.,Ltd. All rights reserved.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//=============================================================================

#define BEE_BUILD_DLL

#include "JGInfoManager.h"
#include "JGEquipment.h"
#include "JGLimitManager.h"
#include "JGTimeModule.h"
#include "JGTaskTrigger.h"
#include "JGCommDevice.h"
#include "sac/JGBitSetSensor.h"
#include "sac/JGIODevManager.h"
#include "BS2ACKMessage.h"
#include "BS2ErrorMessage.h"
#include "BS2ListItem.h"
#include "BS2DeclAtoms.h"

#define VALDEFINED(x)         (((x) != NULL) && (strlen(x) > 0))

extern int setSystemFunction(JGVariable * var);
extern int setLibFunction(JGVariable * var);

static JGInfoManager * _manager = NULL;

//-----------------------------------------------------------------------------
// Convert delemiter in PATH
//-----------------------------------------------------------------------------
void _convDelimiter(string& path)
{
#ifdef WIN32
    for (size_t i = 0; i < path.size(); i++)
    {
        if (path.at(i) == '/')
        {
            path.replace(i, 1, 1, DIR_SEPARATOR_CHAR);
        }
    }
#else
    for (size_t i = 0; i < path.size(); i++)
    {
        if (path.at(i) == '\\')
        {
            path.replace(i, 1, 1, DIR_SEPARATOR_CHAR);
        }
    }
#endif
}

//-----------------------------------------------------------------------------
// Constructor/Destructor
//-----------------------------------------------------------------------------
JGInfoManager::JGInfoManager() : JGManager(CATEGORY_INFO)
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGInfoManager::JGInfoManager");

}

//-----------------------------------------------------------------------------
JGInfoManager::~JGInfoManager()
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGInfoManager::~JGInfoManager");

}

//-----------------------------------------------------------------------------
// Return own.
//-----------------------------------------------------------------------------
JGInfoManager * JGInfoManager::instance()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::instance");
    if (_manager == NULL)
    {
        _manager = new JGInfoManager;
    }
    return _manager;
}

//-----------------------------------------------------------------------------
// Configure
//-----------------------------------------------------------------------------
int JGInfoManager::initConfig(int parm)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::config");
    ACE_UNUSED_ARG(parm);

    this->linkConf();
    this->confVariables();

    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Initialize
//-----------------------------------------------------------------------------
int JGInfoManager::init(void * parm)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::init");
    ACE_UNUSED_ARG(parm);

    this->linkVariables();

    m_ecvStatus = this->variable(VAR_ECV_CHANGED_STATUS);

    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Open and import database.
//-----------------------------------------------------------------------------
int JGInfoManager::open(void * parm)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::open");
    ACE_UNUSED_ARG(parm);

    if (this->activate(THR_NEW_LWP | THR_DETACHED) == -1)
    {
        TRACE_ERROR((_TX("%p\n"), ACE_TEXT("spawn")));
        return -1;
    }
    return BEE_SUCCESS;
}


//-----------------------------------------------------------------------------
// Link variable id and pointer
//-----------------------------------------------------------------------------
void JGInfoManager::linkConf()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::linkConf");

    JGConfigTable::iterator read_it = m_configs.begin();
    for ( ; read_it != m_configs.end(); ++read_it)
    {
        JGConfig * config = &((*read_it).second);
        if (config->name() == CONF_ROOTPATH)
        {
            _convDelimiter(config->m_value);
        }
        string curvid;
        config->vid().get(curvid);
        if (curvid.size() > 0)
        {
            JGid vid(config->vid());
            JGVariableTable::iterator var_it = m_vars.find(vid);
            if (var_it != m_vars.end())
            {   // set variable
                JGVariable * var = &((*var_it).second);
                config->variable(var);
                //
                // set value to variable
                //
            }
        }
    }

    return ;
}


//-----------------------------------------------------------------------------
// Link variable id and pointer
//-----------------------------------------------------------------------------
void JGInfoManager::confVariables()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::confVariables");

    JGVariableTable::iterator read_it = m_vars.begin();
    for ( ; read_it != m_vars.end(); ++read_it)
    {
        JGVariable * var = &((*read_it).second);
        m_varnames.insert(JGVarNamePair(var->name(), var));

        if (var->enabled())
        {
            if (var->varclass() == JGVariable::SV)
            {
                m_svs.insert(JGVidPair(var->svid(), var));
            }
            else if (var->varclass() == JGVariable::ECV)
            {
                m_ecvs.insert(JGVidPair(var->ecid(), var));
            }
        }

        // Set function for getting value
        if (var->func() == _TX("system"))
        {
            setSystemFunction(var);
        }
        else if (var->func() == _TX("lib"))
        {
            setLibFunction(var);
        }

    }
    return ;
}

//-----------------------------------------------------------------------------
// Initial variables
//-----------------------------------------------------------------------------
int JGInfoManager::initVariables()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::initVariables");

    JGVariableTable::iterator read_it = m_vars.begin();
    for ( ; read_it != m_vars.end(); ++read_it)
    {
        JGVariable * var = &((*read_it).second);
        var->init();     // convert ascii to binary value
    }
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Link variable id and pointer
//-----------------------------------------------------------------------------
void JGInfoManager::linkVariables()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::linkVariables");

    JGVariableTable::iterator read_it = m_vars.begin();
    for ( ; read_it != m_vars.end(); ++read_it)
    {
        JGVariable * var = &((*read_it).second);

        // Set io-device table to the variable
        if (! var->iodev().isNil())
        {
            JGIODeviceTable * iodev_tbl = JGIODevManager::instance()->iodevTable();
            JGIODeviceTable::iterator sac_iter = iodev_tbl->find(var->iodev());
            if (sac_iter != iodev_tbl->end())
            {   // Found
                JGIODevice * iodev = (*sac_iter).second;
                var->sac(iodev);
                if (iodev->format() == JGIODevice::BITSET)
                {   // Mapping bit number and variables
                    ((JGBitSetSensor *)iodev)->add(var);
                }
                // else if (iodev->format() == JGIODevice::WORDSET)  // Not support, yet.
                // {   // Mapping word number and variables
                //     ((JGWordSetSensor *)iodev)->add(var);
                // }
                else
                {
                    iodev->variable(var);
                }
            }
        }
    }

    return ;
}

//-----------------------------------------------------------------------------
// Get parameter of communication device
//-----------------------------------------------------------------------------
DeviceParameter * JGInfoManager::getDeviceParameter()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::getDeviceParameter");
    DeviceParameter * dev_parm;
    string valStr;

    // Equipment name
    if (this->getConf(CONF_PROTOCOL) == CONF_VAL_SECS)
    {   // Create for SECS
        CommParameter * comm_parm = new CommParameter;
        comm_parm->m_slave = (this->getConf(CONF_MASTER) == CONF_VAL_YES) ? 0 : 1;

        valStr = this->getConf(CONF_DEVICE_ID);
        if (valStr.size() > 0)
            comm_parm->m_deviceId = _tcstol(valStr.c_str(), NULL, 0);
        else
            comm_parm->m_deviceId = 1;

        valStr = this->getConf(CONF_SOURCE_ID);
        if (valStr.size() > 0)
            comm_parm->m_sourceId = _tcstol(valStr.c_str(), NULL, 0);
        else
            comm_parm->m_sourceId = 0;

        _tcsncpy(comm_parm->m_port, this->getConf(CONF_SECS_PORT).c_str(),
                                    sizeof(comm_parm->m_port) - 1);
        comm_parm->m_port[sizeof(comm_parm->m_port) - 1] = '\0';
        valStr = this->getConf(CONF_BAUDRATE);
        if (valStr.size() > 0)
            comm_parm->m_baudrate = _tcstol(valStr.c_str(), NULL, 0);
        else
            comm_parm->m_baudrate = 9600;

        valStr = this->getConf(CONF_SECS_RETRY);
        if (valStr.size() > 0)
            comm_parm->m_baudrate = _tcstol(valStr.c_str(), NULL, 0);
        else
            comm_parm->m_baudrate = 3;

        valStr = this->getConf(CONF_SECS_T2);
        if (valStr.size() > 0)
            comm_parm->m_t2timeout = _tcstol(valStr.c_str(), NULL, 0) * 100;
        else
            comm_parm->m_t2timeout = 100 * 100;   // 100*100msec

        valStr = this->getConf(CONF_SECS_T3);
        if (valStr.size() > 0)
            comm_parm->m_t3timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            comm_parm->m_t3timeout = 45 * 1000;

        valStr = this->getConf(CONF_SECS_T4);
        if (valStr.size() > 0)
            comm_parm->m_t4timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            comm_parm->m_t4timeout = 45 * 1000;

        _tcscpy(comm_parm->m_parity, _TX("none"));
        comm_parm->m_databit = 8;
        comm_parm->m_stopbit = 1;
        comm_parm->m_read_timeout = 30;
        dev_parm = comm_parm;
    }
    else
    {   // Create for HSMS
        SocketParameter * socket_parm = new SocketParameter;
        socket_parm->m_slave = (this->getConf(CONF_MASTER) == CONF_VAL_YES) ? 0 : 1;
        valStr = this->getConf(CONF_DEVICE_ID);
        if (valStr.size() > 0)
            socket_parm->m_deviceId = _tcstol(valStr.c_str(), NULL, 0);
        else
            socket_parm->m_deviceId = 1;

        valStr = this->getConf(CONF_SOURCE_ID);
        if (valStr.size() > 0)
            socket_parm->m_sourceId = _tcstol(valStr.c_str(), NULL, 0);
        else
            socket_parm->m_sourceId = 0;

        socket_parm->m_mode = (socket_parm->m_slave == 1) ? 0 : 1;

        valStr = this->getConf(CONF_HSMS_PORT);
        if (valStr.size() > 0)
            socket_parm->m_port = _tcstol(valStr.c_str(), NULL, 0);
        else
            socket_parm->m_port = HSMS_PORT_NUMBER;

        strncpy(socket_parm->m_hostname, this->getConf(CONF_HSMS_IP).c_str(),
                                         sizeof(socket_parm->m_hostname) - 1);
        socket_parm->m_hostname[sizeof(socket_parm->m_hostname) - 1] = '\0';

        valStr = this->getConf(CONF_HSMS_T3);
        if (valStr.size() > 0)
            socket_parm->m_t3timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            socket_parm->m_t3timeout = 45 * 1000;

        valStr = this->getConf(CONF_HSMS_T5);
        if (valStr.size() > 0)
            socket_parm->m_t5timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            socket_parm->m_t5timeout = 10 * 1000;

        valStr = this->getConf(CONF_HSMS_T6);
        if (valStr.size() > 0)
            socket_parm->m_t6timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            socket_parm->m_t6timeout = 5 * 1000;

        valStr = this->getConf(CONF_HSMS_T7);
        if (valStr.size() > 0)
            socket_parm->m_t7timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            socket_parm->m_t7timeout = 10 * 1000;

        valStr = this->getConf(CONF_HSMS_T8);
        if (valStr.size() > 0)
            socket_parm->m_t8timeout = _tcstol(valStr.c_str(), NULL, 0) * 1000;
        else
            socket_parm->m_t8timeout = 5 * 1000;

        socket_parm->m_hbtimeout = 0;
        dev_parm = socket_parm;
    }

    string pathname = DIR_SEPARATOR_STRING;
    pathname += _TX("jyugem");
    const string& dir = this->getConf(CONF_ROOTPATH);
    if (dir.size() > 0)
    {
        pathname = dir;
    }
    pathname += DIR_SEPARATOR_STRING;
    pathname += _TX("xml");
    pathname += DIR_SEPARATOR_STRING;
    pathname += _TX("secs.xml");
    if (pathname.size() >= sizeof(dev_parm->m_xmlname))
    {
        pathname = _TX("secs.xml");
    }
    _tcscpy(dev_parm->m_xmlname, pathname.c_str());

    return dev_parm;
}

//-----------------------------------------------------------------------------
// Get configuration data by name
//-----------------------------------------------------------------------------
static const string _nil(_TX(""));

const string& JGInfoManager::getConf(const string& pname)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::getConf");

    JGConfigTable * conftable = JGInfoManager::instance()->configTable();
    JGConfigTable::iterator iter = conftable->find(pname);
    if (iter == conftable->end())
    {
        return _nil;
    }
    JGConfig * conf = &((*iter).second);
    return conf->value();
}

//-----------------------------------------------------------------------------
// Get value by name
//-----------------------------------------------------------------------------
JGvalue& JGInfoManager::value(const string& vname)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::value");

    JGVariable * var = JGInfoManager::variable(vname);
    if (var != NULL)
    {
        return var->getv();
    }
    return JGvalue::zero;
}

//-----------------------------------------------------------------------------
// Get value by id
//-----------------------------------------------------------------------------
JGvalue& JGInfoManager::value(const JGid& vid)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::value");

    JGVariable * var = JGInfoManager::instance()->variable(vid);
    if (var != NULL)
    {
        return var->getv();
    }
    return JGvalue::zero;
}

//-----------------------------------------------------------------------------
// Get variable by name
//-----------------------------------------------------------------------------
JGVariable * JGInfoManager::variable(const string& vname)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::variable");

    JGVarNameTable * vnmtable = JGInfoManager::instance()->nameTable();
    JGVarNameTable::iterator var_it = vnmtable->find(vname);
    if (var_it == vnmtable->end())
    {
        TRACE_DEBUG((_TX("%s manager is not found of variable(%s).\n"),
                     _TX("JGInfoManager::variable"), vname.c_str()));
        return NULL;
    }
    JGVariable * var = (*var_it).second;
    return var;
}

//-----------------------------------------------------------------------------
// Get variable by vid
//-----------------------------------------------------------------------------
JGVariable * JGInfoManager::variable(const JGid& vid)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::variable");

    JGVariableTable * vartable = JGInfoManager::instance()->varTable();
    JGVariableTable::iterator var_it = vartable->find(vid);
    if (var_it == vartable->end())
    {
        TRACE_ERROR((_TX("Not found variable(%s).\n"),
                     vid.toString().c_str()));
        return NULL;
    }
    JGVariable * var = &((*var_it).second);
    return var;
}

//-----------------------------------------------------------------------------
// Get variable by svid
//-----------------------------------------------------------------------------
JGVariable * JGInfoManager::variableBySvid(JGid& svid)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::variableBySvid");

    JGVidTable::iterator var_it = m_svs.find(svid);
    if (var_it == m_svs.end())
    {
        return NULL;
    }
    JGVariable * var = (*var_it).second;
    return var;
}

//-----------------------------------------------------------------------------
// Get variable by ecid
//-----------------------------------------------------------------------------
JGVariable * JGInfoManager::variableByEcid(JGid& ecid)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::variableByEcid");

    JGVidTable::iterator var_it = m_ecvs.find(ecid);
    if (var_it == m_ecvs.end())
    {
        return NULL;
    }
    JGVariable * var = (*var_it).second;
    return var;
}

//-----------------------------------------------------------------------------
// Get message item by id, item name is defined database.
//-----------------------------------------------------------------------------
BS2Item * JGInfoManager::find(JGid& id)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::find");

    JGVariableTable::iterator iter = m_vars.find(id);
    if (iter == m_vars.end())
    {
        return NULL;
    }
    JGVariable * var = &((*iter).second);
    BS2Atom * atom = var->getAtom();
    BS2Assert(var->itemName().size() > 0);
    BS2Item * item = BS2Item::factory(var->itemName().c_str(), atom);
    return item;
}

//-----------------------------------------------------------------------------
// Accept trigger from the variable.
//-----------------------------------------------------------------------------
int JGInfoManager::notify(const string& category, JGVariable * var,
                          void * arg)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::notify");
    ACE_UNUSED_ARG(arg);

    TRACE_ERROR((_TX("%s : %s = %s\n"), category.c_str(), var->charName(),
                                        var->getv().toString().c_str()));

    if (category == TRID_ECV || category == TRG_EQUIPMENT_CONSTANT)
    {
        // Send Event Message (S6F11)
        // Operator changed ecv
        m_equipment->sendEvent(this, EVT_EC_CHANGED, var);

        JGvalue init_val(0);
        m_ecvStatus->setv(init_val);      // Clear request

    }
    else
    {
        return BEE_ERROR;
    }
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Supervise variables.
//-----------------------------------------------------------------------------
int JGInfoManager::monitor()
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::monitor");
    ACE_Guard<ACE_Thread_Mutex> info_mon(this->m_lock);
    if (info_mon.locked () == 0)
    {   // if collision, monitor is pass
        TRACE_ERROR((_TX("Mutex is not locked.\n")));
        return BEE_ERROR;
    }

    JGVidTable::iterator ecv_iter = m_ecvs.begin();
    for ( ; ecv_iter != m_ecvs.end(); ecv_iter++)
    {
        JGVariable * var = (*ecv_iter).second;
        var->getv();
        if (var->changed())
        {
            this->notify(TRG_EQUIPMENT_CONSTANT, var, NULL);

            // m_equipment->sendEvent(this, EVT_EC_CHANGED, var);

            //JGvalue init_val(0);
            //m_ecvStatus->setv(init_val);      // Clear request
        }
    }

    return BEE_SUCCESS;
}


//-----------------------------------------------------------------------------
// Selected Equipment Status Request (S1F3 -> S1F4)
//-----------------------------------------------------------------------------
BS2Message * JGInfoManager::selEquipmentStatus(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::selEquipmentStatus");

    BS2Message * replymsg;
    vector<JGid> svidArray;
    int result = msg->getId(_TX("SVID"), svidArray);    // parse S1F3
    if (result < 0)
    {
        TRACE_ERROR((_TX("Received illegal message (%s).\n"),
                     msg->charName()));
        replymsg = new BS2S9F7Message(msg);
        return replymsg;
    }

    // Get and send status variables
    BS2ListItem * rootlist = new BS2ListItem;
    BS2Item * item;
    JGVariable * variable;
    if (result == 0)
    {   // All ststus variables
        JGVidTable::iterator sv_iter = m_svs.begin();
        for ( ; sv_iter != m_svs.end(); sv_iter++)
        {
            variable = (*sv_iter).second;
            BS2Atom * atom = variable->getAtom();
            BS2Assert(atom);
            item = BS2Item::factory(_TX("SV"), atom);
            rootlist->add(item);
        }
    }
    else
    {   // Status variables are requested by host
        for (size_t i = 0; i < svidArray.size(); i++)
        {
            variable = variableBySvid(svidArray[i]);
            if (variable != NULL)
            {
                BS2Atom * atom = variable->getAtom();
                BS2Assert(atom);
                item = BS2Item::factory(_TX("SV"), atom);
                rootlist->add(item);
            }
            else
            {   // As sv is not found, send length 0's item
                item = BS2Item::factory(_TX("SV"), new BS2Ascii);
                rootlist->add(item);
            }
        }
    }

    // Create reply message.
    replymsg = BS2Message::response(msg);
    BS2Assert(replymsg != NULL);
    replymsg->add(rootlist);

    return replymsg;
}

//-----------------------------------------------------------------------------
// Status Variable Namelist Request (S1F11 -> S1F12)
//-----------------------------------------------------------------------------
BS2Message * JGInfoManager::svNameList(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::svNameList");

    BS2Message * replymsg;
    vector<JGid> svidArray;
    int result = msg->getId(_TX("SVID"), svidArray);  // parse S1F11
    if (result < 0)
    {
        TRACE_ERROR((_TX("Received illegal message (%s).\n"),
                     msg->charName()));
        replymsg = new BS2S9F7Message(msg);
        return replymsg;
    }

    // Get and send status variables
    BS2ListItem * rootlist = new BS2ListItem;
    BS2Item * item;
    JGVariable * variable;
    if (result == 0)
    {   // All ststus variables
        JGVidTable::iterator sv_iter = m_svs.begin();
        for ( ; sv_iter != m_svs.end(); sv_iter++)
        {
            variable = (*sv_iter).second;
            item = variable->createNameItem();
            rootlist->add(item);
        }
    }
    else
    {   // Ststus variables are requested by host
        for (size_t i = 0; i < svidArray.size(); i++)
        {
            variable = variableBySvid(svidArray[i]);
            if (variable != NULL)
            {
                item = variable->createNameItem();
            }
            else
            {   // As sv is not found, send empty SVNAME and UNITS items
                item = variable->nilNameItem(svidArray[i]);
            }
            rootlist->add(item);
        }
    }

    // Create reply message.
    replymsg = BS2Message::response(msg);
    BS2Assert(replymsg != NULL);
    replymsg->add(rootlist);

    return replymsg;
}

//-----------------------------------------------------------------------------
// Equipment Constant Request (S2F13 -> S2F14)
//-----------------------------------------------------------------------------
BS2Message * JGInfoManager::equipmentConstant(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::equipmentConstant");

    BS2Message * replymsg;
    vector<JGid> ecidArray;
    int result = msg->getId(_TX("ECID"), ecidArray);  // parse S2F13
    if (result < 0)
    {
        TRACE_ERROR((_TX("Received illegal message (%s).\n"),
                     msg->charName()));
        replymsg = new BS2S9F7Message(msg);
        return replymsg;
    }

    // Get and send ststus variables
    BS2ListItem * rootlist = new BS2ListItem;
    BS2Item * item;
    JGVariable * variable;
    if (result == 0)
    {   // All equipment constants
        JGVidTable::iterator ecv_iter = m_ecvs.begin();
        for ( ; ecv_iter != m_ecvs.end(); ecv_iter++)
        {
            variable = (*ecv_iter).second;
            item = BS2Item::factory(_TX("ECV"), variable->getAtom());
            rootlist->add(item);
        }
    }
    else
    {   // Equipment constants are requested by host
        for (size_t i = 0; i < ecidArray.size(); i++)
        {
            variable = variableByEcid(ecidArray[i]);
            if (variable != NULL)
            {
                item = BS2Item::factory(_TX("ECV"), variable->getAtom());
                rootlist->add(item);
            }
            else
            {   // As ecv is not found, send length 0's item
                item = BS2Item::factory(_TX("ECV"), new BS2Ascii);
                rootlist->add(item);
            }
        }
    }

    // Create reply message.
    replymsg = BS2Message::response(msg);
    BS2Assert(replymsg != NULL);
    replymsg->add(rootlist);

    return replymsg;
}

//-----------------------------------------------------------------------------
// New Equipment Constant Send (S2F15 -> S2F16)
//-----------------------------------------------------------------------------
class _ParseEcv : public BS2Traverser
{
    friend class JGInfoManager;
public:
    _ParseEcv() {}
    virtual ~_ParseEcv() {}

    struct _EcvInfo
    {
        JGid    m_ecid;
        JGvalue m_value;
        JGVariable * m_var;
    };

    vector<_EcvInfo> m_args;

    virtual int parseItem(BS2Item * item) {
        _EcvInfo ecvinfo;
        JGVariable * variable;
        BS2Atom * atom = item->atom();
        if (item->name() == _TX("ECID"))
        {
            atom->get(ecvinfo.m_ecid);
            m_args.push_back(ecvinfo);
            variable = JGInfoManager::instance()->variableByEcid(ecvinfo.m_ecid);
            if (variable == NULL)
            {
                return -1;              // Variable is not found.
            }
            m_args.back().m_var = variable;
        }
        else if (item->name() == _TX("ECV"))
        {
            atom->get(m_args.back().m_value);
            variable = m_args.back().m_var;
            if (! variable->validValue(m_args.back().m_value,
                                       atom->format() & ~ATOM_ARRAY))
            {
                return -3;              // Invalid value of the variable.
            }
        }
        return 0;
    }
};

//-----------------------------------------------------------------------------
//
BS2Message * JGInfoManager::newEquipmentConstant(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::newEquipmentConstant");

    BYTE ack;
    BS2Message * replymsg;
    _ParseEcv req;

    int result = msg->traverse(&req);    // parse S2F15
    if (result < 0)
    {   // Create reply message (EAC is 1 or 3).
        ack = -result;            // Convert negative to positive
        replymsg = BS2Message::response(msg, ack, _TX("EAC"));
        return replymsg;
    }

    // New equipment constants set to variables
    ack = ACK_OK;
    for (size_t i = 0; i < req.m_args.size(); i++)
    {
        JGVariable * variable = req.m_args[i].m_var;
        variable->setv(req.m_args[i].m_value);
    }

    // Create reply message.
    replymsg = BS2Message::response(msg, ack, _TX("EAC"));
    return replymsg;
}

//-----------------------------------------------------------------------------
// Equipment Constant Request (S2F29 -> S2F30)
//-----------------------------------------------------------------------------
BS2Message * JGInfoManager::ecvNameList(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGInfoManager::ecvNameList");

    BS2Message * replymsg;
    vector<JGid> ecidArray;
    int result = msg->getId(_TX("ECID"), ecidArray);    // parse S2F29
    if (result < 0)
    {
        TRACE_ERROR((_TX("Received illegal message (%s).\n"),
                     msg->charName()));
        replymsg = new BS2S9F7Message(msg);
        return replymsg;
    }

    // Get and send ststus variables
    BS2ListItem * rootlist = new BS2ListItem;
    BS2Item * item;
    JGVariable * variable;
    if (result == 0)
    {   // All equipment constants
        JGVidTable::iterator ecv_iter = m_ecvs.begin();
        for ( ; ecv_iter != m_ecvs.end(); ecv_iter++)
        {
            variable = (*ecv_iter).second;
            item = variable->createEcvName();
            rootlist->add(item);
        }
    }
    else
    {   // Equipment constants are requested by host
        for (size_t i = 0; i < ecidArray.size(); i++)
        {
            variable = variableByEcid(ecidArray[i]);
            if (variable != NULL)
            {
                item = variable->createEcvName();
            }
            else
            {   // As ecv is not found, send length 0's item
                item = variable->nilEcvName(ecidArray[i]);
            }
            rootlist->add(item);
        }
    }

    // Create reply message.
    replymsg = BS2Message::response(msg);
    BS2Assert(replymsg != NULL);
    replymsg->add(rootlist);

    return replymsg;
}

//-----------------------------------------------------------------------------
// Thread of received message event.
//-----------------------------------------------------------------------------
BS2Message * JGInfoManager::msg_svc(JGMessageTrigger * trigger, BS2Message * msg)
{
    ACE_UNUSED_ARG(trigger);
    BS2Message * replymsg = NULL;

    if (msg->sf() == SFCODE(1,3))
    {
        replymsg = this->selEquipmentStatus(msg);
    }
    else if (msg->sf() == SFCODE(1,11))
    {
        replymsg = this->svNameList(msg);
    }
    else if (msg->sf() == SFCODE(2,13))
    {
        replymsg = this->equipmentConstant(msg);
    }
    else if (msg->sf() == SFCODE(2,15))
    {
        replymsg = this->newEquipmentConstant(msg);
    }
    else if (msg->sf() == SFCODE(2,17))
    {
        replymsg = JGTimeModule::instance()->getClock(msg);
    }
    else if (msg->sf() == SFCODE(2,29))
    {
        replymsg = this->ecvNameList(msg);
    }
    else if (msg->sf() == SFCODE(2,31))
    {   // Set system clock
        replymsg = JGTimeModule::instance()->setDateAndTime(msg);
    }
    else
    {   // Unexpected message
        replymsg = this->unrecognized(msg);
    }

    return replymsg;
}

