package org.kne.cloud.network;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
import java.util.function.LongUnaryOperator;
import java.util.function.UnaryOperator;

public class SpeedLimiter {
	
	public boolean isHitlimit() {
		return hitlimit;
	}
	private volatile long limitspeed=1024*1024;
	private long brustTime=2000000L;
	private volatile boolean hitlimit=false;
	public long getLimitspeed() {
		return limitspeed;
	}

	public SpeedLimiter(long limitspeed) {
		super();
		this.limitspeed = limitspeed;
	}
	public SpeedLimiter(long limitspeed, long brustTime) {
		super();
		this.limitspeed = limitspeed;
		this.brustTime = brustTime;
	}

	public void setLimitspeed(long limitspeed) {
		this.limitspeed = limitspeed;
		//System.out.println("更新限速："+limitspeed);
	}
	
	public long getBrustTime() {
		return brustTime;
	}

	public void setBrustTime(long brustTime) {
		this.brustTime = brustTime;
	}
	private AtomicLong ltime=new AtomicLong( System.nanoTime());
	private AtomicLong waitingtime=new AtomicLong();
	@Override
	public String toString() {
		return "SpeedLimiter [limitspeed=" + limitspeed + ", brustTime=" + brustTime + ", hitlimit=" + hitlimit
				+ ", ltime=" + ltime + ", waitingtime=" + waitingtime + "]";
	}
	public void forceTransmit(long datasize) {
		long limitspeedx=limitspeed;
		if(limitspeedx>0) {
		long curtime=System.nanoTime();
		long pasttime=ltime.getAndSet(curtime);
		long nv=waitingtime.updateAndGet(new LongUnaryOperator() {
			@Override
			public long applyAsLong(long t) {
				t-=curtime-pasttime;
				if(t<0L)
					t=0L;
				return t;
			}

		});
			waitingtime.addAndGet((long) (datasize*1000000000.0/limitspeedx));
		}
}
	//用系统计时器的时刻相减得到经过的时间，与数据包除以限速值得到的应消耗的时间做对比，若时间还未到达发送下一个数据包的时机，则返回false
	public boolean checkTransmit(long datasize) {
		long limitspeedx=limitspeed;
		if(limitspeedx<=0) {
			return false;
		}
		
			long curtime=System.nanoTime();
			long pasttime=ltime.getAndSet(curtime);
			long nv=waitingtime.updateAndGet(new LongUnaryOperator() {
				@Override
				public long applyAsLong(long t) {
					t-=curtime-pasttime;
					if(t<0L)
						t=0L;
					return t;
				}

			});
			if(nv<=brustTime) {
				return true;
			}else {
				return false;
			}
	}
	public void transmit(long datasize) {
		long limitspeedx=limitspeed;
		while(!checkTransmit(datasize)) {
		//LockSupport.parkNanos(100000);
			Thread.yield();
		}
		waitingtime.addAndGet((long) (datasize*1000000000.0/limitspeedx));
	}
	
}
