/*
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 "weather.h"




/*
    RELATIVE HUMIDITY

    Relative humidity from Td (dewpoint) and T (current temperature).
    T and Td must be in degrees Celsius (ok if from METAR)
    Here, T and Td are given as integers (int), without decimal

    The formula is : rh = (e / es) * 100

    with :
    e = 6.11 * 10^f(Td)
    es = 6.11 * 10^f(T)

    where : f(X) = (7.5 * X) / (237.7 + X)
*/
float caculRelativeHumidity_Part_f(float X)
{
    return ((7.5 * X) / (237.7 + X));
}

float caculRelativeHumidity_Part_e(float X)
{
    float f;

    f = caculRelativeHumidity_Part_f (X);
    return 6.11 * (pow (10, f));
}

float calculRelativeHumidityFromTTd(int T, int Td)
{
    float e, es;

    e = caculRelativeHumidity_Part_e ((float) Td);
    es = caculRelativeHumidity_Part_e ((float) T);

    return (e / es) * 100;
}



/*
    DECODE METAR

    - structure initialization
    - free
    - parsing
    - decode
*/



/*    Initialisation  */
static OutputMetar* initStructMetar (OutputMetar * ptr)
{
    ptr = (OutputMetar*) malloc (sizeof (OutputMetar));
    /*memset (ptr, 0, sizeof (OutputMetar));*/
    memset (ptr->code, 'A', 6);
    memset (ptr->oaci, '\0', 5);
    memset (ptr->wind_dir, '\0', 4);
    memset (ptr->wind_speed, '\0', 3);
    memset (ptr->wind_gust, '\0', 3);
    memset (ptr->wind_unit, '\0', 4);
    memset (ptr->wind_var_n, '\0', 4);
    memset (ptr->wind_var_x, '\0', 4);
    memset (ptr->weather, '\0', 50);
    memset (ptr->visibility, '\0', 5);
    memset (ptr->nebul_low, '\0', 7);
    memset (ptr->nebul_med, '\0', 7);
    memset (ptr->nebul_high, '\0', 7);
    memset (ptr->temp, '\0', 4);
    memset (ptr->temp_d, '\0', 4);
    memset (ptr->pressure, '\0', 5);
    memset (ptr->reweather, '\0', 50);
    memset (ptr->day, '\0', 3);
    memset (ptr->hour, '\0', 3);
    memset (ptr->minute, '\0', 3);

    return ptr;
}

/*   Libèration*/
static void freeMetarWords (char ** words)
{
    int id = 0;

    while (words[id] != NULL)
    {
        free (*(words+id));
        id++;
    }
    words = NULL;

    return;
}

/*   Save to words the content of the METAR */
static char **saveMetarWords (char * metar)
{
    int id = 0;
    static char * words[MAX_WORD];
    char * word;
    char * separator = {" "};

    word = strtok (metar, separator);

    if (word == NULL)
        return NULL;

    /* allocation tableau dynamique */
    words[id] = (char *) malloc (sizeof (char) * (strlen (word)+1));
    strcpy (words[id], word);

    while (words[id] != NULL)
    {
        id++;
        word = strtok (NULL, separator);

        if (word != NULL)
        {
            words[id] = (char *) malloc (sizeof (char) * (strlen (word)+1));
            strcpy (words[id], word);
        }
        else
            words[id] = NULL;
    }
    return words;
}

/*    retour :
    1 : données d'entrée vides
    2 : station vide
*/
/*OutputMetar * returnMetar (char * metar)*/
static void returnMetar (OutputMetar *ptrO, char *metar)
{
    char ** words;
    char *tmpmetar = NULL;
    int i, id = 0;
    int level_nebulosity = 0; /* low level (0) -> medium level (1) -> high level (2) */
    /*OutputMetar O;*/
    /* OutputMetar * ptrO = NULL; */

    /* élément du message en cours de décodage */
    enum grpWord {code,             /* type du message : METAR, SPECI, ... */
                    station,        /* code OACI de la station concerné */
                    obtime,         /* date et heure de l'observation (UTC) / date and time */
                    wind,           /* vent : direction, force et unité de mesure / wind : direction, force and unit */
                    windvar,        /* vent : variabilité éventuelle de sa direction */
                    visibility,     /* visibilité dominante (à l'exclusion de la visibilité minimale) */
                    weather,        /* temps présent  (au moment d l'observation) */
                    nebulosity,     /* nébulosité par plafond */
                    cavok,          /* cavok (Ceiling And Visibility OK) */
                    temperature,    /* températures mesurée et de point de rosée */
                    pressure,       /* pression atmosphérique réduite au niveau de la mer, soit QNH. (Sea level pressure) */
                    reweather,      /* temps récent (typiquement la dernière heure) / recent weather */

                    end             /* fin de la collecte des données */
                    } grp;

    char WW[20][3];     /* symbôles du temps présent */
    char REww[12][3];   /* symbôles du temps récent */
    const int wwSize = 20;          /* nombre de symbôles du temps présent */
    const int REwwSize = 12;        /* nombre de symbôles du temps récent */

    /* current weather symbols */
    strcpy (WW[0], "DZ");   /* bruine / drizzle */                    /* précipitations */
    strcpy (WW[1], "RA");   /* pluie / rain */
    strcpy (WW[2], "SN");   /* neige / snow */
    strcpy (WW[3], "SG");   /* neige en grains / snow grain */
    strcpy (WW[4], "IC");   /* poudrin de glace / ice crumb */
    strcpy (WW[5], "PL");   /* granule de glace / pellet */
    strcpy (WW[6], "GR");   /* grêle / hail */
    strcpy (WW[7], "GS");   /* grésil et/ou neige roulée / sleet */

    strcpy (WW[8], "BR");   /* brume / mist */                     /* influence l'obscurité */
    strcpy (WW[9], "FG");   /* brouillard / fog */
    strcpy (WW[10], "FU");   /* fumée / smoke */
    strcpy (WW[11], "VA");   /* cendres volcaniques / volcanic ash */
    strcpy (WW[12], "DU");   /* poussières / dust */
    strcpy (WW[13], "SA");   /* sable / sand */
    strcpy (WW[14], "HZ");   /* brume sèche / haze */

    strcpy (WW[15], "PO");   /* tourbillon poussières / sables */    /* autres */
    strcpy (WW[16], "SQ");   /* grain / squall */
    strcpy (WW[17], "FC");   /* trombe / funned cloud */
    strcpy (WW[18], "SS");   /* tempête de sable / sand storm */
    strcpy (WW[19], "DS");   /* tempête de poussières / dust storm */


    /* recent weather symbols */
    strcpy (REww[0], "DZ");   /* bruine / drizzle */                    /* précipitations */
    strcpy (REww[1], "RA");   /* pluie / rain  */
    strcpy (REww[2], "SG");   /* neige en grains / snow grain */
    strcpy (REww[3], "IC");   /* poudrin de glace / ice crumb */
    strcpy (REww[4], "PL");   /* granule de glace / pellet */
    strcpy (REww[5], "GR");   /* grêle / hail */
    strcpy (REww[6], "GS");   /* grésil et/ou neige roulée  / sleet */
    strcpy (REww[7], "SN");   /* neige / snow */

    strcpy (REww[8], "VA");   /* cendres volcaniques / volcanic ash */      /* influence l'obscurité */

    strcpy (REww[9], "FC");   /* trombe / funned cloud */                   /* autres */
    strcpy (REww[10], "SS");   /* tempête de sable / sand storm */
    strcpy (REww[11], "DS");   /* tempête de poussières / dust storm */

    /* structure initialisation */
    /*initStructMetar (&O);*/
    /*ptrO = &O;*/

    /* register */
    tmpmetar = strdup (metar);
    words = saveMetarWords (tmpmetar);
    free (tmpmetar);

    if (words == NULL)
        /*return ptrO;*/
        return;

    grp = code;

    while (words[id] != NULL)
    {
        char * word;
        word = words[id];

        switch (grp)
        {
            /* message type */
            case (code) :
                if (strcmp (word, "METAR") == 0 || strcmp (word, "SPECI") == 0)
                {
                    weather_copyValue (ptrO->code, word, 6);
                    id++;
                }
                grp = station;
                break;

            /* OACI's code */
            case (station) :
                if (word == NULL || strlen (word) != 4)
                {
                    freeMetarWords (words);
                    /*return ptrO;*/
                    return;
                }
                if (nisalpha (word, 1) != 0 && nisalnum (word+1, 3) != 0)
                {
                    weather_copyValue (ptrO->oaci, word, 5);
                    id++;
                }
                else
                {
                    freeMetarWords (words);
                    /*return ptrO;*/
                    return;
                }
                grp = obtime;
                break;

            /* observation date and time (hour and minute) */
            case (obtime):
                if (word != NULL)
                {
                    if (strlen (word) == 4 || strlen (word) == 5) /* time only */
                    {
                        if (nisdigit (word, 4) && (*(word+4) == 'Z'))
                        {
                            weather_copyValue (ptrO->hour, word, 3);
                            weather_copyValue (ptrO->minute, word+2, 3);
                            id++;
                        }
                    }
                    else if (strlen (word) == 6 || strlen (word) == 7) /* date & time */
                    {
                        if (nisdigit (word, 4) && (*(word+6) == 'Z'))
                        {
                            weather_copyValue (ptrO->day, word, 3);
                            weather_copyValue (ptrO->hour, word+2, 3);
                            weather_copyValue (ptrO->minute, word+4, 3);
                            id++;
                        }
                    }
                }
                grp = wind;
                break;

            /* wind */
            case (wind):
                if (strlen (word) >= 7 && strchr (word, 'V') == NULL)
                {
                    /* unit*/
                    int len = strlen (word)-1;
                    if (nisalpha (word+len-3, 1))
                        weather_copyValue (ptrO->wind_unit, "MPS", 4);
                    else if ((*(word+len) == 'H'))
                        weather_copyValue (ptrO->wind_unit, "KMH", 4);
                    else if ((*(word+len) == 'T'))
                        weather_copyValue (ptrO->wind_unit, "KT", 4);
                    else
                        weather_copyValue (ptrO->wind_unit, "UNK", 4); /* unknown */

                    /* direction */
                    if (nisdigit (word, 3) || ((*(word) == 'V') && (*(word+1) == 'R') && (*(word+2) == 'B')))
                        weather_copyValue (ptrO->wind_dir, word, 4);

                    /* speed */
                    if (nisdigit (word+2, 2))
                        weather_copyValue (ptrO->wind_speed, word+3, 3);

                    /* gust */
                    if ((*(word+5) == 'G') && nisdigit (word+6, 2))
                        weather_copyValue (ptrO->wind_gust, word+6, 3);

                    grp = windvar;
                    id++;
                    break;
                }

            /* variabilité du vent dans sa direction */
            case (windvar):
                if (strlen (word) == 7 && (*(word+3) == 'V'))
                {
                    if (nisdigit (word, 3) && nisdigit (word+4, 3))
                    {
                        weather_copyValue (ptrO->wind_var_n, word, 4);
                        weather_copyValue (ptrO->wind_var_x, word+4, 4);
                        id++;
                        grp = visibility;
                        break;
                    }
                }

            /* major visibility (à l'exclusion de la visibilité minimale) */
            case (visibility):
                /* simple visibility data */
                if (strlen (word) == 4 && nisdigit (word, 4))
                {
                    weather_copyValue (ptrO->visibility, word, 5);
                    id++;
                    grp = weather;
                    break;
                }
                /* with NDV */
                else if (strlen (word) == 7 && nisdigit (word, 4) && (*(word+4) == 'N') && (*(word+5) == 'D') && (*(word+6) == 'V'))
                {
                    weather_copyValue (ptrO->visibility, word, 5); /* garde pas l'indication NDV */
                    id++;
                    grp = weather;
                    break;
                }

            /* current weather (excluded : VC and descriptors : MI, BC, DR, PR, BL, FZ; descriptors included : +, -, SH and TS */
            case (weather):
            {
                int weatherOK = 0;
                for (i = 0; i < wwSize; i++)
                {
                    if (strstr (word, WW[i]) != NULL)
                    {
                        if (strchr (word, '+') != NULL && weatherOK == 0)           /* high intensity  */
                            weather_copyPositiveValue (ptrO->weather, "", 0);
                        else if (strchr (word, '-') != NULL && weatherOK == 0)      /* low intensity */
                            weather_copyNegativeValue (ptrO->weather, "", 0);
                        if (strcmp (WW[i], "RA") == 0 || strcmp (WW[i], "SN") == 0 || strcmp (WW[i], "GR") == 0 || strcmp (WW[i], "GS") == 0)
                        {
                            if (strstr (word, "SH") != NULL)        /* shower */
                                strcat (ptrO->weather, "SH");
                            else if (strstr (word, "TS") != NULL)    /* thunderstorm */
                                strcat (ptrO->weather, "TS");
                        }
                        weather_addWeather (ptrO->weather, WW[i]);
                        weatherOK = 1;
                    }
                }
                if (weatherOK == 1)
                {
                    id++;
                    grp = nebulosity;
                    break;
                }
            }

            /* nebulosity (TCU and CB excluded) */
            case (nebulosity):
                if (strcmp (word, "NSC") == 0)      /* No Significant Cloud */
                {
                    weather_copyValue (ptrO->nebul_low, word, 7);
                    weather_copyValue (ptrO->nebul_med, word, 7);
                    weather_copyValue (ptrO->nebul_high, word, 7);
                    if (strlen (ptrO->weather) < 2)
                        weather_copyValue (ptrO->weather, "OK",7);
                    id++;
                    grp = cavok;
                    break;
                }
                else if (strlen (word) == 6) /* TCU, CB excluded... */
                {
                    if (strstr (word, "FEW") != NULL  || strstr (word, "SCT") != NULL || strstr (word, "BKN") != NULL || (strstr (word, "OVC") != NULL))
                    {
                        id++;
                        if (level_nebulosity == 0)
                            weather_copyValue (ptrO->nebul_low, word, 7);
                        else if (level_nebulosity == 1)
                            weather_copyValue (ptrO->nebul_med, word, 7);
                        else if (level_nebulosity == 2)
                            weather_copyValue (ptrO->nebul_high, word, 7);
                        else
                        {
                            grp = cavok;
                            break;
                        }
                        level_nebulosity++;
                        break;
                    }
                }

            /* CAVOK */
            case (cavok):
                if (strcmp (word, "CAVOK") == 0)
                {
                    weather_copyValue (ptrO->visibility, "9999", 5);
                    weather_copyValue (ptrO->weather, "OK", 3);
                    weather_copyValue (ptrO->nebul_low, "NSC", 7);
                    weather_copyValue (ptrO->nebul_med, "NSC", 7);
                    weather_copyValue (ptrO->nebul_high, "NSC", 7);
                    id++;
                    grp = temperature;
                    break;
                }

            /* current temperature and dew point */
            case (temperature):
                if ((strlen (word) >= 5) && (strlen (word) <= 7) && ((*(word+3) == '/') || (*(word+2) == '/')))
                {
                    int posSlash;

                    /* current temperature */
                    if (nisdigit (word, 2))
                        weather_copyValue (ptrO->temp, word, 3);
                    else if (nisdigit (word+1, 2) && (*(word) == 'M'))
                        weather_copyNegativeValue (ptrO->temp, word+1, 2);

                    /* dew point */
                    posSlash = 1+searchChar (word, '/'); /* 3 or 4 */
                    if (nisdigit (word+posSlash, 2))
                        weather_copyValue (ptrO->temp_d, word+posSlash, 3);
                    else if (nisdigit (word+posSlash+1, 2) && (*(word+posSlash) == 'M'))
                        weather_copyNegativeValue (ptrO->temp_d, word+posSlash+1, 2);

                    id ++;
                    break;
                }

            /* sea level pressure (QNH) */
            case (pressure):
                if ((*(word) == 'Q') && strlen (word) == 5)
                {
                    weather_copyValue (ptrO->pressure, word+1, 5);
                    id++;
/*MMechostr (0, "returnMetar : %s  ...  %d  ...  %s\n", word, id, ptrO->pressure);*/
                    grp = reweather;
                    break;
                }

            /* recent weather */
            case (reweather):
            {
                int reweatherOK = 0;
                for (i = 0; i < REwwSize; i++)
                {
                    if ((strstr (word, "RE") != NULL) && (strstr (word, REww[i]) != NULL))
                    {
                        if (strcmp (REww[i], "RA") == 0 || strcmp (REww[i], "SN") == 0 || strcmp (REww[i], "GR") == 0 || strcmp (REww[i], "GS") == 0)
                        {
                            if (strstr (word, "SH") != NULL)    /* shower */
                                strcat (ptrO->reweather, "SH");
                            else if (strstr (word, "TS") != NULL)    /* thunderstorm */
                                strcat (ptrO->reweather, "TS");
                        }
                        weather_addWeather (ptrO->reweather, REww[i]);
                        reweatherOK = 1;
                    }
                }
                if (reweatherOK == 1)
                {
                    id++;
                    grp = end;
                    break;
                }
            }

            /* finished */
            case (end):
            {
                id++;
                break;
            }

            default:
                id++;
        }
    }

    freeMetarWords (words);
    /*ptrO = &O;*/
    /*return ptrO;*/
    return;
}

/*
    Extract data from ftp://tgftp.nws.noaa.gov/data/observations/metar/stations/
    Return the METAR only */
char * extractMetarNOAA (char * metar)
{
    char * out;

    out = strchr (metar, '\n');
    if (out != NULL)
        return out+1;
    else
        return metar;
}



/*
int main()
{
    char metar[1024] = "METAR LFMV 241230Z AUTO 24003G25KT 190V280 9999NDV SCT023 BKN043 OVC064 +SHRADU 16/11 Q1010 RERA";

    printf ("Decode Metar console\n");
    printf ("Enter a OACI code : ");
    printf ("\nMETAR : %s\n", metar);
    parserMetar (metar);
    return 0;
}
*/







/*
    Scol functions

    scienceWeatherDecodeMetar
    scienceWeatherDecodeMetarLight
*/


/* */
int scienceWeatherDecodeMetar (mmachine m)
{
    int mmetar, mflag;
    OutputMetar O;
    OutputMetar *ptrO = NULL;
    char metar[512];
    const int metarmax = 512-1;

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

    mflag = MTOI(MMpull (m));
    mmetar = MTOP (MMpull (m));
    if (mmetar == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherDecodeMetar: METAR is NIL !\n");
        MMpush (m, NIL);
        return 0;
    }
    strncpy (metar, MMstartstr (m, mmetar), metarmax);
    metar[metarmax] = '\0';

    if (mflag == FROM_NOAA)
    {
        strncpy (metar, extractMetarNOAA (metar), metarmax);
        metar[metarmax] = '\0';
    }

    /*O = returnMetar (metar);*/
    /* ptrO = returnMetar (metar);*/
    returnMetar (ptrO, metar);
    /*ptrO = &O;*/
    O = (*(ptrO));

    Mpushstrbloc (m, O.code);
    Mpushstrbloc (m, O.oaci);
    Mpushstrbloc (m, O.day);
    Mpushstrbloc (m, O.hour);
    Mpushstrbloc (m, O.minute);
    Mpushstrbloc (m, O.wind_dir);
    Mpushstrbloc (m, O.wind_speed);
    Mpushstrbloc (m, O.wind_gust);
    Mpushstrbloc (m, O.wind_unit);
    Mpushstrbloc (m, O.wind_var_n);
    Mpushstrbloc (m, O.wind_var_x);
    Mpushstrbloc (m, O.visibility);
    Mpushstrbloc (m, O.weather);
    Mpushstrbloc (m, O.nebul_low);
    Mpushstrbloc (m, O.nebul_med);
    Mpushstrbloc (m, O.nebul_high);
    Mpushstrbloc (m, O.temp);
    Mpushstrbloc (m, O.temp_d);
    Mpushstrbloc (m, O.pressure);
    Mpushstrbloc (m, O.reweather);
    MMpush (m, ITOM (20));
    MBdeftab (m);

    free (ptrO);

    return 0;
}

/* */
int scienceWeatherDecodeMetarLight (mmachine m)
{
    int mmetar, mflag, tmpwind;
    const int metarmax = 512-1;
    OutputMetar O;
    OutputMetar *ptrO = NULL;
    char metar[512];
    char odate[3];
    char otime[6];
    char owinddir[4];
    char owinspeed[3];
    char owinunit[4];
    char oweather[16];
    char opressure[5];
    char otemp[4];
    int orh;

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

    mflag = MTOI(MMpull (m));
    mmetar = MTOP (MMpull (m));
    if (mmetar == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherDecodeMetarLight: METAR is NIL !\n");
        MMpush (m, NIL);
        return 0;
    }
    strncpy (metar, MMstartstr (m, mmetar), metarmax);
    metar[metarmax] = '\0';

    if (mflag == FROM_NOAA)
    {
        strncpy (metar, extractMetarNOAA (metar), metarmax);
        metar[metarmax] = '\0';
    }

    /*O = returnMetar (metar);*/
    /* ptrO = returnMetar (metar);*/
    returnMetar (ptrO, metar);
    O = (*(ptrO));

    strncpy (odate, O.day, 2); odate[2] = '\0';    /* DD*/
    strncpy (otime, O.hour, 2); otime[2] = '\0'; strcat (otime, ":"); strncat (otime, O.minute, 2); otime[5] = '\0'; /* HH:MN */

    if (strcmp (O.wind_dir, "VRB") == 0)
        strcpy (owinddir, "VAR");
    else
    {
        tmpwind = atoi (O.wind_dir);
        if (tmpwind > 330 && tmpwind <= 20) /* North */
            strcpy (owinddir, "N");
        else if (tmpwind > 20 && tmpwind <= 70) /* North-East */
            strcpy (owinddir, "NE");
        else if (tmpwind > 70 && tmpwind <= 120) /* East */
            strcpy (owinddir, "E");
        else if (tmpwind > 120 && tmpwind <= 150) /* South-East */
            strcpy (owinddir, "SE");
        else if (tmpwind > 150 && tmpwind <= 200) /* South */
            strcpy (owinddir, "S");
        else if (tmpwind > 200 && tmpwind <= 240) /* South-West */
            strcpy (owinddir, "SW");
        else if (tmpwind > 240 && tmpwind <= 290) /* West */
            strcpy (owinddir, "W");
        else if (tmpwind > 290 && tmpwind <= 330) /* North-West */
            strcpy (owinddir, "NW");
        else
            strcpy (owinddir, "UNK");   /* UNKnown */
    }
    strncpy (owinspeed, O.wind_speed, 2); owinspeed[2] = '\0';  /* speed */
    strncpy (owinunit, O.wind_unit, 3); owinunit[3] = '\0';     /* unit : KT, KMH, MPS or UNK */

    if (strstr (O.weather, "SH") != NULL)       /* shower */
    {
        strcpy (oweather, "Shower");
        if (strchr (O.weather, '+') != NULL)
            strcat (oweather, "+");
        else if (strchr (O.weather, '-') != NULL)

            strcat (oweather, "-");
    }
    else if (strstr (O.weather, "TS") || strstr (O.weather, "GR") || strstr (O.weather, "SQ") != NULL)  /* thunderstorm, squall and hail */
        strcpy (oweather, "Thunderstorm");
    else if (strstr (O.weather, "DZ") != NULL)  /* drizzle */
        strcpy (oweather, "Drizzle");
    else if (strstr (O.weather, "RA") != NULL)   /* rain */
    {
        strcpy (oweather, "Rain");
        if (strchr (O.weather, '+') != NULL)
            strcat (oweather, "+");
        else if (strchr (O.weather, '-') != NULL)
            strcat (oweather, "-");
    }
    else if (strstr (O.weather, "SN") != NULL || strstr (O.weather, "SG") != NULL || strstr (O.weather, "PL") != NULL || strstr (O.weather, "GS") != NULL)   /* snow (and almost snow ... */
    {
        strcpy (oweather, "Snow");
        if (strchr (O.weather, '+') != NULL)
            strcat (oweather, "+");
        else if (strchr (O.weather, '-') != NULL)
            strcat (oweather, "-");
    }
    else if (strstr (O.weather, "BR") != NULL)  /* mist */
        strcpy (oweather, "Mist");
    else if (strstr (O.weather, "FG") != NULL)  /* fog */
        strcpy (oweather, "Fog");
    else
        strcpy (oweather, "Nice");

    strncpy (opressure, O.pressure, 4); opressure[4] = '\0';
    strncpy (otemp, O.temp, 3); otemp[3] = '\0';

    orh = (int) calculRelativeHumidityFromTTd (atoi (O.temp), atoi (O.temp_d));

    Mpushstrbloc (m, odate);
    Mpushstrbloc (m, otime);

    Mpushstrbloc (m, owinddir);
    MMpush (m, ITOM (atoi (owinspeed)));
    Mpushstrbloc (m, owinunit);

    Mpushstrbloc (m, oweather);
    MMpush (m, ITOM (atoi (opressure)));
    MMpush (m, ITOM (atoi (otemp)));
    MMpush (m, ITOM (orh));

    MMpush (m, ITOM (9));
    MBdeftab (m);

    free (ptrO);
    return 0;
}



int scienceWeatherMetarNew (mmachine m)
{
    int mchannel;
    int len, objtab, k;
    MetarObject *o;

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

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

    o = (MetarObject*) malloc (sizeof (MetarObject));
    if (o == NULL)
	{
	    MMechostr (MSKDEBUG, "scienceWeatherMetarNew : memory allocation failed !\n");
	    MMpull (m);
	    MMpush (m, NIL);
	    return 0;
	}
	/* o->datas = (OutputMetar*) malloc (sizeof (OutputMetar)); */
	o->datas = initStructMetar (o->datas);

	strncpy (o->url_prefix, "ftp://tgftp.nws.noaa.gov/data/observations/metar/stations/", URLMAXLEN);
    strncpy (o->url_sufix, ".TXT", URLMAXLEN);

    len = (sizeof (MetarObject) + 3) >> 2;
    objtab = MMmalloc (m, len, TYPETAB);
    if (objtab == NIL)
	{
	    MMechostr (MSKDEBUG, "scienceWeatherMetarNew : memory allocation failed !\n");
	    MMpull (m);
	    MMpush (m, NIL);
	    return 0;
	}
	MMstore (m, objtab, OBJSCIENCE_WEATHER_METAR_HANDLE, (int) o);
    MMpush (m, PTOM (objtab));

    k = OBJcreate (m, ObjScienceWeatherMetarType, (int) o, -1, -1);
    return k;
}

int scienceWeatherMetarUrlSet (mmachine m)
{
    int mobj, mprefix, msufix;
    MetarObject *o;

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

    msufix = MMpull (m);
    mprefix = MMpull (m);
    mobj = MMpull (m);

    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarUrlSet error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    if (mprefix != NIL)
        strncpy (o->url_prefix, MMstartstr (m, MTOP (mprefix)), URLMAXLEN);
    if (msufix != NIL)
        strncpy (o->url_sufix, MMstartstr (m, MTOP (msufix)), URLMAXLEN);

    MMpush (m, mobj);
    return 0;
}

int scienceWeatherMetarUrlGet (mmachine m)
{
    int mobj;
    MetarObject *o;

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

    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarUrlGet error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    Mpushstrbloc (m, (char*) o->url_prefix);
    Mpushstrbloc (m, (char*) o->url_sufix);
    MMpush (m, ITOM (2));
    MBdeftab (m);
    return 0;
}

int scienceWeatherMetarDatasGet (mmachine m)
{
    int mobj;
    MetarObject *o;

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

    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarDatasGet error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);
    Mpushstrbloc (m, o->metar);
    return 0;
}

int scienceWeatherMetarDatasSet (mmachine m)
{
    int mobj, mdatas;
    MetarObject *o;

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

    mdatas = MMpull (m);
    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarDatasSet error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);
    o->metar = (char *) realloc (o->metar, sizeof (char) * MMsizestr (m, MTOP (mdatas)));
    strncpy (o->metar, MMstartstr (m, MTOP (mdatas)), MMsizestr (m, MTOP (mdatas)));
    /* o->datas = returnMetar (extractMetarNOAA (o->metar));*/
    returnMetar (o->datas, o->metar);

    MMpush (m, mobj);
    return 0;
}

int scienceWeatherMetarDatasSetFromUrl (mmachine m)
{
    int mobj, moaci, mflag;
    int len, flag = 0;
    char *url = NULL;
    MetarObject *o;
    SConnDatas Sconn;

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

    mflag = MMpull (m);
    moaci = MMpull (m);
    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarDatasSetFromUrl error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    strncpy (o->oaci, "LFPG", 5);    /* Paris-CDG airport, by default */
    if (moaci != NIL)
    {
        if (MMsizestr (m, MTOP (moaci)) == 4)
           strncpy (o->oaci, MMstartstr (m, MTOP (moaci)), 5);
    }

    if (FROM_NOAA == MTOI (mflag))
        flag = FROM_NOAA;

    len = strlen (o->url_prefix)+strlen (o->url_sufix)+strlen (o->oaci)+1;
    url = (char *) malloc (sizeof (char) * len);
    strncpy (url, o->url_prefix, len);
    strncat (url, o->oaci, len);
    strncat (url, o->url_sufix, len);

    Sconn = weather_connection_datas_init (url, o->oaci);
    weather_connection_asked (Sconn);

    free (url);

    return 0;
}


/*
int scienceWeatherMetarNewFromNOAA (mmachine m)
{
    int mchannel, mmetar, k, objtab, l;
    char metar[512];
    const int metarmax = 512-1;
    OutputMetar O;
    OutputMetar * ptrO;

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

    mmetar = MTOP (MMpull (m));
    mchannel = MMget (m, 0);

    if (mmetar == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarNewFromNOAA: METAR is NIL !\n");
        MMpush (m, NIL);
        return 0;
    }
    strncpy (metar, MMstartstr (m, mmetar), metarmax);
    metar[metarmax] = '\0';

    if (mflag == FROM_NOAA)
    {
        strncpy (metar, extractMetarNOAA (metar), metarmax);
        metar[metarmax] = '\0';
    }


    ptrO = returnMetar (metar);
    O = (*(ptrO));

    if (ptrO == NULL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarNewFromNOAA: structure creation failed !\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    l = (sizeof (OutputMetar) + 3) >> 2;
    objtab = MMmalloc (m, l, TYPETAB);
    if (objtab == NIL)
	{
	    MMechostr (MSKDEBUG, "scienceWeatherMetarNewFromNOAA : memory allocation failed !");
	    MMpull (m);
	    MMpush (m, NIL);
	    return 0;
	}
	MMstore (m, objtab, OBJSCIENCE_WEATHER_METAR_HANDLE, (int) ptrO);
    MMpush (m, PTOM (objtab));

    k = OBJcreate (m, ObjScienceWeatherMetarType, (int) ptrO, -1, -1);
    return k;
}*/

int scienceWeatherMetarPressure (mmachine m)
{
    int mobj;
    MetarObject *o;

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

    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarPressure error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    MMpush (m, ITOM (atoi (o->datas->pressure)));
    return 0;
}

int scienceWeatherMetarTemperature (mmachine m)
{
    int mobj;
    MetarObject *o;

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

    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarTemperature error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    MMpush (m, ITOM (atoi (o->datas->temp)));
    MMpush (m, ITOM (atoi (o->datas->temp_d)));
    MMpush (m, ITOM (2));
    MBdeftab (m);
    return 0;
}

int scienceWeatherMetarDate (mmachine m)
{
    int mobj;
    MetarObject *o;

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

    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarDate error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    MMpush (m, ITOM (atoi (o->datas->day)));
    MMpush (m, ITOM (atoi (o->datas->hour)));
    MMpush (m, ITOM (atoi (o->datas->minute)));
    MMpush (m, ITOM (3));
    MBdeftab (m);
    return 0;
}

int scienceWeatherMetarWind (mmachine m)
{
    int mobj;
    MetarObject *o;

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

    mobj = MMpull (m);
    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "scienceWeatherMetarWind error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);

    MMpush (m, ITOM (atoi (o->datas->wind_dir)));
    MMpush (m, ITOM (atoi (o->datas->wind_speed)));
    MMpush (m, ITOM (atoi (o->datas->wind_gust)));
    MMpush (m, ITOM (3));
    MBdeftab (m);
    return 0;
}









int ObjScienceWeatherMetarTypeDestroy (mmachine m, int handsys, int mobj)
{
    MetarObject * o;

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

    o = (MetarObject *) MMfetch (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE);
    if ((int) o == 0)
    {
        MMechostr(MSKDEBUG, "ObjScienceWeatherMetarTypeDestroy : object already destroyed\n");
        MMset (m, 0, NIL);
        /*MMpush (m, NIL);*/
        return 0;
    }

    free (o->metar);
    free (o->datas);

    SAFEdelete (o);
    MMstore (m, MTOP (mobj), OBJSCIENCE_WEATHER_METAR_HANDLE, (int) NULL);
    /*MMset (m, 0, NIL);*/
    MMechostr(MSKDEBUG, "ObjScienceWeatherMetarTypeDestroy: object has been destroyed\n");

    return 0;
}



/*
    Loading weather api part
    API defintions
*/

/* packages number */
#define SCIENCE_WEATHER_PKG_NB    14

/* functions name */
char* science_weather_name[SCIENCE_WEATHER_PKG_NB]=
{
    /* SCOL Objects */
    "ObjScienceWeatherMetar",

    /* flags */
    "FROM_NOAA",

    /* Functions */
    "_scienceWeatherDecodeMetar",
    "_scienceWeatherDecodeMetarLight",

    "_scienceWeatherMetarNew",
    "_scienceWeatherMetarUrlSet",
    "_scienceWeatherMetarUrlGet",
    "_scienceWeatherMetarDatasSet",
    "_scienceWeatherMetarDatasGet",
    "_scienceWeatherMetarPressure",
    "_scienceWeatherMetarTemperature",
    "_scienceWeatherMetarDate",
    "_scienceWeatherMetarWind",
    "_scienceWeatherMetarDatasSetFromUrl"
};

/* internals functions */
int (*science_weather_fun[SCIENCE_WEATHER_PKG_NB])(mmachine m)=
{
    /* SCOL Objects */
    NULL,

    /* flags */
    (bullshit) (1*2),

    /* Functions */
    scienceWeatherDecodeMetar,
    scienceWeatherDecodeMetarLight,

    scienceWeatherMetarNew,
    scienceWeatherMetarUrlSet,
    scienceWeatherMetarUrlGet,
    scienceWeatherMetarDatasSet,
    scienceWeatherMetarDatasGet,
    scienceWeatherMetarPressure,
    scienceWeatherMetarTemperature,
    scienceWeatherMetarDate,
    scienceWeatherMetarWind,
    scienceWeatherMetarDatasSetFromUrl
};

/* arguments(number) */
int science_weather_narg[SCIENCE_WEATHER_PKG_NB]=
{
    /* SCOL Objects */
    TYPTYPE,

    /* flags */
    TYPVAR,

    /* Functions */
    2,
    2,

    1,
    3,
    1,
    2,
    1,
    1,
    1,
    1,
    1,
    3
};

/* functions type */
char* science_weather_type[SCIENCE_WEATHER_PKG_NB]=
{
    /* SCOL Objects */
    NULL,

    /* flags */
    "I",

    /* Functions */
    "fun [S I] [S S S S S S S S S S S S S S S S S S S S]",
    "fun [S I] [S S S I S S I I I]",

    "fun [Chn] ObjScienceWeatherMetar",
    "fun [ObjScienceWeatherMetar S S] ObjScienceWeatherMetar",            /* scienceWeatherMetarUrlSet */
    "fun [ObjScienceWeatherMetar] [S S]",                                   /* scienceWeatherMetarUrlGet */
    "fun [ObjScienceWeatherMetar S] ObjScienceWeatherMetar",                /* scienceWeatherMetarDatasSet */
    "fun [ObjScienceWeatherMetar] S",                                       /* scienceWeatherMetarDatasGet */
    "fun [ObjScienceWeatherMetar] I",                                       /* scienceWeatherMetarPressure */
    "fun [ObjScienceWeatherMetar] [I I]",                                   /* scienceWeatherMetarTemperature */
    "fun [ObjScienceWeatherMetar] [I I I]",                                  /* scienceWeatherMetarDate */
    "fun [ObjScienceWeatherMetar] [I I I]",                                  /* scienceWeatherMetarWind */
    "fun [ObjScienceWeatherMetar S I] I"                                  /* scienceWeatherMetarDatasSetFromUrl */
};

int SCOLweatherLoadAPI (mmachine m)
{
    int k;

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

    ObjScienceWeatherMetarType = OBJregister (SCIENCE_METAR_CB, 1, ObjScienceWeatherMetarTypeDestroy, "ObjScienceWeatherMetarType");

    k = PKhardpak (m, "Science_Weather", SCIENCE_WEATHER_PKG_NB, science_weather_name, science_weather_fun, science_weather_narg, science_weather_type);
    return k;
}






