import grpc
from concurrent import futures
import compose_pb2_grpc
import compose_pb2
import save_pb2_grpc
import save_pb2
import sys
import threading
# a threading event to register when terminate is called 
# so as to end the server's execution
done = threading.Event()

# create the composite servers class
class Compose(compose_pb2_grpc.ComposeServicer):
    def __init__(self, address1, address2):
        # initialize the channel and the stubs for the other two servers
        # in here, they behave as clients
        self.sigaAddress = grpc.insecure_channel(address1)
        self.matriculaAddress = grpc.insecure_channel(address2)
        self.sigaStub = save_pb2_grpc.SaveStub(self.sigaAddress)
        self.matriculaStub = save_pb2_grpc.SaveStub(self.matriculaAddress)

    def Search(self, request, context):
        # make a request to siga
        sigaResponse = self.sigaStub.Search(save_pb2.SearchPayload(id=int(request.id)))
        # check if the resposne is not an empty string
        if sigaResponse.description != '':
            # make a request to matricula server
            matriculaResponse = self.matriculaStub.Search(save_pb2.SearchPayload(id=sigaResponse.value))
            # check if the respone is an empty string
            if matriculaResponse.description != '':
                # return the response from both servers 
                return compose_pb2.ConsultResponse(name=sigaResponse.description, matricula=sigaResponse.value,
                course=matriculaResponse.description, credits=matriculaResponse.value)
            else:
                # return response from siga server only
                return compose_pb2.ConsultResponse(name=sigaResponse.description, matricula=sigaResponse.value,
                course="N/M", credits=0)
        else:
            # return response from none of the servers
            return compose_pb2.ConsultResponse(name="", matricula=0,
                course="", credits=0)

    def Terminate(self, request, context):
        # make a request to terminate the siga server
        sigaTerminate =  self.sigaStub.Terminate(save_pb2.TerminatePayload())
        # make a request to terminate the matricula server
        matriculaTerminate = self.matriculaStub.Terminate(save_pb2.TerminatePayload())
        # a setter to set end of server
        done.set()
        # return the sum of both responses
        return compose_pb2.EndResponse(response=(sigaTerminate.response+matriculaTerminate.response))

def run():
    # create the grpc server
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    # add the listener
    compose_pb2_grpc.add_ComposeServicer_to_server(Compose(sys.argv[2],sys.argv[3]), server)
    port = '[::]:' + sys.argv[1]
    server.add_insecure_port(port)
    server.start()
    # end server when terminate is called
    done.wait()
    server.stop(1).wait()


if __name__ == '__main__':
    run()