package org.kne.cloud.network.klalb;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.nio.channels.ServerSocketChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Scanner;

import org.kne.cloud.network.MultiProtocolSocketAddress;
import org.kne.cloud.network.SocketChannelListener;
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
import org.kne.cloud.network.ipv6.RouteItem;
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
import org.kne.cloud.network.klalb.ui.UIEnv;
import org.kne.cloud.network.perf.Kperf;
import org.kne.cloud.network.perf.NodeBenchmark;
import org.kne.debug.TimeDebugger;
import org.kne.membandboost.MembandBenchmark;
import org.kne.membandboost.ObjectPoolBandwidthTest;

public class KLALBMain {
	public static KLALBStateGUI3 ksg;
	public static void main(String[] args) throws IOException {
		try {
			UIEnv.inituie();
		}catch(Throwable e) {
			e.printStackTrace();
		}
		System.out.println(CONST.klalb+" V"+CONST.klalbver);
		Scanner scn=new Scanner(System.in);
		TimeDebugger dtb=new TimeDebugger();
		dtb.putTime("Start");
		File configJson=new File("klalb-config.json");
		
		KLALBProxySystem kpcje=new KLALBProxySystem();
		dtb.putTime("Create");
		kpcje.loadConfigJson(configJson);
		dtb.putTime("Load");
		System.out.println("=".repeat(65));
		System.out.println("  - IPv6 Address / End SID: "+kpcje.getKlalbController().getSelf().getAddress());
		System.out.println("=".repeat(65));
		try {
			if(!kpcje.getControllerConfig().isNogui())
		openGUI(kpcje); 
		}catch(Throwable e) {
			e.printStackTrace();
		}
		try {
			if(kpcje.getControllerConfig() != null && kpcje.getControllerConfig().isWebUI()) {
				kpcje.enableWebServer();
			}
		} catch(Throwable e) {
			System.err.println("Failed to start web server: " + e.getMessage());
		}
		dtb.putTime("UI");
		//dtb.print();
		ServerSocketChannel kpsvr=KLALBVirtualServerSocketChannel.open(kpcje.getKlalbController());
		kpsvr.bind(new InetSocketAddress("::0", 4564));
		SocketChannelListener stlr=new SocketChannelListener(kpsvr);
		stlr.setCon((scl)->{
			try {
				new Kperf(new StreamChannelKLALBPacketLink(scl,false)).startPerfing();
			} catch (IOException e) {
				e.printStackTrace();
			}
		});
		System.out.println("Done!");
		while(true) {
			System.out.print("KLALB>");
			try {
		String s=scn.nextLine();
		String tri=s.trim();
		if(tri.isEmpty()) {
			continue;
		}
		String[]sc=tri.split(" ");
		switch(sc[0]) {
		case "?":
		case "help":
			System.out.println("  help / ?: see help");
			System.out.println("  monitor: show monitor GUI");
			System.out.println("  web [start|stop|status <port>]: manage web dashboard");
			System.out.println("  links-state: query link states");
			System.out.println("  links-add <addr:port>: add link");
			System.out.println("  links-remove <addr:port>: remove link");
			System.out.println("  links-reconnect: reconnect all link");
			System.out.println("  kltp-state: query kltp states");
			System.out.println("  interfaces: show all network interfaces");
			System.out.println("  route: display internal route table");
			System.out.println("  kperf <addr:port>: performance benchmark");
			System.out.println("  exit: Exit");
		break;
		
		case "monitor":
			try {
			openGUI(kpcje);
			}catch(Throwable e) {
				e.printStackTrace();
			}
			break;
		case "web":
			if(sc.length >= 2) {
				String action = sc[1].toLowerCase();
				if("start".equals(action)) {
					int p = 4665;
					if(sc.length >= 3) {
						try { p = Integer.parseInt(sc[2]); } catch (NumberFormatException ignored) {}
					} else if(kpcje.getControllerConfig() != null && kpcje.getControllerConfig().getWebListen() != null) {
						p = kpcje.getControllerConfig().getWebListen().getPort();
					}
					try {
						kpcje.enableWebServer(p);
						System.out.println("Web dashboard started on http://localhost:" + p);
					} catch(Exception e) {
						System.out.println("Failed to start web server: " + e.getMessage());
					}
				} else if("stop".equals(action)) {
					kpcje.disableWebServer();
					System.out.println("Web dashboard stopped.");
				} else if("status".equals(action)) {
					if(kpcje.isWebServerEnabled()) {
						System.out.println("Web dashboard is running on port " + kpcje.getWebServer().getPort());
					} else {
						System.out.println("Web dashboard is stopped.");
					}
				} else {
					System.out.println("Usage: web [start|stop|status <port>]");
				}
			} else {
				if(kpcje.isWebServerEnabled()) {
					System.out.println("Web dashboard is running on port " + kpcje.getWebServer().getPort());
				} else {
					System.out.println("Web dashboard is not running. Use 'web start [port]' to start.");
				}
			}
			break;
		case "links-state":
			System.out.println("links state：");
			//System.out.println("状态\t上传流量\t下载流量\t上传速度\t下载速度\t上传延迟\t下载延迟\t上传抖动\t下载抖动");
			System.out.println("state\tspd↑\tspd↓\tPPS↑\tPPS↓\tdelay↑\tdelay↓\tjitter↑\tjitter↓");
			synchronized (kpcje.getKlalbController().getLines()) {
			for (Iterator<IPv6NetworkLink> iterator = kpcje.getKlalbController().getLines().iterator(); iterator.hasNext();) {
				IPv6NetworkLink link=iterator.next();
				if(link instanceof KLALBRemoteLink) {
				KLALBRemoteLink hostPort =  (KLALBRemoteLink) link;
				System.out.println(hostPort .toString());
				}
			}
			}
			break;
		case "links-add":
			if(sc.length>=2) {
			MultiProtocolSocketAddress mpsa=new MultiProtocolSocketAddress(sc[1]);
			List<KLALBRemoteLink>addl=kpcje.getKlalbController().addRemoteLines(mpsa);
			if(addl.isEmpty()) {
				//System.out.println("添加失败，线路已存在！");
				System.out.println("link already exist!");
			}else {
				for (Iterator<KLALBRemoteLink> iterator = addl.iterator(); iterator.hasNext();) {
					KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) iterator.next();
					
			//System.out.println("添加成功："+klalbRemoteLine.getMonitor().getName());
					System.out.println("Successfully added: "+klalbRemoteLine.getName());
				}
			}
			}else {
			//	System.out.println("请输入要添加地址:端口!");
				System.out.println("Input Address:port");
			}
			break;
		case "links-remove":
			if(sc.length>=2) {
			MultiProtocolSocketAddress mpsa=new MultiProtocolSocketAddress(sc[1]);
			List<KLALBRemoteLink>rmvl=kpcje.getKlalbController().removeRemoteLines(mpsa);
			if(rmvl.isEmpty()) {
				System.out.println("No matched link has been found.");
			}else {
				for (Iterator iterator = rmvl.iterator(); iterator.hasNext();) {
					KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) iterator.next();
					
			System.out.println("Successfully removed: "+klalbRemoteLine.getName());
				}
			}
			}else {
				System.out.println("Invalid arguments.");
			}
			break;
		case "exit":
			System.out.println("Exited.");
			System.exit(0);
			break;
		case "links-reconnect":
			System.out.println("Trying to reconnect all links.");
			kpcje.getKlalbController().reconnectImmediately();
			break;
		case "kltp-state":
			System.out.println(kpcje.getKlalbController().getKLTPregister().toString());
			break;
			case "interfaces":
				NetworkInterfaceManager networkInterfaceManager= kpcje.getKlalbController().getNetworkInterfaceManager();
				List<NetworkInterface> interfaceList=networkInterfaceManager.getAllAvaliableNetworkInterface();
				System.out.println("Network interface detected:");
				for(NetworkInterface networkInterface:interfaceList){
					System.out.println(networkInterface.getName()+"("+networkInterface.getDisplayName()+")");
					List<InetAddress> lst= networkInterfaceManager.getNetworkInterfaceAddress(networkInterface);
					for(InetAddress address :lst){
						System.out.println("	"+address.getHostAddress());
					}
				}
				break;
		case "route":
			List<RouteItem> lri=new ArrayList<>( kpcje.getKlalbController().getIpv6Router().getCurrentRouteTabel());
			Collections.sort(lri);
			System.out.println("Route Table:");
			System.out.println("Prefix\tProtocol\tPref\tCost\tFlag\tNext Hop\tInterface");
			for (Iterator<RouteItem> iterator = lri.iterator(); iterator.hasNext();) {
				RouteItem routeItem = (RouteItem) iterator.next();
				System.out.println(routeItem.getDestination()+"\t"+routeItem.getProto()+"\t"+routeItem.getPre()+"\t"+routeItem.getCost()+"\t"+routeItem.getFlag()+"\t"+routeItem.getNexthop()+"\t"+routeItem.getDestlink().getName());
			}
			
			break;
		case "kperf":
			if(sc.length>=2) {
				MultiProtocolSocketAddress mpsa=new MultiProtocolSocketAddress(sc[1]);
				Kperf kp=new Kperf(mpsa);
				kp.startPerfing();
			}else {
				System.out.println("Invalid arguments.");
			}
				
			break;
		case "membandbenchmark":
			MembandBenchmark.main(args);
			break;
		case "memqueuebenchmark":

			ObjectPoolBandwidthTest.main(args);
			break;
		//case "$$SYSTEM:":
			//System.out.println();
			//break;
		case "nodebenchmark":
			int nodenumber=100;
			if(sc.length>=2) {
				nodenumber=Integer.parseInt(sc[1]);
			}
			NodeBenchmark nbc=new NodeBenchmark(kpcje.getKlalbController(),nodenumber);
			nbc.startPerfing();
			break;
		default:
			System.out.println("Unknown command. See \"help\" or \"?\".");
		}
			}catch (NoSuchElementException err) {
				System.out.println("Exited.");
				System.exit(0);
			}catch(RuntimeException e) {
				System.out.println("Exception Occured!");
				e.printStackTrace();
			}
		}
		
	}
	private static void openGUI(KLALBProxySystem kpcje) throws RuntimeException{
		Thread t=new Thread(()->{
		if(ksg==null) {
			ksg=kpcje.getKLALBGUI();
		}
		ksg.setVisible(true);
		});
		t.start();
	}

}
