/* This software was developed by Bruce Hendrickson and Robert Leland   *
 * at Sandia National Laboratories under US Department of Energy        *
 * contract DE-AC04-76DP00789 and is copyrighted by Sandia Corporation. */

#include <stdio.h>
#include "Gmsh_printf.h"
#include "defs.h"
#include "structs.h"


/* Change from a FORTRAN graph style to our graph data structure. */

int       reformat(start, adjacency, nvtxs, pnedges, vwgts, ewgts, pgraph)
int      *start;		/* start of edge list for each vertex */
int      *adjacency;		/* edge list data */
int       nvtxs;		/* number of vertices in graph */
int      *pnedges;		/* ptr to number of edges in graph */
int      *vwgts;		/* weights for all vertices */
float    *ewgts;		/* weights for all edges */
struct vtx_data ***pgraph;	/* ptr to array of vtx data for graph */
{
    extern FILE *Output_File;           /* output file or null */
    struct vtx_data **graph = NULL;	/* array of vtx data for graph */
    struct vtx_data *links = NULL;	/* space for data for all vtxs */
    int      *edges = NULL;	/* space for all adjacency lists */
    float    *eweights = NULL;	/* space for all edge weights */
    int      *eptr;		/* steps through adjacency list */
    int      *eptr_save;	/* saved index into adjacency list */
    float    *wptr;		/* steps through edge weights list */
    int       self_edge;	/* number of self loops detected */
    int       size;		/* length of all edge lists */
    double    sum;		/* sum of edge weights for a vtx */
    int       using_ewgts;	/* are edge weights being used? */
    int       using_vwgts;	/* are vertex weights being used? */
    int       i, j;		/* loop counters */
    double   *smalloc_ret();

    using_ewgts = (ewgts != NULL);
    using_vwgts = (vwgts != NULL);

    graph = (struct vtx_data **) smalloc_ret((unsigned) (nvtxs + 1) * sizeof(struct vtx_data *));
    *pgraph = graph;
    if (graph == NULL) return(1);

    graph[1] = NULL;

    /* Set up all the basic data structure for the vertices. */
    /* Replace many small mallocs by a few large ones. */
    links = (struct vtx_data *) smalloc_ret((unsigned) (nvtxs) * sizeof(struct vtx_data));
    if (links == NULL) return(1);

    for (i = 1; i <= nvtxs; i++) {
	graph[i] = links++;
    }

    graph[1]->edges = NULL;
    graph[1]->ewgts = NULL;

    /* Now fill in all the data fields. */
    if (start != NULL)
	*pnedges = start[nvtxs] / 2;
    else
	*pnedges = 0;
    size = 2 * (*pnedges) + nvtxs;
    edges = (int *) smalloc_ret((unsigned) size * sizeof(int));
    if (edges == NULL) return(1);

    if (using_ewgts) {
	eweights = (float *) smalloc_ret((unsigned) size * sizeof(float));
        if (eweights == NULL) return(1);
    }

    if (start != NULL) {
        eptr = adjacency + start[0];
        wptr = ewgts;
    }
    self_edge = 0;

    for (i = 1; i <= nvtxs; i++) {
	if (using_vwgts)
	    graph[i]->vwgt = *(vwgts++);
	else
	    graph[i]->vwgt = 1;
	if (start != NULL)
	    size = start[i] - start[i - 1];
	else
	    size = 0;
	graph[i]->nedges = size + 1;
	graph[i]->edges = edges;
	*edges++ = i;
	eptr_save = eptr;
	for (j = size; j; j--) {
	    if (*eptr != i)
		*edges++ = *eptr++;
	    else {		/* Self edge, skip it. */
		if (!self_edge) {
		    printf("WARNING: Self edge (%d,%d) being ignored\n", i, i);
    		    if (Output_File != NULL) {
		        fprintf(Output_File,
			    "WARNING: Self edge (%d,%d) being ignored\n", i, i);
		    }
		}
		++self_edge;
		eptr++;
		--(graph[i]->nedges);
		--(*pnedges);
	    }
	}
	if (using_ewgts) {
	    graph[i]->ewgts = eweights;
	    eweights++;
	    sum = 0;
	    for (j = size; j; j--) {
		if (*eptr_save++ != i) {
		    sum += *wptr;
		    *eweights++ = *wptr++;
		}
		else
		    wptr++;
	    }
	    graph[i]->ewgts[0] = -sum;
	}
	else
	    graph[i]->ewgts = NULL;
    }
    if (self_edge > 1) {
	printf("WARNING: %d self edges were detected and ignored\n", self_edge);
        if (Output_File != NULL) {
	    fprintf(Output_File,
		"WARNING: %d self edges were detected and ignored\n", self_edge);
	}
    }

    return(0);
}
