#!/usr/bin/env python

import pika
import uuid
import json
import os
import sys

from tabulate import tabulate


class AMQPClient(object):
  
    def __init__(self):
        self.rpcQueue = "storage_queue"
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host = "rabbitmq"))
        self.channel = self.connection.channel()
        result = self.channel.queue_declare(queue = '', exclusive = True)
        self.callback_queue = result.method.queue
        self.channel.basic_consume(queue = self.callback_queue, on_message_callback = self.on_response, auto_ack = True)

    def on_response(self, ch, method, props, body):
        if self.corr_id == props.correlation_id:
            self.response = json.loads(body)

    def call(self, msg):
        self.response = None
        self.corr_id = str(uuid.uuid4())
        self.channel.basic_publish(exchange = '',
                                   routing_key = self.rpcQueue,
                                   properties = pika.BasicProperties(reply_to = self.callback_queue,
                                                                     correlation_id = self.corr_id,
                                                                    ),
                                   body = json.dumps(msg))

        while self.response is None:
            self.connection.process_data_events()
        return self.response

    def add(self):
        storageType = None
        storageBasePath = None
        storageHostname = None
        while not storageType in ("cold", "hot", "portal"):
                try:
                    storageType = input("\nStorage type [cold, hot or portal]: ")
                except ValueError:
                    print("Input type is not valid!")
                except EOFError:
                    print("\nPlease, use CTRL+C to quit.")
                except KeyboardInterrupt:
                    sys.exit("\nCTRL+C detected. Exiting...")
        try:
            storageBasePath = input("\nStorage base path: ")
        except ValueError:
            print("Input type is not valid!")
        except EOFError:
            print("\nPlease, use CTRL+C to quit.")
        except KeyboardInterrupt:
            sys.exit("\nCTRL+C detected. Exiting...")
        try:
            storageHostname = input("\nStorage hostname: ")
        except ValueError:
            print("Input type is not valid!")
        except EOFError:
            print("\nPlease, use CTRL+C to quit.")
        except KeyboardInterrupt:
            sys.exit("\nCTRL+C detected. Exiting...")
        storageRequest = { "requestType": "STORAGE_ADD", 
                           "storageType": storageType, 
                           "basePath": storageBasePath,
                           "hostname": storageHostname }
        storageResponse = self.call(storageRequest)
        
        if "responseType" not in storageResponse:
            sys.exit("FATAL: Malformed response, storage acknowledge expected.\n")
        elif storageResponse["responseType"] == "STORAGE_ADD_DONE":
            print("\nStorage point added successfully!\n")
        elif storageResponse["responseType"] == "ERROR":
            errorCode = storageResponse["errorCode"]
            errorMsg = storageResponse["errorMsg"]
            sys.exit(f"\nError code: {errorCode}\nError message: {errorMsg}\n")
        else:
            sys.exit("\nFATAL: Unknown response type.\n")

    def list(self):
        storageRequest = { "requestType": "STORAGE_LST" }
        storageResponse = self.call(storageRequest)
        
        if "responseType" not in storageResponse:
            sys.exit("FATAL: Malformed response, storage acknowledge expected.\n")
        elif storageResponse["responseType"] == "STORAGE_LST_DONE":
            print()
            print(tabulate(storageResponse["storageList"], headers = "keys", tablefmt = "pretty"))
            print()
        elif storageResponse["responseType"] == "ERROR":
            errorCode = storageResponse["errorCode"]
            errorMsg = storageResponse["errorMsg"]
            sys.exit(f"\nError code: {errorCode}\nError message: {errorMsg}\n")
        else:
            sys.exit("\nFATAL: Unknown response type.\n")
            
    def help(self):
        sys.exit("""
NAME
       vos_storage

SYNOPSYS
       vos_storage COMMAND

DESCRIPTION
       Client tool to manage VOSpace storage points.
       
       The client accepts only one (mandatory) command at a time.
       A list of supported commands is shown here below:

       add
           adds a storage point to the database.
           
       list
           prints the storage points list.
    """)

# Create new AMQPClient object
vosStorageCli = AMQPClient()

# Check the number of input args
if len(sys.argv) == 2:
    script, cmd = sys.argv
else:
    vosStorageCli.help()

if cmd == "add":
    vosStorageCli.add()
elif cmd == "list":
    vosStorageCli.list()
else:
    vosStorageCli.help()
