// $Id: JGManager.cpp,v 1.3 2003/03/16 14:51:00 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGManager.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 "JGManager.h"
#include "JGEquipment.h"
#include "JGTaskTrigger.h"
#include "JGTask.h"
#include "JGCommDevice.h"
#include "BS2ErrorMessage.h"
#include "BS2DeclAtoms.h"

typedef map<string, JGManager *, str_less, allocator<JGManager *> >
        ManagerMap;
typedef ManagerMap::value_type ManagerPair;

static ManagerMap _managers;
static ACE_Thread_Mutex _mutex;

static MUTEX_UInt _dataid = 1;

//-----------------------------------------------------------------------------
// Constructor/Destructor
//-----------------------------------------------------------------------------
JGManager::JGManager(const string& name) : JGTask(name), m_hsmTask(NULL)
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGManager::JGManager");
    _mutex.acquire();            // Lock
    _managers.insert(ManagerPair(name, this));
    _mutex.release();           // Unlock
}

//-----------------------------------------------------------------------------
JGManager::~JGManager()
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGManager::~JGManager");
    _mutex.acquire();            // Lock
    ManagerMap::iterator iter = _managers.find(m_program);
    if (iter != _managers.end())
    {
        _managers.erase(iter);
    }
    _mutex.release();           // Unlock
}

//-----------------------------------------------------------------------------
// Global access to Managers.
//-----------------------------------------------------------------------------
JGManager * JGManager::instance(const string& mngrName)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::instance");
    _mutex.acquire();            // Lock
    JGManager * result = _managers[mngrName];
    _mutex.release();           // Unlock
    return result;
}

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

    TRACE_ERROR(("Abstruct method.\n"));

    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Open a service thread.
//-----------------------------------------------------------------------------
int JGManager::open(void * parm)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::open");
    ACE_UNUSED_ARG(parm);

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

//-----------------------------------------------------------------------------
// Close .
//-----------------------------------------------------------------------------
int JGManager::close(int flag)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::close");
    ACE_UNUSED_ARG(flag);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Change state.
//-----------------------------------------------------------------------------
int JGManager::notify(JGTrigger * trig)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::notify(JGTrigger)");

    JGNotifyTrigger * notify = (JGNotifyTrigger *)trig;
    return this->put(new JGNotifyRequest(notify, this));
}

//-----------------------------------------------------------------------------
int JGManager::notify(const string& trig)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::notify(string)");

    JGNotifyTrigger * notify = new JGNotifyTrigger(trig);
    return this->put(new JGNotifyRequest(notify, this));
}

//-----------------------------------------------------------------------------
int JGManager::notify(const string& category, JGVariable * var,
                      void * arg)
{
    TRACE_FUNCTION(TRL_HIGH, "JGManager::notify(string, var, void)");

    JGDeviceRequest * devReq = new JGDeviceRequest(category, var, arg, this);
    return this->put(devReq);
}

//-----------------------------------------------------------------------------
int JGManager::notify(BS2MessageInfo& msginfo)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::notify(BS2MessageInfo)");

    JGMessageRequest * msgReq = new JGMessageRequest(msginfo, this);
    return this->put(msgReq);
}

//-----------------------------------------------------------------------------
int JGManager::notify(JGService * rcmd)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::notify(JGService)");

    JGRemoteRequest * rcmdReq = new JGRemoteRequest(rcmd, this);
    return this->put(rcmdReq);
}


//-----------------------------------------------------------------------------
// Send message.
//-----------------------------------------------------------------------------
int JGManager::send(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::send");

    int trans_id = m_device->send(msg, this);  // *** Send SECS Message ***
    if (trans_id > 0)
    {
         ;
    }
    delete msg;                                // *** Delete SECS Message ***
    return trans_id;
}

//-----------------------------------------------------------------------------
// Send message.
//-----------------------------------------------------------------------------
int JGManager::sendEvent(const string& evtid, JGVariable * arg)
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::sendEvent");

    int result = m_equipment->sendEvent(this, evtid, arg);
    return result;
}

//-----------------------------------------------------------------------------
//  Make unrecognized message
//-----------------------------------------------------------------------------
BS2Message * JGManager::unrecognized(BS2Message * msg)
{
    BS2Message * replymsg = NULL;
    ACE_ERROR((LM_ERROR,
              ACE_TEXT("(%t) %s manager is not support message (%s).\n"),
              this->charName(), msg->charName()));
    if (msg->isPrimary() && msg->reply())
    {
        replymsg = new BS2S9F3Message(msg);
    }
    return replymsg;
}

//-----------------------------------------------------------------------------
//  Make unrecognized message
//-----------------------------------------------------------------------------
BS2Item * JGManager::getDataID()
{
    TRACE_FUNCTION(TRL_LOW, "JGManager::getDataID");

    u_int data_id = _dataid++;
    BS2Atom * atom = new BS2UInt4(data_id);
    BS2Item * item = BS2Item::factory(_TX("DATAID"), atom);
    return item;
}


//-----------------------------------------------------------------------------
//
// Service thread.
//
//-----------------------------------------------------------------------------
int JGManager::svc(void)
{
    int result = 0;

    // Receive trigger request.
    for (;;)
    {
        auto_ptr<ACE_Method_Request> mo(this->m_activation_queue.dequeue());

        // Call it.
        if ((result = mo->call()) == -1)
        {
            break;
        }

        // Destructor automatically deletes it.
    }

    if (result == -1 && errno == EWOULDBLOCK)
    {
        ACE_ERROR((LM_ERROR,
              ACE_TEXT("(%t) %p\n"), "timed out waiting for message"));
    }

    // ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%t) %s::svc end.\n"), this->charName()));
    return 0;
}

//-----------------------------------------------------------------------------
// Parser of SECS message event.
//-----------------------------------------------------------------------------
BS2Message * JGManager::msg_svc(JGMessageTrigger * trigger, BS2Message * msg)
{
    ACE_UNUSED_ARG(msg);
    BS2Message * replymsg = NULL;

    ACE_DEBUG((LM_DEBUG, ACE_TEXT("%s: manager is received message[%s].\n"),
                         this->charName(), trigger->charName()));
    if (m_hsmTask != NULL)
    {
        m_hsmTask->accept(trigger);
    }
    return replymsg;
}

//-----------------------------------------------------------------------------
// I/O device event.
//-----------------------------------------------------------------------------
int JGManager::device_svc(JGDeviceTrigger * trigger)
{
    // ACE_DEBUG((LM_DEBUG, ACE_TEXT("%s: device changes status[%s].\n"),
    //                      this->charName(), trigger->charName()));
    int result = BEE_SUCCESS;
    if (m_hsmTask != NULL)
    {
        result = m_hsmTask->accept(trigger);
    }
    return result;
}

//-----------------------------------------------------------------------------
// Parser of status event.
//-----------------------------------------------------------------------------
int JGManager::notify_svc(JGNotifyTrigger * trigger)
{
    // ACE_DEBUG((LM_DEBUG, ACE_TEXT("%s: notify [%s].\n"),
    //                      this->charName(), trigger->charName()));
    int result = BEE_SUCCESS;
    if (m_hsmTask != NULL)
    {
        result = m_hsmTask->accept(trigger);
    }
    return result;
}

//-----------------------------------------------------------------------------
// Parser of operator event.
//-----------------------------------------------------------------------------
int JGManager::ope_svc(JGOperatorTrigger * trigger)
{
    // ACE_DEBUG((LM_DEBUG, ACE_TEXT("%s: operation[%s].\n"),
    //                      this->charName(), trigger->charName()));
    int result = BEE_SUCCESS;
    if (m_hsmTask != NULL)
    {
        result = m_hsmTask->accept(trigger);
    }
    return result;
}

//-----------------------------------------------------------------------------
// Parser of remote command event.
//-----------------------------------------------------------------------------
int JGManager::rcmd_svc(JGService * trigger)
{
    // ACE_DEBUG((LM_DEBUG, ACE_TEXT("%s: remote command[%s].\n"),
    //                      this->charName(), trigger->charName()));
    int result = BEE_SUCCESS;
    if (m_hsmTask != NULL)
    {
        result = m_hsmTask->accept(trigger);
    }
    return result;
}

