package org.kne.cloud.network.monitor;

import java.util.UUID;

import org.kne.cloud.clock.HighAccuracyClock;
import org.kne.cloud.network.klalb.KLALBUtils;
import org.kne.concurrent.LazyEvaluator;

public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements SpeedAndTrafficMonitorData {

	private TimestampMonitor<UUID>uploadBandwidth;
	private TimestampMonitor<UUID>downloadBandwidth;
	private long timewindow=1000000000L;
	private long timewindowmax=1000000000L;
	private BandwidthSampler upSampler=new BandwidthSampler();
	private BandwidthSampler downSampler=new BandwidthSampler();



	private final long TIME_WINDOW=2000000000L;
	public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
		super();
		this.clock=clock;
		uploadBandwidth=new ArrayListTimestampMonitor<UUID>(clock,"UploadMonitor", 100, TIME_WINDOW);
		downloadBandwidth=new ArrayListTimestampMonitor<UUID>(clock,"DownloadMonitor", 100, TIME_WINDOW);

	}

	private HighAccuracyClock clock;
	public HighAccuracyClock getClock() {
		return clock;
	}

	
	

	
	public SpeedAndTrafficMonitorDataImpl(TimestampMonitor<UUID> uploadBandwidth,
			TimestampMonitor<UUID> downloadBandwidth) {
		super();
		this.uploadBandwidth = uploadBandwidth;
		this.downloadBandwidth = downloadBandwidth;

	}






	public TimestampMonitor<UUID> getUploadBandwidth() {
		return uploadBandwidth;
	}






	public TimestampMonitor<UUID> getDownloadBandwidth() {
		return downloadBandwidth;
	}

	




	@Override
	public String toString() {
		StringBuilder sb=new StringBuilder();
		sb.append(KLALBUtils.convertIBUint(uploadBandwidth.calculateBandwidth(timewindow))).append("/s\t");
		sb.append(KLALBUtils.convertIBUint(downloadBandwidth.calculateBandwidth(timewindow))).append("/s\t");
		sb.append(KLALBUtils.convertUintDefalut(uploadBandwidth.calculatePacketRate(timewindow))).append("PPS\t");
		sb.append(KLALBUtils.convertUintDefalut(downloadBandwidth.calculatePacketRate(timewindow))).append("PPS\t");
		
		/*if(getState()==OFFLINE) {
		sb.append((coolingTime-(System.currentTimeMillis()-mls))/1000L);
		sb.append('s');
		}else {
			sb.append('/');
		}*/
		
		
		return sb.toString();
	}




	private LazyEvaluator<Long> outSpeedEvaluator=new LazyEvaluator<Long>(()->{return uploadBandwidth.calculateBandwidth(timewindow);});
	public long getOutSpeed() {
		return outSpeedEvaluator.get();
	}
	private LazyEvaluator<Long> inSpeedEvaluator=new LazyEvaluator<Long>(()->{return downloadBandwidth.calculateBandwidth(timewindow);});
	public long getInSpeed() {
		return inSpeedEvaluator.get();
	}






	public long getOutTraffic() {
		return uploadBandwidth.getTotalDataSize();
	}






	public long getInTraffic() {
		return downloadBandwidth.getTotalDataSize();
	}






	private LazyEvaluator<Long> outPPSEvaluator=new LazyEvaluator<Long>(()->{return uploadBandwidth.calculatePacketRate(timewindow);});
	public long getOutPPS() {
		return  outPPSEvaluator.get();
	}

	private LazyEvaluator<Long> inPPSEvaluator=new LazyEvaluator<Long>(()->{return downloadBandwidth.calculatePacketRate(timewindow);});

	public long getInPPS() {
		return inPPSEvaluator.get();
	}
	private long inSpeed;
	private long outSpeed;
	
	private long outSpeeedMax=0;
	private long inSpeedMax=0;
	private long outPPSMax=0;
	private long inPPSMax=0;
	
	public long getOutSpeedMax() {
		return outSpeeedMax;
	}
	public long getInSpeedMax() {
		return inSpeedMax;
	}
	public long getOutPPSMax() {
		return outPPSMax;
	}
	public long getInPPSMax() {
		return inPPSMax;
	}
	
	public void recordUploadPacket(int databytes) {
		upSampler.recordPacket(databytes);
	}

	public void recordDownloadPacket(int databytes) {
		downSampler.recordPacket(databytes);
	}
	
	long stime=System.nanoTime();
	@Override
	public void update() {
		upSampler.update();
		downSampler.update();
		long uppacketcount=upSampler.getPacketCountSinceLastSnapshot();
		if(uppacketcount>0) {
			uploadBandwidth.recordPacket(KLALBUtils.createGlobalUUID(), (int) uppacketcount, (int) upSampler.getByteCountSinceLastSnapshot());
			outSpeedEvaluator.markDirty();
			outPPSEvaluator.markDirty();
		}
		long downpacketcount=downSampler.getPacketCountSinceLastSnapshot();
		if(downpacketcount>0) {
			downloadBandwidth.recordPacket(KLALBUtils.createGlobalUUID(), (int) downpacketcount, (int) downSampler.getByteCountSinceLastSnapshot());
			inSpeedEvaluator.markDirty();
			inPPSEvaluator.markDirty();
		}
		long time=System.nanoTime();
		if(time-stime>timewindowmax) {
			stime=time;
		long os=uploadBandwidth.calculateBandwidth(timewindowmax);
		long is=downloadBandwidth.calculateBandwidth(timewindowmax);
		long op=uploadBandwidth.calculatePacketRate(timewindowmax);
		long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
		if(os>outSpeeedMax) {
			outSpeeedMax=(outSpeeedMax+os)/2;
		}else {
			outSpeeedMax=(outSpeeedMax*999+os)/1000;
		}
		if(is>inSpeedMax) {
			inSpeedMax=(inSpeedMax+is)/2;
		}else {
			inSpeedMax=(inSpeedMax*999+is)/1000;
		}
		if(op>outPPSMax) {
			outPPSMax=(outPPSMax+op)/2;
		}else {
			outPPSMax=(outPPSMax*999+op)/1000;
		}
		if(ip>inPPSMax) {
			inPPSMax=(inPPSMax+ip)/2;
		}else {
			inPPSMax=(inPPSMax*999+ip)/1000;
		}
		}
	}
}
