
/**
 * Title:        Overlay Network Monitor<p>
 * Description:  Master Thesis<p>
 * Copyright:    Copyright (c) Frank Chan and Annie Cheng<p>
 * Company:      Information Networking Institute, Carnegie Mellon University<p>
 * @author Frank Chan and Annie Cheng
 * @version 1.0
 */
package userInterfaces;

import network.*;

import java.awt.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;

public class NetworkInfoBox extends JDialog {

    final int NETWORKINFO_UPDATE_DELAY = 1000;

    // Data Model
    NetworkStatDataModel dataModel = null;

    // Timer And Listener
    NetworkInfoUpdateListener networkUpdateListener = null;
    javax.swing.Timer networkUpdateTimer = null;

    // Number format
    NumberFormat numFormat = null;

    JPanel contentPane = new JPanel();
    BorderLayout borderLayout1 = new BorderLayout();
    JPanel singlePanel = new JPanel();
    JPanel buttonPanel = new JPanel();
    JPanel totalPanel = new JPanel();
    BorderLayout borderLayout2 = new BorderLayout();
    JPanel singleNodePanel = new JPanel();
    JPanel singleSendPanel = new JPanel();
    JPanel singleRecvPanel = new JPanel();
    FlowLayout flowLayout1 = new FlowLayout();
    JLabel singleNodeLabel = new JLabel();
    JComboBox nodesComboBox = new JComboBox();
    JLabel singleRecvPacketLabel = new JLabel();
    FlowLayout flowLayout2 = new FlowLayout();
    JTextField singleRecvPacketsText = new JTextField();
    JLabel singleRecvBytesLabel = new JLabel();
    JTextField singleRecvBytesText = new JTextField();
    JLabel singleRecvBandwidthLabel = new JLabel();
    JTextField singleRecvBandwidthText = new JTextField();
    JLabel jLabel1 = new JLabel();
    JTextField singleSendPacketsText = new JTextField();
    JLabel jLabel2 = new JLabel();
    JTextField singleSendBytesText = new JTextField();
    JLabel jLabel3 = new JLabel();
    JTextField singleSendBandwidthText = new JTextField();
    FlowLayout flowLayout3 = new FlowLayout();
    BorderLayout borderLayout3 = new BorderLayout();
    JPanel totalRecvPanel = new JPanel();
    JPanel totalSendPanel = new JPanel();
    JLabel jLabel4 = new JLabel();
    JTextField totalRecvPacketsText = new JTextField();
    JLabel jLabel5 = new JLabel();
    JTextField totalRecvBytesText = new JTextField();
    JLabel jLabel6 = new JLabel();
    JTextField totalRecvBandwidthText = new JTextField();
    JLabel jLabel7 = new JLabel();
    JTextField totalSendPacketsText = new JTextField();
    JLabel jLabel8 = new JLabel();
    JTextField totalSendBytesText = new JTextField();
    JLabel jLabel9 = new JLabel();
    JTextField totalSendBandwidthText = new JTextField();
    FlowLayout flowLayout4 = new FlowLayout();
    FlowLayout flowLayout5 = new FlowLayout();
    JButton okButton = new JButton();
    JPanel totalTitlePanel = new JPanel();
    JLabel totalTitleLabel = new JLabel();
    JLabel singleCurrRecvLabel = new JLabel();
    JLabel singleCurrSendLabel = new JLabel();
    JLabel jLabel12 = new JLabel();
    JLabel jLabel13 = new JLabel();
    JTextField singleCurrRecvText = new JTextField();
    JTextField singleCurrSendText = new JTextField();
    JTextField totalCurrRecvText = new JTextField();
    JTextField totalCurrSendText = new JTextField();

    public NetworkInfoBox(Frame frame) {
        super(frame);
        try {
            jbInit();
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }

        numFormat = NumberFormat.getInstance();
        numFormat.setMaximumFractionDigits(2);
        numFormat.setMinimumFractionDigits(2);
    }

    void jbInit() throws Exception {
        totalPanel.setMinimumSize(new Dimension(100, 90));
        totalPanel.setPreferredSize(new Dimension(100, 90));
        totalPanel.setLayout(borderLayout3);
        buttonPanel.setMinimumSize(new Dimension(100, 40));
        buttonPanel.setPreferredSize(new Dimension(100, 40));
        singlePanel.setMinimumSize(new Dimension(100, 90));
        singlePanel.setPreferredSize(new Dimension(100, 90));
        singlePanel.setLayout(borderLayout2);
        this.setModal(true);
        this.setContentPane(contentPane);
        this.setTitle("Network Information");
        contentPane.setLayout(borderLayout1);
        contentPane.setMinimumSize(new Dimension(720, 250));
        contentPane.setPreferredSize(new Dimension(720, 250));
        singleRecvPanel.setMinimumSize(new Dimension(100, 30));
        singleRecvPanel.setPreferredSize(new Dimension(100, 30));
        singleRecvPanel.setLayout(flowLayout2);
        singleNodePanel.setMinimumSize(new Dimension(100, 30));
        singleNodePanel.setPreferredSize(new Dimension(100, 30));
        singleNodePanel.setLayout(flowLayout1);
        singleSendPanel.setMinimumSize(new Dimension(100, 30));
        singleSendPanel.setPreferredSize(new Dimension(100, 30));
        singleSendPanel.setLayout(flowLayout3);
        singleNodeLabel.setFont(new java.awt.Font("SansSerif", 1, 12));
        singleNodeLabel.setText("Connection to: ");
        nodesComboBox.setFont(new java.awt.Font("SansSerif", 0, 10));
        nodesComboBox.setMinimumSize(new Dimension(180, 20));
        nodesComboBox.setPreferredSize(new Dimension(180, 20));
        singleRecvPacketLabel.setFont(new java.awt.Font("SansSerif", 0, 12));
        singleRecvPacketLabel.setText("Receive: Packets");
        singleRecvBytesLabel.setFont(new java.awt.Font("SansSerif", 0, 12));
        singleRecvBytesLabel.setText("Bytes");
        singleRecvBandwidthLabel.setFont(new java.awt.Font("SansSerif", 0, 12));
        singleRecvBandwidthLabel.setText("Bandwidth: Average(B/s)");
        jLabel1.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel1.setText("Send: Packets");
        singleSendPacketsText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleSendPacketsText.setMinimumSize(new Dimension(50, 20));
        singleSendPacketsText.setPreferredSize(new Dimension(50, 20));
        jLabel2.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel2.setText("Bytes");
        singleSendBytesText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleSendBytesText.setMinimumSize(new Dimension(80, 20));
        singleSendBytesText.setPreferredSize(new Dimension(80, 20));
        jLabel3.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel3.setText("Bandwidth: Average(B/s)");
        singleSendBandwidthText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleSendBandwidthText.setMinimumSize(new Dimension(80, 20));
        singleSendBandwidthText.setPreferredSize(new Dimension(80, 20));
        singleRecvPacketsText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleRecvPacketsText.setMinimumSize(new Dimension(50, 20));
        singleRecvPacketsText.setPreferredSize(new Dimension(50, 20));
        singleRecvBytesText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleRecvBytesText.setMinimumSize(new Dimension(80, 20));
        singleRecvBytesText.setPreferredSize(new Dimension(80, 20));
        singleRecvBandwidthText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleRecvBandwidthText.setMinimumSize(new Dimension(80, 20));
        singleRecvBandwidthText.setPreferredSize(new Dimension(80, 20));
        flowLayout2.setAlignment(FlowLayout.RIGHT);
        flowLayout3.setAlignment(FlowLayout.RIGHT);
        totalSendPanel.setMinimumSize(new Dimension(100, 30));
        totalSendPanel.setPreferredSize(new Dimension(100, 30));
        totalSendPanel.setLayout(flowLayout5);
        totalRecvPanel.setMinimumSize(new Dimension(100, 30));
        totalRecvPanel.setPreferredSize(new Dimension(100, 30));
        totalRecvPanel.setLayout(flowLayout4);
        jLabel4.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel4.setText("Receive: Packets");
        totalRecvPacketsText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalRecvPacketsText.setMinimumSize(new Dimension(50, 20));
        totalRecvPacketsText.setPreferredSize(new Dimension(50, 20));
        jLabel5.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel5.setMaximumSize(new Dimension(45, 13));
        jLabel5.setMinimumSize(new Dimension(45, 13));
        jLabel5.setText("Bytes");
        totalRecvBytesText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalRecvBytesText.setMinimumSize(new Dimension(80, 20));
        totalRecvBytesText.setPreferredSize(new Dimension(80, 20));
        jLabel6.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel6.setText("Bandwidth: Average(B/s)");
        totalRecvBandwidthText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalRecvBandwidthText.setMinimumSize(new Dimension(80, 20));
        totalRecvBandwidthText.setPreferredSize(new Dimension(80, 20));
        jLabel7.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel7.setText("Send: Packets");
        totalSendPacketsText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalSendPacketsText.setMinimumSize(new Dimension(50, 20));
        totalSendPacketsText.setPreferredSize(new Dimension(50, 20));
        jLabel8.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel8.setMaximumSize(new Dimension(45, 13));
        jLabel8.setMinimumSize(new Dimension(45, 13));
        jLabel8.setText("Bytes");
        totalSendBytesText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalSendBytesText.setMinimumSize(new Dimension(80, 20));
        totalSendBytesText.setPreferredSize(new Dimension(80, 20));
        jLabel9.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel9.setText("Bandwidth: Average(B/s)");
        totalSendBandwidthText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalSendBandwidthText.setMinimumSize(new Dimension(80, 20));
        totalSendBandwidthText.setPreferredSize(new Dimension(80, 20));
        flowLayout4.setAlignment(FlowLayout.RIGHT);
        flowLayout5.setAlignment(FlowLayout.RIGHT);
        okButton.setText("OK");
        okButton.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(ActionEvent e) {
                okButton_actionPerformed(e);
            }
        });
        totalTitlePanel.setMinimumSize(new Dimension(100, 30));
        totalTitlePanel.setPreferredSize(new Dimension(100, 30));
        totalTitleLabel.setFont(new java.awt.Font("SansSerif", 1, 12));
        totalTitleLabel.setText("Overall Statistics");
        singleCurrRecvLabel.setFont(new java.awt.Font("SansSerif", 0, 12));
        singleCurrRecvLabel.setText("Current(B/s)");
        singleCurrSendLabel.setFont(new java.awt.Font("SansSerif", 0, 12));
        singleCurrSendLabel.setText("Current(B/s)");
        jLabel12.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel12.setText("Current(B/s)");
        jLabel13.setFont(new java.awt.Font("SansSerif", 0, 12));
        jLabel13.setText("Current(B/s)");
        singleCurrRecvText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleCurrRecvText.setMinimumSize(new Dimension(80, 20));
        singleCurrRecvText.setPreferredSize(new Dimension(80, 20));
        singleCurrSendText.setFont(new java.awt.Font("SansSerif", 0, 10));
        singleCurrSendText.setMinimumSize(new Dimension(80, 20));
        singleCurrSendText.setPreferredSize(new Dimension(80, 20));
        totalCurrRecvText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalCurrRecvText.setMinimumSize(new Dimension(80, 20));
        totalCurrRecvText.setPreferredSize(new Dimension(80, 20));
        totalCurrSendText.setFont(new java.awt.Font("SansSerif", 0, 10));
        totalCurrSendText.setMinimumSize(new Dimension(80, 20));
        totalCurrSendText.setPreferredSize(new Dimension(80, 20));
        this.getContentPane().add(singlePanel, BorderLayout.NORTH);
        singlePanel.add(singleNodePanel, BorderLayout.NORTH);
        singleNodePanel.add(singleNodeLabel, null);
        singleNodePanel.add(nodesComboBox, null);
        singlePanel.add(singleSendPanel, BorderLayout.SOUTH);
        singleSendPanel.add(jLabel1, null);
        singleSendPanel.add(singleSendPacketsText, null);
        singleSendPanel.add(jLabel2, null);
        singleSendPanel.add(singleSendBytesText, null);
        singleSendPanel.add(jLabel3, null);
        singleSendPanel.add(singleSendBandwidthText, null);
        singleSendPanel.add(singleCurrSendLabel, null);
        singleSendPanel.add(singleCurrSendText, null);
        singlePanel.add(singleRecvPanel, BorderLayout.CENTER);
        singleRecvPanel.add(singleRecvPacketLabel, null);
        singleRecvPanel.add(singleRecvPacketsText, null);
        singleRecvPanel.add(singleRecvBytesLabel, null);
        singleRecvPanel.add(singleRecvBytesText, null);
        singleRecvPanel.add(singleRecvBandwidthLabel, null);
        singleRecvPanel.add(singleRecvBandwidthText, null);
        singleRecvPanel.add(singleCurrRecvLabel, null);
        singleRecvPanel.add(singleCurrRecvText, null);
        this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
        buttonPanel.add(okButton, null);
        this.getContentPane().add(totalPanel, BorderLayout.CENTER);
        totalPanel.add(totalRecvPanel, BorderLayout.CENTER);
        totalRecvPanel.add(jLabel4, null);
        totalRecvPanel.add(totalRecvPacketsText, null);
        totalRecvPanel.add(jLabel5, null);
        totalRecvPanel.add(totalRecvBytesText, null);
        totalRecvPanel.add(jLabel6, null);
        totalRecvPanel.add(totalRecvBandwidthText, null);
        totalRecvPanel.add(jLabel12, null);
        totalRecvPanel.add(totalCurrRecvText, null);
        totalPanel.add(totalSendPanel, BorderLayout.SOUTH);
        totalSendPanel.add(jLabel7, null);
        totalSendPanel.add(totalSendPacketsText, null);
        totalSendPanel.add(jLabel8, null);
        totalSendPanel.add(totalSendBytesText, null);
        totalSendPanel.add(jLabel9, null);
        totalSendPanel.add(totalSendBandwidthText, null);
        totalSendPanel.add(jLabel13, null);
        totalSendPanel.add(totalCurrSendText, null);
        totalPanel.add(totalTitlePanel, BorderLayout.NORTH);
        totalTitlePanel.add(totalTitleLabel, null);

        this.setSize(720, 250);

    }

    public void refresh() {
        Vector data = dataModel.getRecords();

        if (data.size() == 0)
            return;

        updateNodesList(data);

        double diffTime = (double)(Calendar.getInstance().getTime().getTime() -
                                   dataModel.startTime) / 1000;

        // Update Single Connection
        int selectedIndex = nodesComboBox.getSelectedIndex();
        if (selectedIndex != -1) {
            NetworkStatRecord record = (NetworkStatRecord)data.elementAt(selectedIndex);
            singleRecvPacketsText.setText(Integer.toString(record.recvNumPackets));
            singleRecvBytesText.setText(Long.toString(record.recvNumBytes));
            singleSendPacketsText.setText(Integer.toString(record.sendNumPackets));
            singleSendBytesText.setText(Long.toString(record.sendNumBytes));

            double recvRate = (double)record.recvNumBytes / diffTime;
            double sendRate = (double)record.sendNumBytes / diffTime;

            singleRecvBandwidthText.setText(numFormat.format(recvRate));
            singleSendBandwidthText.setText(numFormat.format(sendRate));

            singleCurrRecvText.setText(numFormat.format(record.currentRecvBytes));
            singleCurrSendText.setText(numFormat.format(record.currentSendBytes));

        }

        // Clear Transcient data
        // Possible race condition, but not a big deal
        dataModel.clearNodeTranscient();

        // Update overall
        totalRecvPacketsText.setText(Integer.toString(dataModel.totalRecvPackets));
        totalRecvBytesText.setText(Long.toString(dataModel.totalRecvBytes));
        totalSendPacketsText.setText(Integer.toString(dataModel.totalSendPackets));
        totalSendBytesText.setText(Long.toString(dataModel.totalSendBytes));

        double recvRate = (double)dataModel.totalRecvBytes / diffTime;
        double sendRate = (double)dataModel.totalSendBytes / diffTime;

        totalRecvBandwidthText.setText(numFormat.format(recvRate));
        totalSendBandwidthText.setText(numFormat.format(sendRate));

        totalCurrRecvText.setText(numFormat.format(dataModel.currentRecvBytes));
        totalCurrSendText.setText(numFormat.format(dataModel.currentSendBytes));

        // Clear Transcient data
        // Possible race condition, but not a big deal
        dataModel.clearOverallTranscient();

    }

    public void setNetworkStatDataModel(NetworkStatDataModel model) {
        dataModel = model;
        refresh();

        networkUpdateListener = new NetworkInfoUpdateListener(this);
        networkUpdateTimer = new javax.swing.Timer(NETWORKINFO_UPDATE_DELAY, networkUpdateListener);

        networkUpdateTimer.start();

    }

    private void updateNodesList(Vector data) {
        if (nodesComboBox.getItemCount() != data.size())
            for (int i = nodesComboBox.getItemCount(); i < data.size(); i++)
                nodesComboBox.addItem((String)(((NetworkStatRecord)data.elementAt(i)).hostname));

    }

    void okButton_actionPerformed(ActionEvent e) {
        networkUpdateTimer.stop();
        this.dispose();
    }

}
