// Carnegie Mellon University
//   Information Networking Institute and
//   School of Computer Science
//
// Master Thesis: A Monitoring Tool for Overlay Network
// By: TungFai Chan and Annie Cheng
//
// File: TableManager.java
// Path: userInterfaces/componentManager/
// Description: Manageing table and interact with database


package userInterfaces.componentManagers;

import eventbase.*;
import eventbase.link.*;
import eventbase.neighbor.*;
import eventbase.routing.*;
import userInterfaces.*;
import userInterfaces.graph.*;

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;


public class TableManager {

    final static Color NORMAL_COLOR = Color.black;
    final static Color DEAD_COLOR = Color.red;
    final static Color LEAVE_COLOR = Color.blue;
    final static Color DROP_COLOR = Color.cyan;

    final String[] nodeTableSelectionOptions = {"Neighbor Table", "Routing Table"};
    final String[] linkTableSelectionOptions = {"Delay"};
    final int NUM_ELEMENT_TYPE = 2;

    MainScreen mainScreen = null;
    EventBaseAgent dbAgent = null;
    JTable infoTable = null;
    JComboBox tableSelectionComboBox = null;

    DefaultTableModel tableModel = null;

    int currentType;
    int[] currentSelection;

    double currentTime;
    int srcID;
    int destID;

    boolean resetEffect = false;

    public TableManager(JTable table, JComboBox selectionComboBox, EventBaseAgent agent,
                        MainScreen mScreen) {
        infoTable = table;
        tableSelectionComboBox = selectionComboBox;
        dbAgent = agent;
        mainScreen = mScreen;

        currentSelection = new int[NUM_ELEMENT_TYPE];
        currentType = -1;
    }

    public void updateTable(double time) {
        currentTime = time;
        tableModel = new DefaultTableModel();
        infoTable.setModel(tableModel);

	if (currentType == -1)
	    return;

        switch (currentType) {
            case VisualElement.NODE:
                updateNodeTable(time);
                break;
            case VisualElement.LINK:
                updateLinkTable(time);
                break;
        }

        //infoTable.setModel(tableModel);

    }


    public void updateElementType(int elementType, int src, int dest) {

        currentType = elementType;

        resetTableSelectionComboBox();
        tableSelectionComboBox.setSelectedIndex(currentSelection[currentType]);

        srcID = src;
        destID = dest;

        updateTable(currentTime);
    }

    public void clearSelection() {
	currentType = -1;
	resetTableSelectionComboBox();

        tableModel = new DefaultTableModel();
        infoTable.setModel(tableModel);


    }

    public void updateTableSelection(int index) {
        if (index == -1 || resetEffect)
            return;

        currentSelection[currentType] = index;
        updateTable(currentTime);
    }

    private void updateNodeTable(double time) {
        switch (currentSelection[VisualElement.NODE]) {
            case 0: // Neighbor Table
                Vector nbrTable = dbAgent.getNbrTableForDisplay(srcID, time);
                tableModel.addColumn("Neighbor");
                tableModel.addColumn("Join");
                tableModel.addColumn("Leave");

                infoTable.getColumn("Neighbor").setCellRenderer(new LabelTableCellRenderer());
                infoTable.getColumn("Join").setCellRenderer(new LabelTableCellRenderer());
                infoTable.getColumn("Leave").setCellRenderer(new LabelTableCellRenderer());

                for (Enumeration e = nbrTable.elements(); e.hasMoreElements();) {
                   DisplayNeighborTableEntry entry = (DisplayNeighborTableEntry)e.nextElement();

                   Color useColor = null;
                   switch (entry.getReasonToLeave()) {
                       case NeighborType.UNKNOWN:
                           useColor = NORMAL_COLOR;
                           break;
                       case NeighborType.DEAD:
                           useColor = DEAD_COLOR;
                           break;
                       case NeighborType.LEAVE:
                           useColor = LEAVE_COLOR;
                           break;
                       case NeighborType.DROP:
                           useColor = DROP_COLOR;
                           break;
                   }

                   LightWeightLabel neighLabel = new LightWeightLabel(entry.getNeighbor().getName(),
                                                                      useColor, null);
                   LightWeightLabel joinLabel = new LightWeightLabel(mainScreen.toTimeString(entry.getTimeSinceNeighbor(), false),
                                                                     useColor, null);
                   double leaveTime = entry.getTimeCeaseNeighbor();
                   LightWeightLabel leaveLabel = null;
                   if (leaveTime == -1)
                       leaveLabel = new LightWeightLabel("", useColor, null);
                   else
                       leaveLabel = new LightWeightLabel(mainScreen.toTimeString(leaveTime, false),
                                                         useColor, null);
                   tableModel.addRow(new Object[] {neighLabel, joinLabel, leaveLabel});
                }
                break;
           case 1:
                Vector routeTable = dbAgent.getRoutingTableForDisplay(time, srcID);
                tableModel.addColumn("Dest");
                 tableModel.addColumn("Next Hop");
                 tableModel.addColumn("Cost");
		 tableModel.addColumn("Children");

                 infoTable.getColumn("Dest").setCellRenderer(new LabelTableCellRenderer());
                 infoTable.getColumn("Next Hop").setCellRenderer(new LabelTableCellRenderer());
                 infoTable.getColumn("Cost").setCellRenderer(new LabelTableCellRenderer());
		 infoTable.getColumn("Children").setCellRenderer(new LabelTableCellRenderer());

                 for (Enumeration e = routeTable.elements(); e.hasMoreElements();) {
                    VirtualRoutingTableEntry entry = (VirtualRoutingTableEntry)e.nextElement();

                    Color useColor = null;
                    if (entry.getDeadFlg() == 0)
                        useColor = NORMAL_COLOR;
                    else
                        useColor = DEAD_COLOR;

                    LightWeightLabel destLabel = new LightWeightLabel(entry.getDest().getName(),
                                                                       useColor, null);
                    LightWeightLabel nextHopLabel = new LightWeightLabel(entry.getNextHop().getName(),
                                                            useColor, null);
                    LightWeightLabel costLabel = new LightWeightLabel(Integer.toString(entry.getCost()),
                                                                      useColor, null);
		    LightWeightLabel childLabel = new LightWeightLabel("<No Child>", useColor, null);
		    if (entry.getNumChild() == 0)
			tableModel.addRow(new Object[] {destLabel, nextHopLabel, costLabel, childLabel});
		    else {
			String[] childList = entry.getChildList();
			childLabel = new LightWeightLabel(childList[0], useColor, null);
			tableModel.addRow(new Object[] {destLabel, nextHopLabel, costLabel, childLabel});
			destLabel = new LightWeightLabel("", useColor, null);
			nextHopLabel = new LightWeightLabel("", useColor, null);
			costLabel = new LightWeightLabel("", useColor, null);
			for (int i = 1; i < entry.getNumChild(); i++) {
			    childLabel = new LightWeightLabel(childList[i], useColor, null);
			    tableModel.addRow(new Object[] {destLabel, nextHopLabel, costLabel, childLabel});
			}
		    }

                }
                break;


        }

    }

    private void updateLinkTable(double time) {
        DisplayLinkInfo info = dbAgent.getLinkInfo(time, srcID, destID,
                                                   currentSelection[VisualElement.LINK]);

        Vector forward = new Vector();
        Vector reverse = new Vector();

        switch (currentSelection[VisualElement.LINK]) {
            case LinkInfoType.DELAY:
                forward.addElement(new Object[] {"Delay",
                                                 Integer.toString(info.getSrcToTargetDelay())});
                reverse.addElement(new Object[] {"Delay",
                                                 Integer.toString(info.getTargetToSrcDelay())});
                break;
            // TODO: More info type later - tungfai
        }

        tableModel.addColumn("Properties");
        tableModel.addColumn("Values");

        tableModel.addRow(new Object[] {"Forward", ""});
        for (Enumeration e = forward.elements(); e.hasMoreElements();)
            tableModel.addRow((Object[])e.nextElement());

        // Add an empty line
        tableModel.addRow(new Object[] {"",""});

        tableModel.addRow(new Object[] {"Reverse", ""});
        for (Enumeration e = reverse.elements(); e.hasMoreElements();)
            tableModel.addRow((Object[])e.nextElement());

    }

    private void resetTableSelectionComboBox() {
        resetEffect = true;
        tableSelectionComboBox.removeAllItems();
        switch(currentType) {
            case VisualElement.NODE:
                for (int i = 0; i < nodeTableSelectionOptions.length; i++)
                    tableSelectionComboBox.addItem(nodeTableSelectionOptions[i]);
                break;
            case VisualElement.LINK:
                for (int i =0; i < linkTableSelectionOptions.length; i++)
                    tableSelectionComboBox.addItem(linkTableSelectionOptions[i]);
                break;
        }
        resetEffect = false;

    }

}
