// $Id: JGRecipeManager.cpp,v 1.16 2003/03/16 14:51:01 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGRecipeManager.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 "JGRecipeManager.h"
#include "JGEquipment.h"
#include "JGInfoManager.h"
#include "JGRecipeClass.h"
#include "JGRecipe.h"
#include "JGErrorList.h"
#include "JGSpecification.h"
#include "JGObject.h"
#include "JGAttrData.h"
#include "JGObjTraverser.h"
#include "JGObserver.h"
#include "JGTaskTrigger.h"
//#include "rms/RecipeExecutorModel.h"
//#include "rms/ExecutionRecipeModel.h"
#include "BS2ACKMessage.h"
#include "BS2ErrorMessage.h"
#include "BS2ListItem.h"
#include "BS2DeclAtoms.h"
#include "BS2Traverser.h"
#include  <stack>
using namespace std;

static JGRecipeManager * _manager = NULL;


class UnloadOperation : public JGOperationInfo
{
public:
    BS2ListItem * m_list;
    JGService * m_rcmd;
    JGErrorList m_errlist;
    string      m_rcpspec;

    UnloadOperation(JGServiceManager * mngr, BS2Message * msg)
            : JGOperationInfo(mngr, mngr->opid(), msg),
              m_errlist(_TX("RMACK"), ATOM_UINT1), m_rcpspec(_TX("")) {}
    virtual ~UnloadOperation() {}

    virtual void timeout()
    {
        ACE_DEBUG((LM_DEBUG, ACE_TEXT("Recipe Unload Service is timeout.\n")));
        this->makeNack(ERRCODE_BUSY);
        m_manager->send(m_msg);
    }
    virtual void call()
    {
        ACE_DEBUG((LM_DEBUG, ACE_TEXT("Recipe Unload Service is complete.\n")));
        string rcpbody(_TX(""));
        if (m_rcmd->m_obj != NULL)
        {
            b_objtype * klass = m_rcmd->m_obj->getObjType();
            if (klass->name() == OBJTYPE_RECIPE)
            //if (klass->name() == _TX("JYUGEM.Recipe")) // Name of application's class
            {
                JGRecipe * recipe = (JGRecipe *)m_rcmd->m_obj;
                JGAttrData * body = recipe->findData(_TX("Body"));
                //JGAttrData * body = recipe->findData(_TX("m_body"));
                rcpbody = body->get().toString();
            }
            else
            {
                ACE_ERROR((LM_ERROR, ACE_TEXT("Illegal ObjType (%s)\n"),
                           klass->name().c_str()));
            }
            // delete m_rcmd->m_obj;
        }
        m_list->add(BS2Item::factory(_TX("RCPSPEC"), new BS2Ascii(m_rcpspec)));
        m_list->add(new BS2ListItem);
        m_list->add(BS2Item::factory(_TX("RCPBODY"), new BS2Ascii(rcpbody)));
        m_list->add(m_errlist.makeItem());
        m_manager->send(m_msg);

        ACE_Proactor::instance()->cancel_timer(this->m_tmid);
    }

    BS2Message * makeNack(u_long errcode)
    {
        m_errlist.append(errcode);
        m_list->add(BS2Item::factory(_TX("RCPSPEC"), new BS2Ascii(m_rcpspec)));
        m_list->add(new BS2ListItem);
        m_list->add(BS2Item::factory(_TX("RCPBODY"), new BS2Ascii()));
        m_list->add(m_errlist.makeItem());
        return m_msg;
    }
};


class RecipeAssistant : public JGTask
{
public:
    RecipeAssistant() : JGTask(CATEGORY_RECIPE) {}
};

//-----------------------------------------------------------------------------
//
// Parse request recipe parameter
//
//-----------------------------------------------------------------------------
class RecipeNotify : public JGTriggerRequest
{
    friend class JGRecipeManager;
public:
    RecipeNotify(JGService * rcmd, JGRecipeManager * mngr)
            : JGTriggerRequest((JGTrigger *)rcmd, (JGTask *)mngr) {}

    virtual int call()
    {
            TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::RecipeNotify::call");
            JGRecipeManager * mngr = (JGRecipeManager *)m_task;
            auto_ptr<JGService> rcmd((JGService *)m_trigger);

            JGvalue nameval;
            bool isExist = rcmd->getValue(_TX("Name"), nameval);
            TRACE_DEBUG((_TX("Changed recipe(%s)\n"),
                        (isExist) ? nameval.toString().c_str(): "Unknown"));
            if (! isExist)
            {
                return 0;           // Ignore request
            }

            BYTE st;
            if (rcmd->m_subject == "Delete")
            {
                // if same recipe is not exist then ignore recipe
                // JGid rcpid(nameval);
                // int result = mnger->erase(rcpid);
                // if (result < 0)
                // {
                //    return 0;          // Ignore !? (case to delete is request by host)
                // }
                st = JGRecipe::DELETED;
            }
            else if (rcmd->m_subject == "Create")
            {
                // if same recipe is not exist then create the recipe
                // JGRecipe * recipe = mngr->m_rcptype->instance(nameval.toString().c_str());
                // mngr->entry(recipe);

                st = JGRecipe::CREATED;
            }
            else if (rcmd->m_subject == "Upload")
            {
                if (rcmd->isResponse())
                {
                    UnloadOperation * unlOpe = (UnloadOperation *)mngr->findOperation(rcmd->getRequestID());
                    if (unlOpe != NULL)
                    {
                        unlOpe->m_rcmd = rcmd.get();
                        unlOpe->call();  // Send S15F32
                        mngr->removeOperation(rcmd->getRequestID());
                    }
                    else
                    {
                        TRACE_ERROR((_TX("Recipe's indicator is not found(%s: %d)\n"),
                            (isExist) ? nameval.toString().c_str() : "Unknown",
                            rcmd->getRequestID()));

                    }
                }
                return 0;   // Ignore
            }
            else if (rcmd->m_subject == "Update")
            {
                st = JGRecipe::UPDATED;
            }
            else if (rcmd->m_subject == "Verified")
            {
                st = JGRecipe::VERIFIED;
            }
            else if (rcmd->m_subject == "Selected")
            {
                st = JGRecipe::SELECTED;
            }
            else if (rcmd->m_subject == "Deselected")
            {
                st = JGRecipe::DESELECTED;
            }
            else
            {
                TRACE_DEBUG((_TX("Illegal Changed Status(%s)\n"),
                            rcmd->m_subject.c_str()));
                return 0;   // Ignore
            }

            // Set DVVAL
            mngr->m_changed->setv(nameval);
            JGvalue stval(st);
            mngr->m_chgStatus->setv(stval);

            // S6F11 (CEID = RECIPE-CHANGED)
            mngr->equipment()->sendEvent(mngr, EVT_RECIPE_STATUS);

            return 0;
        }
};

//-----------------------------------------------------------------------------
//
// Parse request recipe parameter
//
//-----------------------------------------------------------------------------
class RecipeParam : public BS2Traverser
{
public:
    RecipeParam(JGSpecification * spec) : BS2Traverser(), m_env(spec) {
            m_errs.set(_TX("RMACK"), ATOM_UINT1);
        }
    virtual ~RecipeParam() {}

    JGSpecification * m_env;
    JGErrorList m_errs;
    string      m_respec;
    JGid        m_dataid;

    // RecipeExecutor(= Object) specification
    int checkRespec(BS2Atom * atom) {
        TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::RecipeParam::checkRespec");
        m_respec = ((BS2Ascii *)atom)->value();
        if (m_respec.size() > 0 && m_env->name() != m_respec)
        {
            TRACE_ERROR(("Unexpect RESPEC name\n"));
            m_errs.append(ERRCODE_INVALID_PARAMETER, m_respec);
            return -1;
        }
        return 0;
    }

};

//-----------------------------------------------------------------------------
// Constructor/Destructor
//-----------------------------------------------------------------------------
JGRecipeManager::JGRecipeManager() : JGServiceManager(CATEGORY_RECIPE)
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGRecipeManager::JGRecipeManager");
    m_assistant = new RecipeAssistant();
}

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

}

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

//-----------------------------------------------------------------------------
// Initialize
//-----------------------------------------------------------------------------
int JGRecipeManager::init(void * parm)
{
    TRACE_FUNCTION(TRL_MIDDLE, "JGRecipeManager::save");
    ACE_UNUSED_ARG(parm);

    m_changed = m_equipment->variable(VAR_RCP_CHANGE_NAME);
    m_chgStatus = m_equipment->variable(VAR_RCP_CHANGE_STATUS);

    m_env = (JGSpecification *)ObjSpec::instance();

    m_rcptype = new JGRecipeClass();
    m_rcptype->init();

    if (m_assistant != NULL)
    {
        m_assistant->open();
    }

    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Entry the recipe
//-----------------------------------------------------------------------------
int JGRecipeManager::entry(JGRecipe * recipe)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::entry");

    JGid rcpid = recipe->rcpid();
    m_recipes.insert(JGRecipePair(rcpid, recipe));
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Find the recipe
//-----------------------------------------------------------------------------
JGRecipe * JGRecipeManager::find(JGid& rcpid)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::find");

    JGRecipe * recipe;
    JGRecipeTable::iterator iter = m_recipes.find(rcpid);
    if (iter == m_recipes.end())
    {
        return NULL;
    }
    recipe = (*iter).second;
    return recipe;
}

//-----------------------------------------------------------------------------
// Find the recipe
//-----------------------------------------------------------------------------
int JGRecipeManager::erase(JGid& rcpid)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::find");

    JGRecipe * recipe;
    JGRecipeTable::iterator iter = m_recipes.find(rcpid);
    if (iter == m_recipes.end())
    {
        return BEE_ERROR;
    }
    recipe = (*iter).second;
    delete recipe;
    m_recipes.erase(iter);
    return BEE_SUCCESS;
}

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

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

    string recipeName;
    JGRecipe * recipe;
    JGid rcpid;
    if (category == TRID_RECIPE)
    {
        int status = var->getv().getInt();
        if (status == JGRecipe::CREATED)
        {
            m_changed->getv().get(recipeName);
            rcpid = recipeName;
            recipe = this->find(recipeName);    // check of duplicate name
            if (recipe != NULL)
            {
                TRACE_ERROR((_TX("Recipe is duplicate %s.\n"),
                            recipeName.c_str()));
                return BEE_ERROR;
            }
            recipe = reinterpret_cast<JGRecipe *>(m_rcptype->instance(recipeName.c_str()));
            this->entry(recipe);

            //
            // Notify recipe created
            //

            // Send S6F11
            m_equipment->sendEvent(this, EVT_RECIPE_NEW);
        }
        else
        {
            m_changed->getv().get(recipeName);
            recipe = this->find(recipeName);    // check of duplicate name
            if (recipe == NULL)
            {
                TRACE_ERROR((_TX("Recipe is not found by %s.\n"),
                             m_changed->charName()));
                return BEE_ERROR;
            }
            rcpid = recipe->rcpid();
            // Send S6F11
            m_equipment->sendEvent(this, EVT_RECIPE_STATUS);
        }

    }
    else if (category == TRID_RECIPE_EXEC)
    {
        TRACE_ERROR((_TX("Not implement: %s\n"), category.c_str()));
        return BEE_ERROR;
    }
    else
    {
        TRACE_ERROR((_TX("Not implement: %s\n"), category.c_str()));
        return BEE_ERROR;
    }
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
int JGRecipeManager::notify(JGTrigger * command)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::notify");

    RecipeNotify * rcpnote = new RecipeNotify((JGService *)command, this);

    this->JGManager::put(rcpnote);

    return 0;
}

//-----------------------------------------------------------------------------
// Delete Recipe (S15F35 -> S15F36)
//-----------------------------------------------------------------------------
class DelRecipeParam : public RecipeParam
{
public:
    DelRecipeParam(JGSpecification * spec) : RecipeParam(spec) {}
    virtual ~DelRecipeParam() {}

    int    m_rcpdel;
    vector<JGid> m_ids;

    //
    virtual int parseItem(BS2Item * item) {
        TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::remove::parseItem");
        BS2Atom * atom = item->atom();
        int result = 0;
        if (item->name() == _TX("RCPID"))
        {
            JGid rcpid;
            atom->get(rcpid);
            m_ids.push_back(rcpid);
        }
        else if (item->name() == _TX("RESPEC"))
        {
            result = this->checkRespec(atom);
        }
        else if (item->name() == _TX("RCPDEL"))
        {
            m_rcpdel = ((BS2UInt1 *)atom)->value();
        }
        else if (item->name() == _TX("DATAID"))
        {
             atom->get(m_dataid);
        }
        return 0;
    }
};

//-----------------------------------------------------------------------------
BS2Message * JGRecipeManager::remove(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::remove");

    // Create reply message.
    BS2Message * replymsg = BS2Message::response(msg);

    DelRecipeParam delinfo(m_env);
    int result = msg->traverse(&delinfo);    // parse S15F35
    if (result < 0)
    {
        replymsg->add(delinfo.m_errs.makeItem());
        return replymsg;
    }

    if (delinfo.m_ids.size() == 0)
    {   // all recipe
        if (delinfo.m_rcpdel == DELETE_)
        {
            //
            // Notify recipe command (Delete)
            //
        }
        else
        {
            //
            // Notify recipe command (Deselect)
            //
        }
    }
    else
    {
        for (size_t i = 0; i < delinfo.m_ids.size(); i++)
        {
            JGRecipe * recipe = this->find(delinfo.m_ids[i]);
            if (recipe == NULL)
            {   // Not found
                delinfo.m_errs.append(ERRCODE_UNKNOWN_OBJECT_INSTANCE,
                                         delinfo.m_ids[i].toString());
            }
        }
        // Reply error message
        if (delinfo.m_errs.count() > 0)
        {
            replymsg->add(delinfo.m_errs.makeItem());
            return replymsg;
        }

        // Delete recipes
        for (size_t j = 0; j < delinfo.m_ids.size(); j++)
        {
            if (delinfo.m_rcpdel == DELETE_)
            {
                //
                // Notify recipe command (Delete by id)
                //
            }
            else
            {
                //
                // Notify recipe command (Deselect by id)
                //
            }
        }
    }

    // Set ack code
    replymsg->add(delinfo.m_errs.makeItem());
    return replymsg;
}

//-----------------------------------------------------------------------------
// Unload Recipe (S15F31 -> S15F32)
//-----------------------------------------------------------------------------
BS2Message * JGRecipeManager::unload(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::unload");

    BS2ListItem * rootlist = new BS2ListItem;
    BS2Message * replymsg = BS2Message::response(msg);
    replymsg->add(rootlist);

    // Get Operation id
    UnloadOperation * ope = new UnloadOperation(this, replymsg);
    ope->m_list = rootlist;

    BS2Atom * atom = msg->getAtom(_TX("RCPSPEC"));
    if (atom == NULL)
    {
        replymsg = ope->makeNack(ERRCODE_ILLEGAL_RECIPE);
        delete ope;
        return replymsg;
    }

    ope->m_rcpspec = ((BS2Ascii *)atom)->value();

    // Get recipe attribute
    JGRecipe * recipe = this->find(ope->m_rcpspec);
    if (recipe == NULL)
    {   // The recipe is not found.
        replymsg = ope->makeNack(ERRCODE_UNKNOWN_OBJECT_INSTANCE);
        delete ope;
        return replymsg;
    }

    //
    // Watchdog timer start
    //
    this->entryOperation(ope);

#if 1
    JGService * rcmd = new JGService(_TX("Upload"), NULL, _TX("RECIPE-EXEC"), CATEGORY_RECIPE);
    rcmd->setRequestID(ope->m_opid);
    JGvalue rcpid(ope->m_rcpspec);
    rcmd->add(_TX("Name"), rcpid);    // Set Recipe Name
    m_observer->notify(rcmd);
#endif

    return NULL;
}

//-----------------------------------------------------------------------------
// Download Recipe (S15F27 -> S15F28)
//-----------------------------------------------------------------------------
class DownloadRecipeParm : public JGObjTraverser
{
    friend class JGRecipeManager;
public:
    DownloadRecipeParm(JGManager * mngr, JGClass * klass)
        : JGObjTraverser(mngr, klass, _TX("RMACK"), ATOM_UINT1) {}
    virtual ~DownloadRecipeParm() {}

    string  m_rcpspec;
    bool    m_rcpowcode;
    JGid    m_dataid;

    virtual int parseItem(BS2Item * item) {
        TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::download::parseItem");

        BS2Atom * atom = item->atom();
        if (item->name() ==  _TX("RCPATTRID"))
        {
            // TRACE_DEBUG((_TX("%s : %d\n"), atom->toString().c_str(), m_nest));
            m_setter.setID((JGid&)atom->getValue(), m_nest);
        }
        else if (item->name() == _TX("RCPATTRDATA"))
        {
            m_setter.setData(atom->getValue(), m_nest);
        }
        else if (item->name() == _TX("RCPBODY"))
        {
            if (atom->isAscii() || atom->isBinary())
            {
                JGAttrData * rcpbody = (JGAttrData *)(m_object->findData("Body"));
                if (rcpbody == NULL)
                {
                    TRACE_ERROR((_TX("Can't find RCPBODY variable.\n")));
                    m_errs.append(ERRCODE_INVALID_PARAMETER, _TX("RCPBODY"));
                    return -1;
                }
                atom->b_value::get(*rcpbody);
            }
            else
            {
                TRACE_ERROR(("Unexpect RCPBODY format\n"));
                m_errs.append(ERRCODE_INVALID_PARAMETER, _TX("RCPBODY"));
                return -1;
            }
        }
        else if (item->name() == _TX("RCPSPEC"))
        {   // RCPSPEC = recipe class
            m_rcpspec = ((BS2Ascii *)atom)->value();

            m_object = (JGObject *)m_clazz->findObject(m_rcpspec);
            if (m_object != NULL && (! m_rcpowcode))
            {
                 m_errs.append(ERRCODE_IDENTIFIER_USED);
                 return -1;
            }
            else if (m_object != NULL)
            {   // Delete old & Create new recipe
                JGRecipe * oldRecipe = (JGRecipe *)m_object;
                JGid rcpid = oldRecipe->rcpid();
                ((JGRecipeManager *)m_manager)->erase(rcpid);
                m_object = m_clazz->instance(m_rcpspec);
            }
            else if (m_object == NULL)
            {   // Create new recipe
                m_object = m_clazz->instance(m_rcpspec);
            }
            m_setter = m_object->start(&m_errs);

        }
        else if (item->name() == _TX("RCPOWCODE"))
        {
            m_rcpowcode = ((BS2Boolean *)atom)->value();
        }
        else if (item->name() == _TX("DATAID"))
        {
            atom->get(m_dataid);
        }
        return 0;
    }
};

//-----------------------------------------------------------------------------
BS2Message * JGRecipeManager::download(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::download");

    // Create reply message.
    BS2Message * replymsg = BS2Message::response(msg);
    BS2ListItem * rootlist = new BS2ListItem;
    replymsg->add(rootlist);

    DownloadRecipeParm dwinfo(this, m_rcptype);
    int result = msg->traverse(&dwinfo);    // parse S15F27
    if (result < 0)
    {
        if (dwinfo.m_object != NULL)
        {
            delete dwinfo.m_object;
        }
        rootlist->add(BS2Item::factory(_TX("RCPID"),
                                       new BS2Ascii(dwinfo.m_rcpspec)));
        rootlist->add(new BS2ListItem);
        rootlist->add(dwinfo.m_errs.makeItem());
        return replymsg;
    }

    JGRecipe * recipe = (JGRecipe *)dwinfo.m_object;
    TRACE_DEBUG((_TX("RCPID = %s\n"), recipe->rcpid().toString().c_str()));

    this->entry(recipe);  // Need response from recipe executor

    //
    // Send recipe body & attribute to executor
    //
#if 1
    JGService * rcmd = new JGService(_TX("Create"), recipe, _TX("RECIPE-EXEC"), CATEGORY_RECIPE);
    m_observer->notify(rcmd);
#endif
    //
    // Wait responce
    //
    rootlist->add(BS2Item::factory(_TX("RCPID"),
                                   new BS2Ascii(recipe->rcpid().toString())));
    rootlist->add(recipe->makeAttrList());
    // Set ack code
    rootlist->add(dwinfo.m_errs.makeItem());

    return replymsg;
}

//-----------------------------------------------------------------------------
// Verify Recipe (S15F29 -> S15F30)
//-----------------------------------------------------------------------------
class VerifyRecipeParam : public RecipeParam
{
public:
    VerifyRecipeParam(JGSpecification * spec) : RecipeParam(spec) {}
    virtual ~VerifyRecipeParam() {}

    JGid         m_opid;
    vector<JGid> m_ids;

    //
    virtual int parseItem(BS2Item * item) {
        TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::verify::parseItem");
        BS2Atom * atom = item->atom();
        int result = 0;
        if (item->name() == _TX("RCPID"))
        {
            JGid rcpid;
            atom->get(rcpid);
            m_ids.push_back(rcpid);
        }
        else if (item->name() == _TX("OPID"))
        {
            atom->get(m_opid);
        }
        else if (item->name() == _TX("RESPEC"))
        {   //
            result = checkRespec(atom);
        }
        return result;
    }

    //
    // Set items in reply message when was error
    void makeErrorReply(BS2Message * replymsg, BS2ListItem * rootlist) {
        rootlist->add(BS2Item::factory(_TX("OPID"), m_opid));
        rootlist->add(BS2Item::factory(_TX("LINKID"), new BS2UInt4(0)));
        rootlist->add(BS2Item::factory(_TX("RCPID"),
                      new BS2Ascii(m_respec)));
        rootlist->add(new BS2ListItem);
        replymsg->add(m_errs.makeItem());
    }

};

//-----------------------------------------------------------------------------
BS2Message * JGRecipeManager::verify(BS2Message * msg)
{
    TRACE_FUNCTION(TRL_LOW, "JGRecipeManager::verify");

    // Create reply message.
    BS2Message * replymsg = BS2Message::response(msg);
    BS2ListItem * rootlist = new BS2ListItem;
    replymsg->add(rootlist);

    VerifyRecipeParam vrfinfo(m_env);
    int result = msg->traverse(&vrfinfo);    // parse S15F29
    if (result < 0)
    {
        vrfinfo.makeErrorReply(replymsg, rootlist);
        return replymsg;
    }

    // Check recipe count
    if (vrfinfo.m_ids.size() != 1)
    {   // Not support plural recipe
        TRACE_ERROR((_TX("Received plural recipe\n")));
        vrfinfo.makeErrorReply(replymsg, rootlist);
        return replymsg;
    }

    u_int linkid = 0;
    BS2Item * attritem;
    BS2Atom * rcpidAtom;
    JGRecipe * recipe;
    if (vrfinfo.m_ids.size() == 1)
    {   // Verify a recipe
        recipe = this->find(vrfinfo.m_ids[0]);
        if (recipe != NULL)
        {   // find recipe id

            //
            // Verify recipe in recipe executor
            //

            rcpidAtom = BS2Atom::factory(recipe->rcpid());
            JGRecipe * userRecipe;
            // userRecipe = m_executor->find(vrfinfo.m_ids[0]);
            // int result = m_executor->verify(vrfinfo.m_ids[0]);
            // find & verify
            int result = 0;  // #### dummy statement ####
            if (result >= 0)
            {   // verify OK
                ////////////////////////////
                // Get current recipe data
                // recipe->set(userRecipe);
                attritem = userRecipe->makeAttrList();   // Make Attrubute Data
                delete userRecipe;
            }
            else
            {   // verify NG
                vrfinfo.m_errs.append(ERRCODE_VERIFICATION_ERROR);
            }
        }
        else
        {
            vrfinfo.m_errs.append(ERRCODE_UNKNOWN_OBJECT_INSTANCE);
            rcpidAtom = BS2Atom::factory(vrfinfo.m_ids[0]);
            attritem = new BS2ListItem;
        }
    }
#if 0
    else if (vrfinfo.m_ids.size() == 0)
    {   // all recipe
        // Not support, yet.
    }
    else
    {   // rcpid count > 1
        // Not support, yet.
    }
#endif

    // Create reply message
    rootlist->add(BS2Item::factory(_TX("LINKID"), new BS2UInt4(linkid)));
    rootlist->add(BS2Item::factory(_TX("RCPID"), rcpidAtom));
    rootlist->add(attritem);

    // Set ack code
    replymsg->add(vrfinfo.m_errs.makeItem());
    return replymsg;
}


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

    if (msg->sf() == SFCODE(15,35))
    {   // delete rquest
        replymsg = this->remove(msg);
    }
    else if (msg->sf() == SFCODE(15,31))
    {   // upload request
        replymsg = this->unload(msg);
    }
    else if (msg->sf() == SFCODE(15,27))
    {   // download request
        replymsg = this->download(msg);
    }
    else if (msg->sf() == SFCODE(15,29))
    {   // verify request
        replymsg = this->verify(msg);
    }
#if 0   // dispatch to JGObjectManager
    else if (msg->sf() == SFCODE(14,1))
    {   // GetAttr (recipe names)
    }
#endif
    else
    {
        replymsg = this->unrecognized(msg);
    }

    return replymsg;
}


