/*! \file scol_gbase.c
*	\brief all functions of this API
*   \author Stephane Bisaro
*/
/*
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 "../include/scol_gbase.h"

#ifdef __cplusplus
#error This source file is not C++ but rather C. Please use a C-compiler
#endif

#if ((defined _WIN32) || (defined __WIN32__))
cbmachine ww;
#endif
mmachine  mm;


/**
 * \brief _gbaseUserName : Returns the user (or real) name
 *
 * fun [] S
 *
 * \param void : nothing
 * \return S : this name
 */
int SCOL_gbaseUserName (mmachine m)
{
    const gchar * name;

    name = g_get_user_name ();
    if (name == NULL)
        name = g_get_real_name ();

    if (name == NULL)
    {
        Mpushstrbloc (m, "unknown");
        return 0;
    }
    Mpushstrbloc (m, (char *) name);
    return 0;
}

/**
 * \brief _gBaseHostName : Returns the host name
 *
 * fun [] S
 *
 * \param void : nothing
 * \return S : this name
 */
int SCOL_gBaseHostName (mmachine m)
{
    const gchar * name;

    name = g_get_host_name ();
    if (name == NULL)
    {
        Mpushstrbloc (m, "unknown");
        return 0;
    }
    Mpushstrbloc (m, (char *) name);
    return 0;
}

/**
 * \brief _gBaseDirCur : Returns the current directory (by default on MS Windows "C:\Program Files\Scol Voyager")
 *
 * fun [] S
 *
 * \param void : nothing
 * \return S : this directory or "unknown" if undefined
 */
int SCOL_gBaseDirCur (mmachine m)
{
    const gchar * name;

    name = g_get_current_dir ();
    if (name == NULL)
    {
        Mpushstrbloc (m, "unknown");
        return 0;
    }
    Mpushstrbloc (m, (char *) name);
    return 0;
}

/**
 * \brief _gBasePathAbsolute : Returns 1 if the given file_name is an absolute file name.
 *
 * fun [S] I
 *
 * \param S : any path
 * \return I : 1 if TRUE,otherwise 0
 */
 int SCOL_gBasePathAbsolute (mmachine m)
 {
    int mpath;
    gboolean value;

    mpath = MMpull (m);
    if (mpath == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }

    value = g_path_is_absolute (MMstartstr (m, MTOP (mpath)));
    MMpush (m, ITOM (value));
    return 0;
 }

/**
 * \brief _gBasePathBase : Returns the last component of the filename
 *
 * fun [S] S
 *
 * \param S : any path
 * \return S : this last component
 */
int SCOL_gBasePathBase (mmachine m)
{
    int mpath;
    gchar *base;

    mpath = MMpull (m);
    if (mpath == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    base = g_path_get_basename (MMstartstr (m, MTOP (mpath)));
    Mpushstrbloc (m, base);
    g_free (base);
    return 0;
}

/**
 * \brief _gBasePathDir : Returns the directory components of a file name.
 *
 * fun [S] S
 *
 * \param S : any path
 * \return S : this directory
 */
int SCOL_gBasePathDir (mmachine m)
{
    int mpath;
    gchar *dir;

    mpath = MMpull (m);
    if (mpath == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    dir = g_path_get_dirname (MMstartstr (m, MTOP (mpath)));
    Mpushstrbloc (m, dir);
    g_free (dir);
    return 0;
}

/**
 * \brief _gBasePathBuild : Creates a filename from a list of elements using the correct separator for filenames.
 *
 * fun [[S r1] I] S
 *
 * \param [S r1] : a list of elements (typically, a list of directory = a :: b :: c :: file.ext)
 * \param I : 1 = OS separator (e.g. "\" on MS Windows, "/" on Linux), otherwise Scol separator ("/")
 * \return S : the filename
 */
int SCOL_gBasePathBuild (mmachine m)
{
    int mlist, mflag;
    int size = 0, i = 0;
    gchar **list;
    gchar *fn;

    mflag = MTOI (MMpull (m));
    mlist = MMget (m, 0);
    if (mlist == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    mlist = MTOP (mlist);

    while (mlist != NIL)
    {
        size++;
        mlist = MMfetch (m, mlist, 1)>>1;
    }

    list = g_new0 (gchar*, size + 2);
    mlist = MTOP (MMpull (m));
    for (; i < size; i++)
    {
        list[i] = MMstartstr (m, MTOP (MMfetch (m, mlist, 0)));
        mlist = MTOP (MMfetch (m, mlist, 1));
    }

    if (mflag == 1)
        fn = g_build_filenamev (list);
    else
        fn = g_build_pathv ("/", list);
    Mpushstrbloc (m, fn);
    g_free (list);
    g_free (fn);
    return 0;
}

/**
 * \brief _gBaseStringUTF8 : Converts a string in the current locale into a UTF-8 string or reverse.
 *
 * fun [S I] S
 *
 * \param S : any string
 * \param I : 1 from locale to UTF8, 0 from UTF-8 to current locale
 * \return S : the new string
 */
int SCOL_gBaseStringUTF8 (mmachine m)
{
    int mstring, mflag;
    gchar *string;

    mflag = MMpull (m);
    mstring = MMpull (m);

    if (mstring == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    if (mflag)
        string = SCOLUTF8 (MMstartstr (m, MTOP (mstring)), -1);
    else
        string = UTF8SCOL (MMstartstr (m, MTOP (mstring)), -1);
    Mpushstrbloc (m, string);
    g_free (string);
    return 0;
}

/**
 * \brief _gbaseChecksumS : Computes the checksum of a string.
 *
 * fun [S I] S
 *
 * \param S : any string
 * \param I : the hashing algorithm to use = 0 -> MD5 (default), 1 -> SHA-1, 2 -> SHA-256
 * \return S : the checksum as an hexadecimal string.
 */
int SCOL_gbaseChecksumS (mmachine m)
{
    int mstring, mtype;
    GChecksumType type = G_CHECKSUM_MD5;
    gchar *string;

    mtype = MTOI (MMpull (m));
    mstring = MMpull (m);

    if (mstring == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    mstring = MTOP (mstring);

    if (mtype == 1)
        type = G_CHECKSUM_SHA1;
    else if (mtype == 2)
        type = G_CHECKSUM_SHA256;

    string = g_compute_checksum_for_string (type, MMstartstr (m, mstring), -1);
    Mpushstrbloc (m, string);
    g_free (string);
    return 0;
}

/**
 * \brief _gbaseChecksumP : Computes the checksum of a file.
 *
 * fun [P I] S
 *
 * \param S : any file (read referenced only)
 * \param I : the hashing algorithm to use = 0 -> MD5 (default), 1 -> SHA-1, 2 -> SHA-256
 * \return S : the checksum as an hexadecimal string.
 */
int SCOL_gbaseChecksumP (mmachine m)
{
    /* #define SCSP_MAX_SIZE G_MAXUINT-1 */ /* i'm stupid ! */
    #define SCSP_MAX_SIZE 1024*32   /* 32 ko / each loop */
    int mfile, mtype;
    guchar data[SCSP_MAX_SIZE];
    gsize size = 0;
    GChecksumType type = G_CHECKSUM_MD5;
    GChecksum *cs;
    const gchar *string;
    FILE *file;

    mtype = MTOI (MMpull (m));
    mfile = MMpull (m);

    if (mfile == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    mfile = MTOP (mfile);

    file = fopen (MMstartstr (m, mfile), "rb");
    if (file == NULL)
    {
        MMpush (m, NIL);
        return 0;
    }

    if (mtype == 1)
        type = G_CHECKSUM_SHA1;
    else if (mtype == 2)
        type = G_CHECKSUM_SHA256;

    cs = g_checksum_new (type);
    do
    {
        size = fread((void *) data, sizeof (guchar), SCSP_MAX_SIZE, file);
        g_checksum_update (cs, data, size);
    }
    while (size == SCSP_MAX_SIZE);
    fclose (file);

    string = g_checksum_get_string (cs);
    Mpushstrbloc (m, (char *) string);
    g_checksum_free (cs);
    return 0;
}

/**
 * \brief _gbaseSleep : Pauses the current thread for the given number of milliseconds.
 *
 * fun [I] I
 *
 * \param I : the number of milliseconds
 * \return I : 0 if success, nil if error
 */
int SCOL_gbaseSleep (mmachine m)
{
    int msleep;

    msleep = MTOI (MMpull (m));
    if (msleep <= 0)
    {
        MMpush (m, NIL);
        return 0;
    }

    g_usleep (1000*msleep);
    MMpush (m, ITOM (0));
    return 0;
}

/**
 * \brief _gbaseFileStat : it should not be used, at this time
 *
 * fun [P] [I I I I]
 *
 * \param P : a filename (read reference only)
 * \return [I I I I] : size, last access, last modification, last state changed
 */
int SCOL_gbaseFileStat (mmachine m)
{
    int mfile;
    int result;
    #if ((defined _WIN32) || (defined __WIN32__))
    GStatBuf *s = NULL;
    #else
    struct stat *s = NULL;
    #endif

    mfile = MMpull(m);
    if (mfile == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    mfile = MTOP (mfile);

    result = g_stat (MMstartstr (m, mfile), s);
    if (result != 0)
    {
        MMpush (m, NIL);
        return 0;
    }
    MMpush (m, ITOM (s->st_size));
    MMpush (m, ITOM (s->st_atime));
    MMpush (m, ITOM (s->st_mtime));
    MMpush (m, ITOM (s->st_ctime));
    MMpush (m, ITOM (4));
    MBdeftab (m);

    return 0;
}

/**
 * \brief _gbaseIsIp : Tests if a string is a form of an IPv4 or IPv6 address (like "123.210.012.231").
 * fun [S] I
 * \param S : any string
 * \return I : 1 if TRUE (the string is an IP address), 0 if FALSE
 */
int SCOL_gbaseIsIp (mmachine m)
{
    int ms;

    ms = MMpull (m);
    if (ms == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }
    MMpush (m, ITOM (g_hostname_is_ip_address (MMstartstr (m, MTOP (ms)))));
    return 0;
}






/* API définitions : */

char* gbase_name[GBASE_PKG_NB]=
{
    "_gbaseUserName",
    "_gBaseHostName",
    "_gBaseDirCur",
    "_gBasePathAbsolute",
    "_gBasePathBase",
    "_gBasePathDir",
    "_gBasePathBuild",
    "_gBaseStringUTF8",
    "_gbaseChecksumS",
    "_gbaseChecksumP",
    "_gbaseSleep",
    "_gbaseFileStat",
    "_gbaseIsIp"
};

int (*gbase_fun[GBASE_PKG_NB])(mmachine m)=
{
    SCOL_gbaseUserName,
    SCOL_gBaseHostName,
    SCOL_gBaseDirCur,
    SCOL_gBasePathAbsolute,
    SCOL_gBasePathBase,
    SCOL_gBasePathDir,
    SCOL_gBasePathBuild,
    SCOL_gBaseStringUTF8,
    SCOL_gbaseChecksumS,
    SCOL_gbaseChecksumP,
    SCOL_gbaseSleep,
    SCOL_gbaseFileStat,
    SCOL_gbaseIsIp
};

int gbase_narg[GBASE_PKG_NB]=
{
    0,      /* SCOL_gbaseUserName */
    0,      /* SCOL_gBaseHostName */
    0,      /* SCOL_gBaseDirCur */
    1,      /* SCOL_gBasePathAbsolute */
    1,      /* SCOL_gBasePathBase */
    1,      /* SCOL_gBasePathDir */
    2,      /* SCOL_gBasePathBuild */
    2,       /* SCOL_gBaseStringUTF8 */
    2,       /* SCOL_gbaseChecksumS */
    2,       /* SCOL_gbaseChecksumP */
    1,       /* SCOL_gbaseSleep */
    1,       /* SCOL_gbaseFileStat */
    1       /* SCOL_gbaseIsIp */
};

char* gbase_type[GBASE_PKG_NB]=
{
    "fun [] S",                     /* SCOL_gbaseUserName */
    "fun [] S",                     /* SCOL_gBaseHostName */
    "fun [] S",                     /* SCOL_gBaseDirCur */
    "fun [S] I",                    /* SCOL_gBasePathAbsolute */
    "fun [S] S",                    /* SCOL_gBasePathBase */
    "fun [S] S",                    /* SCOL_gBasePathDir */
    "fun [[S r1] I] S",             /* SCOL_gBasePathBuild */
    "fun [S I] S",                  /* SCOL_gBaseStringUTF8 */
    "fun [S I] S",                  /* SCOL_gbaseChecksumS */
    "fun [P I] S",                  /* SCOL_gbaseChecksumS */
    "fun [I] I",                    /* SCOL_gbaseSleep */
    "fun [P] [I I I I]",            /* SCOL_gbaseFileStat */
    "fun [S] I"                    /* SCOL_gbaseIsIp */
};

int SCOLinitGbaseClass (mmachine m)
{
    int k;

    MMechostr (0, "SCOLinitGbaseClass : entering\n");

    k = PKhardpak (m, "GBaseEngine", GBASE_PKG_NB, gbase_name, gbase_fun, gbase_narg, gbase_type);
    return k;
}




int GBaseRelease ()
{
    MMechostr (0, "\nGBASE library released !\n");
    return 0;
}

#if ((defined _WIN32) || (defined __WIN32__))
# define SCOL_GBASE_PLUGIN_EXPORT __declspec (dllexport)
#elif ((defined linux) || (defined __linux))
# define SCOL_GBASE_PLUGIN_EXPORT
#else
# error no platform supported
#endif

SCOL_GBASE_PLUGIN_EXPORT int SCOLloadGBASE(mmachine m, cbmachine w)
{
    ww = w;
    mm = m;

    SCOLinitplugin(w);
    return SCOLinitGbaseClass(m);
}

SCOL_GBASE_PLUGIN_EXPORT int SCOLfreeGBASE()
{
    return 0;
}
