/*************************************************************************
 *  Kompilacja:  javac EdgeWeightedDigraph.java
 *  Wykonanie:    java EdgeWeightedDigraph V E
 *  Zależności: Bag.java DirectedEdge.java
 *
 *  Digraf ważony, zaimplementowany za pomocą list sąsiedztwa.
 *
 *************************************************************************/

/**
 *  Klasa <tt>EdgeWeightedDigraph</tt> reprezentuje graf skierowany z wierzchołkami
 *  o nazwach od 0 do V-1, gdzie każda krawędź ma wagę w postaci liczby rzeczywistej.
 *  Obsługuje następujące operacje: dodawanie krawędzi do grafu,
 *  przechodzenie po wszystkich krawędziach wychodzących z wierzchołka.
 *  Krawędzie równoległe i pętle zwrotne są dozwolone.
 *  <p>
 *  Dodatkową dokumentację znajdziesz w <a href="http://algs4.cs.princeton.edu/44sp">podrozdziale 4.4</a> książki
 *  <i>Algorytmy, wydanie czwarte</i> Roberta Sedgewicka i Kevina Wayne'a.
 */



public class EdgeWeightedDigraph {
    private final int V;
    private int E;
    private Bag<DirectedEdge>[] adj;
    
    /**
     * Tworzy pusty digraf ważony o V wierzchołkach.
     */
    public EdgeWeightedDigraph(int V) {
        if (V < 0) throw new RuntimeException("Liczba wierzchołków musi być nieujemna");
        this.V = V;
        this.E = 0;
        adj = (Bag<DirectedEdge>[]) new Bag[V];
        for (int v = 0; v < V; v++)
            adj[v] = new Bag<DirectedEdge>();
    }

   /**
     * Tworzy digraf ważony o V wierzchołkach i E krawędziach.
     */
    public EdgeWeightedDigraph(int V, int E) {
        this(V);
        if (E < 0) throw new RuntimeException("Liczba wierzchołków musi być nieujemna");
        for (int i = 0; i < E; i++) {
            int v = (int) (Math.random() * V);
            int w = (int) (Math.random() * V);
            double weight = Math.round(100 * Math.random()) / 100.0;
            DirectedEdge e = new DirectedEdge(v, w, weight);
            addEdge(e);
        }
    }

    /**
     * Tworzy digraf ważony na podstawie strumienia wejściowego.
     */
    public EdgeWeightedDigraph(In in) {
        this(in.readInt());
        int E = in.readInt();
        for (int i = 0; i < E; i++) {
            int v = in.readInt();
            int w = in.readInt();
            double weight = in.readDouble();
            addEdge(new DirectedEdge(v, w, weight));
        }
    }


   /**
     * Zwraca liczbę wierzchołków w digrafie.
     */
    public int V() {
        return V;
    }

   /**
     * Zwraca liczbę krawędzi w digrafie.
     */
    public int E() {
        return E;
    }


   /**
     * Dodaje krawędź e do digrafu.
     */
    public void addEdge(DirectedEdge e) {
        int v = e.from();
        adj[v].add(e);
        E++;
    }


   /**
     * Zwraca wychodzące z wierzchołka v krawędzie jako obiekt Iterable.
     * Aby przejść po krawędziach wychodzących z wierzchołka v, użyj zapisu foreach:
     * <tt>for (DirectedEdge e : graph.adj(v))</tt>.
     */
    public Iterable<DirectedEdge> adj(int v) {
        return adj[v];
    }

   /**
     * Zwraca wszystkie krawędzie grafu jako obiekt Iterable.
     * Aby przejść po krawędziach, użyj zapisu foreach:
     * <tt>for (DirectedEdge e : graph.edges())</tt>.
     */
    public Iterable<DirectedEdge> edges() {
        Bag<DirectedEdge> list = new Bag<DirectedEdge>();
        for (int v = 0; v < V; v++) {
            for (DirectedEdge e : adj(v)) {
                list.add(e);
            }
        }
        return list;
    } 

   /**
     * Zwraca liczbę krawędzi wychodzących z v.
     */
    public int outdegree(int v) {
        return adj[v].size();
    }



   /**
     * Zwraca reprezentację łańcucha znaków dla grafu.
     */
    public String toString() {
        String NEWLINE = System.getProperty("line.separator");
        StringBuilder s = new StringBuilder();
        s.append(V + " " + E + NEWLINE);
        for (int v = 0; v < V; v++) {
            s.append(v + ": ");
            for (DirectedEdge e : adj[v]) {
                s.append(e + "  ");
            }
            s.append(NEWLINE);
        }
        return s.toString();
    }

    /**
     * Klient testowy.
     */
    public static void main(String[] args) {
        int V = Integer.parseInt(args[0]);
        int E = Integer.parseInt(args[1]);
        EdgeWeightedDigraph G = new EdgeWeightedDigraph(V, E);
        StdOut.println(G);
    }

}
