static char *SccsId = "@(#)add_grpnbr.c 4.2 (TU-Delft) 06/18/90";
/**********************************************************

Name/Version      : NBOOL/4.2

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author(s)         : J. Liedorp
Creation date     : 24-Jun-1985
Modified by       : S. de Graaf
Modification date : 10-Dec-1985


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1985 , All rights reserved
**********************************************************/
#include "nbool.h"

/* This file contains the procedures to add the group_	 */
/* numbers to the edges. Most of them have been copied	 */
/* from the program makevln.				 */

add_grpnbr (form_nbr)
int   form_nbr;			/* bool_form_number	 */
{
/* main procedure for the addition of the group_numbers	 */
/* A state_ruler is built containing only the group_pntrs*/
/* As its input it uses the binary files made by nbool	 */
/* so far. (the TEMP_ONE files).			 */
/* First a tempory file (TEMP_TWO) is made containing the*/
/* group_pointers, and the TEMP_ONE file is removed.	 */
/* Then the TEMP_TWO file is read and the group_pointers */
/* replaced by the group_numbers. At last the vln_file	 */
/* in the 'normal' format is made and the TEMP_TWO file	 */
/* is also deleted.					 */

    char    fw_name[10];	/* bool_ filename	 */
    struct grp_sr  *g_sr;	/* ptr to groupstruct.	 */
    FILE   *f_in;		/* input_file		 */
    FILE   *f_int;		/* intermediate_file	 */
    DM_STREAM   *f_out;		/* output_file		 */
    int     x_sr;		/* state_ruler position	 */

    sprintf (fr_name, TEMP_ONE, form_nbr, pid);
    sprintf (fi_name, TEMP_TWO, form_nbr, pid);

    OPEN (f_in, fr_name, "r");
    OPEN (f_int, fi_name, "w");

    x_sr = -MAXINT;
    group_ptr = NULL;

    /* initialize state ruler */
    g_sr = &grp_sr_head;
    g_sr -> yt = MAXINT;
    g_sr -> yb = -MAXINT;
    g_sr -> group = NULL;
    g_sr -> next = g_sr -> prev = &grp_sr_head;

    while (fread ((char *) b_pntr, sizeof (*b_pntr), 1, f_in) != 0) {
	if (b_pntr -> x != x_sr) {
	    x_sr = b_pntr -> x;
	    g_sr = &grp_sr_head;
	    update_grp_sr (g_sr);
	}
	if ((b_pntr -> edge & START_EDGE) != 0) {
	    ins_sr (&g_sr, b_pntr -> yb, b_pntr -> yt, START_EDGE);
	    update_group (g_sr);
	}
	else
	    if ((b_pntr -> edge & STOP_EDGE) != 0) {
		update_group (g_sr);
		ins_sr (&g_sr, b_pntr -> yb, b_pntr -> yt, STOP_EDGE);
	    }
	    else
		update_group (g_sr);

	fwrite ((char *) b_pntr, sizeof (*b_pntr), 1, f_int);
    }
    free_grp_sr ();
    CLOSE (f_in);
    CLOSE (f_int);
    unlink (fr_name);

    number_groups ();

    sprintf (fw_name, "bool_%d", form_nbr);
    OPEN (f_int, fi_name, "r");
    f_out = dmOpenStream (mod_key, fw_name, "w");

    while (fread ((char *) b_pntr, sizeof (*b_pntr), 1, f_int)) {
	gvlnlay.x  = b_pntr -> x;
	gvlnlay.yb = b_pntr -> yb;
	gvlnlay.yt = b_pntr -> yt;
	gvlnlay.occ_type = b_pntr -> edge;
	gvlnlay.con_type = b_pntr -> conn;
	gvlnlay.chk_type = b_pntr -> ct;
	gvlnlay.grp_number = fdgrp_name (b_pntr -> grp);
	dmPutDesignData (f_out, GEO_VLNLAY);
    }
    CLOSE (f_int);
    dmCloseStream (f_out, COMPLETE);
    unlink (fi_name);
    free_groups ();
}

ins_sr (r_srp, yb, yt, edge_type)
struct grp_sr **r_srp;		/* ptr to first field of rsr   */
int     yb, yt;			/* bottom, top value of edge_type */
unsigned    edge_type;		/* edge type		 */
{
    struct grp_sr  *c_sr;	/* current rsr-pointer	 */

    c_sr = (*r_srp);
    while (yb >= c_sr -> yt) {
	c_sr = c_sr -> next;
    }
    (*r_srp) = c_sr;
    if (yb > c_sr -> yb) {
	split_grp_fld (c_sr, yb);
	c_sr = c_sr -> next;
    }
    while (yt >= c_sr -> yt) {
	update_grp_fld (c_sr, edge_type);
	c_sr = c_sr -> next;
    }
    if (yt > c_sr -> yb) {
	split_grp_fld (c_sr, yt);
	update_grp_fld (c_sr, edge_type);
    }
}

split_grp_fld (c_sr, ysplit)
register struct grp_sr *c_sr;
int     ysplit;
{
    struct grp_sr  *p_nf;	/* ptr to new state ruler field */

    ALLOC (p_nf, grp_sr);
    p_nf -> yb = ysplit;
    p_nf -> yt = c_sr -> yt;
    p_nf -> group = c_sr -> group;
    p_nf -> next = c_sr -> next;
    p_nf -> prev = c_sr;
    p_nf -> next -> prev = p_nf;
    p_nf -> prev -> next = p_nf;
    c_sr -> yt = ysplit;
}

update_grp_fld (c_sr, edge_type)
register struct grp_sr *c_sr;
unsigned    edge_type;
{
    struct group_tree  *grp_prev;
    struct group_tree  *grp_next;
    struct group_tree  *group1;

    if (edge_type == START_EDGE) {
	grp_prev = c_sr -> prev -> group;
	grp_next = c_sr -> next -> group;
	if ((grp_prev != NULL) && (grp_next != NULL)) {
	    c_sr -> group = merge_groups (c_sr -> group, grp_prev);
	    c_sr -> group = merge_groups (c_sr -> group, grp_next);
	}
	if ((grp_prev != NULL) && (grp_next == NULL)) {
	    c_sr -> group = merge_groups (c_sr -> group, grp_prev);
	}
	if ((grp_prev == NULL) && (grp_next != NULL)) {
	    c_sr -> group = merge_groups (c_sr -> group, grp_next);
	}
	if ((grp_prev == NULL) && (grp_next == NULL)) {
	    ALLOC (group1, group_tree);
	    c_sr -> group = group1;
	    group1 -> tree.count = 1;
	    group1 -> parent = NULL;
	    group1 -> next = group_ptr;
	    group_ptr = group1;
	}
    }
    if (edge_type == STOP_EDGE) {
	c_sr -> group = NULL;
    }
}

update_grp_sr (g_sr)
struct grp_sr  *g_sr;
{
    struct grp_sr  *gsr_pntr;

    gsr_pntr = g_sr -> next;
    while (gsr_pntr != g_sr) {
	if (gsr_pntr -> group == gsr_pntr -> prev -> group) {
	    gsr_pntr -> prev -> yt = gsr_pntr -> yt;
	    gsr_pntr -> next -> prev = gsr_pntr -> prev;
	    gsr_pntr -> prev -> next = gsr_pntr -> next;
	    FREE (gsr_pntr);
	}
	gsr_pntr = gsr_pntr -> next;
    }
}

update_group (gsr_pntr)
struct grp_sr  *gsr_pntr;
{
    while (gsr_pntr -> yb > b_pntr -> yb) {
	gsr_pntr = gsr_pntr -> prev;
    }
    while (gsr_pntr -> yt <= b_pntr -> yb) {
	gsr_pntr = gsr_pntr -> next;
    }
    b_pntr -> grp = gsr_pntr -> group;
}

free_groups () /* free all groups */
{
    struct group_tree  *group;

    while (group_ptr) {
	group = group_ptr;
	group_ptr = group -> next;
	FREE (group);
    }
}

struct group_tree  *merge_groups (group1, group2)
struct group_tree  *group1, *group2;
{
/* Merge two groups, i.e. make one the parent of the other */

    struct group_tree  *large,
                       *fdgrp_ptr (),
                       *small;

    if (group1 == NULL && group2 == NULL) {
	fprintf (stderr, " Function : merge_groups \n");
	fprintf (stderr, " ??? Unidentified situation\n");
	return (NULL);
    }
    else
	if (group1 == NULL)
	    return (group2);
	else
	    if (group2 == NULL)
		return (group1);
	    else {
		group1 = fdgrp_ptr (group1);
		group2 = fdgrp_ptr (group2);
		if (group1 == group2)
		    return (group1);
		if (group1 -> tree.count <= group2 -> tree.count) {
		    large = group2;
		    small = group1;
		}
		else {
		    large = group1;
		    small = group2;
		}
		small -> parent = large;
		large -> tree.count += small -> tree.count;
		return (large);
	    }
}

number_groups () {
/* Number the groups in the group_tree */

    struct group_tree  *group;
    int     group_number = 0;

    group = group_ptr;
    while (group) {
	if (group -> parent == NULL)
	    group -> tree.name = ++group_number;
	group = group -> next;
    }

    return (group_number);
}

fdgrp_name (group)
struct group_tree  *group;
{
/* Find the root node of the group_tree from which the
** group is part. Collaps path to root node, and return
** name of root node.
*/
    struct group_list  *head = NULL;
    struct group_list  *tmp;

    while (group -> parent && group -> parent -> parent) {
	ALLOC (tmp, group_list);
	tmp -> group = group;
	tmp -> next = head;
	head = tmp;
	group = group -> parent;
    }

    if (group -> parent)
	group = group -> parent;

    while (head) {
	head -> group -> parent = group;
	tmp = head;
	head = head -> next;
	FREE (tmp);
    }

    return (group -> tree.name);
}

struct group_tree  *fdgrp_ptr (group)
struct group_tree  *group;
{
/* Find the root node of the group_tree from which the
** group is part. Collaps path to root node, and return
** pointer to root node.
*/
    struct group_list  *head = NULL;
    struct group_list  *tmp;

    while (group -> parent && group -> parent -> parent) {
	ALLOC (tmp, group_list);
	tmp -> group = group;
	tmp -> next = head;
	head = tmp;
	group = group -> parent;
    }

    if (group -> parent)
	group = group -> parent;

    while (head) {
	head -> group -> parent = group;
	tmp = head;
	head = head -> next;
	FREE (tmp);
    }

    return (group);
}

free_grp_sr ()
{
    struct grp_sr  *gsr_pntr;

    gsr_pntr = (&grp_sr_head) -> next;
    while (gsr_pntr != &grp_sr_head) {
	FREE (gsr_pntr);
	gsr_pntr = gsr_pntr -> next;
    }
}
