package org.kne.cloud.network.klalb.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
import org.kne.cloud.network.ipv6.IPv6Address;
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
import org.kne.cloud.network.ipv6.IPv6Packet;
import org.kne.cloud.network.klalb.KLALBRemoteLink;
import org.kne.cloud.network.monitor.LinkStatus;
import org.kne.cloud.network.monitor.TimestampMonitorValue;
import org.kne.math.Long128;
import org.kne.ui.XFrame;

import java.awt.BasicStroke;
import java.awt.BorderLayout;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JSlider;

public class LineMonitorGUI extends XFrame {
	private Timer timer;
	private Timer timer1;
	private Timer timer2;
	private Timer timer3;
	private TimerTask tsk3;

	private TimerTask tsk4, tsk5,tsk6;
	private TimerTask d1;
	private TimerTask d2;
	private TimerTask d3;

	private TimeSeries spdup = new TimeSeries(UIEnv.getRsb().getString("uploadspeed"));
	private TimeSeries spddown = new TimeSeries(UIEnv.getRsb().getString("downloadspeed"));

	private TimeSeries delayup = new TimeSeries(UIEnv.getRsb().getString("uploaddelay"));
	private TimeSeries delaydown = new TimeSeries(UIEnv.getRsb().getString("downloaddelay"));
	 private TimeSeries delayupmin=new TimeSeries(UIEnv.getRsb().getString("uploadbasedelay"));
	private TimeSeries delaydownmin=new TimeSeries(UIEnv.getRsb().getString("downloadbasedelay"));
	

	private TimeSeries bufferused = new TimeSeries(UIEnv.getRsb().getString("usedbuffer"));
	private TimeSeries queueused = new TimeSeries(UIEnv.getRsb().getString("queueused"));
	private TimeSeries buffermax = new TimeSeries(UIEnv.getRsb().getString("maxbuffer"));

	private KLALBRemoteLink tr;
	private JFreeChart jfc;
	private JFreeChart jfce;
	private JFreeChart jbfc;
	private JLabel spdp;
	private JLabel delp;
	private JLabel sbpdp;
	private long timeRange = 5000;
	private long[] values = new long[] { 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 };
	private JPanel panel_1;
	private JLabel lblNewLabel;

	// private ChartPanel delp;
	// private ChartPanel spdp;
	public LineMonitorGUI(KLALBRemoteLink t) {
		this.tr = t;
		setSize(1200, 780);
		setLocationRelativeTo(null);

		setIconImage(UIEnv.getIcon());
		setTitle("Line Monitor:" + t.getName());
		setTitleColor(UIEnv.getDefaultTitleColor());
		getContentPane().setBackground(UIEnv.getDefaultBackgroundColor());
		getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
		getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));

		JPanel jp = new JPanel();
		jp.setLayout(new GridLayout(2, 2));
		getContentPane().add(jp);

		TimeSeriesCollection tsc = new TimeSeriesCollection();
		tsc.addSeries(spdup);
		tsc.addSeries(spddown);
		jfc = ChartFactory.createTimeSeriesChart(UIEnv.getRsb().getString("speermonitor"),
				UIEnv.getRsb().getString("time") + "(s)", UIEnv.getRsb().getString("speed") + "(KiB/s)", tsc);
		jfc.getXYPlot().setBackgroundPaint(Color.BLACK);
		jfc.getXYPlot().getRenderer().setSeriesPaint(0, Color.RED);
		jfc.getXYPlot().getRenderer().setSeriesPaint(1, Color.GREEN);
		changeFont(jfc);
		spdp = new JLabel();
		spdp.setBorder(new LineBorder(Color.DARK_GRAY));
		jp.add(spdp);

		
		
		
		
		TimeSeriesCollection tsce = new TimeSeriesCollection();
		tsce.addSeries(delayup);
		tsce.addSeries(delaydown);

		 tsce.addSeries(delayupmin);
		 tsce.addSeries(delaydownmin);
		 
		jfce = ChartFactory.createTimeSeriesChart(UIEnv.getRsb().getString("delaymonitor"),
				UIEnv.getRsb().getString("time") + "(s)", UIEnv.getRsb().getString("delay") + "(ms)", tsce);
		jfce.getXYPlot().setBackgroundPaint(Color.BLACK);
		jfce.getXYPlot().getRenderer().setSeriesPaint(0, Color.RED);
		jfce.getXYPlot().getRenderer().setSeriesPaint(1, Color.GREEN);

		BasicStroke dotted = new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0,
				new float[] { 0, 6, 0, 6 }, 0);
		
		  jfce.getXYPlot().getRenderer().setSeriesPaint(2,Color.RED);
		  jfce.getXYPlot().getRenderer().setSeriesStroke(2, dotted);
		  jfce.getXYPlot().getRenderer().setSeriesPaint(3,Color.GREEN);
		  jfce.getXYPlot().getRenderer().setSeriesStroke(3, dotted);
		 
		changeFont(jfce);
		delp = new JLabel();
		delp.setBorder(new LineBorder(Color.DARK_GRAY));
		jp.add(delp);

		
		
		
		
		TimeSeriesCollection tbsc = new TimeSeriesCollection();
		tbsc.addSeries(bufferused);
		tbsc.addSeries(queueused);
		tbsc.addSeries(buffermax);
		jbfc = ChartFactory.createTimeSeriesChart(UIEnv.getRsb().getString("bufferusagemonitor"),
				UIEnv.getRsb().getString("time") + "(s)", UIEnv.getRsb().getString("buffer") + "(KB)", tbsc);
		jbfc.getXYPlot().setBackgroundPaint(Color.BLACK);
		jbfc.getXYPlot().getRenderer().setSeriesPaint(0, Color.BLUE);
		jbfc.getXYPlot().getRenderer().setSeriesPaint(1, Color.MAGENTA);
		jbfc.getXYPlot().getRenderer().setSeriesPaint(2, Color.CYAN);
		changeFont(jbfc);
		sbpdp = new JLabel();
		sbpdp.setBorder(new LineBorder(Color.DARK_GRAY));
		jp.add(sbpdp);
		
		
		
		
		
		JPanel panel = new JPanel();
		panel.setOpaque(false);
		getContentPane().add(panel, BorderLayout.NORTH);
		panel.setLayout(new GridLayout(1, 1, 0, 0));

		panel_1 = new JPanel();
		panel.add(panel_1);
		panel_1.setLayout(new BorderLayout(0, 0));

		JSlider windowSlider = new JSlider();
		windowSlider.setValue(2);
		windowSlider.setMaximum(9);
		panel_1.add(windowSlider, BorderLayout.CENTER);
		JLabel windowSelect = new JLabel("5s");
		windowSlider.addChangeListener(new ChangeListener() {

			@Override
			public void stateChanged(ChangeEvent e) {
				updateTimeRange(windowSlider, windowSelect);
			}
		});
		updateTimeRange(windowSlider, windowSelect);
		panel_1.add(windowSelect, BorderLayout.EAST);

		lblNewLabel = new JLabel(UIEnv.getRsb().getString("timerange"));
		panel_1.add(lblNewLabel, BorderLayout.WEST);
		Dimension dms = new Dimension(140, 20);

		/*
		 * JButton btnNewButton_2 = new JButton("Pressure test");
		 * btnNewButton_2.setPreferredSize(dms); btnNewButton_2.addActionListener(new
		 * ActionListener() { public void actionPerformed(ActionEvent e) {
		 * tr.pressureTest(); } }); panel_1.add(btnNewButton_2);
		 * btnNewButton_2.setForeground(Color.BLUE);
		 */
		addWindowListener(new WindowListener() {

			@Override
			public void windowOpened(WindowEvent e) {

			}

			@Override
			public void windowIconified(WindowEvent e) {
				// TODO 自动生成的方法存根

			}

			@Override
			public void windowDeiconified(WindowEvent e) {
				// TODO 自动生成的方法存根

			}

			@Override
			public void windowDeactivated(WindowEvent e) {
				// TODO 自动生成的方法存根

			}

			@Override
			public void windowClosing(WindowEvent e) {

			}

			@Override
			public void windowClosed(WindowEvent e) {
				// TODO 自动生成的方法存根

			}

			@Override
			public void windowActivated(WindowEvent e) {
				// TODO 自动生成的方法存根

			}
		});
	}

	protected void updateTimeRange(JSlider windowSlider, JLabel windowSelect) {
		timeRange = values[windowSlider.getValue()];
		synchronized (jfc) {

			jfc.getXYPlot().getDomainAxis().setFixedAutoRange(timeRange);
			spdup.setMaximumItemCount((int) timeRange/5);
			spddown.setMaximumItemCount((int) timeRange/5);
		}
		synchronized (jfce) {

			jfce.getXYPlot().getDomainAxis().setFixedAutoRange(timeRange);
			delayup.setMaximumItemCount((int) timeRange/5);
			delaydown.setMaximumItemCount((int) timeRange/5);
			delayupmin.setMaximumItemCount((int) timeRange/5);
			delaydownmin.setMaximumItemCount((int) timeRange/5);
		}
		

		synchronized (jbfc) {

			jbfc.getXYPlot().getDomainAxis().setFixedAutoRange(timeRange);
			bufferused.setMaximumItemCount((int) timeRange/5);
			buffermax.setMaximumItemCount((int) timeRange/5);
			queueused.setMaximumItemCount((int) timeRange/5);
		}
		windowSelect.setText(timeRange / 1000 + "s");
	}

	private void changeFont(JFreeChart jfc2) {
		jfc2.getTitle().setFont(UIEnv.getFont().deriveFont(16.0f));
		jfc2.getLegend().setItemFont(UIEnv.getFont());
		jfc2.getXYPlot().getRangeAxis().setLabelFont(UIEnv.getFont());
		jfc2.getXYPlot().getRangeAxis().setTickLabelFont(UIEnv.getFont());
		jfc2.getXYPlot().getDomainAxis().setLabelFont(UIEnv.getFont());
		jfc2.getXYPlot().getDomainAxis().setTickLabelFont(UIEnv.getFont());
	}

	private void recordSpeedData() {
		if (isVisible()) {
			Millisecond ms = new Millisecond(
					new Date(tr.getMonitor().getClock().getCurrentTimeMillis()));
			synchronized (jfc) {
				spdup.addOrUpdate(ms, tr.getMonitor().getOutSpeed() / 1024.0);
				spddown.addOrUpdate(ms, tr.getMonitor().getInSpeed() / 1024.0);
			}

		}
	}

	private void recordDelayData() {
		if (isVisible()) {

			synchronized (jfce) {
				TimestampMonitorValue valup = tr.getMonitor().getUploadBandwidth().getRecentDelayEntry();
				if (valup != null) {
					Millisecond ms = new Millisecond(
							new Date(valup.getTimestamp().divide(new Long128(1000000L)).longValue()));
					//System.out.println(ms+" "+new Millisecond());
					delayup.addOrUpdate(ms, valup.getDelay() / 1000000.0);
				}
				TimestampMonitorValue valdown = tr.getMonitor().getDownloadBandwidth().getRecentDelayEntry();
				if (valdown != null) {
					Millisecond ms2 = new Millisecond(
							new Date(valdown.getTimestamp().divide(new Long128(1000000L)).longValue()));
					delaydown.addOrUpdate(ms2, valdown.getDelay() / 1000000.0);
				}

				Millisecond ms = new Millisecond(
						new Date(tr.getMonitor().getClock().getCurrentTimeMillis()));
				delayupmin.addOrUpdate(ms, tr.getMonitor().getOutDelayMin() / 1000000.0);
				delaydownmin.addOrUpdate(ms, tr.getMonitor().getInDelayMin() / 1000000.0);
			}

		}
	}

	private void recordBufferData() {
		if (isVisible()) {
			Millisecond ms = new Millisecond(
					new Date(tr.getMonitor().getClock().getCurrentTimeMillis()));
			synchronized (jbfc) {
			SendPacketSlidingWindow<UUID, IPv6Packet> window=tr.getWindow();
			if(window !=null) {
				bufferused.addOrUpdate(ms, window.getSendWindowUsed() / 1024.0);
				//queueused.addOrUpdate(ms, tr.getQueueUsed() / 1024.0);
				buffermax.addOrUpdate(ms, window.getWindowSize() / 1024.0);
				
			}
			}
		}
	}
	@Override
	public void setVisible(boolean b) {
		if (b) {
			if (timer == null) {
				timer = new Timer();
				timer1 = new Timer();
				timer2 = new Timer();
				timer3 = new Timer();
				tsk3 = new TimerTask() {

					@Override
					public void run() {
						updateTraffic();
					}
				};
				tsk4 = new TimerTask() {

					@Override
					public void run() {
						recordSpeedData();
					}
				};

				tsk5 = new TimerTask() {

					@Override
					public void run() {
						recordDelayData();
					}
				};
				tsk6 = new TimerTask() {

					@Override
					public void run() {
						recordBufferData();
					}
				};
				d1 = new TimerTask() {

					@Override
					public void run() {
						if (isVisible()) {
							synchronized (jfc) {
								ImageIcon i1 = new ImageIcon(
										jfc.createBufferedImage(spdp.getWidth(), spdp.getHeight()));
								spdp.setIcon(i1);
							}
						}
					}
				};
				d2 = new TimerTask() {

					@Override
					public void run() {
						if (isVisible()) {
							synchronized (jfce) {
								ImageIcon i2 = new ImageIcon(
										jfce.createBufferedImage(delp.getWidth(), delp.getHeight()));
								delp.setIcon(i2);
							}

						}
					}
				};
				d3 = new TimerTask() {

					@Override
					public void run() {
						if (isVisible()) {
							synchronized (jbfc) {
								ImageIcon i3 = new ImageIcon(
										jbfc.createBufferedImage(sbpdp.getWidth(), sbpdp.getHeight()));
								sbpdp.setIcon(i3);
							}

						}
					}
				};
				timer.scheduleAtFixedRate(tsk3, 25, 25);
				timer1.scheduleAtFixedRate(tsk4, 10, 10);
				timer1.scheduleAtFixedRate(d1, 25, 25);
				timer2.scheduleAtFixedRate(tsk5, 10, 10);
				timer2.scheduleAtFixedRate(d2, 25, 25);
				timer3.scheduleAtFixedRate(tsk6, 10, 10);
				timer3.scheduleAtFixedRate(d3, 25, 25);
			}

		} else {
			if (tsk3 != null)
				tsk3.cancel();
			if (tsk4 != null)
				tsk4.cancel();
			if (tsk5 != null)
				tsk5.cancel();
			if (d1 != null)
				d1.cancel();
			if (d2 != null)
				d2.cancel();
			if (d3 != null)
				d3.cancel();
			if (timer != null)
				timer.cancel();
			if (timer1 != null)
				timer1.cancel();

			if (timer2 != null)
				timer2.cancel();

			if (timer3 != null)
				timer3.cancel();
			timer = null;
		}
		super.setVisible(b);
	}

	public void updateTraffic() {
		switch (tr.getState()) {
		case LinkStatus.DOWN:
			getTitlelabel().setForeground(Color.RED);
			break;
		case LinkStatus.UNSTABLE:
			getTitlelabel().setForeground(Color.YELLOW);
			break;
		case LinkStatus.UP:
			getTitlelabel().setForeground(Color.GREEN);

			break;
		default:
			break;
		}
		if (isVisible()) {
			// spddown.fireSeriesChanged();
			// delaydown.fireSeriesChanged();
			IPv6AddressGroup irg = tr.getRemoteVaddr();
			String text;
			if (irg == null) {

				text = "unknown";
			} else {
				IPv6Address i6a = irg.getAddress();

				text = i6a.toString();

			}
		}

	}
}
