#ifndef _graph_hpp_
#define _graph_hpp_
#include "../ex10/queue.hpp"
#include "vector.hpp"
#include <iomanip>
#include <iostream>
#include <string>
#define DISCOVERED 1
#define UNDISCOVERED 0
#define VISITED 2

template <class Te>
class Edge
{
public:
    Te data;
    int weight;
    Edge()
    {
        weight = 0;
    }
    Edge(int w)
    {
        weight = w;
    }

    Edge(Te d, int w)
    {
        data = d;
        weight = w;
    }
};

template <class Tv>
class Vertex
{
public:
    Tv data;
    int inDegree;
    int outDegree;
    int status;
    Vertex()
    {
        // data = NULL;
        inDegree = 0;
        outDegree = 0;
        status = UNDISCOVERED;
    }
    Vertex(Tv d)
    {
        data = d;
        inDegree = 0;
        outDegree = 0;
    }
};

template <class Te, class Tv>
class graphVertex
{
private:
    Vector<Vertex<Tv> *> V;
    Edge<Te> *E[100][100] = {NULL};

    int v;
    int e;

public:
    graphVertex()
    {
        v = 0;
        e = 0;
    }
    ~graphVertex()
    {
        int n = v;
        for (int j = 0; j < n; j++)
            for (int k = 0; k < n; k++)
                delete E[j][k];
        for (int j = 0; j < n; j++)
            delete V[j];
    }
    virtual Tv vertex(int i)
    {
        return V[i]->data;
    }
    virtual int inDegree(int i)
    {
        return V[i]->inDegree;
    }
    virtual int outDegree(int i)
    {
        return V[i]->outDegree;
    }
    virtual int insect(int id, Tv value)
    {
        // if (V[id] == NULL)
        // {
        Vertex<Tv> *temp1 = new Vertex<Tv>(value);
        V.put(id, temp1);
        // }
        // else
        //     V[id]->data = value;
        v++;
        return id;
    }
    virtual Tv remove(int id)
    {
        if (V[id] == NULL)
            return (Tv)0;
        for (int j = 0; j < v; j++)
        {
            if (E[id][j] != NULL)
            {
                delete E[id][j];
                E[id][j] = NULL;
                V[j]->inDegree--;
            }
        }
        v--;
        Tv temp = vertex(id);
        delete V[id];
        V.put(id, NULL);
        return temp;
    }

    // id1->id2 进行连接
    // return：
    //        -1 顶点不存在
    //        -2 边已存在
    //         0 成功
    virtual int link(int id1, int id2, int w)
    {
        if (V[id1] == NULL || V[id2] == NULL)
            return -1;
        if (E[id1][id2] != NULL)
            return -2;
        V[id1]->outDegree++;
        V[id2]->inDegree++;
        e++;
        Edge<Te> *temp = new Edge<Te>(w);
        E[id1][id2] = temp;
        return 0;
    }
    // 解除 id1->id2 连接
    // return：
    //       -1 顶点不存在
    //       -2 边不存在
    //        0 成功
    virtual int unlink(int id1, int id2)
    {
        if (V[id1] == NULL || V[id2] == NULL)
            return -1;

        if (E[id1][id2] == NULL)
            return -2;

        V[id1]->outDegree--;
        V[id2]->inDegree--;

        delete E[id1][id2];
        E[id1][id2] = NULL;
        e--;

        return 0;
    }

    virtual void display()
    {
        // std::cout << std::setw(14) << temp->weight;
        //第一行
        std::cout << std::left << std::setw(14) << " ";
        for (int i = 0; i < V._len; i++)
            if (V[i] != NULL)
                std::cout << std::setw(4) << i << std::setw(10) << V[i]->data;
        printf("\n");

        for (int i = 0; i < V._len; i++)
            if (V[i] != NULL)
            {
                //每行第一个
                std::cout << std::setw(4) << i << std::setw(10) << V[i]->data;

                //后面的
                for (int j = 0; j < V._len; j++)
                    if (V[j] != NULL)
                    {
                        if (E[i][j] != NULL)
                            std::cout << std::setw(14) << E[i][j]->weight;
                        else
                            std::cout << std::setw(14) << "-";
                    }
                printf("\n");
            }
    }

    virtual void BFS(int id)
    {
        reset();
        
        if(V[id]==NULL)
            return;
        Queue<int> q;
        V[id]->status = DISCOVERED;
        q.enqueue(id);
        while (!q.empty())
        {
            int vid = q.dequeue();

            for (int j = 0; j < 100; j++)
            {
                if (E[vid][j] != NULL)
                {
                    if (V[j]->status == UNDISCOVERED)
                    {
                        q.enqueue(j);
                        V[j]->status = DISCOVERED;
                        
                    }
                }
            }

            // std::cout << node->pos;
            printf("VISIT ID: %d \n", vid);
            V[vid]->status = VISITED;
        }
    }
    void reset()
    {
        for (int j = 0; j < V._len; j++)
        {
            if (V[j] != NULL)
            {

                V[j]->status = UNDISCOVERED;
            }
        }
    }
};

#endif