/**************************************************************************
 *{@C
 *      Copyright:      1988-2024 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         Utilities
 *      Filename:       UTT_SwatchIf.c
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    Functions for the Tcl standard function library which
 *                      use the system clock to simulate stop watches which run
 *                      in real time.
 *
 *                      This module implements a new command "poSwatch" to
 *                      generate a swatch and miscellaneous swatch operations.
 *
 *      Additional documentation:
 *                      None.
 *                      
 *      Exported functions:
 *
 **************************************************************************/

#include <stdio.h>
#include <string.h>
#include <math.h>

#include "UT_Compat.h"

#include "UT_Error.h"
#include "UT_Memory.h"
#include "UT_Swatch.h"

#include <tcl.h>
#include "UTT_TclIf.h"

#include "UTT_SwatchTclIf.h"

static UT_Bool
    initialized = UT_False;

UT_Bool UTT_SwatchNew (OBJPARAMLIST)
{
    UT_Swatch sw;

    if (!(sw = UT_SwatchNew ())) {
        return UT_False;
    }
    UT_SwatchReset (sw);
    UT_SwatchStop  (sw);
    UT_SwatchReset (sw);
    *clientData = sw;
    return UT_True;
}

UT_Bool UTT_SwatchStop (ELEMPARAMLIST)
{
    UT_Swatch sw = (UT_Swatch) clientData;

    UT_SwatchStop (sw);
    return UT_True;
}

UT_Bool UTT_SwatchRun (ELEMPARAMLIST)
{
    UT_Swatch sw = (UT_Swatch) clientData;

    UT_SwatchRun (sw);
    return UT_True;
}

UT_Bool UTT_SwatchReset (ELEMPARAMLIST)
{
    UT_Swatch sw = (UT_Swatch) clientData;

    UT_SwatchReset (sw);
    return UT_True;
}

UT_Bool UTT_SwatchLookup (ELEMPARAMLIST)
{
    UT_Swatch sw = (UT_Swatch) clientData;

    UTT_SetFixFloat64Result (UT_SwatchLookup (sw));
    return UT_True;
}

/* Delete a Tcl swatch object. */

static void DeleteSwatch (ClientData clientData)
{
    UT_Swatch sw = (UT_Swatch) clientData;

    UT_SwatchDelete (sw);
    return;
}

static UTT_TclObjFunc swatchfunc[] =
{
    {UTT_SwatchNew,    "new"},
};

static UTT_TclElemFunc swatchelemfunc[] =
{
    {UTT_SwatchStop,   "stop"},
    {UTT_SwatchRun,    "run"},
    {UTT_SwatchReset,  "reset"},
    {UTT_SwatchLookup, "lookup"},
};

static int SwatchElementCmd (TCLPARAMLIST)
{
    Int32 i;

    if (argc == 2 && argv[1][0] == '?') {
        for (i=0; i< sizeof (swatchelemfunc) / sizeof (UTT_TclElemFunc); i++) {
            Tcl_AppendResult (interp, swatchelemfunc[i].name, "\n", (char *)NULL);
        }
        return TCL_OK;
    }
    if (argc < 2) {
        Tcl_AppendResult (interp, "Available swatch subcommands:\n", (char *)NULL);
        for (i=0; i< sizeof (swatchelemfunc) / sizeof (UTT_TclElemFunc); i++) {
            Tcl_AppendResult (interp, "\t", swatchelemfunc[i].name, "\n", (char *)NULL);
        }
        return TCL_ERROR;
    }

    for (i=0; i< sizeof (swatchelemfunc) / sizeof (UTT_TclElemFunc); i++) {
        if (strcmp (argv[1], swatchelemfunc[i].name) == 0) {
            if (!swatchelemfunc[i].func (clientData, interp, argc, argv)) {
                Tcl_AppendResult (interp, UT_ErrStr, "\n(",
                                  UT_ErrAddStr, ")\n", (char *)NULL); 
                return TCL_ERROR;
            } else {
                return TCL_OK;
            }
        }
    }

    Tcl_AppendResult (interp, "Bad swatch subcommand \"", argv[1], (char *)NULL); 
    return TCL_ERROR;
}

static int SwatchCmd (TCLPARAMLIST)
{
    Int32 i;
    UT_Bool found = UT_False;
    UT_Swatch sw;
    char swatchName[40];
    static Int32 swatchNo = 1;

    /* OPA TODO RTT_Obj_Help ("String entityName"); */
    if (argc < 2) {
        Tcl_AppendResult (interp, "Available swatch commands:\n", (char *)NULL);
        for (i=0; i< sizeof (swatchfunc) / sizeof (UTT_TclObjFunc); i++)
            Tcl_AppendResult (interp, "\t", swatchfunc[i].name, "\n", (char *)NULL);
        return TCL_ERROR;
    }

    for (i=0; i< sizeof (swatchfunc) / sizeof (UTT_TclObjFunc); i++) {
        if (strcmp (argv[1], swatchfunc[i].name) == 0) {
            if (!swatchfunc[i].func ((ClientData *)&sw, interp, argc, argv)) {
                Tcl_AppendResult (interp, UT_ErrStr, "\n(",
                                  UT_ErrAddStr, ")\n", (char *)NULL);
                return TCL_ERROR;
            } else {
                found = UT_True;
                break;
            }
        }
    }
    if (!found) {
        Tcl_AppendResult (interp, "Available swatch commands:\n", (char *)NULL);
        for (i=0; i< sizeof (swatchfunc) / sizeof (UTT_TclObjFunc); i++) {
            Tcl_AppendResult (interp, "\t", swatchfunc[i].name, "\n", (char *)NULL);
        }
        return TCL_ERROR;
    }
    sprintf (swatchName, "poSwatch%d", swatchNo);
    Tcl_CreateCommand (interp, swatchName, (Tcl_CmdProc *)SwatchElementCmd,
                       (ClientData) sw, (Tcl_CmdDeleteProc *)DeleteSwatch);
    Tcl_SetResult (interp, swatchName, TCL_VOLATILE);
    swatchNo++;
    return TCL_OK;
}

int UTT_InitTclSwatchLib (Tcl_Interp *interp)
{
    if (initialized) {
        return TCL_OK;
    }
    Tcl_CreateCommand (interp, "poSwatch", (Tcl_CmdProc *) SwatchCmd,
                       (ClientData) NULL, (Tcl_CmdDeleteProc *) DeleteSwatch);
    initialized = UT_True;
    return TCL_OK;
}
