def my_conv(self):
        """
        Display under table format available conversations 
        of the user fetched from the server
        """

        self.app.log.info("Inside BaseController.my_conv()")
        if CURRENT_USER is not None:
            client = ClientSocket()
            client.open_connection(HOST, PORT)

            request = data_handler.format_fetch_conv(CURRENT_USER)
            response = client.send_message(request)
            if response == "None":
                print("You don't have any conversation.")
            else:
                reqs = response.split(", ")
                table_data = []
                for i in reqs:
                    table_data.append(i.split(' '))
                print(
                    tabulate(table_data, ["ID", "User 1", "User 2"],
                             tablefmt="psql"))
        else:
            self.app.log.error("You have not logged in yet.")
            print("Type 'shelf login' to login.")
    def request(self):
        """
        Answer incoming requests
        Conversation will be created if request is accepted
        """

        self.app.log.info("Inside BaseController.request()")
        if len(sys.argv) < 3 or len(sys.argv) < 5:
            print("usage: 'shelf request -r [request id] -a [answer(y/n)]'")
        else:
            client_res = self.app.pargs.answer
            req = self.app.pargs.request
            if client_res.lower().strip() in ANSWERS and req.isdigit():
                if CURRENT_USER is not None:
                    client = ClientSocket()
                    client.open_connection(HOST, PORT)

                    request = data_handler.format_answer(
                        CURRENT_USER, req, client_res.lower())
                    response = client.send_message(request)
                    if response == "True" and client_res.lower(
                    ) == 'y' or client_res.lower() == 'yes':
                        self.app.log.info("Conversation request accepted.")
                        print(
                            "Type 'shelf my-conv' to see available conversations"
                        )
                    elif response == "True" and client_res.lower(
                    ) == 'n' or client_res.lower() == 'no':
                        self.app.log.info("Conversation request declined.")
                    else:
                        self.app.log.error(
                            "You are not authenticated to access this conversation "
                            "or conversation not found.")
                else:
                    self.app.log.error("You have not logged in yet.")
                    print("Type 'shelf login' to login.")
            else:
                self.app.log.error("Invalid arguments.")
    def sent_req(self):
        """Display under table format sent requests fetched from the server"""

        self.app.log.info("Inside BaseController.sent_request()")
        if CURRENT_USER is not None:
            client = ClientSocket()
            client.open_connection(HOST, PORT)

            request = data_handler.format_sent_request(CURRENT_USER)
            response = client.send_message(request)
            if response == "None":
                print("You have not sent any request.")
            else:
                reqs = response.split(", ")
                table_data = []
                for i in reqs:
                    table_data.append(i.split(' '))
                print(
                    tabulate(table_data, ["ID", "Receiver", "Status"],
                             tablefmt="psql"))
        else:
            self.app.log.error("You have not logged in yet.")
            print("Type 'shelf login' to login.")
    def enter_conv(self):
        """Enter a conversation to exchange messages"""

        self.app.log.info("Inside BaseController.enter_conv()")
        if CURRENT_USER is not None:
            if len(sys.argv) < 3:
                print("usage: 'shelf enter-conv -c [conversation id]'")
            else:
                client = ClientSocket()
                client.open_connection(HOST, PORT)
                conv_id = self.app.pargs.conv
                # fetch = 0 if self.app.pargs.fetch is None else self.app.pargs.fetch
                if conv_id.isdigit():
                    request = data_handler.format_enter_conv(
                        CURRENT_USER, self.app.pargs.conv)
                    response = client.send_message(request)
                    if response == "False":
                        self.app.log.error(
                            "Something went wrong. Make sure you entered the correct conversation id."
                        )
                        print(
                            "Type 'shelf my-conv' to see available conversations"
                        )
                    else:
                        f_key = None
                        conv_data = data_handler.parse_json(
                            response.replace("'", '"'))
                        for k in conv_data.keys():
                            if k != "room" and k != "messages" and k != CURRENT_USER.name + "_key":
                                f_key = User.load_key(conv_data[k])

                        print("Connected. You can now start sending messages")
                        print("Press 'Ctrl + C' to disconnect.")

                        sys.stdout.write('>> ')
                        sys.stdout.flush()
                        client.in_conversation(CURRENT_USER, conv_data['room'],
                                               f_key)
                else:
                    self.app.log.error("Invalid conversation ID.")
        else:
            self.app.log.error("Please login before starting a conversation.")
            print("Type 'shelf login' to login.")
    def start_conv(self):
        """
        Send a request to start a conversation with another user
        Conversation won't be created until the request is accepted
        """

        self.app.log.info("Inside BaseController.start_conv()")
        if CURRENT_USER is not None:
            if len(sys.argv) < 3:
                print("usage: 'shelf start-conv -u [username]'")
            else:
                client = ClientSocket()
                client.open_connection(HOST, PORT)

                target = self.app.pargs.user
                if NAME_RULE.fullmatch(str(target)) is not None:
                    if target == CURRENT_USER.name:
                        print("This feature is not available yet.")
                    else:
                        request = data_handler.format_username(target)
                        response = client.send_message(request)
                        if response == "None":
                            print("User " + target + " does not exist.")
                        else:
                            print(
                                "Sending request to start conversation with " +
                                target + "...")
                            request = data_handler.format_req(
                                CURRENT_USER.name, target,
                                CURRENT_USER.publickey())
                            response = client.send_message(request)
                            if response == "Success":
                                self.app.log.info(
                                    "Request sent. Please wait for the other user to accept."
                                )
                            else:
                                print(
                                    "Something went wrong. Please try again later."
                                )
                else:
                    self.app.log.error("Invalid username or invalid argument.")
        else:
            self.app.log.error("Please login before starting a conversation.")
            print("Type 'shelf login' to login.")
    def register(self):
        """Create new user"""

        client = ClientSocket()
        client.open_connection(HOST, PORT)

        self.app.log.info("Inside BaseController.register()")

        print(
            "Username must be at least 4 chars, only including alphanumeric & underscore"
        )

        username = input("Type your name (any name you like): ").strip()

        # Username must matched with the name rules
        if NAME_RULE.fullmatch(username) is not None:
            # Data will be sent and processed on the server
            request = data_handler.format_username(username)
            response = client.send_message(request)

            if response != "None":
                self.app.log.warning(
                    "Username already existed. Please use another one.")

            else:  # If username is not duplicated, proceed
                salt = bcrypt.gensalt().decode()
                psw = getpass.getpass("Type your password: "******"Do it again (just making sure you're not forgetting it): "
                )

                if psw == confirm_psw:
                    user = User(username, salt, psw)
                    request = data_handler.format_register_user(user)

                    if client.send_message(request) is not None:
                        self.app.log.info("User successfully created.")
                        print("Type 'shelf login' to login")
                else:
                    self.app.log.error("Password does not match. Try again.")
        else:
            self.app.log.error("Username invalid. Try again.")
    def login(self):
        """
        Authenticate username and password
        Set current user if all matched
        """

        self.app.log.info("Inside BaseController.login()")
        client = ClientSocket()
        client.open_connection(HOST, PORT)

        username = input("Username: "******"Password: "******"None":
                user = User(username, response, psw)
                request = data_handler.format_login(user)
                auth = client.send_message(request)

                if auth == "True":
                    user.gen_key()
                    user.set_current_user()
                    self.app.log.info("Logged in successfully as " + user.name)

                else:  # Wrong password
                    self.app.log.error(
                        "Username or password is incorrect. Please try again.")

            else:  # Username not registered in db
                self.app.log.error(
                    "Username or password is incorrect. Please try again.")