/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <mars.h>
#include <ctype.h>

typedef struct data
{
    boolean serve;
} data;

static option opts[] = {
    {
        "serve",
        NULL,
        "-serve",
        "0",
        t_boolean,
        sizeof(boolean),
        OFFSET(data, serve),
    },
};

static data setup;

const char* reserved[] = {
    "if",
    "then",
    "else",
    "and",
    "not",
    "or",
    "function",
    "return",
    "end",
    "while",
    "global",
    "do",
    "on",
    "for",
    "to",
    "by",
    "in",
    "of",
    "case",
    "otherwise",
    "repeat",
    "until",
    "loop",
    "when",
    "include",
    "extern",
    "tell",
    "task",
    "nil",
    "object",
    "import",
    "export",
    "inline",
};

const char* import(FILE* f, const char* icon);
static void formula1(FILE* f, const char* ref, math* m, math* p);
static void formula2(FILE* f, math* m);
static int need_case(request* r, parameter* p, value* v);
static int value_need_case(value* w, value* v);
static request* link1(FILE*, request*);

static int cvtdates = 0;

static char tab[256] = ""; /* either a tab string or else a row of spaces, set in main() */
static boolean spaces = false;

static void putdate(FILE* f, long date)
{
    if (date > 0)
        fprintf(f, "%ld", date);
    else
        fprintf(f, "today - %ld", -date);
}

static request* find_object(const char* name)
{
    request* u = mars.setup;
    const char* c;

    if (!name)
        return NULL;

    while (u) {
        if (strcmp(u->name, "object") == 0 &&
            (c = get_value(u, "class", 0)) &&
            strcmp(c, name) == 0)
            return u;
        u = u->next;
    }

    return NULL;
}

static const char* ascii(char a)
{
    static char buf[5];
    if (isspace(a) || a == '_')
        return "_";
    sprintf(buf, "_%02x_", (unsigned char)a);
    return buf;
}


static const char* low(const char* s, int under, int clean)
{
    static char buf[1024];
    int i = 0;
    int c = 0;
    buf[0] = 0;

    if (under && !isalpha(*s)) {
        const char* p = ascii(*s);
        while (*p)
            buf[i++] = *p++;
        s++;
    }

    while (*s) {
        if (*s >= 'A' && *s <= 'Z')
            buf[i++] = *s - 'A' + 'a';
        else {
            c = (unsigned char)(*s);
            if ((under && !isalnum(c)) || (c > 127)) {
                const char* p = ascii(*s);
                while (*p)
                    buf[i++] = *p++;
            }
            else
                buf[i++] = *s;
        }
        s++;
    }

    buf[i] = 0;

    if (clean) {
        for (i = 0; i < NUMBER(reserved); i++)
            if (strcmp(reserved[i], buf) == 0)
                strcat(buf, "_");
    }
    return buf;
}

static void importing(FILE* f, const char* icon)
{
    static char* tag = NULL;
    if (!tag)
        tag = getenv("MVIMPORT_TAG");
    if (!tag)
        tag = "# Importing : ";
    fprintf(f, "%s%s\n\n", tag, icon);
}

static boolean import_link(FILE* f, const char* icon, request* r)
{
    request* s = link1(f, r);
    int i, j, c = 0, m, n;

    importing(f, icon);
    fprintf(f, "%s = ", low(mbasename(icon), 1, 1));

    fprintf(f, "[");

    n = count_values(s, "Window");

    for (i = 0; i < n; i++) {
        if (c)
            fprintf(f, ",");
        fprintf(f, "%s", get_value(s, "Window", i));
        c++;
    }

    m = count_values(s, "Visdef");
    n = count_values(s, "File");

    for (i = 0; i < n; i++) {
        if (c)
            fprintf(f, ",");
        fprintf(f, "%s", get_value(s, "File", i));
        c++;
        for (j = 0; j < m; j++) {
            if (c)
                fprintf(f, ",");
            fprintf(f, "%s", get_value(s, "Visdef", j));
            c++;
        }
    }

    n = count_values(s, "Data");

    for (i = 0; i < n; i++) {
        if (c)
            fprintf(f, ",");
        fprintf(f, "%s", get_value(s, "Data", i));
        c++;
        for (j = 0; j < m; j++) {
            if (c)
                fprintf(f, ",");
            fprintf(f, "%s", get_value(s, "Visdef", j));
            c++;
        }
    }


    fprintf(f, "]\n\n");

    free_all_requests(s);
    return true;
}

static boolean import_compute(FILE* f, const char* icon, request* r)
{
    math* m;
    if ((m = compmath(no_quotes(get_value(r, "FORMULA", 0))))) {
        formula1(f, icon, m, m);
        importing(f, icon);
        fprintf(f, "%s = ", low(mbasename(icon), 1, 1));
        formula2(f, m);
        free_math(m);
        fprintf(f, "\n\n");
        return true;
    }
    return false;
}

typedef struct cache
{
    struct cache* next;
    const char* name;
    request* lang;
} cache;

static request* get_language(const char* name)
{
    static cache* langs = NULL;
    cache* c;
    char* obj = strcache("object");
    request* r = mars.setup;
    const char* file = NULL;

    while (r) {
        if (r->name == obj) {
            const char* p = get_value(r, "class", 0);
            if (p == name) {
                file = get_value(r, "definition_file", 0);
                break;
            }
        }
        r = r->next;
    }

    strfree(obj);

    if (!file)
        return NULL;

    c = langs;
    while (c) {
        if (c->name == file)
            break;
        c = c->next;
    }

    if (c == NULL) {
        c = NEW_CLEAR(cache);
        c->next = langs;
        langs = c;
        c->name = strcache(file);
        c->lang = read_language_file(file);
    }

    return c->lang;
}

static int value_need_case(value* w, value* v)
{
    while (w) {
        if (w->ref) {
            if (value_need_case(w->ref, v) == 0)
                return 0;
        }
        else {
            value* o = w->other_names;
            if (w->name == v->name)
                return 0;

            while (o) {
                if (o->name == v->name)
                    return 0;
                o = o->next;
            }
        }
        w = w->next;
    }
    return 1;
}

static int need_case(request* r, parameter* p, value* v)
{
    request* l = get_language(r->name);
    while (l) {
        if (l->name == r->name) {
            parameter* q = l->params;
            while (q) {
                if (q->name == p->name)
                    return value_need_case(q->values, v);
                q = q->next;
            }
        }
        l = l->next;
    }
    return 0;
}

static void import_sub_objects(FILE* f, const char* icon, request* r, request* dot)
{
    parameter* p;
    int n;

    /* Look for references */
    request* l = get_language(r->name);

    while (l && (l->name != r->name))
        l = l->next;

    if (l) {
        p = l->params;
        while (p) {
            const char* i = get_value(p->interface, "interface", 0);
            if (i && (strcmp(i, "icon") == 0)) {
                int i = 0;
                const char* q;
                unset_value(r, "_temp");
                while ((q = get_value(r, p->name, i++))) {
                    q = makepath(mdirname(icon), q);
                    add_value(r, "_temp", ".%s", import(f, q));
                }
                unset_value(r, p->name);
                i = 0;
                while ((q = get_value(r, "_temp", i++)))
                    add_value(r, p->name, "%s", q);
                unset_value(r, "_temp");
            }

            p = p->next;
        }
    }

    /* Check in dot fil for macroparmas */


    if ((n = count_values(dot, "references"))) {
        int i = 0;
        const char* s;
        while ((s = get_value(dot, "references", i++))) {
            int i = 0;
            const char* q;
            unset_value(r, "_temp");
            while ((q = get_value(r, s, i++))) {
                q = makepath(mdirname(icon), q);
                add_value(r, "_temp", ".%s", import(f, q));
            }
            unset_value(r, s);
            i = 0;
            while ((q = get_value(r, "_temp", i++)))
                add_value(r, s, "%s", q);
            unset_value(r, "_temp");
        }
    }
}


static void import_values(FILE* f, request* r, parameter* p)
{
    value* v = p->values;
    int flg = v && v->next;
    int dateflg = 0;

    if (strcmp(p->name, "DATE") == 0 && cvtdates)
        dateflg = 1;

    if (flg)
        fprintf(f, "[");

    while (v) {
        /*Handling multi-line text for ODB query */
        if (strcmp(p->name, "ODB_QUERY") == 0 || strcmp(p->name, "ODB_WHERE") == 0) {
            if (strstr(v->name, "\n") == 0) {
                fprintf(f, "\"%s\"", v->name);
            }
            else {
                char* pch;
                int len = strlen(v->name);
                if (len > 0) {
                    char* buff = (char*)calloc(len + 1, sizeof(char));
                    sprintf(buff, "%s", v->name);
                    pch = strtok(buff, "\n");
                    fprintf(f, "\"%s \"", pch);

                    while (pch != NULL) {
                        pch = strtok(NULL, "\n");
                        if (pch != NULL) {
                            fprintf(f, " &\n");
                            fprintf(f, "%s%s%s%s%s\"%s \"", tab, tab, tab, tab, tab, pch);
                        }
                    }

                    free(buff);
                }
                /*fprintf(f,"\n",pch);*/

                /*fprintf(f,"string inline\n");
                fprintf(f,"%s\n",v->name);
                fprintf(f,"%s%s%stend inline", tab, tab, tab);*/
            }
        }
        else if (isdate(v->name))
            fprintf(f, "%s", v->name);
        else if (is_number(v->name))
            if (dateflg)
                putdate(f, atof(v->name));
            else
                fprintf(f, "%s", v->name); /*-- do not convert to number --*/
        else if (v->name[0] == '.')
            fprintf(f, "%s", v->name + 1);
        else if (*v->name == '"')
            fprintf(f, "%s", v->name);
        else if (need_case(r, p, v))
            fprintf(f, "\"%s\"", v->name);
        else
            fprintf(f, "\"%s\"", low(v->name, 0, 0));
        if (v->next)
            fprintf(f, ",");
        v = v->next;
    }

    if (flg)
        fprintf(f, "]");
}

static boolean import_simple_formula(FILE* f, const char* icon, request* r)
{
    request* lang;
    import_sub_objects(f, icon, r, NULL);

    lang = get_language(r->name);
    expand_flags(0);
    r = expand_all_requests(lang, NULL, r);
    if (!r)
        return false;

    {
        parameter* p0 = find_parameter(r, "PARAMETER");
        parameter* p1 = find_parameter(r, "PARAMETER_1");
        parameter* p2 = find_parameter(r, "PARAMETER_2");
        const char* fn = get_value(r, "FUNCTION", 0);
        const char* op = get_value(r, "OPERATOR", 0);

        if (!(p0 || (p1 && p2)))
            return false;
        importing(f, icon);
        fprintf(f, "%s = ", low(mbasename(icon), 1, 1));

        if (fn) {
            fprintf(f, "%s(", fn);
            if (p1 && p2) {
                import_values(f, r, p1);
                fprintf(f, ",");
                import_values(f, r, p2);
            }
            else if (p0)
                import_values(f, r, p0);
            fprintf(f, ")");
        }
        else if (op) {
            import_values(f, r, p1);
            fprintf(f, " %s", op);
            if (op[strlen(op) - 1] != ' ')
                fprintf(f, " ");
            import_values(f, r, p2);
        }
        else
            return false;
        fprintf(f, "\n");
        return true;
    }
    free_all_requests(r);
}

const char* clean(const char* p)
{
    static char buf[1024];
    int quote = 0;
    int i;
    const char* q = p;

    for (i = 0; i < NUMBER(reserved); i++)
        if (strcmp(reserved[i], p) == 0)
            quote++;


    if (*p != '_' && !isalpha(*p))
        quote++;

    while (*q) {
        if (*q != '_' && !isalnum(*q))
            quote++;
        q++;
    }

    if (quote) {
        char c = '\'';
        q = p;
        while (*q)
            if (*q++ == '\'')
                c = '"';

        i = 0;
        buf[i++] = c;
        q = p;
        while (*q) {
            if (*q == c)
                buf[i++] = '\\';
            buf[i++] = *q++;
        }
        buf[i++] = c;
        buf[i++] = 0;
        return buf;
    }
    return p;
}

static boolean import_request(FILE* f, const char* icon, request* r, request* u)
{
    const char* m = NULL;
    parameter* p;

    if (!r) {
        return false;
    }

    if (strncmp(r->name, "SAMPLE_FORMULA", strlen("SAMPLE_FORMULA")) == 0)
        return import_simple_formula(f, icon, r);


    /* Note: TABLE_READER does not have an associated macro in
    ObjecList because we want to over-ride it here. */

    if (strncmp(r->name, "TABLE_READER", strlen("TABLE_READER")) == 0)
        m = "read_table";

    u = u ? u : find_object(r->name);

    if (u != NULL && (m || (m = get_value(u, "macro", 0)))) {
        size_t maxlen = 1;

        import_sub_objects(f, icon, r, u);

        importing(f, icon);
        fprintf(f, "%s = ", low(mbasename(icon), 1, 1));

        fprintf(f, "%s(\n", m);

        p = r->params;

        /* if using spaces, then we can be more clever in how we align
           the colons after the parameter names; start by finding the length
           of the longest parameter name. */
        if (spaces) {
            while (p) {
                const char* str = clean(low(p->name, 0, 0));
                size_t thislen = strlen(str);
                if (thislen > maxlen)
                    maxlen = thislen;

                p = p->next;
            }
        }


        p = r->params; /* reset p */

        while (p) {
            const char* str = clean(low(p->name, 0, 0));
            size_t thislen = strlen(str);
            size_t i;
            fprintf(f, "%s%s", tab, clean(low(p->name, 0, 0)));
            if (spaces) {
                for (i = 0; i < (maxlen - thislen) + 1; i++) {
                    fprintf(f, " ");
                }
                fprintf(f, ": ");
            }
            else {
                fprintf(f, "%s:%s", tab, tab); /* not using spaces, just put param<tab>colon */
            }
            import_values(f, r, p);

            if (p->next)
                fprintf(f, ",");
            fprintf(f, "\n");
            p = p->next;
        }

        fprintf(f, "%s)\n\n", tab);
        return true;
    }
    return false;
}

static boolean import_all_requests(FILE* f, const char* icon, request* r, request* u)
{
    const char* p;
    if (r->next == NULL)
        return import_request(f, icon, r, u);

    fprintf(f, "%s = []\n",
            low(mbasename(icon), 1, 1));

    while (r) {
        import_request(f, "tmp", r, u);
        fprintf(f, "%s = %s & [tmp]\n",
                low(mbasename(icon), 1, 1),
                low(mbasename(icon), 1, 1));
        r = r->next;
    }
    return true;
}

static boolean import_macro(FILE* f, const char* icon, const char* file)
{
    char line[1024];
    FILE* g = fopen(file, "r");
    importing(f, icon);

    if (g) {
        int c, last = -1;
        fprintf(f, "##### Start of macro %s\n", icon);

        while ((c = fgetc(g)) != -1) {
            last = c;
            fputc(c, f);
        }
        fclose(g);
        if (last != '\n')
            fputc('\n', f);
        fprintf(f, "##### End of macro %s\n", icon);
    }
    else
        fprintf(f, "# Cannot read file %s\n", file);


    return true;
}

static boolean import_file(FILE* f, const char* icon, const char* file)
{
    char line[1024];
    importing(f, icon);
    fprintf(f, "%s = read(\"%s\")\n\n", low(mbasename(icon), 1, 1), file);
    return true;
}

static boolean import_macroparam(FILE* f, const char* icon, request* r, request* dot)
{
    char buf[1024];
    char name[1024];
    const char* p;

    strcpy(name, low(mbasename(icon), 1, 1));
    set_value(dot, "macro", "");
    import_request(f, icon, r->next, dot);

    fprintf(f, "# NOTE: You may want to change the execute to visualize\n");
    fprintf(f, "%s = execute(%s)\n\n", name, name);


    sprintf(buf, "%s%s",
            getenv("METVIEW_USER_DIRECTORY"),
            makepath(mdirname(icon), get_value(r, "MACRO", 0)));
    import_macro(f, get_value(r, "MACRO", 0), buf);

    return true;
}

static boolean import_shell(FILE* f, const char* icon, const char* file)
{
    importing(f, icon);
    fprintf(f, "%s = shell(\"%s\")\n\n", low(mbasename(icon), 1, 1), file);
    return true;
}

static boolean import_magml(FILE* f, const char* icon, const char* file)
{
    importing(f, icon);
    fprintf(f, "%s = magml(\"%s\")\n\n", low(mbasename(icon), 1, 1), file);
    return true;
}

static boolean import_note(FILE* f, const char* icon, const char* file)
{
    FILE* g = fopen(file, "r");
    importing(f, icon);

    if (g) {
        int c, last = -1;
        fprintf(f, "%s = string inline\n", low(mbasename(icon), 1, 1));
        while ((c = fgetc(g)) != -1) {
            last = c;
            fputc(c, f);
        }
        if (last != '\n')
            fputc('\n', f);
        fprintf(f, "end inline\n");
        fclose(g);
    }
    else
        fprintf(f, "# Cannot read file %s\n", file);

    return true;
}

boolean import_read(FILE* f, const char* icon, request* r)
{
    /* if only PATH is set, use the read function */
    parameter* p = r->params;
    const char* path = get_value(r, "SOURCE", 0);
    int n = 0;

    while (p) {
        if (*p->name != '_')
            n++;
        p = p->next;
    }

    if (path && (n == 1)) {
        importing(f, icon);
        fprintf(f, "%s = read(\"%s\")\n\n", low(mbasename(icon), 1, 1), no_quotes(path));
        return true;
    }

    return import_request(f, icon, r, NULL);
}


boolean import_table_reader(FILE* f, const char* icon, request* r)
{
    /* DATA is set, then it will be more efficient to change it to SOURCE */

    const char* data = get_value(r, "DATA", 0);

    if (data != NULL) {
        set_value(r, "TABLE_FILENAME", data);
        unset_value(r, "DATA");
    }


    return import_request(f, icon, r, NULL);
}

boolean import_table_visualiser(FILE* f, const char* icon, request* r)
{
    /* TABLE_DATA is set, then it will be more efficient to change it to SOURCE */

    const char* data = get_value(r, "TABLE_DATA", 0);

    if (data != NULL) {
        set_value(r, "TABLE_FILENAME", data);
        unset_value(r, "TABLE_DATA");
    }


    return import_request(f, icon, r, NULL);
}


boolean import_rttov_visualiser(FILE* f, const char* icon, request* r)
{
    /* DATA is set, then it will be more efficient to change it to SOURCE */

    const char* data = get_value(r, "RTTOV_DATA", 0);

    if (data != NULL) {
        set_value(r, "RTTOV_FILENAME", data);
        unset_value(r, "RTTOV_DATA");
    }


    return import_request(f, icon, r, NULL);
}

const char* import(FILE* f, const char* name)
{
    char buf[1024];
    char dot[1024];
    char icon[1024];
    boolean ok = false;
    const char* c = NULL;
    request *r, *u;

    strcpy(icon, name);

    const char* mvhome = getenv("METVIEW_USER_DIRECTORY");
    if (!mvhome)
        return 0;

    if (strstr(name, mvhome) != 0)
        sprintf(buf, "%s", icon);
    else
        sprintf(buf, "%s/%s", mvhome, icon);

    sprintf(dot, "%s/.%s", mdirname(buf), mbasename(buf));

    r = read_request_file(buf);
    u = read_request_file(dot);

    if (u && (c = get_value(u, "ICON_CLASS", 0))) {
        if (strcmp(c, "NOTE") == 0)
            ok = import_note(f, icon, buf);
        else if (strcmp(c, "SHELL") == 0)
            ok = import_shell(f, icon, buf);
        else if (strcmp(c, "MAGML") == 0)
            ok = import_magml(f, icon, buf);
        else if (strcmp(c, "READ") == 0)
            ok = import_read(f, icon, r);
        else if (strcmp(c, "GEOPOINTS") == 0)
            ok = import_file(f, icon, buf);
        else if (strcmp(c, "MACROPARAM") == 0)
            ok = import_macroparam(f, icon, r, u);
        else if (strcmp(c, "TABLE_READER") == 0)
            ok = import_table_reader(f, icon, r);
        else if (strcmp(c, "TABLE_VISUALISER") == 0)
            ok = import_table_visualiser(f, icon, r);
        else if (strcmp(c, "RTTOV_VISUALISER") == 0)
            ok = import_rttov_visualiser(f, icon, r);
    }

    if (!ok && (r != NULL || c != NULL)) {
        request* u = find_object(r ? r->name : c);
        const char* t = u ? get_value(u, "type", 0) : NULL;

        if (t) {
            if (strcmp(t, "Macro") == 0)
                ok = import_macro(f, icon, buf);
            else if (strcmp(t, "Family") == 0 || strcmp(t, "FamilyWindow") == 0)
                ok = import_request(f, icon, r ? r->next : NULL, NULL);
            else if (strcmp(t, "File") == 0)
                ok = import_file(f, icon, buf);
            else
                ;
            /* printf("Type is %s\n",t); */
        }
    }

    if (!ok && (r != NULL) && (c = r->name)) {
        if (strcmp(c, "LINK") == 0)
            ok = import_link(f, icon, r);
        else if (strcmp(c, "COMPUTE") == 0)
            ok = import_compute(f, icon, r);
        else
            ok = import_request(f, icon, r, NULL);
    }

    if (!ok) {
        importing(f, icon);
        fprintf(f, "# Warning: cannot import : %s\n", icon);
        fprintf(f, "# Using the metview function, not available in batch\n\n");
        fprintf(f, "%s = metview(\"%s\")\n\n", low(mbasename(icon), 1, 1), icon);
        /* print_all_requests(r); */
        /* print_all_requests(u); */
    }

    free_all_requests(r);
    free_all_requests(u);
    return low(mbasename(icon), 1, 1);
}

static void formula3(math* m, char* name, const char* sub)
{
    if (m) {
        if (m->name && (m->arity <= 0) && (name == m->name)) {
            strfree(name);
            m->name = strcache(sub);
        }
        formula3(m->left, name, sub);
        formula3(m->right, name, sub);
    }
}

static void formula1(FILE* f, const char* ref, math* m, math* x)
{
    if (m) {
        formula1(f, ref, m->left, x);
        formula1(f, ref, m->right, x);
        if (m->name)
            if (m->arity <= 0)
                if (!is_number(m->name) && (m->name[0] != '.')) {
                    char buf[1024];
                    char *y, *name;
                    const char* p = buf;
                    char* o;
                    sprintf(buf, "%s", m->name);

                    if (*buf == '"' || *buf == '\'') {
                        p = buf + 1;
                        buf[strlen(buf) - 1] = 0;
                    }

                    if (*p != '/')
                        p = makepath(mdirname(ref), p);

                    o = strcache(p);
                    y = strcache(import(f, o));
                    strfree(o);

                    name = strcache(m->name);
                    sprintf(buf, ".%s", y);
                    formula3(x, name, buf);
                    strfree(name);
                    strfree(y);
                }
    }
}

static void formula2(FILE* f, math* m)
{
    if (m) {
        if (m->name)
            if (m->arity <= 0) {
                if (is_number(m->name))
                    fprintf(f, "%.12g", atof(m->name));
                else {
                    fprintf(f, "%s", m->name + 1);
                }
                if (m->arity < 0) {
                    fprintf(f, "[");
                    formula2(f, m->left);
                    fprintf(f, "]");
                }
            }
            else {
                fprintf(f, "(");
                if (isalpha(m->name[0])) {
                    fprintf(f, "%s(", m->name);
                    formula2(f, m->left);
                    fprintf(f, ")");
                }
                else {
                    formula2(f, m->left);
                    fprintf(f, " %s ", m->name);
                    formula2(f, m->right);
                }
                fprintf(f, ")");
            }
        else {
            formula2(f, m->left);
            if (m->right)
                fprintf(f, ",");
            formula2(f, m->right);
        }
    }
}


static request* link1(FILE* f, request* r)
{
    request* s = empty_request(NULL);
    r = r->next;
    while (r) {
        request* u = find_object(get_value(r, "CLASS", 0));
        if (u)
            add_value(s, get_value(u, "type", 0), "%s",
                      import(f, get_value(r, "NAME", 0)));
        r = r->next;
    }
    return s;
}


static void import_window(FILE* f, request* r)
{
    const char* user = getenv("METVIEW_USER_DIRECTORY");
    char icon[1024];
    int m = 0;
    int i = 0;
    const char* p;

    while (r) {
        int w = strcmp(r->name, "PLOTWINDOW") == 0 || strcmp(r->name, "CAROUSEL") == 0;

        strcpy(icon, "y");

        if (w)
            fprintf(f, "if not retval then # Don't create windows\n");

        /* It's an object */
        if ((p = get_value(r, "_NAME", 0))) {
            char buf[1024];
            sprintf(buf, "%s/%s", user, p);
            if (access(buf, 0) == 0) {
                fprintf(f, "if use_objects then\n");
                fprintf(f, "  %s = metview(\"%s\")\n", icon, p);
                fprintf(f, "else\n");
                fprintf(f, "	%s = %s\n", icon, import(f, p));
                fprintf(f, "end if\n");
            }
            else
                p = NULL;
        }
        if (!p) {
            if (!import_request(f, icon, r, NULL)) {
                /* The request is not known */
                request* u = empty_request(NULL);
                set_value(u, "macro", "");
                set_value(r, "_VERB", "%s", r->name);
                import_request(f, icon, r, u);
                free_all_requests(u);
            }
        }
        fprintf(f, "x = x & [%s]\n", icon);

        if (w)
            fprintf(f, "end if\n");

        r = r->next;
    }
}

static void serve(svcid* id, request* r, void* misc)
{
    char name[1024];
    char icon[1024];
    FILE* f;
    request* u;
    const char* p;
    int n = 0;
    const char* userd = getenv("METVIEW_USER_DIRECTORY");
    long now = mars_julian_to_date(mars_date_to_julian(0), 1);

    /* mars.debug = 1; */
    /* print_all_requests(r); */
    /* mars.debug = 0; */

    p = get_value(r, "TITLE", 0);
    if (!p)
        p = "Plot Window";

    sprintf(name, "%s/Content of %s", userd, p);
    while (access(name, 0) == 0)
        sprintf(name, "%s/Content of %s (%d)", userd, p, ++n);

    if (r && strcmp(r->name, "VISTOOL") == 0)
        r = r->next;

    cvtdates = 1;

    sprintf(icon, "%s/.%s", userd, mbasename(name));
    f = fopen(icon, "w");
    fprintf(f, "USER_INTERFACE,ICON_CLASS=WMACRO\n");
    fclose(f);

    f = fopen(name, "w");
    fprintf(f, "# This macro was gererated automagicaly\n");
    fprintf(f, "# by %s the %ld\n", user(NULL), now);
    fprintf(f, "# The metview user directory was %s", userd);
    fprintf(f, "\n\n");
    fprintf(f, "# You can control the playback of the macro by changing\n");
    fprintf(f, "# the two following variables (set to 0 or 1):\n\n");

    fprintf(f, "use_objects = 1 # Use the original icon definitions.\n");
    fprintf(f, "rel_dates   = 1 # Make date relatives to today.\n");

    fprintf(f, "\n#\n\n");
    fprintf(f, "retval = runmode(\"visualise\")\n\n");
    fprintf(f, "if rel_dates then\n");
    fprintf(f, "   today = 0\n");
    fprintf(f, "else\n");
    fprintf(f, "   today = %ld\n", now);
    fprintf(f, "end if\n\n");

    fprintf(f, "if use_objects then\n");
    fprintf(f, "   putenv(METVIEW_USER_DIRECTORY : '%s' )\n", userd);
    fprintf(f, "end if\n\n");

    fprintf(f, "x = []\n\n");

    /* Mode ? */
    if ((u = get_subrequest(r, "_MODE", 0))) {
        import_window(f, u);
        free_all_requests(u);
    }
    else
        import_window(f, r);

    fprintf(f, "\n");
    fprintf(f, "if retval then\n");
    fprintf(f, "   return x\nelse\n   plot(x)\nend if\n");

    fclose(f);


    u = empty_request("STATUS");
    set_value(u, "NAME", "/%s", mbasename(name));
    set_value(u, "CLASS", "WMACRO");
    set_value(u, "STATUS", "CREATED");
    send_message(id->s, u);
    free_all_requests(u);

    u = empty_request("USER_MESSAGE");
    set_value(u, "INFO", "Window content saved in '%s'", mbasename(name));
    send_message(id->s, u);
    free_all_requests(u);

    u = empty_request("STRING");
    set_value(u, "VALUE", "Window content saved in '%s'", mbasename(name));
    send_reply(id, u);
    free_all_requests(u);
}

int main(int argc, char** argv)
{
    marsinit(&argc, argv, &setup, NUMBER(opts), opts);
    if (setup.serve) {
        svc* s = create_service(progname());
        add_service_callback(s, NULL, serve, NULL);
        service_run(s);
    }
    else
        /*
        argv[1]: path to icon file
        argv[2]: path to output file
        argv[3]: number of spaces to use instead of tabs (optional) */

        if (argc > 3) {
            int num_spaces = atoi(argv[3]);
            int i;
            spaces = true;
            for (i = 0; i < num_spaces; i++)
                tab[i] = ' ';
            tab[i] = '\0';
        }
        else
            strcpy(tab, "\t");

    import(fopen(argv[2], "w"), argv[1]);
    return 0;
}
