'''
This function is run from the command line as:

python visualize.py --testcase testcase.json --tcp [fast|vegas|reno]

Raw measurements are dumped to /results/all_measurements.txt
Parsed measurements and plots are stored in /Code/Python/results/[rawdata,plots]
These directories are cleared at the start of each run.

Currently, supported plots include:
- link rate (mpbs) 					
- buffer occupancy (%) 				
- packet loss (packets)				
- flow rate (Mbps) 					
- flow window size (packets) 		
- packet round trip time (ms)		

Plenty more measurements are made, so check out the actual data dumps.
Any plot for which data is reported is plotted. 

Time/Bin Averages are used when they improve understanding, but not when
they hide the inner workings of the network. In many cases events are
plotted directly. 

Last Revised by Sushant Sundaresh on 6 Dec 2015

References:
	http://matplotlib.org/examples/pylab_examples/simple_plot.html
	http://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python
	http://stackoverflow.com/questions/14245227/python-reset-stdout-to-normal-after-previously-redirecting-it-to-a-file
	http://stackoverflow.com/questions/273192/in-python-check-if-a-directory-exists-and-create-it-if-necessary
'''
import constants

import sys, os
import json
import matplotlib.pyplot as plt
import numpy as np
from main import MainLoop

from link import Link
from flow import Flow, Data_Source
from tcp_reno_working import Working_Data_Source_TCP_RENO, Working_Data_Sink_TCP_RENO
from tcp_fast_working import Working_Data_Source_TCP_FAST
from tcp_vegas_working import Working_Data_Source_TCP_VEGAS


def handle_linkrate (datamap, datalog):	
	if datalog["measurement"] == "linkrate":			
		if not (datalog["linkid"] in datamap.keys()):								
			datamap[datalog["linkid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["linkid"]].keys()):			
			datamap[datalog["linkid"]][datalog["measurement"]] = []		

		datamap[datalog["linkid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(datalog["mbits_propagated"])\
				]\
				)		

def handle_flowrate (datamap, datalog):	
	if datalog["measurement"] == "flowrate":			
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []		

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(datalog["mbits_received_at_sink"])\
				]\
				)		

def handle_packet_loss (datamap, datalog):
	if datalog["measurement"] == "packetloss":	
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}	
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []		

		# exactly one packet loss is reported each time
		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(1.0)\
				]\
				)			

# Data is parsed into triply nested dict with key-levels at link-id,
# measurement type, and link buffer direction. The final values
# are just [time (ms), buffer fractional occupancy (0-1)]
def handle_buffer_occupancy (datamap, datalog):	
	if datalog["measurement"] == "bufferoccupancy":			
		if not (datalog["linkid"] in datamap.keys()):								
			datamap[datalog["linkid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["linkid"]].keys()):			
			datamap[datalog["linkid"]][datalog["measurement"]] = {}

		if not (datalog["direction"] in datamap[datalog["linkid"]][datalog["measurement"]].keys()):	
			datamap[datalog["linkid"]][datalog["measurement"]][datalog["direction"]] = []		

		datamap[datalog["linkid"]][datalog["measurement"]][datalog["direction"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(datalog["fractional_buffer_occupancy"])\
				]\
				)		

def handle_flow_window (datamap, datalog):	
	if datalog["measurement"] == "windowsize":			
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(datalog["windowsize"])\
				]\
				)		

def handle_flow_state (datamap, datalog):	
	if datalog["measurement"] == "flowstate":			
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(datalog["state"])\
				]\
				)		

def handle_packets_outstanding (datamap, datalog):	
	if datalog["measurement"] == "outstandingpackets":			
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				float(datalog["packets_out"]), \
				float(datalog["packets_left"]),\
				float(datalog["packets_in_transit"]),\
				float(datalog["packets_ackd"]),\
				float(datalog["total_packets"]),\
				]\
				)		

def handle_flow_reno_debug (datamap, datalog):	
	if datalog["measurement"] == "fullrenodebug":			
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				datalog["SendReceive"],\
				int(datalog["whichPacket"]),\
				int(datalog["EPIT"]),\
				int(datalog["LPIA"]),\
				float(datalog["WS"]),\
				float(datalog["CAT"]),\
				float(datalog["STT"]),\
				int(datalog["L3P0"]),\
				int(datalog["L3P1"]),\
				int(datalog["L3P2"]),\
				datalog["TAF"],\
				datalog["DAF"],\
				datalog["SAF"],\
				int(datalog["State"]),\
				datalog["isTimeoutOccurring"],\
				float(datalog["RTTactEst"]) ])		

def handle_flow_vegas_debug (datamap, datalog):	
	if datalog["measurement"] == "fullvegasdebug":			
		if not (datalog["flowid"] in datamap.keys()):								
			d
atamap[data
log["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				datalog["SendReceive"],\
				int(datalog["whichPacket"]),\
				int(datalog["EPIT"]),\
				int(datalog["LPIA"]),\
				float(datalog["WS"]),\
				float(datalog["STT"]),\
				int(datalog["L3P0"]),\
				int(datalog["L3P1"]),\
				int(datalog["L3P2"]),\
				datalog["TAF"],\
				datalog["DAF"],\
				datalog["SAF"],\
				int(datalog["State"]),\
				datalog["FlagObserveRTT"],\
				datalog["FlagRampWS"],\
				datalog["isTimeoutOccurring"],\
				float(datalog["RTTmin"]),\
				float(datalog["RTTactEst"]),\
				int(datalog["ICAPTUW"]) ])		

def handle_flow_true_fast_debug (datamap, datalog):	
	if datalog["measurement"] == "fulltruefastdebug":			
		if not (datalog["flowid"] in datamap.keys()):								
			datamap[datalog["flowid"]] = {}					
		
		if not (datalog["measurement"] in datamap[datalog["flowid"]].keys()):			
			datamap[datalog["flowid"]][datalog["measurement"]] = []

		datamap[datalog["flowid"]][datalog["measurement"]].append(\
			[	float(datalog["ms_globaltime"]), \
				datalog["SendReceive"],\
				int(datalog["whichPacket"]),\
				int(datalog["EPIT"]),\
				int(datalog["LPIA"]),\
				float(datalog["WS"]),\
				float(datalog["STT"]),\
				int(datalog["L3P0"]),\
				int(datalog["L3P1"]),\
				int(datalog["L3P2"]),\
				datalog["TAF"],\
				datalog