#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "global.h"

#ifndef DBL_MAX
#define DBL_MAX 9999999999999999999999.9
#define DBL_MIN -99999999999999999999.9
#endif

static void make_head(struct Map_info *);
static int find_next_header_variable(struct dxf_file *);

static struct bound_box ext, dxf_ext;

/* returns 1 on success, otherwise 0 */
int dxf_to_vect(struct dxf_file *dxf, struct Map_info *Map)
{
    int code;
    int bounds = 0;

    if (dxf_find_header(dxf)) {
        /* code == 0: end of the header section */
        code = dxf_get_code(dxf);
        while (code != 0) { /* ENDSEC */
            if (code == -2) /* EOF */
                return 0;

            /* only looking for header groups (code == 9) */
            if (code != 9) {
                code = find_next_header_variable(dxf);
                continue;
            }

            if (strcmp(dxf_buf, "$EXTMAX") == 0) {
                /* read in lines and process information until a 9
                 * or a 0 is read in */
                while ((code = dxf_get_code(dxf)) != 9 && code != 0) {
                    if (code == -2) /* EOF */
                        return 0;

                    switch (code) {
                    case 10:
                        dxf_ext.E = atof(dxf_buf);
                        bounds++;
                        break;
                    case 20:
                        dxf_ext.N = atof(dxf_buf);
                        bounds++;
                        break;
                    case 30:
                        dxf_ext.T = atof(dxf_buf);
                        bounds++;
                        break;
                    default:
                        break;
                    }
                }
            }
            else if (strcmp(dxf_buf, "$EXTMIN") == 0) {
                /* read in lines and process information until a 9
                 * or a 0 is read in */
                while ((code = dxf_get_code(dxf)) != 9 && code != 0) {
                    if (code == -2) /* EOF */
                        return 0;

                    switch (code) {
                    case 10:
                        dxf_ext.W = atof(dxf_buf);
                        bounds++;
                        break;
                    case 20:
                        dxf_ext.S = atof(dxf_buf);
                        bounds++;
                        break;
                    case 30:
                        dxf_ext.B = atof(dxf_buf);
                        bounds++;
                        FALLTHROUGH;
                    default:
                        break;
                    }
                }
            }
            else
                code = find_next_header_variable(dxf);

            if (bounds == 6)
                break;
        }
    }
    else
        code = dxf_get_code(dxf);

    arr_max = ARR_INCR;
    ext.E = ext.N = ext.T = DBL_MIN;
    ext.W = ext.S = ext.B = DBL_MAX;

    xpnts = (double *)G_malloc(arr_max * sizeof(double));
    ypnts = (double *)G_malloc(arr_max * sizeof(double));
    zpnts = (double *)G_malloc(arr_max * sizeof(double));

    if (!flag_list)
        Points = Vect_new_line_struct();

    while (!feof(dxf->fp)) {
        /* avoid TEXT having object names: '0' should be followed by objects */
        if (code != 0)
            code = dxf_get_code(dxf);

        else if (strcmp(dxf_buf, "POINT") == 0)
            add_point(dxf, Map);

        else if (strcmp(dxf_buf, "LINE") == 0)
            add_line(dxf, Map);

        else if (strcmp(dxf_buf, "POLYLINE") == 0)
            add_polyline(dxf, Map);

        else if (strcmp(dxf_buf, "LWPOLYLINE") == 0)
            add_lwpolyline(dxf, Map);

        else if (strcmp(dxf_buf, "ARC") == 0)
            add_arc(dxf, Map);

        else if (strcmp(dxf_buf, "CIRCLE") == 0)
            add_circle(dxf, Map);

        else if (strcmp(dxf_buf, "3DFACE") == 0)
            add_3dface(dxf, Map);

        else if (strcmp(dxf_buf, "TEXT") == 0)
            add_text(dxf, Map);

        else
            code = dxf_get_code(dxf);
    }

    G_free(xpnts);
    G_free(ypnts);
    G_free(zpnts);

    if (flag_list)
        return 1;

    Vect_destroy_line_struct(Points);

    if (write_done(Map)) {
        make_head(Map);
        return 1;
    }

    return 0;
}

int find_next_header_variable(struct dxf_file *dxf)
{
    int code;

    /* code  9: header variable
     * code  0: ENDSEC
     * code -2: EOF
     */
    while ((code = dxf_get_code(dxf)) != 9 && code != 0 && code != -2)
        ;

    return code;
}

int check_ext(double x, double y, double z)
{
    if (x < ext.W)
        ext.W = x;
    if (x > ext.E)
        ext.E = x;
    if (y < ext.S)
        ext.S = y;
    if (y > ext.N)
        ext.N = y;
    if (z < ext.B)
        ext.B = z;
    if (z > ext.T)
        ext.T = z;

    return 0;
}

static void make_head(struct Map_info *Map)
{
    char *organization;

    if ((organization = getenv("GRASS_ORGANIZATION"))) /* added MN 5/2001 */
        Vect_set_organization(Map, organization);
    else
        Vect_set_organization(Map, "GRASS Development Team");
    Vect_set_date(Map, G_date());
    Vect_set_person(Map, G_whoami());
    Vect_set_map_date(Map, "");
    Vect_set_scale(Map, 2400);
    Vect_set_comment(Map, "");
    Vect_set_zone(Map, 0);
    Vect_set_thresh(Map, 0.0);

    if (!flag_extent)
        Vect_box_copy(&(Map->plus.box), &dxf_ext);

    return;
}
