#include <stdio.h>
#include <math.h>
#include <float.h>
#include <grass/gis.h>
#include <grass/vector.h>
#include <grass/display.h>
#include "sw_defs.h"
#include "defs.h"

static int write_skeleton(struct line_pnts *Points)
{
    int i, area1, area2;
    static struct line_pnts *APoints = NULL;
    static struct line_cats *Cats = NULL;
    int ret;

    if (!APoints) {
	APoints = Vect_new_line_struct();
	Cats = Vect_new_cats_struct();
    }

    if ((area1 = Vect_find_area(&In, Points->x[0], Points->y[0])) == 0)
	return 0;
    if ((area2 = Vect_find_area(&In, Points->x[1], Points->y[1])) == 0)
	return 0;

    ret = 1;
    if (!Vect_get_area_centroid(&In, area1))
	ret = 0;

    if (ret) {
	Vect_get_area_points(&In, area1, APoints);
	if (Vect_line_check_intersection(Points, APoints, 0))
	    ret = 0;
    }

    if (ret) {
	for (i = 0; i < Vect_get_area_num_isles(&In, area1); i++) {
	    Vect_get_isle_points(&In, Vect_get_area_isle(&In, area1, i), APoints);
	    if (Vect_line_check_intersection(Points, APoints, 0)) {
		ret = 0;
		break;
	    }
	}
    }


    if (!ret && area1 != area2) {
	ret = 1;
	if (!Vect_get_area_centroid(&In, area2))
	    ret = 0;
	if (ret) {
	    Vect_get_area_points(&In, area2, APoints);
	    if (Vect_line_check_intersection(Points, APoints, 0))
		ret = 0;
	}

	if (ret) {
	    for (i = 0; i < Vect_get_area_num_isles(&In, area2); i++) {
		Vect_get_isle_points(&In, Vect_get_area_isle(&In, area2, i), APoints);
		if (Vect_line_check_intersection(Points, APoints, 0)) {
		    ret = 0;
		    break;
		}
	    }
	}
    }
    if (!ret)
	return 0;

    Vect_get_area_cats(&In, area1, Cats);
    Vect_write_line(&Out, GV_LINE, Points, Cats);

    return 1;
}

int vo_write(void)
{
    struct Halfedge *lbnd;

    for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd)) {
	write_ep(lbnd->ELedge);
    }

    /* TODO: free memory */

    return 1;
}


int write_ep(struct Edge *e)
{
    static struct line_pnts *Points = NULL;
    static struct line_cats *Cats = NULL;
    double x1, y1, x2, y2;

    if (!Points) {
	Points = Vect_new_line_struct();
	Cats = Vect_new_cats_struct();
	if (in_area)
	    Vect_cat_set(Cats, 1, 1);
    }

    if (in_area && e->reg[le]->sitenbr == e->reg[re]->sitenbr)
	return 0;

    if (e->ep[le] != NULL && e->ep[re] != NULL) {	/* both end defined */
	x1 = e->ep[le]->coord.x + xcenter;
	y1 = e->ep[le]->coord.y + ycenter;
	x2 = e->ep[re]->coord.x + xcenter;
	y2 = e->ep[re]->coord.y + ycenter;

	if (!Vect_point_in_box(x1, y1, 0.0, &Box) ||
	    !Vect_point_in_box(x2, y2, 0.0, &Box)) {
	    Vect_box_clip(&x1, &y1, &x2, &y2, &Box);
	}

	/* Don't write zero length */
	if (x1 == x2 && y1 == y2)
	    return 0;

	Vect_reset_line(Points);
	Vect_append_point(Points, x1, y1, 0.0);
	Vect_append_point(Points, x2, y2, 0.0);
	if (skeleton)
	    write_skeleton(Points);
	else
	    Vect_write_line(&Out, Type, Points, Cats);
    }
    else {
	int knownPointAtLeft = -1;

	if (e->ep[le] != NULL) {
	    x1 = e->ep[le]->coord.x + xcenter;
	    y1 = e->ep[le]->coord.y + ycenter;
	    knownPointAtLeft = 1;
	}
	else if (e->ep[re] != NULL) {
	    x1 = e->ep[re]->coord.x + xcenter;
	    y1 = e->ep[re]->coord.y + ycenter;
	    knownPointAtLeft = 0;
	}

	if (knownPointAtLeft == -1) {
	    x2 = (e->reg[le]->coord.x + e->reg[re]->coord.x) / 2.0 + xcenter;
	    y2 = (e->reg[le]->coord.y + e->reg[re]->coord.y) / 2.0 + ycenter;
	    knownPointAtLeft = 0;
	    if (!extend_line(Box.S, Box.N, Box.W, Box.E,
			     e->a, e->b, e->c, x2, y2, &x1, &y1,
			     knownPointAtLeft)) {
				 
		G_warning("Undefined edge, unable to extend line");
		
		return 0;
	    }
	    knownPointAtLeft = 1;
	}
	if (extend_line(Box.S, Box.N, Box.W, Box.E,
			e->a, e->b, e->c, x1, y1, &x2, &y2,
			knownPointAtLeft)) {

	    /* Don't write zero length */
	    if (x1 == x2 && y1 == y2)
		return 0;

	    Vect_reset_line(Points);
	    Vect_append_point(Points, x1, y1, 0.0);
	    Vect_append_point(Points, x2, y2, 0.0);
	    if (skeleton)
		write_skeleton(Points);
	    else
		Vect_write_line(&Out, Type, Points, Cats);
	}
    }

    return 0;
}
