package com.alibaba.druid.util;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class ListDG {
   private List<VNode> mVexs;

   public ListDG(List vexs, List<Edge> edges) {
      int vlen = vexs.size();
      int elen = edges.size();
      this.mVexs = new ArrayList();

      for(int i = 0; i < vlen; ++i) {
         VNode vnode = new VNode();
         vnode.data = vexs.get(i);
         vnode.firstEdge = null;
         this.mVexs.add(vnode);
      }

      for(int i = 0; i < elen; ++i) {
         Object c1 = ((Edge)edges.get(i)).from;
         Object c2 = ((Edge)edges.get(i)).to;
         int p1 = this.getPosition(((Edge)edges.get(i)).from);
         int p2 = this.getPosition(((Edge)edges.get(i)).to);
         ENode node1 = new ENode();
         node1.ivex = p2;
         if (((VNode)this.mVexs.get(p1)).firstEdge == null) {
            ((VNode)this.mVexs.get(p1)).firstEdge = node1;
         } else {
            this.linkLast(((VNode)this.mVexs.get(p1)).firstEdge, node1);
         }
      }

   }

   private void linkLast(ENode list, ENode node) {
      ENode p;
      for(p = list; p.nextEdge != null; p = p.nextEdge) {
      }

      p.nextEdge = node;
   }

   private int getPosition(Object ch) {
      for(int i = 0; i < this.mVexs.size(); ++i) {
         if (((VNode)this.mVexs.get(i)).data == ch) {
            return i;
         }
      }

      return -1;
   }

   private void DFS(int i, boolean[] visited) {
      visited[i] = true;

      for(ENode node = ((VNode)this.mVexs.get(i)).firstEdge; node != null; node = node.nextEdge) {
         if (!visited[node.ivex]) {
            this.DFS(node.ivex, visited);
         }
      }

   }

   public void DFS() {
      boolean[] visited = new boolean[this.mVexs.size()];

      for(int i = 0; i < this.mVexs.size(); ++i) {
         visited[i] = false;
      }

      for(int i = 0; i < this.mVexs.size(); ++i) {
         if (!visited[i]) {
            this.DFS(i, visited);
         }
      }

   }

   public void BFS() {
      int head = 0;
      int rear = 0;
      int[] queue = new int[this.mVexs.size()];
      boolean[] visited = new boolean[this.mVexs.size()];

      for(int i = 0; i < this.mVexs.size(); ++i) {
         visited[i] = false;
      }

      for(int i = 0; i < this.mVexs.size(); ++i) {
         if (!visited[i]) {
            visited[i] = true;
            System.out.printf("%c ", ((VNode)this.mVexs.get(i)).data);
            queue[rear++] = i;
         }

         while(head != rear) {
            int j = queue[head++];

            for(ENode node = ((VNode)this.mVexs.get(j)).firstEdge; node != null; node = node.nextEdge) {
               int k = node.ivex;
               if (!visited[k]) {
                  visited[k] = true;
                  System.out.printf("%c ", ((VNode)this.mVexs.get(k)).data);
                  queue[rear++] = k;
               }
            }
         }
      }

   }

   public void print() {
      System.out.printf("== List Graph:\n");

      for(int i = 0; i < this.mVexs.size(); ++i) {
         System.out.printf("%d(%c): ", i, ((VNode)this.mVexs.get(i)).data);

         for(ENode node = ((VNode)this.mVexs.get(i)).firstEdge; node != null; node = node.nextEdge) {
            System.out.printf("%d(%c) ", node.ivex, ((VNode)this.mVexs.get(node.ivex)).data);
         }
      }

   }

   public boolean topologicalSort() {
      return this.topologicalSort(new Object[this.mVexs.size()]);
   }

   public boolean topologicalSort(Object[] tops) {
      int index = 0;
      int num = this.mVexs.size();
      int[] ins = new int[num];
      Queue<Integer> queue = new LinkedList();

      for(int i = 0; i < num; ++i) {
         for(ENode node = ((VNode)this.mVexs.get(i)).firstEdge; node != null; node = node.nextEdge) {
            ++ins[node.ivex];
         }
      }

      for(int i = 0; i < num; ++i) {
         if (ins[i] == 0) {
            queue.offer(i);
         }
      }

      while(!queue.isEmpty()) {
         int j = (Integer)queue.poll();
         tops[index++] = ((VNode)this.mVexs.get(j)).data;

         for(ENode node = ((VNode)this.mVexs.get(j)).firstEdge; node != null; node = node.nextEdge) {
            --ins[node.ivex];
            if (ins[node.ivex] == 0) {
               queue.offer(node.ivex);
            }
         }
      }

      if (index != num) {
         return false;
      } else {
         return true;
      }
   }

   public static class Edge {
      public Object from;
      public Object to;

      public Edge(Object from, Object to) {
         this.from = from;
         this.to = to;
      }
   }

   private class ENode {
      int ivex;
      ENode nextEdge;

      private ENode() {
      }
   }

   private class VNode {
      Object data;
      ENode firstEdge;

      private VNode() {
      }
   }
}
