/* Cell-file line extraction */
/*   Input/output and line tracing routines */

/* Mike Baba */
/* DBA Systems */
/* Farfax, VA */
/* Jan 1990 */

/* Jean Ezell */
/* US Army Corps of Engineers */
/* Construction Engineering Research Lab */
/* Modelling and Simulation Team */
/* Champaign, IL  61820 */
/* March 1988 */

/* input is a GRASS raster map */
/* output is a binary or ascii digit file */

/*
 * Modified for the new Grass 5.0 floating point and
 * null values raster map format.
 * Pierre de Mouveaux - 20 april 2000.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef _WIN32
#include <process.h>
#else
#include <sys/wait.h>
#endif

#include <grass/gis.h>
#include <grass/glocale.h>
#include <grass/dbmi.h>
#include <grass/vector.h>
#include "global.h"

/* function prototypes */
static int write_ln(struct COOR *, struct COOR *, int);

/* write_line - attempt to write a line to output */
/* just returns if line is not completed yet */

int write_line(struct COOR *seed)
{
    struct COOR *point, *begin, *end, *last;
    int dir, line_type, n, n1;

    point = seed;
    if ((dir = at_end(point))) { /* already have one end of line */
        begin = point;
        end = find_end(point, dir, &line_type, &n);
        if (line_type == OPEN) {
            return (-1); /* unfinished line */
        }
        direction = dir;
    }
    else { /* in middle of a line */
        end = find_end(point, FORWARD, &line_type, &n);
        if (line_type == OPEN) { /* line not finished */
            return (-1);
        }

        if (line_type ==
            END) { /* found one end at least */ /* look for other one */
            begin = find_end(point, BACKWARD, &line_type, &n1);
            if (line_type == OPEN) { /* line not finished */
                return (-1);
            }

            if (line_type == LOOP) { /* this should NEVER be the case */
                G_warning(_("write_line:  found half a loop!"));
                return (-1);
            }

            direction = at_end(begin); /* found both ends now; total length */
            n += n1;                   /*   is sum of distances to each end */
        }
        else { /* line_type = LOOP by default */
            /* already have correct length */
            begin = end;         /* end and beginning are the same */
            direction = FORWARD; /* direction is arbitrary */
        }
    }

    dir = direction;

    /* if (n > 2) */
    write_ln(begin, end, n);

    /* now free all the pointers */
    direction = dir;
    point = begin;

    /* skip first and last point */
    while ((point = move(point)) == begin)
        ;

    while (point && point != end) {
        last = point;

        point = move(point);
        if (point == last) {
            /* should not happen */
            G_warning("loop during free ptrs, ptr %d of %d", n1, n);
            point = move(point);
        }

        if (last->fptr != NULL)
            if (last->fptr->fptr == last)
                last->fptr->fptr = NULL;

        /* now it can already ne NULL */
        if (last->fptr != NULL)
            if (last->fptr->bptr == last)
                last->fptr->bptr = NULL;
        if (last->bptr != NULL)
            if (last->bptr->fptr == last)
                last->bptr->fptr = NULL;
        if (last->bptr != NULL)
            if (last->bptr->bptr == last)
                last->bptr->bptr = NULL;
        free_ptr(last);
    } /* end of for i */

    if (point != end) {
        /* should not happen */
        G_warning("Line end not reached, possible memory leak");
    }

    /* free first and last point */
    free_ptr(begin);
    if (end != begin)
        free_ptr(end);

    return (0);
}

/* write_ln - actual writing part of write_line */
/* writes binary and supplemental file */

static int write_ln(struct COOR *begin,
                    struct COOR *end G_UNUSED, /* start and end point of line */
                    int n)
{ /* number of points to write */
    static struct line_pnts *points = NULL;
    double x, y;
    struct COOR *p, *last;
    int i, cat, field;
    static int count = 1;

    if (!points)
        points = Vect_new_line_struct();
    Vect_reset_line(points);

    field = 1;

    Vect_reset_cats(Cats);

    p = begin;
    y = cell_head.north - ((double)p->row + 0.5) * cell_head.ns_res;
    x = cell_head.west + ((double)p->col + 0.5) * cell_head.ew_res;

    /* value_flag is used only for CELL type */
    cat = (value_flag) ? p->val : count;

    Vect_cat_set(Cats, field, cat);
    Vect_append_point(points, x, y, 0.0);

    for (i = 0; i < n; i++) {
        last = p;

        /* this should NEVER happen */
        if ((p = move(p)) == NULL)
            G_fatal_error(_("write_line: line terminated unexpectedly\n"
                            "  previous (%d) point %d (%d,%d,%d) %p %p"),
                          direction, i, last->row, last->col, last->node,
                          (void *)last->fptr, (void *)last->bptr);

        y = cell_head.north - ((double)p->row + 0.5) * cell_head.ns_res;
        x = cell_head.west + ((double)p->col + 0.5) * cell_head.ew_res;

        if (p->val != cat && value_flag) {
            Vect_append_point(points, x, y, 0.0);

            if ((driver != NULL) && !value_flag) {
                insert_value(cat, p->val, p->dval);
            }

            Vect_write_line(&Map, GV_LINE, points, Cats);
            Vect_reset_line(points);
            Vect_reset_cats(Cats);
            cat = (value_flag) ? p->val : (++count);
            Vect_cat_set(Cats, field, cat);
        }

        Vect_append_point(points, x, y, 0.0);
    }

    if ((driver != NULL) && !value_flag) {
        insert_value(cat, p->val, p->dval);
    }

    Vect_write_line(&Map, GV_LINE, points, Cats);

    count++;

    return 0;
}
