package org.kne.cloud.network;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;

import org.kne.cloud.network.klalb.KLALBController;
import org.kne.cloud.network.klalb.KLALBController.KLALBSocketType;
import org.kne.cloud.network.klalb.KLALBRemoteLine;
import org.kne.cloud.network.klalb.StreamKLALBPacketLink;
import org.kne.cloud.network.minecraft.KLALBJsonMotdInserter;
import org.kne.cloud.network.minecraft.MinecraftSocketToSocketProxy;

import java.util.Set;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class KLALBProxyConfigJsonExecuter {
	private Set<Proxy> proxys=new HashSet<>();
	private KLALBController klalbController;
	public Set<Proxy> getProxys() {
		return proxys;
	}
	public KLALBController getKlalbController() {
		return klalbController;
	}
	public KLALBProxyConfigJsonExecuter(Reader json) {
		loadConfigJson(json);
	}
	public KLALBProxyConfigJsonExecuter(String json) {
		loadConfigJson(json);
	}

	public KLALBProxyConfigJsonExecuter(JsonElement json) {
		loadConfigJson(json);
	}
	public KLALBProxyConfigJsonExecuter(File jsonFile) throws IOException {
		loadConfigJson(jsonFile);
	}
	public KLALBProxyConfigJsonExecuter() {
	}
	
	
	
	public void loadConfigJson(File jsonFile) throws IOException {
		FileReader fr = null;
		try {
		fr=new FileReader(jsonFile);
		loadConfigJson(fr);
		}finally {
			if(fr!=null)
			fr.close();
		}
		
	}
	public void loadConfigJson(String json) {
		loadConfigJson(new JsonParser().parse(json));
	}
	public void loadConfigJson(Reader json) {
		loadConfigJson(new JsonParser().parse(json));
	}
	public void loadConfigJson(JsonElement json) {
		JsonArray jobj=(JsonArray) json;
		jobj.forEach((val)->{
			solveEntry((JsonObject) val);
		});
	}
	protected void solveEntry(JsonObject entry){
		switch (entry.get("Type").getAsString()) {
		case "KLALBController":
			JsonElement vase= entry.get("VirtualAddress");
			if(vase!=null) {
			try {
				klalbController=new KLALBController((Inet6Address) InetAddress.getByName(vase.getAsString()));
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
			}else {
				klalbController=new KLALBController();
			}
			JsonElement vsne=entry.get("VirtualSocketName");
			//if(vsne!=null) {
				MultipurposeSocketAddress.getSocketTypeRegister().put(vsne.getAsString(), klalbController.getSocketType());
			//}
			JsonElement tcple=entry.get("TCPListen");
			if(tcple!=null) {
				MultipurposeSocketAddress mpsa=new MultipurposeSocketAddress(tcple.getAsString());
				SocketListener tcpl = null;
				try {
					tcpl = new SocketListener(mpsa);
				
				tcpl.setCon((soc)->{
				
					KLALBRemoteLine krs=null;
					try {
						krs = new KLALBRemoteLine(new StreamKLALBPacketLink(soc));
						klalbController.addRemoteLine(krs);
					} catch (IOException e) {
						e.printStackTrace();
					}
					
				});
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			JsonElement linele=entry.get("LineTable");
			if(linele!=null) {
				JsonArray jary=(JsonArray)linele;
				StringBuilder sb=new StringBuilder();
				jary.forEach((aline)->{
					sb.append(aline.getAsString());
					sb.append('\n');
				});
				klalbController.setSelflineTableSupplier(()->{return sb.toString();});
			}
			break;
		case "SocketBridge":
			HostPortMap mapp=new HostPortMap();
			
			MultipurposeSocketAddress l=new MultipurposeSocketAddress(entry.get("Listen").getAsString());
			MultipurposeSocketAddress r=getDefault(entry.get("Connect"),mapp);
			try {
				proxys.add(new SocketToSocketProxy(l ,new MultipurposeSocketAddress("0.0.0.0:0"), r,mapp));
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;
		case "MinecraftSocketBridge":
			
			HostPortMap mapp2=new HostPortMap();
			MultipurposeSocketAddress l2=new MultipurposeSocketAddress(entry.get("Listen").getAsString());
			MultipurposeSocketAddress r2=getDefault(entry.get("Connect"),mapp2);
			try {
				MinecraftSocketToSocketProxy mcp=new MinecraftSocketToSocketProxy(l2 ,new MultipurposeSocketAddress("0.0.0.0:0"), r2,mapp2);
				//if(MultipurposeSocketAddress.getSocketTypeRegister().get( l2.getType()) instanceof KLALBSocketType )
				mcp.getTransformersBA().add(new KLALBJsonMotdInserter(()->{return klalbController.getSelf();},()->{return 23332;}));
				proxys.add(mcp);
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;

		default:
			break;
		}
	}
	private MultipurposeSocketAddress getDefault(JsonElement jsonElement, HostPortMap mapp) {
		if(jsonElement instanceof JsonObject) {
			JsonObject jobj=(JsonObject) jsonElement;
			jobj.entrySet().forEach((en)->{
				mapp.put(en.getKey(), new MultipurposeSocketAddress( en.getValue().getAsString()));
			});
			return mapp.get("DEFAULT");
		}else {
		return new MultipurposeSocketAddress(jsonElement.getAsString());
		}
	}
}
