/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2010 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser 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, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/

#include "benchmark.h"

static int ObjBenchmarkDestroy (mmachine m, int handsys, int mobj)
{
    struct Benchmark_s * s;

    MMechostr(MSKDEBUG, "ObjBenchmarkDestroy: entering ...\n");

	/* return the object handle */
    s = (struct Benchmark_s *) MMfetch (m, MTOP (mobj), OBJBENCHMARK_HANDLE);
    if (s == NULL)
    {
        MMechostr(MSKDEBUG, "ObjBenchmarkDestroy : object already destroyed\n");
        return 0;
    }

	/* unregister this object to the Scol machine */
    MMstore (m, MTOP (mobj), OBJBENCHMARK_HANDLE, (int) NULL);
    MMechostr(MSKDEBUG, "ObjBenchmarkDestroy: object has been destroyed\n");
    return 0;
}

/**
 * \brief _benchmarkEnd : end
 * \param ObjBenchmark : a valid object
 * \return [[S S] r1] : a list
 */ 
int SCOLendBenchmark (mmachine m)
{
    int mo, i, n = 0;
    float r;
    char *out_s;
    char *out_key;

    struct Benchmark_s *s;

    MMechostr (MSKDEBUG, "SCOLendBenchmark : entering\n");

    mo = MTOP (MMpull (m));

    if (mo == NIL)
    {
        MMechostr (0, "SCOLendBenchmark error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    s = (struct Benchmark_s *) MMfetch (m, OBJBENCHMARK_HANDLE, mo);
    s->end = clock ();
    r = (s->end - s->start) / (float) CLOCKS_PER_SEC;

    OBJdelTH (m, OBJBENCHMARK_HANDLE, (int) s);

    out_s = (char *) malloc (sizeof (char) * (BENCHMARK_MAX_S +1));
    out_key = (char *) malloc (sizeof (char) * (BENCHMARK_MAX_KEY +1));

    /*FSET (f, r);
    MMpush (m, f);*/
    snprintf (out_s, BENCHMARK_MAX_S, "%f", r);
    /*out_s [BENCHMARK_MAX_S] = '\0';*/
    strncpy (out_key, "running_time", BENCHMARK_MAX_KEY);
    /*out_key[BENCHMARK_MAX_KEY] = '\0';*/

    Mpushstrbloc (m, (char *) out_key);
    Mpushstrbloc (m, (char *) out_s);
    MMpush (m, ITOM (2));
    MBdeftab (m);
    n++;

    MMpush (m, NIL);
    for (i = 0; i < n; i++)
    {
        MMpush (m, ITOM (2));
        MBdeftab (m);
    }

    free (out_s);
    return 0;
}

/**
 * \brief _benchmarkStart : start
 * \param Chn : a channel
 * \return ObjBenchmark : a newobject
 */
int SCOLstartBenchmark (mmachine m)
{
    int mchannel;
    int sizetab, benchtab;
    struct Benchmark_s *s;

    MMechostr (MSKDEBUG, "SCOLstartBenchmark : entering\n");

    mchannel = MMget (m, 0);
    if (mchannel == NIL)
    {
        MMechostr (0, "SCOLstartBenchmark error : channel is nil\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    s = (struct Benchmark_s *) malloc (sizeof (struct Benchmark_s));
    s->r = rand ();
    s->start = clock ();
    s->end = 0;

    sizetab = sizeof (struct Benchmark_s)+1;
    benchtab = MMmalloc (m, sizetab, TYPETAB);

    if ((benchtab == NIL))
    {
        MMechostr (0, "SCOLstartBenchmark error : not enough memory\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    MMstore (m, benchtab, OBJBENCHMARK_HANDLE, (int) s);
    MMpush (m, PTOM (benchtab));
    OBJcreate (m, ObjBenchmark, (int) s, -1, -1);
    return 0;
}




/* API definitions */

char* benchmark_name[BENCHMARK_PKG_NB] =
{
    "ObjBenchmark",

    "_benchmarkStart",
    "_benchmarkEnd"
};

int (*benchmark_fun[BENCHMARK_PKG_NB]) (mmachine m) =
{
    NULL,

    SCOLstartBenchmark,
    SCOLendBenchmark
};

int benchmark_narg[BENCHMARK_PKG_NB] =
{
    TYPTYPE,

    1,
    1
};

char* benchmark_type[BENCHMARK_PKG_NB] =
{
    NULL,

    "fun [Chn] ObjBenchmark",
    "fun [ObjBenchmark] [[S S] r1]"
};

int SCOLinitBENCHMARKclass (mmachine m)
{
    int k = 0;
    MMechostr (MSKDEBUG, "SCOLinitBENCHMARKclass library : entering\n");

    ObjBenchmark = OBJregister (BENCHMARK_RFL_NB, 1, ObjBenchmarkDestroy, "ObjBenchmarkType");
    k = PKhardpak (m, "BENCHMARKengine", BENCHMARK_PKG_NB, benchmark_name, benchmark_fun, benchmark_narg, benchmark_type);
    return k;
}

