package eu.teraflow.tid.bgp4Peer.grpc;



import com.google.common.net.InetAddresses;

import eu.teraflow.tid.bgp4Peer.models.LinkNLRIMsg;
import eu.teraflow.tid.bgp4Peer.models.NodeNLRIMsg;
import eu.teraflow.tid.bgp4Peer.models.UpdateMsg;
import eu.teraflow.tid.bgp4Peer.models.UpdateMsgList;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;
import src.main.proto.GrpcService.linkInfo;
import src.main.proto.GrpcService.nodeInfo;
import src.main.proto.GrpcService.NodeDescriptors;
import src.main.proto.GrpcService.updateRequest;
import src.main.proto.GrpcService.updateResponse;
import src.main.proto.updateServiceGrpc;
import src.main.proto.updateServiceGrpc.updateServiceStub;


public class grpcClient {

	
	public static void sendGrpcUpdateMsg(UpdateMsg update) {
		
		final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:2021").usePlaintext().build();
		updateServiceStub stub = updateServiceGrpc.newStub(channel);
		
		updateRequest request=null;
		nodeInfo n=null;
		linkInfo l=null;
		if(update.getNode()==null && update.getLink()==null){
			return;
		}
//		Build node for grpc message
		if(update.getNode()!=null && update.getNode().getNodeName()!=null) {		

				n = nodeInfo.newBuilder().setNodeName(update.getNode().getNodeName()).
						setIgpID(update.getNode().getLocalBgplsID()).
						setBgplsID(update.getNode().getBgplsID().toString()).
						setAsID(InetAddresses.coerceToInteger(update.getNode().getAs_number())).
						setLearntFrom(update.getNode().getLearntFrom()).
					buildPartial();
				
		}
		if(update.getLink()!=null) {
			
//			String strIPlocal;
//			String strIPremote;
			String strIgpR;
			String strIgpL;
			LinkNLRIMsg link=update.getLink();
		
//			if(link.getiPv4RouterIDLocalNodeLATLV()==null) 
//				 strIPlocal="-";
//			else {
//				strIPlocal=link.getiPv4RouterIDLocalNodeLATLV();
//			}
//			if(link.getiPv4RouterIDNeighborNodeLATLV()==null) 
//				 strIPremote="-";
//			else {
//				strIPremote=link.getiPv4RouterIDNeighborNodeLATLV();
//			}
			
			if(link.getRemoteNodeIGPId()==null) 
				strIgpR="-";
			else {
				strIgpR=link.getRemoteNodeIGPId().toString();
			}
			if(link.getLocalNodeIGPId()==null) 
				strIgpL="-";
			else {
				strIgpL=link.getLocalNodeIGPId().toString();
			}
			String ipv4R;
			if(link.getiPv4RouterIDNeighborNodeLATLV()==null) 
				ipv4R="-";
			else {
				ipv4R=link.getiPv4RouterIDNeighborNodeLATLV();
			}
			String ipv4L;
			if(link.getiPv4RouterIDLocalNodeLATLV()==null) 
				ipv4L="-";
			else {
				ipv4L=link.getiPv4RouterIDLocalNodeLATLV();
			}
					
//			Build link for grpc message. need non null values in some cases
			
			l = linkInfo.newBuilder().setLocalID(strIgpR).
					setLocalIPv4ID(ipv4L).
					setRemoteID(strIgpL).
					setRemoteIPv4ID(ipv4R).
					setLocal(NodeDescriptors.newBuilder().
							setAsNumber(link.getLocalDomainID().toString()).
							setBgplsID(link.getLocalBgplsID())).
					setRemote(NodeDescriptors.newBuilder().
							setAsNumber(link.getRemoteDomainID().toString()).
							setBgplsID(link.getRemoteBgplsID())).
					setAvailableBw(link.getAvailableBw()).
					setResidualBw(link.getResidualBw()).setUtilized(link.getUtilizedBw()).
					setMinLinkDelay(link.getMinDelay()).setMaxLinkDelay(link.getMaxDelay()).
					setDelayVariation(link.getLinkDelayVar()).setDelay(link.getLinkDelay()).
					setTEDefaultMetric(1).setAdjacencySid("0").setLearntFrom(link.getLearntFrom()).buildPartial();
			
			
		} 
		
		if(n==null && l!=null) {
			request=updateRequest.newBuilder().
					setNextHop(update.getNextHop().toString()).
					setAddressFamilyID(Integer.toString(update.getAFI())).
					setAsPathSegment(Integer.toString(update.getAsPathSegment())).
					addLink(l).build();
		}else if(l==null && n!=null) {
			request=updateRequest.newBuilder().
					setNextHop(update.getNextHop().toString()).
					setAddressFamilyID(Integer.toString(update.getAFI())).
					setAsPathSegment(Integer.toString(update.getAsPathSegment())).
					addNode(n).build();
		}else {
			//might not be possible
			//Error if node name is null 
			// TODO: handle seng grpc error?
//			request=updateRequest.newBuilder().
//					setNextHop("-"+update.getNextHop().toString()).
//					setAddressFamilyID(Integer.toString(update.getAFI())).
//					setAsPathSegment(Integer.toString(update.getAsPathSegment())).
//					addNode(n).addLink(l).build();
			
		}
				
		//TODO: this to a function
		stub.update(request, new StreamObserver <updateResponse>() {
      		
	        public void onNext(updateResponse response) {
	          System.out.println("respuesta del server: "+response);
	        }
	        public void onError(Throwable t) {
	        	System.out.println("error: "+t.getMessage());
	        }
	        public void onCompleted() {
	          // Typically you'll shutdown the channel somewhere else.
	          // But for the purpose of the lab, we are only making a single
	          // request. We'll shutdown as soon as this request is done.
	        	System.out.println("channel shutdown");
	          channel.shutdownNow();
	        }
	      });
		
	}

	public static void sendGrpc(UpdateMsgList update) {
		//construir mensaje
		//update get node,lin,path
		//getname,ids,as
		final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:2021").usePlaintext().build();
		updateServiceStub stub = updateServiceGrpc.newStub(channel);
		
		
		if(update.getNodeList().isEmpty()&&update.getLinkList().isEmpty()) {
			return;
		}
		updateRequest request=null;
		nodeInfo n=null;
		linkInfo l=null;
		if(!update.getNodeList().isEmpty()) {
			
			for(NodeNLRIMsg node: update.getNodeList()) {
				
				n = nodeInfo.newBuilder().setNodeName(node.getNodeName()).setIgpID(node.getLocalBgplsID()).
						setBgplsID(node.getBgplsID().toString()).setAsID(InetAddresses.coerceToInteger(node.getAs_number())).
					buildPartial();
			} 
			
			
		}
		if(!update.getLinkList().isEmpty()) {
			
			String strIPlocal;
			String strIPremote;
			String strIgpR;
			String strIgpL;
			
			for(LinkNLRIMsg link: update.getLinkList()) {
				
				if(link.getiPv4RouterIDLocalNodeLATLV()==null) 
					 strIPlocal="-";
				else {
					strIPlocal=link.getiPv4RouterIDLocalNodeLATLV();
				}
				if(link.getiPv4RouterIDNeighborNodeLATLV()==null) 
					 strIPremote="-";
				else {
					strIPremote=link.getiPv4RouterIDNeighborNodeLATLV();
				}
				
				if(link.getRemoteNodeIGPId()==null) 
					strIgpR="-";
				else {
					strIgpR=link.getRemoteNodeIGPId().toString();
				}
				if(link.getLocalNodeIGPId()==null) 
					strIgpL="-";
				else {
					strIgpL=link.getLocalNodeIGPId().toString();
				}
				String ipv4R;
				if(link.getiPv4RouterIDNeighborNodeLATLV()==null) 
					ipv4R="-";
				else {
					ipv4R=link.getiPv4RouterIDNeighborNodeLATLV();
				}
				String ipv4L;
				if(link.getiPv4RouterIDLocalNodeLATLV()==null) 
					ipv4L="-";
				else {
					ipv4L=link.getiPv4RouterIDLocalNodeLATLV();
				}
				
//				NodeDescriptors local= NodeDescriptors.newBuilder().
//						setAsNumber(link.getLocalDomainID().toString()).
//						setBgplsID(link.getLocalBgplsID()).buildPartial();
						
				
				l = linkInfo.newBuilder().setLocalID(strIgpR).
						setLocalIPv4ID(ipv4L).
						setRemoteID(strIgpL).
						setRemoteIPv4ID(ipv4R).
						setLocal(NodeDescriptors.newBuilder().
								setAsNumber(link.getLocalDomainID().toString()).
								setBgplsID(link.getLocalBgplsID())).
						setRemote(NodeDescriptors.newBuilder().
								setAsNumber(link.getRemoteDomainID().toString()).
								setBgplsID(link.getRemoteBgplsID())).
						setAvailableBw(link.getAvailableBw()).
						setResidualBw(link.getResidualBw()).setUtilized(link.getUtilizedBw()).
						setMinLinkDelay(link.getMinDelay()).setMaxLinkDelay(link.getMaxDelay()).
						setDelayVariation(link.getLinkDelayVar()).setDelay(link.getLinkDelay()).
						setTEDefaultMetric(1).setAdjacencySid("0").buildPartial();
			} 
			
		}
		if(n==null) {
			request = updateRequest.newBuilder().addLink(l).build();
		}else if(l==null) {
			request = updateRequest.newBuilder().addNode(n).build();
		}else {
			request = updateRequest.newBuilder().addNode(n).addLink(l).build();
		}
		
		
		
		
	    
	    stub.update(request, new StreamObserver <updateResponse>() {
      		
	        public void onNext(updateResponse response) {
	          System.out.println("respuesta del server: "+response);
	        }
	        public void onError(Throwable t) {
	        	System.out.println("error: "+t.getMessage());
	        }
	        public void onCompleted() {
	          // Typically you'll shutdown the channel somewhere else.
	          // But for the purpose of the lab, we are only making a single
	          // request. We'll shutdown as soon as this request is done.
	        	System.out.println("channel shutdown");
	          channel.shutdownNow();
	        }
	      });
	    
	    
	    
		
		
	}
	public static void main( String[] args ) throws Exception
    {
	      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:50052").usePlaintext().build();

	    	      // Replace the previous synchronous code with asynchronous code.
	    	      // This time use an async stub:
	    	       updateServiceStub stub = updateServiceGrpc.newStub(channel);

	    	      // Construct a request
	    	       int a = 123;
	    	       nodeInfo n = nodeInfo.newBuilder().setNodeName("router 3").setIgpID("1341234").buildPartial();
	    	      updateRequest request =
	    	        updateRequest.newBuilder().addNode(n).build();

	    	      // Make an Asynchronous call. Listen to responses w/ StreamObserver
	    	      	stub.update(request, new StreamObserver <updateResponse>() {
	    	      		
	    	        public void onNext(updateResponse response) {
	    	          System.out.println("respuesta del server: "+response);
	    	        }
	    	        public void onError(Throwable t) {
	    	        	System.out.println("error: "+t.getMessage());
	    	        }
	    	        public void onCompleted() {
	    	          // Typically you'll shutdown the channel somewhere else.
	    	          // But for the purpose of the lab, we are only making a single
	    	          // request. We'll shutdown as soon as this request is done.
	    	        	System.out.println("channel shutdown");
	    	          channel.shutdownNow();
	    	        }
	    	      });
	    	    }
}
