/*************************************************************************
 * Copyright (c) 2011 AT&T Intellectual Property 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors: Details at https://graphviz.org
 *************************************************************************/


/*
 * Classify edges for rank assignment phase to
 * create temporary edges.
 */

#include "config.h"

#include <dotgen/dot.h>
#include <stdbool.h>

bool nonconstraint_edge(edge_t *e) {
    char *constr;

    if (E_constr && (constr = agxget(e, E_constr))) {
	if (constr[0] && !mapbool(constr))
	    return true;
    }
    return false;
}

static void 
interclust1(graph_t * g, node_t * t, node_t * h, edge_t * e)
{
    node_t *v, *t0, *h0;
    int offset, t_len, h_len, t_rank, h_rank;

    if (ND_clust(agtail(e)))
	t_rank = ND_rank(agtail(e)) - ND_rank(GD_leader(ND_clust(agtail(e))));
    else
	t_rank = 0;
    if (ND_clust(aghead(e)))
	h_rank = ND_rank(aghead(e)) - ND_rank(GD_leader(ND_clust(aghead(e))));
    else
	h_rank = 0;
    offset = ED_minlen(e) + t_rank - h_rank;
    if (offset > 0) {
	t_len = 0;
	h_len = offset;
    } else {
	t_len = -offset;
	h_len = 0;
    }

    v = virtual_node(g);
    ND_node_type(v) = SLACKNODE;
    t0 = UF_find(t);
    h0 = UF_find(h);
    edge_t *const rt = make_aux_edge(v, t0, t_len, CL_BACK * ED_weight(e));
    edge_t *const rh = make_aux_edge(v, h0, h_len, ED_weight(e));
    ED_to_orig(rt) = ED_to_orig(rh) = e;
}
void class1(graph_t * g)
{
    node_t *n, *t, *h;
    edge_t *e, *rep;

    mark_clusters(g);
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
	for (e = agfstout(g, n); e; e = agnxtout(g, e)) {

	    /* skip edges already processed */
	    if (ED_to_virt(e))
		continue;

	    /* skip edges that we want to ignore in this phase */
	    if (nonconstraint_edge(e))
		continue;

	    t = UF_find(agtail(e));
	    h = UF_find(aghead(e));

	    /* skip self, flat, and intra-cluster edges */
	    if (t == h)
		continue;


	    /* inter-cluster edges require special treatment */
	    if (ND_clust(t) || ND_clust(h)) {
		interclust1(g, agtail(e), aghead(e), e);
		continue;
	    }

	    if ((rep = find_fast_edge(t, h)))
		merge_oneway(e, rep);
	    else
		virtual_edge(t, h, e);
	}
    }
}

