// $Id: melsvrCmd.cpp,v 1.3 2003/03/10 15:45:25 fukasawa Exp $

// ============================================================================
//
// = LIBRARY
//     tclmelsvr
//
// = FILENAME
//     melsvrCmd.cpp
//
// = AUTHOR(S)
//     Fukasawa Mitsuo
//
// = COPYRIGHT
//     Copyright (c) 2001-2002 by BEE Co.,Ltd.  All rights reserved.
//
//     This file is part of the tclgxml that can be used free.
//     The tclgxml and this file are covered by the GNU Lesser General Public
//     License, which should be included with libxml++ as the file COPYING.
//
// ============================================================================

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

#include "MELMemory.h"
#include "MELDeviceServer.h"
#ifdef _MSC_VER
#include <windows.h>
#endif
#include "tclbee.h"

// function prototype
extern int parseMemoryAddr(Tcl_Interp * interp, char * devAddr,
                           PLCDevice ** retmem, unsigned long * top);
extern int parseSize(Tcl_Interp * interp, PLCDevice * mem, char * sizeStr,
                     size_t * size);
extern int parseWordData(Tcl_Interp * interp, char * datastr,
                         unsigned short ** bufpp, size_t * size);
extern int parseBitData(Tcl_Interp * interp, char * datastr,
                        unsigned short ** bufpp, size_t * size);
extern int parseData(Tcl_Interp * interp, char * datastr,
                     unsigned short ** bufpp, size_t * size);

//
static bool _initialized = false;

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

    /* ARGSUSED */
int Melsvr_initCmd(ClientData arg, Tcl_Interp * interp, int objc,
                   Tcl_Obj *CONST objv[])
{

    static char * opencmds[] = {
        "-path",
        "-channel",
        "-station",
        "-unit",
        "-clear",
        "-xml",
        NULL
    };
    /*
     * All commands enums below ending in X are compatibility
     */
    enum opencmds {
        OPEN_PATH,
        OPEN_CHANNEL,
        OPEN_STATION,
        OPEN_UNIT,
        OPEN_CLEAR,
        OPEN_XML,
    };

    int cmdindex, result = TCL_OK;
    int channelNum = 12;
    int stationNum = 1;
    int unitNum = 0xFF;
    int doClear = 0;
    char * pathName = "\\jyugem\\shared";
    char * xmlName = "\\jyugem\\xml\\melsec.xml";

    Tcl_ResetResult(interp);

    /*
     * Get the command name index from the object based on the spoolcmds
     * defined above.
     */
    int end = objc;
    int i = 1;
    while (i < end)
    {
        if (Tcl_GetIndexFromObj(interp, objv[i], (const char **)opencmds, "option",
                                TCL_EXACT, &cmdindex) != TCL_OK) {
            return TCL_ERROR;
        }
        i++;
        switch ((enum opencmds)cmdindex)
        {
        case OPEN_PATH:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "?-path pathname?");
                result = TCL_ERROR;
                break;
            }
            pathName = Tcl_GetStringFromObj(objv[i++], NULL);
            break;
        case OPEN_XML:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "?-xml xmlname?");
                result = TCL_ERROR;
                break;
            }
            xmlName = Tcl_GetStringFromObj(objv[i++], NULL);
            break;
        case OPEN_CHANNEL:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "?-channel number?");
                result = TCL_ERROR;
                break;
            }
            result = Tcl_GetIntFromObj(interp, objv[i++], &channelNum);
            if (result != TCL_OK) {
                Tcl_SetResult(interp,
                              "Open: Invalid channel number. \n", TCL_STATIC);
                result = TCL_ERROR;
            }
            break;
        case OPEN_STATION:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "?-station number?");
                result = TCL_ERROR;
                break;
            }
            result = Tcl_GetIntFromObj(interp, objv[i++], &stationNum);
            if (result != TCL_OK) {
                Tcl_SetResult(interp,
                              "Open: Invalid station number. \n", TCL_STATIC);
                result = TCL_ERROR;
            }
            break;
        case OPEN_UNIT:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "-unit number");
                result = TCL_ERROR;
                break;
            }
            result = Tcl_GetIntFromObj(interp, objv[i++], &unitNum);
            if (result != TCL_OK) {
                Tcl_SetResult(interp, "Open: Invalid unit number.\n",
                              TCL_STATIC);
            }
            break;

        case OPEN_CLEAR:
            if (i > (end - 1)) {
                Tcl_WrongNumArgs(interp, 2, objv, "-clear flag");
                result = TCL_ERROR;
                break;
            }
            result = Tcl_GetBooleanFromObj(interp, objv[i++], &doClear);
            if (result != TCL_OK) {
                Tcl_SetResult(interp, "Open: Invalid clear flag.\n",
                              TCL_STATIC);
            }
            break;

        }
        if (result != TCL_OK)
            break;
    }
    if (result == TCL_ERROR)
        return (result);

    try {

        PLCMemory::SetClearMemory((doClear == 0) ? false : true);

        MELDeviceServer * melsvr = MELDeviceServer::instance();
        if (melsvr == NULL) {
            return TCL_ERROR;
        }

        result = melsvr->init(pathName, xmlName, channelNum, stationNum, unitNum);
        if (result < 0)
        {
            return TCL_ERROR;
        }
        _initialized = true;

    }
    catch (...) {
        Tcl_AppendResult(interp, "open memory error ",
                         NULL);
        return TCL_ERROR;
    }
    return TCL_OK;
}


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

    /* ARGSUSED */
int
Melsvr_openCmd(ClientData arg, Tcl_Interp * interp, int objc,
               Tcl_Obj *CONST objv[])
{
    if (! _initialized)
    {
        Tcl_AppendResult(interp, "not yet initialized ", NULL);
        return TCL_ERROR;
    }
    if (objc > 1)
    {
        Tcl_WrongNumArgs(interp, 1, objv, "open ?value value ...?");
        return TCL_ERROR;
    }
    MELDeviceServer * melsvr = MELDeviceServer::instance();
    if (melsvr == NULL)
    {
        return TCL_ERROR;
    }

    melsvr->open();

    return TCL_OK;
}

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

    /* ARGSUSED */
int
Melsvr_closeCmd(ClientData arg, Tcl_Interp * interp, int objc,
                Tcl_Obj *CONST objv[])
{
    if (! _initialized)
    {
        Tcl_AppendResult(interp, "not yet initialized ", NULL);
        return TCL_ERROR;
    }
    if (objc > 1)
    {
        Tcl_WrongNumArgs(interp, 1, objv, "close ?value value ...?");
        return TCL_ERROR;
    }
    MELDeviceServer * melsvr = MELDeviceServer::instance();
    if (melsvr == NULL)
    {
        return TCL_ERROR;
    }

    melsvr->end();

    return TCL_OK;
}


/*
 *----------------------------------------------------------------------
 *
 * Melsvr_eventCmd --
 *
 *      This procedure is invoked to process the "melsvr::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
Melsvr_eventCmd(ClientData arg, Tcl_Interp * interp, int objc,
                Tcl_Obj *CONST objv[])
{
    if (! _initialized)
    {
        Tcl_AppendResult(interp, "not yet initialized ", NULL);
        return TCL_ERROR;
    }
    if (objc != 2)
    {
        Tcl_WrongNumArgs(interp, 1, objv, "event on/off");
        return TCL_ERROR;
    }
    MELDeviceServer * melsvr = MELDeviceServer::instance();
    if (melsvr == NULL)
    {
        return TCL_ERROR;
    }

    char * switchStr = Tcl_GetString(objv[1]);
    if (EQUALSTR(switchStr, "on") || EQUALSTR(switchStr, "ON") ||
        EQUALSTR(switchStr, "On"))
    {
        melsvr->startSemaphore();
    }
    else if (EQUALSTR(switchStr, "off") || EQUALSTR(switchStr, "OFF") ||
             EQUALSTR(switchStr, "Off"))
    {
        melsvr->stopSemaphore();
    }
    else
    {
        Tcl_AppendResult(interp, "Illegal event switch \"", switchStr , "\"",
                         NULL);
        return TCL_ERROR;
    }
    return TCL_OK ;
}
