static char *SccsId = "@(#)neteqv.cls 4.10 (TU-Delft) 10/21/92";
/**********************************************************

Name/Version      : sls_mkdb/4.10

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

Author(s)         : A.C. de Graaf
Creation date     : 10-Jul-1986
Modified by       : S. de Graaf
Modification date : 04-Aug-1986


        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) 1986 , All rights reserved
**********************************************************/
#include "sys_incl.h"
#class
#include "class.h"
#include "mkdbdefs.h"
#include "mkdbincl.h"

extern Dictionary * ntw_dict;
extern Dictionary * sym_dict;
extern Network * ntw;

extern Netelem *notconnected;

extern int n_net_cnt;
extern int n_inst_cnt;
extern int n_term_cnt;

Stack * stackcpy();
Stack * xstackcpy();
void    net_eqv ();

Stack * flatten_xs (xs)
Stack * xs;
{
    int     i, j, k, l, n;
    int    *m, *x, *y;
    int    *lb, *rb;
    char  **px;
    Xelem * pxelem;
    Stack * newxs, *pxs;

    n = xs -> length ();
    x = new int [n];
    y = new int [n];
    m = new int [n];
    lb = new int    [n];
    rb = new int    [n];


    for (i = 0, px = xs -> base (); px != xs -> limit (); i++, px++) {
	lb[i] = ((Xelem *) * px) -> left_bound;
	rb[i] = ((Xelem *) * px) -> right_bound;
	y[i] = rb[i] - lb[i] + 1;
    }

    m[n - 1] = 1;
    for (i = n - 2; i >= 0; i--)
	m[i] = y[i + 1] * m[i + 1];
    k = y[0] * m[0];

    newxs = new Stack (k);

    for (i = 1; i <= k; i++) {

	pxs = new Stack (n);

	for (l = 0; l < n; l++) {
	    pxelem = new Xelem (*(x + l) + lb[l], *(x + l) + lb[l]);
	    pxs -> push ((char *) pxelem);
	}

	newxs -> push ((char *) pxs);

	for (j = n - 1; j >= 0; j--) {
	    if ((i % m[j]) == 0) {
		(*(x + j))++;
		*(x + j) %= y[j];
	    }
	}
    }

    delete x;
    delete y;
    delete m;
    delete lb;
    delete rb;

    return (newxs);
}

int flatten (netref, flat_inst, flat_net, que)
NetReference * netref;
int flat_inst;
int flat_net;
Queue * que;
{
    int i, j;
    int inst_xs_len;
    int net_xs_len;
    NetReference * newnref;
    Stack * inst_xs;
    Stack * net_xs;

    if (flat_inst && (inst_xs = netref -> inst_xs)) {
        inst_xs = flatten_xs (inst_xs);
        inst_xs_len = inst_xs -> length ();
    }
    else
        inst_xs_len = 0;

    if (flat_net && (net_xs = netref -> net_xs)) {
        net_xs = flatten_xs (net_xs);
        net_xs_len = net_xs -> length ();
    }
    else
        net_xs_len = 0;

    if (inst_xs_len > 0) {
        for (i = 0; i < inst_xs_len; i++) {
            if (net_xs_len > 0) {
                for (j = 0; j < net_xs_len; j++) {
		    newnref = new NetReference (netref -> net, 
                                              (Stack *) net_xs -> access (j));
		    newnref -> inst = netref -> inst;
		    newnref -> inst_xs = (Stack *) inst_xs -> access (i);
		    que -> put ((Link *) newnref);
                }
            }
            else {
		newnref = new NetReference (netref -> net, netref -> net_xs);
		newnref -> inst = netref -> inst;
		newnref -> inst_xs = (Stack *) inst_xs -> access (i);
		que -> put ((Link *) newnref);
            }
        }
    }
    else {
        if (net_xs_len > 0) {
            for (j = 0; j < net_xs_len; j++) {
		newnref = new NetReference (netref -> net, 
                                         (Stack *)  net_xs -> access (j));
	        newnref -> inst = netref -> inst;
	        newnref -> inst_xs = netref -> inst_xs;
		que -> put ((Link *) newnref);
            }
        }
        else {
            newnref = new NetReference (netref -> net, netref -> net_xs);
	    newnref -> inst = netref -> inst;
	    newnref -> inst_xs = netref -> inst_xs;
	    que -> put ((Link *) newnref);
        }
    }

    delete netref;

    if (inst_xs_len == 0)
        inst_xs_len = 1;
    if (net_xs_len == 0)
        net_xs_len = 1;

    return (inst_xs_len * net_xs_len);
}

int match_net (pdstq, psrcq, nettype)
Queue ** pdstq;
Queue ** psrcq;
char nettype;
{
    int i, j;
    int j_max;
    int inst_xs_len;
    int net_xs_len;
    Xelem *px;
    Stack *net_xs;
    Stack *ref_xs;
    Stack *inst_xs;
    Netelem *pnet;
    NetReference *pnref;
    NetReference *psrc;
    NetReference *pdst;
    Queue * srcq;
    Queue * dstq;
    Queue * new_srcq;
    Queue * new_dstq;
    char *isGlobalNet ();

    int src_len;
    int dst_len;
    int newsrc_cnt = 0;
    int newdst_cnt = 0;
    int src_action;
    int dst_action;
    int flag;

    srcq = *psrcq;
    dstq = *pdstq;

    new_srcq = new Queue (QueueType);
    new_dstq = new Queue (QueueType);
    *psrcq = new_srcq;
    *pdstq = new_dstq;

    psrc = (NetReference *) srcq -> get ();
    pdst = (NetReference *) dstq -> get ();

    if ((psrc == NULL || isGlobalNet (psrc -> net -> name))
	&& pdst -> net == notconnected && dstq -> length () == 0) {
	pdst = NULL;
	n_net_cnt = 0;
    }

    src_len = getnetlength(psrc);
    dst_len = getnetlength(pdst);

    if (psrc == NULL && pdst)
	return (1);
    else if (psrc && !isGlobalNet (psrc -> net -> name) && pdst == NULL)
	return (-1);

    while (psrc || pdst) {

	if (n_inst_cnt > 0) {

	    flag = 0;

	    while ((nettype == 'i' 
		    && ((newsrc_cnt % n_term_cnt) >= (n_net_cnt / n_inst_cnt)))
	           || ((nettype == 'p'
		       && (newsrc_cnt + 1) > n_net_cnt))) {

		if (psrc && psrc -> net_xs == NULL 
		    && isGlobalNet (psrc -> net -> name)) {

		    /* add global net as extra to new dst queue */

		    flag = 1;

		    if (nettype == 'p' && pdst) {
			/* flush dst queue (happens if instance array) */
			new_dstq -> put ((Link *) pdst);
			newdst_cnt += dst_len;
			pdst = (NetReference *) dstq -> get ();
			dst_len = getnetlength(pdst);
		    }

		    pnet = sym_dict -> fetch (psrc -> net -> name);
		    if (!pnet) {
			pnet = new Netelem (psrc -> net -> name, NULL, NetType);
			sym_dict->store (pnet->name, (char *) pnet);
			ntw -> netq -> put ((Link *) pnet);
		    }
		    else if (pnet -> xs) {
			sls_errno = ILLRANGE;
			return (-999);
		    }
		    if (psrc -> inst_xs)
			j_max = getxslength (psrc -> inst_xs);
		    else
			j_max = 1;
		    for (j = 0; j < j_max; j++) {
			pnref = new NetReference (pnet, NULL);
			new_dstq -> put ((Link *) pnref);
			newdst_cnt++;
		    }

		    if (j_max > 1) {
			src_len = flatten (psrc, 1, 1, new_srcq);
			newsrc_cnt += src_len;
		    }
		    else {
			new_srcq -> put ((Link *) psrc);
			newsrc_cnt += src_len;
		    }
		    psrc = (NetReference *) srcq -> get ();
		    src_len = getnetlength(psrc);
		}
		else
		    break;
	    }

	    if (flag == 0
	        && (nettype == 'i' || nettype == 'p')
		&& newdst_cnt == newsrc_cnt
		&& psrc && psrc -> net_xs == NULL 
		 && isGlobalNet (psrc -> net -> name)
		&& pdst
		 && !isGlobalNet (pdst -> net -> name)
		 && pdst -> net != notconnected) {

		/* this terminal is not connected to an actual parameter
		   that is a global net; so add (a) connection(s) between
		   the actual parameter(s) and the global net */

		pnet = sym_dict -> fetch (psrc -> net -> name);
		if (!pnet) {
		    pnet = new Netelem (psrc -> net -> name, NULL, NetType);
		    sym_dict->store (pnet->name, (char *) pnet);
		    ntw -> netq -> put ((Link *) pnet);
		}
		else if (pnet -> xs) {
		    sls_errno = ILLRANGE;
		    return (-999);
		}

		if (psrc -> inst_xs)
		    j_max = getxslength (psrc -> inst_xs);
		else
		    j_max = 1;
		for (j = 0; j < j_max; j++) {
		    pnref = new NetReference (pnet, NULL);
		    new_dstq -> put ((Link *) pnref);

                    if (!pdst -> net_xs) {
			pnref = new NetReference (pdst -> net, NULL);
			new_srcq -> put ((Link *) pnref);
		    }
		}
		if (pdst -> net_xs) {
		    pnref = new NetReference (pdst -> net, pdst -> net_xs);
		    j = flatten (pnref, 1, 1, new_srcq);
		}
	    }
	}

	if ((psrc == NULL && pdst == NULL))
	    break;

        if (newsrc_cnt > newdst_cnt) {
            src_action = 0;
        }
        else if (newsrc_cnt == newdst_cnt && src_len == dst_len) {
            src_action = 1;
        }
        else {
            src_action = 2;
        }

        if (newdst_cnt > newsrc_cnt) {
            dst_action = 0;
        }
        else if (newdst_cnt == newsrc_cnt && dst_len == src_len) {
            dst_action = 1;
        }
        else {
            dst_action = 2;
        }
        
        if (src_action == 1) {
            if (psrc == NULL)
                return (1);
   	    new_srcq -> put ((Link *) psrc);
            newsrc_cnt += src_len;
            psrc = (NetReference *) srcq -> get ();
            src_len = getnetlength(psrc);
        }
        else if (src_action == 2) {
            if (psrc == NULL)
                return (1);

            src_len = flatten (psrc, 1, 1, new_srcq);

            newsrc_cnt += src_len;
            psrc = (NetReference *) srcq -> get ();
            src_len = getnetlength (psrc);
        }

        if (dst_action == 1) {
            if (pdst == NULL)
                return (-1);
   	    new_dstq -> put ((Link *) pdst);
            newdst_cnt += dst_len;
            pdst = (NetReference *) dstq -> get ();
            dst_len = getnetlength(pdst);
        }
        else if (dst_action == 2) {
            if (pdst == NULL)
                return (-1);

            dst_len = flatten (pdst, 1, 1, new_dstq);

            newdst_cnt += dst_len;
            pdst = (NetReference *) dstq -> get ();
            dst_len = getnetlength (pdst);
        }
    }

    delete srcq;
    delete dstq;

    if(newsrc_cnt < newdst_cnt)
	return (1);
    else if(newsrc_cnt > newdst_cnt)
	return (-1);
    else
        return (0);
}

int getnetlength (net)
NetReference * net;
{
    int n;
    int i;
    int lb;
    int rb;
    int len = 1;

    if (! net ) {
        return (0);
    }

    if (net -> net_xs)
        n = net -> net_xs -> length ();
    else
        n = 0;

    for (i = 0; i < n; i++) {
        lb = ((Xelem *) net -> net_xs -> access (i)) -> left_bound;
        rb = ((Xelem *) net -> net_xs -> access (i)) -> right_bound;
        len = len * (1 + abs (lb - rb));
    }

    if (net -> inst_xs)
        n = net -> inst_xs -> length ();
    else
        n = 0;

    for (i = 0; i < n; i++) {
        lb = ((Xelem *) net -> inst_xs -> access (i)) -> left_bound;
        rb = ((Xelem *) net -> inst_xs -> access (i)) -> right_bound;
        len = len * (1 + abs (lb - rb));
    }

    return (len);
}

chk_bounds (xs1, xs2)
Stack * xs1, *xs2;
{
    int     i;
    int     xs1_dim,
            xs2_dim;
    int     lb1,
            rb1;
    int     lb2,
            rb2;
    char  **px1;
    char  **px2;

    if (xs1 && xs2) {
	/* both net definition and net reference have array structure */
	xs1_dim = xs1 -> length ();
	xs2_dim = xs2 -> length ();
	if (xs1_dim != xs2_dim) { /* the arrays have different dimension */
	    return 1;
	}
	for (i = 0, px1 = xs1 -> base (), px2 = xs2 -> base ();
	    i < xs1_dim; i++, px1++, px2++) {
	    lb1 = ((Xelem *) * px1) -> left_bound;
	    rb1 = ((Xelem *) * px1) -> right_bound;
	    lb2 = ((Xelem *) * px2) -> left_bound;
	    rb2 = ((Xelem *) * px2) -> right_bound;
	    if (lb1 > lb2 || rb1 < rb2)
		/* the arrays have inconsistent bounds */
	        return 1;
	}
    }
    else {
	if(xs1 || xs2) 
	    return 1;
    }

    return 0;
}

int    inst_net_eqv (inst, cons)
        NetworkInstance * inst;
Queue * cons;
{
    int     i;
    Network * pntw;
    Netelem * pterm;
    Netelem * pnet;
    Netelem * peqv;
    NetReference * nref1, *nref2;

    switch (cons -> type) {
	case PmQueue: 
	    return(pm_net_eqv (inst, cons));
	case ImQueue: 
	    return(im_net_eqv (inst, cons));
	default: 
	    fprintf (stderr, "inst_net_eqv: Illegal Queue type %x\n",
			     cons -> type);
	    die();
    }
}

int pm_net_eqv (inst, netq)
NetworkInstance * inst;
Queue * netq;
{
    int     i, j, k;
    Stack * pxs;
    Stack * net_xs;
    Netelem * pterm;
    NetReference *net_ref, *term_ref;

    Queue * term_refq =  new Queue (QueueType);
    Stack * inst_xs = stackcpy(inst -> inst_struct -> inst_construct);
    Queue * termq = inst -> ntw -> termq;
    int     termq_len = termq -> length ();

    for (j = 0, pterm = (Netelem *) termq -> first_elem ();
	    j < termq_len;
	    j++, pterm = (Netelem *) termq -> next_elem ((Link *) pterm)) {

        if ((net_xs = stackcpy(pterm -> xs))) {
	    net_xs = flatten_xs (net_xs);
	    k = net_xs -> length ();
        }
        else
	    k = 1;

	for (i = 0; i < k; i++) {

	    pxs = net_xs ? (Stack *) net_xs -> access (i) : NULL;
	    term_ref = new NetReference (pterm, pxs);
	    term_ref -> inst = inst;
	    term_ref -> inst_xs = inst_xs;
	    term_refq->put ((Link *) term_ref);
	}
    }

    k = match_net (&netq, &term_refq, 'p');

    if (k < -900)
	return (1);

    if(k > 0)
    {
	sls_errno = ATERM_GT_FTERM;
	return (1);
    }
    else if (k < 0)
    {
	sls_errno = ATERM_LT_FTERM;
	return (1);
    }
    else
        net_eqv (netq, term_refq);

    return (0);
}

int im_net_eqv (inst, netq)
NetworkInstance * inst;
Queue * netq;
{
    int     i, j, k;
    Stack * pxs;
    Netelem * pterm;
    NetReference * net_ref, *term_ref;

    Queue * termq = inst -> ntw -> termq;
    Stack * inst_xs = inst -> inst_struct -> inst_construct;
    Queue * term_refq = new Queue (QueueType);
    int	    termq_len =  termq -> length ();

    if (inst_xs) {
	inst_xs = flatten_xs (inst_xs);
	k = inst_xs -> length ();
    }
    else
	k = 1;

    for (i = 0; i < k; i++) {
	pxs = inst_xs ? (Stack *) inst_xs -> access (i) : NULL;
	for (j = 0, pterm = (Netelem *) termq -> first_elem ();
		j < termq_len;
		j++, pterm = (Netelem *) termq -> next_elem ((Link *) pterm)) {

	    term_ref = new NetReference (pterm, stackcpy(pterm -> xs));
	    term_ref -> inst = inst;
	    term_ref -> inst_xs = pxs;
	    term_refq->put ((Link *) term_ref);
	}
    }

    k = match_net (&netq, &term_refq, 'i');

    if (k < -900)
	return (1);

    if(k > 0)
    {
	sls_errno = ATERM_GT_FTERM;
	return (1);
    }
    else if (k < 0)
    {
	sls_errno = ATERM_LT_FTERM;
	return (1);
    }
    else
        net_eqv (netq, term_refq);

    return (0);
}

void    net_eqv (dst, src)
Queue * dst;
Queue * src;
{
    Netelem * pnet;
    NetReference * dst_ref, *src_ref;

    while(! dst -> empty())
    {
	dst_ref = (NetReference *) dst -> get ();
	src_ref = (NetReference *) src -> get ();
	src_ref -> ref_xs = stackcpy (dst_ref -> net_xs);

	pnet = dst_ref -> net;
	if (doSimpleNet) {
	    joinSimple (pnet, src_ref -> ref_xs,
			src_ref -> inst, src_ref -> inst_xs,
			src_ref -> net, src_ref -> net_xs);
	    delete src_ref;
	}
	else {
	    if (pnet -> eqv == NULL)
		pnet -> eqv = new Queue (QueueType);

	    pnet -> eqv -> put (src_ref);
	}
	delete dst_ref;
    }
    delete dst;
    delete src;
}

int    neteqv (netq)
Queue * netq;
{
     int i, k;
     Link * psrc;
     Stack * dst_net_xs;
     Stack * src_net_xs;
     Netelem * dst_net;
     NetReference * pnref;
     NetReference * src_ref, *dst_ref;

     Link * pdst = netq -> get();

     switch(pdst->type)
     {
	 case QueueType:
             while(! netq->empty()) {
	        psrc = netq -> get ();
        
	        k = match_net ( ((Queue **) &pdst),  ((Queue **) &psrc), '\0');
        
		if (k < -900)
		    return (1);

	        if(k > 0)
    		{
		    sls_errno = DNET_GT_SNET;
		    return(1);
    		}
	        else if (k < 0)
    		{
		    sls_errno = DNET_LT_SNET;
		    return(1);
    		}
	        else
		    net_eqv ((Queue *) pdst, (Queue *) psrc);
             }
	     delete netq;
	     break;
	 case NetRefType:
	     dst_ref = (NetReference *) pdst;
	     dst_net = dst_ref -> net;
	     if (dst_net -> eqv == NULL && !doSimpleNet)
	         dst_net -> eqv = new Queue (QueueType);

	     if(dst_ref -> net_xs) {
		 dst_net_xs = flatten_xs (dst_ref -> net_xs);

		 for(i=0; i < dst_net_xs -> length(); i++) {
		     pnref = new NetReference (dst_ref->net,
			     (Stack *) dst_net_xs -> access(i));
		     pnref -> ref_xs = stackcpy (dst_net_xs -> access(0));
		     pnref -> inst = dst_ref -> inst;
		     pnref -> inst_xs = dst_ref -> inst_xs;
		     if (doSimpleNet) {
			 joinSimple (dst_net, pnref -> ref_xs,
				     pnref -> inst, pnref -> inst_xs,
				     pnref -> net, pnref -> net_xs);
			 delete pnref;
		     }
		     else
			 dst_net -> eqv -> put (pnref);
		 }
	     }

             while(! netq->empty()) {
	         psrc = netq -> get ();
		 src_ref = (NetReference *) psrc;

		 if (src_ref -> net_xs) {
		     src_net_xs = flatten_xs (src_ref -> net_xs);
		     for(i=0; i < src_net_xs -> length(); i++) {
		         pnref = new NetReference (src_ref->net,
			         (Stack *) src_net_xs -> access(i));
	     		 if(dst_ref -> net_xs)
		             pnref -> ref_xs = stackcpy (dst_net_xs -> access(0));
		         pnref -> inst = src_ref -> inst;
		         pnref -> inst_xs = src_ref -> inst_xs;
			 if (doSimpleNet) {
			     joinSimple (dst_net, pnref -> ref_xs,
					 pnref -> inst, pnref -> inst_xs,
					 pnref -> net, pnref -> net_xs);
			     delete pnref;
			 }
			 else
			     dst_net -> eqv -> put (pnref);
		     }
		     delete src_ref;
		 }
		 else {
	     	     if(dst_ref -> net_xs)
		         src_ref -> ref_xs = stackcpy (dst_net_xs -> access(0));
		     if (doSimpleNet) {
			 joinSimple (dst_net, src_ref -> ref_xs,
				     src_ref -> inst, src_ref -> inst_xs,
				     src_ref -> net, src_ref -> net_xs);
			 delete src_ref;
		     }
		     else
			 dst_net -> eqv -> put (src_ref);
		 }
	     }
	     delete dst_ref;
	     delete netq;
	     break;
     }
     return(0);
}

int getxslength (xs)
Stack * xs;
{
    int n;
    int i;
    int lb;
    int rb;
    int len = 1;
    Xelem *pxelem;

    if (xs)
        n = xs -> length ();
    else
        n = 0;

    for (i = 0; i < n; i++) {
        pxelem = (Xelem *) xs -> access (i);
        lb = pxelem -> left_bound;
        rb = pxelem -> right_bound;
        len = len * (1 + abs (lb - rb));
    }

    return (len);
}

int getnetcnt(netq)
Queue * netq;
{
    int i;
    int net_cnt = 0;
    int netq_len = netq -> length();
    NetReference * pq;

    for(i=0, pq = (NetReference *) netq -> first_elem();
        i < netq_len;
        i++, pq = (NetReference *) netq -> next_elem((Link *) pq))
    {
	net_cnt += getnetlength(pq);
    }

    return (net_cnt);
}
