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

//=============================================================================
/**
 *  @file    JGProcess.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 "JGProcess.h"
#include "JGProcessManager.h"
#include "JGEquipment.h"
#include "JGInfoManager.h"
#include "JGTaskTrigger.h"
#include "BS2ACKMessage.h"
#include "BS2ListItem.h"
#include "BS2DeclAtoms.h"

/*
 * Process Manager's State Model Class
 */
OBJECT_STATE(JGProcessState, JGProcess, CATEGORY_PROCESS);
    // Terminate state
    EDGE_STATE_ID(Init, 1);
    EDGE_STATE_ID(Idle, 2);
    EDGE_STATE_ID(Setup, 3);
    EDGE_STATE_ID(Ready, 4);
    EDGE_STATE_ID_EX(Executing, 5);
    EDGE_STATE_ID(Complete, 6);
    EDGE_STATE_ID(Pause, 7);

END_ROOT_STATE();


//------------------------------------------------------------------------------
// State
//------------------------------------------------------------------------------
#define STATE_PROC      _TX("/PROC")
#define STATE_INIT      _TX("/PROC/INIT")
#define STATE_IDLE      _TX("/PROC/IDLE")
#define STATE_ACTIVE    _TX("/PROC/ACTIVE")
#define STATE_PROCESS   _TX("/PROC/ACTIVE/PROCESS")
#define STATE_SETUP     _TX("/PROC/ACTIVE/PROCESS/SETUP")
#define STATE_READY     _TX("/PROC/ACTIVE/PROCESS/READY")
#define STATE_EXECUTING _TX("/PROC/ACTIVE/PROCESS/EXECUTING")
#define STATE_COMPLETE  _TX("/PROC/ACTIVE/PROCESS/COMPLETE")
#define STATE_PAUSE     _TX("/PROC/ACTIVE/PAUSE")

// Instance base state
static FixState   _st_base(STATE_PROC, STATE_INIT);
static FixState   _st_active(STATE_ACTIVE, STATE_SETUP);
static HistState  _st_process(STATE_PROCESS, STATE_SETUP);
static JGProcessState::Init        _st_init(STATE_INIT);
static JGProcessState::Idle        _st_idle(STATE_IDLE);
static JGProcessState::Setup       _st_setup(STATE_SETUP);
static JGProcessState::Ready       _st_ready(STATE_READY);
static JGProcessState::Executing   _st_executing(STATE_EXECUTING);
static JGProcessState::Complete    _st_complete(STATE_COMPLETE);
static JGProcessState::Pause       _st_pause(STATE_PAUSE);

//------------------------------------------------------------------------------
//
//  Declare Transition Data of Process Manager
//
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
BEGIN_STATE_TABLE(JGProcessState);
    NEXT_TRANSITION(&JGStateTask::Root, TRIGGER_START, STATE_PROC, _TX("NULL"));
    NODE_TRANSITION(&_st_base, _TX("PROCESS BASE"));
    NODE_TRANSITION(&_st_active, _TX("ACTIVE"));
    NODE_TRANSITION(&_st_process, _TX("PROCESS"));
    NEXT_TRANSITION(&_st_init,
                    TRIGGER_INITIALIED,
                    STATE_IDLE,
                    _TX("INIT to IDLE"));
    NEXT_TRANSITION(&_st_idle,
                    TRIGGER_SETUP,
                    STATE_SETUP,
                    _TX("IDLE to SETUP"));
    NEXT_TRANSITION(&_st_setup,
                    TRIGGER_SELECT,
                    STATE_READY,
                    _TX("SETUP to READY"));
    NEXT_TRANSITION(&_st_ready,
                    TRIGGER_PROC_START,
                    STATE_EXECUTING,
                    _TX("READY to EXECUTING"));
    NEXT_TRANSITION(&_st_executing,
                    TRIGGER_COMPLETE,
                    STATE_COMPLETE,
                    _TX("EXECUTING to COMPLETE"));
    NEXT_TRANSITION(&_st_complete,
                    TRIGGER_STOP,
                    STATE_IDLE,
                    _TX("COMPLETE to IDLE"));
    NEXT_TRANSITION(&_st_active,
                    TRIGGER_STOP,
                    STATE_IDLE,
                    _TX("ACTIVE to IDLE"));
    NEXT_TRANSITION(&_st_active,
                    TRIGGER_ABORT,
                    STATE_IDLE,
                    _TX("ACTIVE to IDLE"));
    NEXT_TRANSITION(&_st_process,
                    TRIGGER_PAUSE,
                    STATE_PAUSE,
                    _TX("PROCESS to PAUSE"));
    NEXT_TRANSITION(&_st_pause,
                    TRIGGER_RESUME,
                    STATE_PROCESS,
                    _TX("PAUSE to PROCESS"));
END_STATE_TABLE();

//-----------------------------------------------------------------------------
// Action: Initial State
//-----------------------------------------------------------------------------
int JGProcessState::actInit(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actInit");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_STATE);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Action: Idle State
//-----------------------------------------------------------------------------
int JGProcessState::actIdle(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actIdle");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    if (trigger->name() == TRIGGER_STOP)
    {
        m_manager->sendEvent(EVT_PROC_STOPPED);
    }
    m_manager->sendEvent(EVT_PROC_STATE);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Action: Setup State
//-----------------------------------------------------------------------------
int JGProcessState::actSetup(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actSetup");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_STATE);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Action: Ready State
//-----------------------------------------------------------------------------
int JGProcessState::actReady(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actReady");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_STATE);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Action: Execute State
//-----------------------------------------------------------------------------
int JGProcessState::actExecuting(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actExecuting");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_START);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
int JGProcessState::endExecuting(JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::endExecuting");
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_COMPLETED);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Action: Complete State
//-----------------------------------------------------------------------------
int JGProcessState::actComplete(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actComplete");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_COMPLETED);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Action: Pause State
//-----------------------------------------------------------------------------
int JGProcessState::actPause(JGState * prev, JGTrigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::actPause");
    ACE_UNUSED_ARG(prev);
    ACE_UNUSED_ARG(trigger);

    m_manager->sendEvent(EVT_PROC_STATE);
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Unexpected event
//-----------------------------------------------------------------------------
int JGProcessState::unexpect(b_trigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcessState::unexpect");

    {
        this->b_context::unexpect(trigger);
    }

    return BEE_ERROR;
}

///////////////////////////////////////////////////////////////////////////////
//
// P R O C E S S
//
//
//-----------------------------------------------------------------------------
// Constructor/Destoructor
//-----------------------------------------------------------------------------
JGProcess::JGProcess(int id, const string& name) : JGManager(name), m_procid(id)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcess::JGProcess");
}


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

//    string varState = this->name();
//    varState += _TX(".");
//    varState += VAR_PROCESS_STATE;
    string varState = VAR_PROCESS_STATE;
    m_curProcStatus = m_equipment->variable(varState);

//    string varPrevState = this->name();
//    varPrevState += _TX(".");
//    varPrevState += VAR_PREV_PROCESS_STATE;
    string varPrevState = VAR_PREV_PROCESS_STATE;
    m_prevProcStatus = m_equipment->variable(VAR_PREV_PROCESS_STATE);
    m_savedState = _TX("UNKNOWN");
    m_prev = 0;

    // Initial State Model
    m_procState = new JGProcessState();
    m_procState->manager(this);
    m_procState->equipment(m_equipment);
    m_procState->init();         // initialized transitions
    // m_procState->open();      // start thread

    m_subsys = NULL;
    m_job = NULL;

    return BEE_SUCCESS;
}

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

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

    int result = BEE_SUCCESS;
    JGvalue numval(m_prev);             // Make previous status value
    m_prevProcStatus->setv(numval);

    if (category == TRG_EXECUTING)
    {   // make trigger from command variable.
        if (m_savedState == TRG_READY)
        {
            m_equipment->sendEvent(this, EVT_PROC_START);
        }
        else
        {
            m_equipment->sendEvent(this, EVT_PROC_STATE);
        }
    }
    else if (category == TRG_COMPLETE)
    {   // make trigger from command variable.
        if (m_savedState == TRG_EXECUTING)
        {
            m_equipment->sendEvent(this, EVT_PROC_COMPLETED);
        }
        else
        {
            m_equipment->sendEvent(this, EVT_PROC_STATE);
        }
        m_prev = (BYTE)(var->getv().getInt());
    }
    else if (category == TRG_IDLE)
    {   // make trigger from command variable.
        if (m_savedState != TRG_INIT)
        {
            m_equipment->sendEvent(this, EVT_PROC_STOPPED);
        }
        else
        {
            m_equipment->sendEvent(this, EVT_PROC_STATE);
        }
    }
    else if (category == TRG_INIT || category == TRG_SETUP ||
             category == TRG_READY || category == TRG_PAUSE)
    {   // make trigger from command variable.
        m_prevProcStatus->setv(numval);

        m_equipment->sendEvent(this, EVT_PROC_STATE);
    }
    else
    {
        TRACE_ERROR((_TX("Not implement: %s\n"), category.c_str()));
        result = BEE_ERROR;
    }
    m_savedState = category;
    m_prev = (BYTE)(var->getv().getInt());
    return result;
}

//-----------------------------------------------------------------------------
// Accept trigger from the variable.
//-----------------------------------------------------------------------------
int JGProcess::notify(JGService * rcmd)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcess::notify");

    return this->JGManager::notify(rcmd);
    
}

//----------------------------------------------------------------------------
// Is process active or not
//-----------------------------------------------------------------------------
bool JGProcess::isActive()
{
    TRACE_FUNCTION(TRL_LOW, "JGProcess::active");
    string stateValue = m_procState->current();

    int relat = strRelation(stateValue.c_str(), STATE_ACTIVE);
    if (relat == b_state::SAME_STATE || relat == b_state::ANCESTOR_STATE)
    {
        return true;
    }
    return false;
}

//----------------------------------------------------------------------------
// Check to be enable trigger or not
//-----------------------------------------------------------------------------
int JGProcess::enable(const string& trigName)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcess::enable");

    int result = m_procState->enable(trigName);
    if (result == -2)
    {
        return 2;    // 2 = CANNOT_PERFORM
    }
    else if (result < 0)
    {
        return 1;    // 1 = ILLEGAL_RCMD
    }
    return 0;
}


//-----------------------------------------------------------------------------
// Set current status.
//-----------------------------------------------------------------------------
int JGProcess::update(JGState * state)
{
    TRACE_FUNCTION(TRL_LOW, "JGProcess::update");
    m_prevProcStatus->setv(m_curProcStatus->getv());
    JGvalue value((BYTE)state->idx());
    m_curProcStatus->setv(value);
    return BEE_SUCCESS;
}

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

    {   // Unexpected message
        replymsg = this->unrecognized(msg);
    }

    return replymsg;
}

//-----------------------------------------------------------------------------
//
// Service of received message.
//
//-----------------------------------------------------------------------------
int JGProcess::rcmd_svc(JGService * trigger)
{
    ACE_UNUSED_ARG(trigger);

    int result = BEE_SUCCESS;
    if (m_hsmTask != NULL)
    {
        result = m_hsmTask->accept(trigger);
    }
    return result;
}
