#pragma once

#include <iostream>
#include <numeric>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <vector>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include <map>
#include <set>
#include <omp.h>

#define FNAME_LEN 256

#if defined(CLOCK_MONOTONIC)
#define CLOCK CLOCK_MONOTONIC
#elif defined(CLOCK_REALTIME)
#define CLOCK CLOCK_REALTIME
#else
#error "Failed to find a timing clock."
#endif

typedef uint32_t vertex_id_t;
typedef uint64_t edge_id_t;
typedef double weight_t;

using namespace std;

typedef map<vertex_id_t, weight_t> map_edges_t;
typedef map<vertex_id_t, map_edges_t> map_graph_t;

/* The graph data structure */
struct graph_t
{
    /**********************************************************
     The minimal graph repesentation consists of:
     n        -- the number of vertices
     m        -- the number of edges
     endV     -- an array of size m that stores the 
                 destination ID of an edge <src->dest>.
     rowsIndices -- an array of size n+1 that stores the degree 
                 (out-degree in case of directed graphs) and pointers to
                 the endV array. The degree of vertex i is given by 
                 rowsIndices[i+1]-rowsIndices[i], and the edges out of i are
                 stored in the contiguous block endV[rowsIndices[i] .. rowsIndices[i+1]-1].
     Vertices are ordered from 0 in our internal representation
    ***********************************************************/
    vertex_id_t n;
    edge_id_t m;
    edge_id_t *rowsIndices;
    vertex_id_t *endV;
    
    /* Edge weights */
    weight_t *weights;
    weight_t min_weight, max_weight;
    
    /* other graph parameters */
    int scale; /* log2 of vertices number */
    int avg_vertex_degree; /* relation m / n */
    bool directed;
    char filename[FNAME_LEN]; /* filename for output graph */
};

/* write graph to file */
void writeBinaryGraph(graph_t *G, char *filename);

/* read graph from file */
void readGraph(graph_t *G, char *filename);

/* free graph memory */
void freeGraph(graph_t *G);

/* main */
void build_map_graph_structure(graph_t &graph, map_graph_t &map_graph);
void set_map_graph_weights(graph_t &graph, map_graph_t &map_graph);
void community_detection(size_t n, map_graph_t &graph, vector<vertex_id_t> &component_id);

