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

//=============================================================================
/**
 *  @file    eventCmd.cpp
 *
 *  @author  Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 2002 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

#ifdef _MSC_VER
#pragma warning(disable: 4786)  // too long identifier
#endif

#include "JGEquipment.h"
#include "JGInfoManager.h"
#include "JGEventManager.h"
#include "tclbee.h"

#ifdef _MSC_VER
#include <windows.h>
#endif

// function prototype
static int dump_events(Tcl_Interp * interp);
static int set_event(Tcl_Interp * interp, JGEvent * event, int argc,
                     Tcl_Obj * CONST objv[]);
static JGEvent * find_event(Tcl_Interp * interp, char * ceidStr);
static int parse_rptids(Tcl_Interp * interp, char * idsStr, vector<BS2id>& ids);
static int add_reports(Tcl_Interp * interp, JGEvent * event,
                       char * idsStr);
static int del_reports(Tcl_Interp * interp, JGEvent * event,
                       char * idsStr);

/*
 *----------------------------------------------------------------------
 *
 * Gem_eventCmd --
 *
 *      This procedure is invoked to process the "gem::event"
 *      command. See the user documentation for details on what it does.
 *
 * Results:
 *      A standard Tcl result.
 *
 * Side effects:
 *      See the user documentation.
 *
 *----------------------------------------------------------------------
 */

    /* ARGSUSED */
int
Gem_eventCmd(ClientData , Tcl_Interp * interp, int objc,
              Tcl_Obj *CONST objv[])
{
    static char *gemcmds[] = {
        "init",
        "set",
        "get",
        "add",
        "del",
        "dump",
        NULL
    };
    /*
     * All commands enums below ending in X are compatibility
     */
    enum gemcmds {
        GEMCMD_INIT,
        GEMCMD_SET,
        GEMCMD_GET,
        GEMCMD_ADD,
        GEMCMD_DEL,
        GEMCMD_DUMP,
    };

    Tcl_Obj * res;
    int     cmdindex, result;
    JGEvent * event;
    string  buf;

    Tcl_ResetResult(interp);
    result = TCL_OK;

    /*
     * Get the command name index from the object based on the spoolcmds
     * defined above.
     */
    if (Tcl_GetIndexFromObj(interp,
        objv[1], (const char **)gemcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
        return TCL_ERROR;

    if (objc >= 3)
    {
        // Find variable by ceidStr
        event = find_event(interp, Tcl_GetStringFromObj(objv[2], NULL));
        if (event == NULL)
        {
            return TCL_ERROR;
        }
    }

    res = NULL;
    switch ((enum gemcmds)cmdindex) {
    case GEMCMD_INIT:
        break;
    case GEMCMD_SET:
        if (objc < 3)
        {
            Tcl_WrongNumArgs(interp, 2, objv, "ceid ?args ?");
            return TCL_ERROR;
        }

        // Convert string to value
        set_event(interp, event, objc - 3, &objv[3]);

        break;
    case GEMCMD_GET:
        if (objc != 3)
        {
            Tcl_WrongNumArgs(interp, 2, objv, "ceid");
            return TCL_ERROR;
        }
        Tcl_AppendResult(interp, (event->enabled()) ? "true" : "false", NULL);
        break;

    case GEMCMD_ADD:
        if (objc != 4)
        {
            Tcl_WrongNumArgs(interp, 2, objv, "ceid reports");
            return TCL_ERROR;
        }
        result = add_reports(interp, event,
                             Tcl_GetStringFromObj(objv[3], NULL));
        break;

    case GEMCMD_DEL:
        if (objc == 3)
        {
            event->clearReports();
        }
        else if (objc == 4)
        {
            result = del_reports(interp, event,
                                 Tcl_GetStringFromObj(objv[3], NULL));
        }
        else
        {
            Tcl_WrongNumArgs(interp, 2, objv, "ceid ?reports ?");
            return TCL_ERROR;
        }
        break;

    case GEMCMD_DUMP:
        if (objc == 2)
        {
            dump_events(interp);
        }
        else if (objc == 3)
        {
            event->printOn(buf);
            Tcl_AppendResult(interp, "{", NULL);            // print header
            Tcl_AppendResult(interp, buf.c_str(), NULL);
            Tcl_AppendResult(interp, "} ", NULL);
        }
        else
        {
            Tcl_WrongNumArgs(interp, 2, objv, "?ceid ?");
            return TCL_ERROR;
        }
        break;

    }

    /*
     * For each different arg call different function to create
     * new commands (or if version, get/return it).
     */
    if (result == TCL_OK && res != NULL)
        Tcl_SetObjResult(interp, res);

    return TCL_OK;
}

/*----------------------------------------------------------------------
 * Dump all variables
 *----------------------------------------------------------------------
 */
static int dump_events(Tcl_Interp * interp)
{
    string buf;

    // Variable tables in the equipment
    JGEventTable * evtbl = JGEventManager::instance()->eventTable();
    JGEventTable::iterator evt_it = evtbl->begin();

    for ( ; evt_it != evtbl->end(); ++evt_it)
    {
        JGEvent * event = &((*evt_it).second);
        event->printOn(buf);

        Tcl_AppendResult(interp, "{", NULL);            // print header
        Tcl_AppendResult(interp, buf.c_str(), NULL);
        Tcl_AppendResult(interp, "} ", NULL);
    }
    return TCL_OK;
}

/*----------------------------------------------------------------------
 * Set value in the variable
 *----------------------------------------------------------------------
 */
int set_event(Tcl_Interp * interp, JGEvent * event, int argc,
              Tcl_Obj * CONST objv[])
{
    static char * setcmds[] = {
        "-enable",
        "-report",
        NULL
    };
    /*
     * All commands enums below ending in X are compatibility
     */
    enum setcmds {
        SET_ENABLE,
        SET_REPORT,
    };

    int  cmdindex, result = TCL_OK;
    vector<BS2id> ids;
    bool updateEnabled = false;
    bool updateReports = false;
    bool enableFlag = false;
    char * boolStr;
    char * idsStr;

    /*
     * Get the command name index from the object based on the spoolcmds
     * defined above.
     */
    int end = argc;
    int i = 0;
    while (i < end)
    {
        if (Tcl_GetIndexFromObj(interp, objv[i], (const char **)setcmds, "args", TCL_EXACT,
                                &cmdindex) != TCL_OK) {
            return TCL_ERROR;
        }
        i++;
        switch ((enum setcmds)cmdindex)
        {
        case SET_ENABLE:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "?-enable boolean?");
                result = TCL_ERROR;
                break;
            }
            updateEnabled = true;
            boolStr = Tcl_GetStringFromObj(objv[i++], NULL);
            enableFlag = (EQUALSTR(boolStr, "true")) ? true : false;
            break;
        case SET_REPORT:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "?-report ids?");
                result = TCL_ERROR;
                break;
            }
            updateReports = true;
            idsStr = Tcl_GetStringFromObj(objv[i++], NULL);
            result = parse_rptids(interp, idsStr, ids);
            if (result != TCL_OK) {
                Tcl_AppendResult(interp, "Illegal Report IDs : ", idsStr, NULL);
            }
            break;
        }
        if (result != TCL_OK)
            break;
    }
    if (result == TCL_ERROR)
        return (result);

    // Set event properties
    if (updateEnabled)
    {
        event->enabled(enableFlag);
    }
    if (updateReports)
    {
    }

    return TCL_OK;
}

//---------------------------------------------------------------------------
// Parse ceid in command parameter
//---------------------------------------------------------------------------
static JGEvent * find_event(Tcl_Interp * interp, char * ceidStr)
{
    BS2id  ceid;

    const string& typeName = JGEquipment::instance()->getConf(_TX("IdentificationType"));
    if (typeName == _TX("UINT4"))
    {
        unsigned int num = strtoul(ceidStr, NULL, 0);
        if (num == 0)
        {
            Tcl_AppendResult(interp, _TX("Illegal CEID : "), ceidStr, NULL);
            return NULL;
        }
        ceid = num;
    }
    else
    {
        ceid = ceidStr;
    }

    JGEvent * event = JGEventManager::instance()->find(ceid);
    return event;
}

//---------------------------------------------------------------------------
// Parse ceid in command parameter
//---------------------------------------------------------------------------
static int parse_rptids(Tcl_Interp * interp, char * idsStr,
                        vector<BS2id>& ids)
{
    bool  isAscii = true;
    BS2id  id;
    int   result;
    int   count, i;
    const char  **lists;

    const string& typeName = JGEquipment::instance()->getConf(_TX("IdentificationType"));
    if (typeName == _TX("UINT4"))
    {
        isAscii = false;
    }

    result = Tcl_SplitList(interp, idsStr, &count, &lists);
    if (result != TCL_OK)
    {
        return result;
    }

    // parse id
    for (i = 0; i < count; i++)
    {
        if (isAscii)
        {
            id = lists[i];
        }
        else
        {
            unsigned int num = strtoul(lists[i], NULL, 0);
            if (num == 0)
            {
                Tcl_AppendResult(interp, "Illegal ID : ", lists[i], NULL);
                Tcl_Free((char *)lists);   // release list area
                return TCL_ERROR;
            }
            id = num;
        }
        JGReport * report = JGEventManager::instance()->findReport(id);
        if (report == NULL)
        {
            Tcl_AppendResult(interp, "Illegal Report ID : ", lists[i], NULL);
            return TCL_ERROR;
        }
        ids.push_back(id);
    }

    Tcl_Free((char *)lists);               // release list area
    return TCL_OK;
}

//---------------------------------------------------------------------------
// Add reports in the event
//---------------------------------------------------------------------------
static int add_reports(Tcl_Interp * interp, JGEvent * event, char * idsStr)
{
    int result = TCL_OK;
    vector<BS2id> ids;

    result = parse_rptids(interp, idsStr, ids);
    if (result != TCL_OK)
    {
        return result;
    }

    // Not check duplicate.

    for (size_t i = 0; i < ids.size(); i++)
    {
        JGReport * report = JGEventManager::instance()->findReport(ids[i]);
        event->insert(report);
    }

    return TCL_OK;
}

//---------------------------------------------------------------------------
// Add reports in the event
//---------------------------------------------------------------------------
static int del_reports(Tcl_Interp * interp, JGEvent * event, char * idsStr)
{
    int result = TCL_OK;
    size_t i;
    vector<BS2id> ids;

    result = parse_rptids(interp, idsStr, ids);
    if (result != TCL_OK)
    {
        return result;
    }

    // Check report id.
    for (i = 0; i < ids.size(); i++)
    {
        if (! event->exist(ids[i]))
        {
            string badid;
            ids[i].get(badid);
            Tcl_AppendResult(interp, "Report Not found: ", badid.c_str(), NULL);
            return TCL_ERROR;
        }
    }

    // Erase
    for (i = 0; i < ids.size(); i++)
    {
        JGReport * report = JGEventManager::instance()->findReport(ids[i]);
        event->erase(report);
    }

    return TCL_OK;
}

