/* graphio- generic i/o functions for reading and writing graph files from and
**          to lower-triangular matrix and edgelist formats. The storage matrix
**          may contain values of any bitsize that evenly divides the bitsize
**          of the underlying matrix datatype (which may be 1, 2, 4, or 8
**          bytes). The values will be thresholded before storing/writing, and
**          a flag value for an invalid edge is also required.
*/
#ifndef _JSW_JRN_GRAPHIO_H_
#define _JSW_JRN_GRAPHIO_H_

#include <stdio.h>
#include <limits.h>
#include "labellist.h"
#include "layout.h"
#include "globals.h"
#include "processing.h"

/* these make sure I have types that I know are 1, 2, 4, and 8 bytes */
#if defined WINDOWS || defined WIN32 || defined WIN64
   typedef __int8  int8_t;
   typedef __int16 int16_t;
   typedef __int32 int32_t;
   typedef __int64 int64_t;

   typedef unsigned __int8  uint8_t;
   typedef unsigned __int16 uint16_t;
   typedef unsigned __int32 uint32_t;
   typedef unsigned __int64 uint64_t;
#else
#  include <inttypes.h>
#endif

#ifndef INAN
	#define INAN -30000
#endif
#define DENOM_THRESH 10000.f


#ifdef __cplusplus
extern "C" {
#endif


/* printMatrixLT- prints a lower triangular matrix to a file pointer
**
** *input parameters*
** FILE       * out       file pointer to print the matrix to
** double       threshold cutoff value, values < threshold will not be printed
** int          absval    if 0, do not take absolute value before thresholding
**                        if nonzero, take absolute value before thresholding
** int          prec      number of digits past the decimal to output
** int          len       number of vertices in the graph
** const char **labels    labels of the vertices in the graph
** const void * mat       a pointer to the values in the graph in the following
**                        order: (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
** int          bbytes    the number of bytes of the datatype mat points to
**                        needed mainly for big? endian machines like Intel
** int          valbits   number of bits in a value, should evenly divide
**                        number of bits in the datatype that mat points to
** int64_t      denom     an amount used to normalize each value, useful for
**                        fixed-point values
** int64_t      flag      value to consider an edge invalid
**                        values = flag will not be printed
**
** *return*
** int                    0 for no errors, < 0 if there is an error
*/
int printMatrixLT(FILE *out, double threshold, int absval, int prec,
                  int len, const char **labels, const void *mat,
                  int bbytes, int valbits, int64_t denom, int64_t flag);

/* printEdgeList- prints an edgelist to a file pointer
**
** *input parameters*
** FILE       * out       file pointer to print the edgelist to
** double       threshold cutoff value, values < threshold will not be printed
** int          absval    if 0, do not take absolute value before thresholding
**                        if nonzero, take absolute value before thresholding
** int          prec      number of digits past the decimal to output
**                        if 0, the weight will not be printed
** int          len       number of vertices in the graph
** const char **labels    labels of the vertices in the graph
** const void * mat       a pointer to the values in the graph in the following
**                        order: (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
** int          bbytes    the number of bytes of the datatype mat points to
**                        needed mainly for big? endian machines like Intel
** int          valbits   number of bits in a value, should evenly divide
**                        number of bits in the datatype that mat points to
** int64_t      denom     an amount used to normalize each value, useful for
**                        fixed-point values
** int64_t      flag      value to consider an edge invalid
**                        values = flag will not be printed
**
** *return*
** int                    0 for no errors, < 0 if there is an error
*/
int printEdgeList(FILE *out, double threshold, int absval, int prec,
                  int len, const char **labels, const void *mat,
                  int bbytes, int valbits, int64_t denom, int64_t flag);

/* printDefaultUnweightedEdgeList- prints an unweighted edgelist to a file
**
** *input parameters*
** char*		filename  filename to print to
** const void * mat       a pointer to the values in the graph in the following
**                        order: (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
**
** *return*
** int                    0 for no errors, < 0 if there is an error
*/
int printDefaultUnweightedEdgeList(char* filename, int length, const void *mat, const char **labels);

/* printDefaultWeightedEdgeList - prints a weighted edgelist to a file
**
** *input parameters*
** char*		filename  filename to print to
** const void * mat       a pointer to the values in the graph in the following
**                        order: (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
** double       threshold cutoff value, values < threshold will not be printed
**
** *return*
** int                    0 for no errors, < 0 if there is an error
*/
int printDefaultWeightedEdgeList(char* filename, int length, const void *mat, const char** labels, double threshold);

/* getEdgeCnt- determines the number of edges (and vertices) that are in
**             with the given parameters
**
** *input parameters*
** double       threshold cutoff value, values < threshold will not be counted
** int          absval    if 0, do not take absolute value before thresholding
**                        if nonzero, take absolute value before thresholding
** const void * mat       a pointer to the values in the graph in the following
**                        order: (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
** int          bbytes    the number of bytes of the datatype mat points to
**                        needed mainly for big? endian machines like Intel
** int          valbits   number of bits in a value, should evenly divide
**                        number of bits in the datatype that mat points to
** int64_t      denom     an amount used to normalize each value, useful for
**                        fixed-point values
** int64_t      flag      value to consider an edge invalid
**                        values = flag will not be counted
**
** *input/output parameter*
** int        * len       input    number of vertices in the graph
**                        output   number of vertices in the graph with
**                                 the given parameters
**
** *return*
** unsigned long          number of edges in the graph
**                        if return is 0 and len is nonzero upon return,
**                        an error occured
*/
unsigned long getEdgeCount(double threshold, int absval,
                           const void *mat, int bbytes, int valbits,
                           int64_t denom, int64_t flag, unsigned int *len);

/* readMatrixLT- reads a lower triangular matrix from a file pointer
**
** *input parameters*
** FILE       * in        file pointer to read the matrix from
** double       threshold cutoff value, values < threshold will be assigned
**                        the flag value
** int          absval    if 0, do not take absolute value before thresholding
**                        if nonzero, take absolute value before thresholding
** int          bbytes    the number of bytes of the datatype mat points to
**                        needed mainly for big? endian machines like Intel
** int          valbits   number of bits in a value, should evenly divide
**                        number of bits in the datatype that mat points to
** int64_t      denom     an amount used to normalize each value, useful for
**                        fixed-point values
** int64_t      flag      value to assign invalid edges
**
** *output parameters*
** LabelList  **labels    optional labels of the vertices in the graph
** void       **mat       required a pointer to the values in the graph
**                                 in the following order:
**                                 (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
** int        * errLine   optional line on which an error occured
**                                 if 0, no error
**                                 if < 0, error was not due to an invalid line
** const char **errStr    optional error message
**
** *return*
** int                    number of vertices in the graph
**                        < 0 if there is an error
*/
int readMatrixLT(FILE *in, double threshold, int absval, int bbytes,
                 int valbits, int64_t denom, int64_t flag,
                 LabelList **labels, void **mat, int *errLine,
                 const char **errStr);

/* readEdgeList- reads an edgelist from a file pointer
**
** *input parameters*
** FILE       * in        file pointer to read the edgelist from
** double       threshold cutoff value, values < threshold will be assigned
**                        the flag value
** int          absval    if 0, do not take absolute value before thresholding
**                        if nonzero, take absolute value before thresholding
** int          bbytes    the number of bytes of the datatype mat points to
**                        needed mainly for big? endian machines like Intel
** int          valbits   number of bits in a value, should evenly divide
**                        number of bits in the datatype that mat points to
** int64_t      denom     an amount used to normalize each value, useful for
**                        fixed-point values
** int64_t      flag      value to assign invalid edges
**
** *output parameters*
** LabelList  **labels    optional labels of the vertices in the graph
** void       **mat       required a pointer to the values in the graph
**                                 in the following order:
**                                 (0,1),(0,2),(1,2),(0,3),(1,3),(2,3)...
** int        * errLine   optional line on which an error occured
**                                 if 0, no error
**                                 if < 0, error was not due to an invalid line
** const char **errStr    optional error message
**
** *return*
** int                    number of vertices in the graph
**                        < 0 if there is an error
*/
int readEdgeList(FILE *in, double threshold, int absval, int bbytes,
                 int valbits, int64_t denom, int64_t flag,
                 LabelList **labels, void **mat, int *errLine,
                 const char **errStr);

/* readDefaultUnweighted- reads a typical unweighted edgelist from a file
**
** *input parameters*
** char*		filename	filename to be read from
** double       threshold	cutoff value, values < threshold will be assigned
**							the flag value
**
** *output parameters*
** void       **mat       required a pointer to the values in the graph
**
** *return*
** int                    number of vertices in the graph
**                        < 0 if there is an error
*/
int readDefaultUnweighted(char* filename, void** mat, LabelList **labels);


/* readDefaultWeighted- reads a typical weighted edgelist from a file
**
** *input parameters*
** char*		filename	filename to be read from
** double       threshold	cutoff value, values < threshold will be assigned
**							the flag value
**
** *output parameters*
** void       **mat       required a pointer to the values in the graph
**
** *return*
** int                    number of vertices in the graph
**                        < 0 if there is an error
*/
int readDefaultWeighted(char* filename, void** mat, LabelList **labels, double threshold);

/* readDefaultWeighted2D- reads a typical weighted edgelist from a file
**
** *input parameters*
** char*		filename	filename to be read from
** double       threshold	cutoff value, values < threshold will be assigned
**							the flag value
** int	       absVal		flag as to whether we should take the absolute value while thresholding
**
** *output parameters*
** void       ***mat       returns a 2D matrix of edge weights in g->mat2d
**
** *return*
** int                    number of vertices in the graph
**                        < 0 if there is an error
*/
int readDefaultWeighted2D(char* filename, double threshold, int absVal, graph* g);

/* readLTMDefaultWeighted2D- reads a typical weighted edgelist from a file
**
** *input parameters*
** char*		filename	filename to be read from in data structure/LTM format
** double       threshold	cutoff value, values < threshold will be assigned
**							the flag value
** int	       absVal		flag as to whether we should take the absolute value while thresholding
**
** *output parameters*
** void       ***mat       returns a 2D matrix of edge weights in g->mat2d
**
** *return*
** int                    number of vertices in the graph ( <0 if there is an error)
*/
int readLTMDefaultWeighted2D(char* filename, double threshold,int absoluteValue, graph* g);

/* readDefaultWeighted2D_deprecated- reads a typical weighted edgelist from a file
**
** *input parameters*
** char*		filename	filename to be read from
** double       threshold	cutoff value, values < threshold will be assigned
**							the flag value
** int	       absVal		flag as to whether we should take the absolute value while thresholding
**
** *output parameters*
** void       ***mat       returns a 2D matrix of edge weights
**
** *return*
** int                    number of vertices in the graph
**                        < 0 if there is an error
*/
int readDefaultWeighted2D_deprecated(char* filename, short int*** mat, LabelList **labels, double threshold, int absVal);

/* readLTMDefaultWeighted2D_deprecated- reads a typical weighted edgelist from a file
**
** *input parameters*
** char*		filename	filename to be read from in data structure/LTM format
** double       threshold	cutoff value, values < threshold will be assigned
**							the flag value
** int	       absVal		flag as to whether we should take the absolute value while thresholding
**
** *output parameters*
** void       ***mat       returns a 2D matrix of edge weights
**
** *return*
** int                    number of vertices in the graph ( <0 if there is an error)
*/
int readLTMDefaultWeighted2D_deprecated(char* filename, short int*** mat, double threshold, int absoluteValue);

/* normalizeWeights - normalize the weights of a matrix
**
** *input parameters*
** int			numVerts	number of vertices for the given LTM weights
**
** *output parameters*
** void       ***mat       returns the 2D matrix of edge weights after normalization
*/
void normalizeWeights(int numVerts, short int** data);

/* loadGVL- reads the graph vertex layout/locations into an array
**
** *input parameters*
** char*		filename	filename to be read from
**
** *output parameters*
** short int**	location  returns a 1D array of vertex locations
**
** *return*
** int                    number of vertices in the graph
*/
int loadGVL(char* filename, short int** loc);

/* getLowestWeight- finds the lowest weight in a given graph file
**
** *input parameters*
** char*		filename	   filename to be read from
**
** *output parameters*
** float* threshold     returns the lowest weight value in the graph
**
** *return*
** int                    -1 if file doesn't exist
*/
int getLowestWeight(char* filename,float* threshold);

#ifdef __cplusplus
}
#endif

#endif //_JSW_JRN_GRAPHIO_H_
