package com.example.demotunnel;

import com.peergine.tunnel.pgJniTunnel;

import java.util.Scanner;

import static com.peergine.tunnel.pgJniTunnel.PG_TUNNEL_ERROR_OK;
import static com.peergine.tunnel.pgJniTunnel.PG_TUNNEL_ERROR_BADPARAM;
import static com.peergine.tunnel.pgJniTunnel.PG_TUNNEL_ERROR_REJECT;

import static com.peergine.tunnel.pgJniTunnel.PG_TUNNEL_GET_STA_LOGIN;
import static com.peergine.tunnel.pgJniTunnel.PG_TUNNEL_EVENT_PEER_AUTH_REQUEST;

import static java.lang.Thread.sleep;


public class demoJniTunnel {

	private String m_sPeerID = "";
	static Scanner in = new Scanner(System.in);

	public static int ParseInt(String sInt, int iDef) {
		try {
			if (sInt.equals("")) {
				return iDef;
			}
			return Integer.parseInt(sInt);
		}
		catch (Exception ex) {
			return iDef;
		}
	}

	static void TunnelEventPeerAuthRequest(String sParam) {
		
		String sHandle = "";
		int iPos = sParam.indexOf("\"handle\":", 0);
		if (iPos > 0) {
			iPos += ("\"handle\":\"").length();
			int iPos1 = sParam.indexOf("\"", iPos);
			if (iPos1 > 0) {
				sHandle = sParam.substring(iPos, iPos1);
				iPos = iPos1 + 1;
			}
		}

		String sInfo = "";
		iPos = sParam.indexOf("\"info\":", iPos);
		if (iPos > 0) {
			iPos += ("\"info\":\"").length();
			int iPos1 = sParam.indexOf("\"", iPos);
			if (iPos1 > 0) {
				sInfo = sParam.substring(iPos, iPos1);
			}
		}

		int iErrCode;
		if (sInfo.equals("abcd1234")) {
			iErrCode = PG_TUNNEL_ERROR_OK;
		}
		else {
			iErrCode = PG_TUNNEL_ERROR_REJECT;
		}

		int iErr = pgJniTunnel.PeerAuthReply(sHandle, iErrCode, "test reply");
		if (iErr != PG_TUNNEL_ERROR_OK) {
			System.out.println("PeerAuthReply failed, Error: "+ iErr);
		}		
	}

	// event callback
	private static pgJniTunnel.OnCallback m_eventCB = new pgJniTunnel.OnCallback() {
		public void EventProc(int iEvent, String sParam) {
			System.out.println("Callback: event=" + iEvent + ", param=" + sParam);
			
			if (iEvent == PG_TUNNEL_EVENT_PEER_AUTH_REQUEST) {
				TunnelEventPeerAuthRequest(sParam);
			}
		}
	};

	static void VersionGet() {
		pgJniTunnel.OutVersion stVersion = new pgJniTunnel.OutVersion();
		int iErr = pgJniTunnel.VersionGet(stVersion);
		if (iErr == PG_TUNNEL_ERROR_OK) {
			System.out.println("Version: " +stVersion.sVersion);
		}
		else {
			System.out.println("Get version failed, Error: "+ iErr);
		}
	}

	static void StatusGet() {
		pgJniTunnel.OutStatus stStatus = new pgJniTunnel.OutStatus();
		int iErr = pgJniTunnel.StatusGet(PG_TUNNEL_GET_STA_LOGIN, stStatus);
		if (iErr == PG_TUNNEL_ERROR_OK) {
			System.out.println("Status: " + stStatus.iStatus);
		}
		else {
			System.out.println("Get status failed, Error: " + iErr);
		}
	}

	static void DomainSet() {
		String szPasscode = "";

		System.out.print("passcode: ");
		szPasscode = in.nextLine();

		int iErr1 = pgJniTunnel.DomainSet(szPasscode);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Set domain success");
		}
		else {
			System.out.println("Set domain failed, Error: "+ iErr1);
		}
	}

	static void DomainGet() {
		pgJniTunnel.OutDomain stDomain = new pgJniTunnel.OutDomain();
		int iErr = pgJniTunnel.DomainGet(stDomain);
		if (iErr == PG_TUNNEL_ERROR_OK) {
			System.out.println("Domain: " + stDomain.sDomain);
		}
		else {
			System.out.println("Get domain failed, Error: " + iErr);
		}
	}

	static void CommentSet() {
		String szComment = "";

		System.out.print("comment: ");
		szComment = in.nextLine();

		int iErr1 = pgJniTunnel.CommentSet(szComment);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Set comment success");
		}
		else {
			System.out.println("Set comment failed, Error: " + iErr1);
		}
	}

	static void CommentGet() {
		pgJniTunnel.OutComment stComment = new pgJniTunnel.OutComment();
		int iErr = pgJniTunnel.CommentGet(stComment);
		if (iErr == PG_TUNNEL_ERROR_OK) {
			System.out.println("Comment: " + stComment.sComment);
		}
		else {
			System.out.println("Get comment failed, Error: " + iErr);
		}
	}

	static void TunnelSet() {
		String szPasscode = "";
		String szComment = "";

		System.out.print("passcode: ");
		szPasscode = in.nextLine();

		System.out.print("comment: ");
		szComment = in.nextLine();

		int iErr1 = pgJniTunnel.TunnelSet(szPasscode, szComment);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Set tunnel success");
		}
		else {
			System.out.println("Set tunnel failed, Error: " + iErr1);
		}
	}

	static void PeerInfoGet() {
		String szPeerID = "";
		System.out.print("peer id: ");
		szPeerID = in.nextLine();

		pgJniTunnel.OutPeerInfo stPeerInfo = new pgJniTunnel.OutPeerInfo();
		int iErr1 = pgJniTunnel.PeerInfoGet(szPeerID, stPeerInfo);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Get peer info success\n");

			System.out.println("peer id: " + stPeerInfo.sPeerID);
			System.out.println("type: " + stPeerInfo.iType);
			System.out.println("local login addr: " + stPeerInfo.sAddrLocal);
			System.out.println("remote login addr: "+ stPeerInfo.sAddrRemote);
			System.out.println("local tunnel addr: "+ stPeerInfo.sTunnelLocal);
			System.out.println("remote tunnel addr: "+ stPeerInfo.sTunnelRemote);
			System.out.println("remote private addr: "+ stPeerInfo.sPrivateRemote);
		}
		else {
			System.out.println("Get peer info failed, Error: " + iErr1);
		}
	}

	static void ConnectAdd() {
		String szPeerID = "";
		String szType = "";
		String szEncrypt = "";
		String szListenAddr = "";
		String szClientAddr = "";

		System.out.print("peer id: ");
		szPeerID = in.nextLine();
		System.out.print("type: ");
		szType = in.nextLine();
		System.out.print("encrypt: ");
		szEncrypt = in.nextLine();
		System.out.print("listen addr: ");
		szListenAddr = in.nextLine();
		System.out.print("client addr: ");
		szClientAddr = in.nextLine();

		pgJniTunnel.OutClientAddr stClientAddr = new pgJniTunnel.OutClientAddr();
		int iErr1 = pgJniTunnel.ConnectAdd("", szPeerID, ParseInt(szType, 0),
			ParseInt(szEncrypt, 0), szListenAddr, szClientAddr, stClientAddr);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("The connect's local client addr: " + stClientAddr.sClientAddr);
		}
		else {
			System.out.println("Add connect failed, Error: " + iErr1);
		}
	}

	static void ConnectDelete() {
		String szPeerID = "";
		String szType = "";
		String szEncrypt = "";
		String szListenAddr = "";
		String szClientAddr = "";

		System.out.print("peer id: ");
		szPeerID = in.nextLine();
		System.out.print("type: ");
		szType = in.nextLine();
		System.out.print("encrypt: ");
		szEncrypt = in.nextLine();
		System.out.print("listen addr: ");
		szListenAddr = in.nextLine();
		System.out.print("client addr: ");
		szClientAddr = in.nextLine();

		int iErr1 = pgJniTunnel.ConnectDelete("", szPeerID, ParseInt(szType, 0),
			ParseInt(szEncrypt, 0), szListenAddr, szClientAddr);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Delete connect success");
		}
		else {
			System.out.println("Delete connect failed, Error: "+ iErr1);
		}
	}

	static void ConnectQuery() {
		String szPeerID = "";
		String szType = "";
		String szEncrypt = "";
		String szListenAddr = "";
		
		System.out.print("peer id: ");
		szPeerID = in.nextLine();
		System.out.print("type: ");
		szType = in.nextLine();
		System.out.print("encrypt: ");
		szEncrypt = in.nextLine();
		System.out.print("listen addr: ");
		szListenAddr = in.nextLine();

		pgJniTunnel.OutClientAddr stClientAddr = new pgJniTunnel.OutClientAddr();
		System.out.print("client addr: ");
		stClientAddr.sClientAddr = in.nextLine();		

		int iErr1 = pgJniTunnel.ConnectQuery(szPeerID, ParseInt(szType, 0),
			ParseInt(szEncrypt, 0), szListenAddr, stClientAddr);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("The connect's client addr: " + stClientAddr.sClientAddr);
		}
		else {
			System.out.println("Query connect failed, Error: " + iErr1);
		}
	}

	static void ConnectLocalDelete() {
		String szClientAddr = "";

		System.out.print("client addr: ");
		szClientAddr  = in.nextLine();

		int iErr1 = pgJniTunnel.ConnectLocalDelete("", szClientAddr);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Delete connect by local address success\n");
		}
		else {
			System.out.println("Delete connect by local address failed, Error: " + iErr1);
		}
	}

	static void ConnectLocalQuery() {
		String szClientAddr = "";

		System.out.print("client addr: ");
		szClientAddr = in.nextLine();

		pgJniTunnel.OutConnectInfo stConnectInfo = new pgJniTunnel.OutConnectInfo();
		int iErr1 = pgJniTunnel.ConnectLocalQuery(szClientAddr, stConnectInfo);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Query connect by local address success\n");
			System.out.println("peer id: " + stConnectInfo.sPeerID);
			System.out.println("type: " + stConnectInfo.iType);
			System.out.println("encrypt: " + stConnectInfo.iEncrypt);
			System.out.println("listen addr: " + stConnectInfo.sListenAddr);
			System.out.println("client addr: " + stConnectInfo.sClientAddr);
		}
		else {
			System.out.println("Query connect by local address failed, Error: " + iErr1);
		}
	}

	static void UserExtend() {
		String szReqData = "";
		String ucReplyData = "";

		System.out.print("input request data: ");
		szReqData = in.nextLine();

		pgJniTunnel.OutData stReplyData =new pgJniTunnel.OutData();
		int iErr1 = pgJniTunnel.UserExtend(szReqData, stReplyData, 0);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("User extend request success\n");

			System.out.println("reply data: " + stReplyData.sData);
		}
		else {
			System.out.println("User extend request failed, Error: " + iErr1);
		}
	}

	static void PushGet() {
		pgJniTunnel.OutData stPushData = new pgJniTunnel.OutData();
		int iErr1 = pgJniTunnel.PushGet(stPushData, 3000);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Push get success\n");

			System.out.println("push data: " + stPushData.sData);
		}
		else {
			System.out.println("Push get failed, Error: " + iErr1);
		}
	}

	static void SelfGet() {
		pgJniTunnel.OutSelf stSelf = new pgJniTunnel.OutSelf();
		int iErr1 = pgJniTunnel.SelfGet(stSelf);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Self get success\n");

			System.out.println("Self ID: " + stSelf.sSelf);
		}
		else {
			System.out.println("Self get failed, Error: " + iErr1);
		}
	}

	static void ConnectEnum() {
		String szIndex = "";

		System.out.print("index: ");
		szIndex = in.nextLine();

		pgJniTunnel.OutConnectInfo stConnectInfo = new pgJniTunnel.OutConnectInfo();
		int iErr1 = pgJniTunnel.ConnectEnum(ParseInt(szIndex, 0), stConnectInfo);
		if (iErr1 == PG_TUNNEL_ERROR_OK) {
			System.out.println("Connect enum success\n");

			System.out.println("peer id: " + stConnectInfo.sPeerID);
			System.out.println("type: " + stConnectInfo.iType);
			System.out.println("encrypt: " + stConnectInfo.iEncrypt);
			System.out.println("listen addr: " + stConnectInfo.sListenAddr);
			System.out.println("client addr: " + stConnectInfo.sClientAddr);
		}
		else {
			System.out.println("Connect enum failed, Error: " + iErr1);
		}
	}

	static void ConnectList() {
		int iIndex = 0;
		while (true) {

			pgJniTunnel.OutConnectInfo stConnectInfo = new pgJniTunnel.OutConnectInfo();
			int iErr1 = pgJniTunnel.ConnectEnum(iIndex, stConnectInfo);
			if (iErr1 != PG_TUNNEL_ERROR_OK) {
				break;
			}

			System.out.println("---------------------------------------");
			System.out.println("index: " + iIndex);
			System.out.println("peer id: " + stConnectInfo.sPeerID);
			System.out.println("type: " + stConnectInfo.iType);
			System.out.println("encrypt: " + stConnectInfo.iEncrypt);
			System.out.println("listen addr: " + stConnectInfo.sListenAddr);
			System.out.println("client addr: " + stConnectInfo.sClientAddr);
			System.out.println("\n");

			iIndex++;
		}
	}

	static void PeerFwdCfg() {
		String sValue = "";

		int iSpeed = -1;
		System.out.print("speed: ");
		sValue = in.nextLine();
		if (!sValue.equals("")) {
			iSpeed = ParseInt(sValue, -1);
		}

		int iGate = -1;
		System.out.print("gate: ");
		sValue = in.nextLine();
		if (!sValue.equals("")) {
			iGate = ParseInt(sValue, -1);
		}

		int iUse = -1;
		System.out.print("use: ");
		sValue = in.nextLine();
		if (!sValue.equals("")) {
			iUse = ParseInt(sValue, -1);
		}

		int iMaxSess = -1;
		System.out.print("maxsess: ");
		sValue = in.nextLine();
		if (!sValue.equals("")) {
			iMaxSess = ParseInt(sValue, -1);
		}

		int iErr1 = pgJniTunnel.PeerFwdCfg(iSpeed, iGate, iUse, iMaxSess, "");
		if (iErr1 < PG_TUNNEL_ERROR_OK) {
			System.out.println("PeerFwdCfg failed, Error: " + iErr1);
		}
	}

	static void PeerAuthSet() {

		String sPeerID = "";
		System.out.print("peer id: ");
		sPeerID = in.nextLine();

		String sAuthInfo = "";
		System.out.print("auth info: ");
		sAuthInfo = in.nextLine();

		int iErr = pgJniTunnel.PeerAuthSet(sPeerID, sAuthInfo);
		if (iErr < PG_TUNNEL_ERROR_OK) {
			System.out.println("PeerAuthSet failed, Error: " + iErr);
		}
	}

	static void PeerAuthReply() {

		String sHandle = "";
		System.out.print("handle: ");
		sHandle = in.nextLine();

		int iErrCode = -PG_TUNNEL_ERROR_BADPARAM;
		String sValue = "";
		System.out.print("errcode: ");
		sValue = in.nextLine();
		if (!sValue.equals("")) {
			iErrCode = ParseInt(sValue, -PG_TUNNEL_ERROR_BADPARAM);
		}

		String sParam = "";
		System.out.print("param: ");
		sParam = in.nextLine();

		int iErr = pgJniTunnel.PeerAuthReply(sHandle, iErrCode, sParam);
		if (iErr < PG_TUNNEL_ERROR_OK) {
			System.out.println("PeerAuthReply failed, Error: " + iErr);
		}
	}

	static void TestConnect(int uTimes) throws InterruptedException {
		int uTestTimes = uTimes;

		if (uTestTimes == 0) {
			System.out.println("test times: ");
			String szTestTimes = "";
			(szTestTimes) = in.nextLine();
			uTestTimes = ParseInt(szTestTimes, 0);
		}

		int uInd = 0;
		while (uInd < uTestTimes) {
			pgJniTunnel.OutClientAddr stClientAddr = new pgJniTunnel.OutClientAddr();
			

			int iErr = pgJniTunnel.ConnectAdd("", "ctkj0004", 0, 0,
					"127.0.0.1:8000", "127.0.0.1:18000", stClientAddr);
			if (iErr == PG_TUNNEL_ERROR_OK) {
				System.out.println("The connect's local client addr: " + stClientAddr.sClientAddr);
			}
			else {
				System.out.println("Add connect failed, Error: " + iErr);
			}

			sleep(200);

			int iErr1 = pgJniTunnel.ConnectDelete("", "ctkj0004", 0, 0,
					"127.0.0.1:8000", "127.0.0.1:18000");
			if (iErr1 == PG_TUNNEL_ERROR_OK) {
				System.out.println("Delete connect success\n");
			}
			else {
				System.out.println("Delete connect failed, Error: " + iErr1);
			}

			sleep(200);
			uInd++;
		}
	}


	static void PrintHelp()
	{
		System.out.println("  quit");
		System.out.println("  versionget");
		System.out.println("  statusget");
		System.out.println("  domainget");
		System.out.println("  domainset");
		System.out.println("  commentget");
		System.out.println("  commentset");
		System.out.println("  tunnelset");
		System.out.println("  peerinfoget");
		System.out.println("  connectadd");
		System.out.println("  connectdelete");
		System.out.println("  connectquery");
		System.out.println("  connectlocaldelete");
		System.out.println("  connectlocalquery");
		System.out.println("  userextend");
		System.out.println("  pushget");
		System.out.println("  selfget");
		System.out.println("  connectenum");
		System.out.println("  connectlist");
		System.out.println("  peerfwdcfg");
		System.out.println("  peerauthset");
		System.out.println("  peerauthreply");
	}

	public static void main(String sArg[]) {

		String	sCfgPath = "demoTunnel.cfg";
		if (sArg.length > 0) {
			sCfgPath = sArg[0];
		}

		System.out.println("config file path: " + sCfgPath);

		String sDevID = "";
		do {
			System.out.print("Input device id: ");
			sDevID = in.nextLine();
		}
		while (sDevID.equals(""));

		if (!TunnelStart(sCfgPath, sDevID)) {
			return;
		}

		String szBuf = "";
		while (true) {
			System.out.print("\n> ");
			in.hasNextLine();

			szBuf = in.nextLine();
			if ("quit".equals(szBuf)) {
				break;
			}

			if ("versionget".equals(szBuf)) {
				VersionGet();
			}
			else if ("statusget".equals(szBuf)) {
				StatusGet();
			}
			else if ("domainset".equals(szBuf) ) {
				DomainSet();
			}
			else if ("domainget".equals(szBuf) ) {
				DomainGet();
			}
			else if ("commentset".equals(szBuf) ) {
				CommentSet();
			}
			else if ("commentget".equals(szBuf) ) {
				CommentGet();
			}
			else if ("tunnelset".equals(szBuf)) {
				TunnelSet();
			}
			else if ("peerinfoget".equals(szBuf)) {
				PeerInfoGet();
			}
			else if ("connectadd".equals(szBuf)) {
				ConnectAdd();
			}
			else if ("connectdelete".equals(szBuf)) {
				ConnectDelete();
			}
			else if ("connectquery".equals(szBuf)) {
				ConnectQuery();
			}
			else if ("connectlocaldelete".equals(szBuf)) {
				ConnectLocalDelete();
			}
			else if ("connectlocalquery".equals(szBuf)) {
				ConnectLocalQuery();
			}
			else if ("userextend".equals(szBuf)) {
				UserExtend();
			}
			else if ("pushget".equals(szBuf)) {
				PushGet();
			}
			else if ("selfget".equals(szBuf)) {
				SelfGet();
			}
			else if ("connectenum".equals(szBuf)) {
				ConnectEnum();
			}
			else if ("connectlist".equals(szBuf)) {
				ConnectList();
			}
			else if ("peerfwdcfg".equals(szBuf)) {
				PeerFwdCfg();
			}
			else if ("peerauthset".equals(szBuf)) {
				PeerAuthSet();
			}
			else if ("peerauthreply".equals(szBuf)) {
				PeerAuthReply();
			}
			else if ("testconnect".equals(szBuf)) {
				try {
					TestConnect(0);
				}
				catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			else {
				PrintHelp();
			}
		}

		TunnelStop();
	}
	
    // Generate the random MAC address
    private static String genMacAddr() {
    	try {
	    	java.util.Random rand = new java.util.Random();
	    	byte[] byMac = new byte[6];
	    	rand.nextBytes(byMac);
	    	return String.format("%02X%02X%02X%02X%02X%02X",
	    		byMac[0], byMac[1], byMac[2], byMac[3], byMac[4], byMac[5]);
    	}
    	catch (Exception ex) {
    		return "";
    	}
    }


	private static boolean TunnelStart(String sCfgPath, String sLocalDevID) {

		// Set event callback.
		pgJniTunnel.CallbackSet(m_eventCB);

        String sSysInfo = "(DevID){" + sLocalDevID
        	+ "}(MacAddr){" + genMacAddr() + "}(CpuMHz){0}"
        	+ "(MemSize){0}(BrwVer){}(OSVer){}(OSSpk){}(OSType){Android}";

		// Init tunnel sdk.
        int iErr = pgJniTunnel.Start(sCfgPath, sSysInfo);
		if (iErr != pgJniTunnel.PG_TUNNEL_ERROR_OK) {
			System.out.println("demoTunnel:	pgJniTunnel.Start: iError=" + iErr);
			return false;
		}

		// Test VersionGet()
		pgJniTunnel.OutVersion resVer = new pgJniTunnel.OutVersion();
		iErr = pgJniTunnel.VersionGet(resVer);
		if (iErr != 0) {
			System.out.println("demoTunnel:	VersionGet, iError=" + iErr);
		}
		else {
			System.out.println(resVer.sVersion);
		}

		// Test CommentGet()
		pgJniTunnel.OutComment resCmt = new pgJniTunnel.OutComment();
		iErr = pgJniTunnel.CommentGet(resCmt);
		if (iErr != 0) {
			System.out.println("demoTunnel:	CommentGet, iError=" + iErr);
		}
		else {
			System.out.println(resCmt.sComment);
		}

		return true;
	}

	private static void TunnelStop() {
    	pgJniTunnel.Stop();
	}
}
