#!/usr/bin/env python
""" S3 access for data """
import sys
import os
import json

from os import path
from os.path import expanduser

import argparse
import asyncio
import logzero

from logzero import logger
from logzero import logging


from edgex_access import EdgexConfig
from edgex_access import EdgexDataAccess
from edgex_access import EdgexMeta

DEFAULT_CONFIG = "/.sp3"
SAMPLE_CONFIG = {
	"stores" : [
	{
		"NAME" : "edgex",
		"STORE_TYPE" :"S3",
		"ACCESS" : "",
		"SECRET" : "",
		"REGION" : "",
		"ENDPOINT" : "https://edge.nexenta.com",
		"TOKEN" : "",
		"SSL" : "False",
		"BUCKET" : "",
		"TAG" : "edgex"
	},
	{
		"NAME" : "ix",
		"STORE_TYPE" :"FS",
		"TOKEN" : "",
		"BUCKET" : "stuff",
		"TAG" : "ix",
        "ENDPOINT" : "/Users/sample.user/Workspace"
	}
	],
	"PRIMARY" : "edgex",
	"SYNCIO" : "QUEUED",
	"DEBUG" : 5,
    "DATATEST" : "data/",
    "META" : "meta/"
}


def config_usage():
    logger.info(sys.argv[0] + "\t--config  [ <ls> <create> <del> ] ...")

def config_cmd(cmd, args):
    """ commands to configure the utility with the json config """
    cfg_file = expanduser("~") + DEFAULT_CONFIG
    if cmd != "create":
        if not path.exists(cfg_file):
            logger.error(str("Unable to access " + cfg_file))
            return
    try:
        if cmd == "ls":
            cfg = EdgexConfig(cfg_file)
            cfg.show_all()
        elif cmd == "create":
            if path.exists(cfg_file):
                cfg_file_bak = cfg_file + ".bak"
                os.rename(cfg_file, cfg_file_bak)
            if not path.exists(cfg_file):
                with open(cfg_file, "w") as open_cfg:
                    json.dump(SAMPLE_CONFIG, open_cfg, indent=4, sort_keys=True)
        elif cmd == "del":
            if path.exists(cfg_file):
                cfg_file_bak = cfg_file + ".bak"
                os.rename(cfg_file, cfg_file_bak)
                #os.remove(cfg_file)
        elif cmd == "edit":
            if not path.exists(cfg_file):
                logger.error(cfg_file + " not found")
            cfg = EdgexConfig(cfg_file)
            cfg.change_cfg_value(args[0], args[1:])
        else:
            config_usage()
    except Exception as exp:
        logger.exception(exp)

def store_usage():
    logger.info(sys.argv[0] +"--store\t [ <ls> <create> <del> ] .....")

def store_cmd(cfg, loop, args, r):
    if len(args) < 1:
        store_usage()
        return
    cfg_file = expanduser("~") + DEFAULT_CONFIG
    if not path.isfile(cfg_file) or not os.access(cfg_file, os.R_OK):
        logger.error(str("Unable to access " + cfg_file))
        return
    try:
        if args[0] == "ls":
            cfg.show_stores()
        elif args[0] == "create":
            st_name = args[1]
            st_type = args[2]
            st_bucket = args[3]
            store = cfg.create_store(st_name, st_type, st_bucket)
            cfg.add_store(st_name, store)
            cfg.save()
        elif args[0] == "del":
            st_name = args[0]
            cfg.del_store(st_name)
        elif args[0] == "edit":
            st_name = args[1]
            st_key = args[2]
            st_value = args[3]
            cfg.change_store_value(st_name,st_key, st_value)
            cfg.save()
        else:
            store_usage()
    except Exception as exp:
        logger.exception(exp)

def meta_usage():
    logger.info(sys.argv[0] + "\t [ <ls> <create> <del> <info> ] ...")

def meta_cmd(cfg, loop, args, r):
    if len(args) < 1:
        meta_usage()
        return
    try:
        if args[0] == "ls":
            logger.info(str(os.listdir(cfg.get_meta_location())))
        elif args[0] == "create":
            meta = EdgexMeta(cfg, args[1])
            meta.init()
        elif args[0] == "del":
            meta = EdgexMeta(cfg, args[1])
            meta.wipe() 
        elif args[0] == "info":
            meta = EdgexMeta(cfg, args[1])
        else:
            meta_usage()
    except Exception as exp:
        logger.exception(exp)

def copy_usage():
    logger.info("copy <source> <dest>")
    logger.info("e.g.\t % sd3 --copy aws3://mbucket/file1 minio://obucket/file1")

def copy_cmd(cfg, loop, args, r):
    if len(args) < 2:
        copy_usage()
        return
    source_obj = args[0]
    dest_obj = args[1]
    logger.info("copy\t" + source_obj +"\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('copy', source_obj, dest_obj, r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def move_usage():
    logger.info("move <source> <dest>")
    logger.info("e.g.\t % sd3 --move aws3://mbucket/file1 minio://obucket/file1")

def move_cmd(cfg, loop, args, r):
    if len(args) < 2:
        move_usage()
        return
    source_obj = args[0]
    dest_obj = args[1]
    logger.info("move\t" + source_obj +"\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('move', source_obj, dest_obj, r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def delete_usage():
    logger.info("delete <dest>")
    logger.info("e.g.\t % sd3 --delete aws3://mbucket/file1")


def delete_cmd(cfg, loop, args, r):
    if len(args) < 1:
        delete_usage()
        return
    dest_obj = args[0]
    logger.info("delete\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('delete', dest_obj, "", r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def ls_usage():
    logger.info(sys.argv[0] + "\t ls \t [ store://folder/.../object ]")

def ls_cmd(cfg, loop, args, r):
    if len(args) < 1:
        ls_usage()
        return
    dest_obj = args[0]
    logger.info("ls\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('ls', dest_obj, "", r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def info_usage():
    logger.info(sys.argv[0] + "\t info \t [ store://folder/.../object ]")

def info_cmd(cfg, loop, args, r):
    if len(args) < 1:
        info_usage()
        return
    dest_obj = args[0]
    logger.info("info\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('info', dest_obj, "", r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def exists_usage():
    logger.info(sys.argv[0] + "\t exists \t [ store://folder/.../object ]")

def exists_cmd(cfg, loop, args, r):
    if len(args) < 1:
        exists_usage()
        return
    dest_obj = args[0]
    logger.info("exists\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('exists', dest_obj, "", r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def get_usage():
    logger.info(sys.argv[0] + "\t get \t[ store1://folder/.../object ] [ store2://folderX/obj2] ")

def get_cmd(cfg, loop, args, r):
    if len(args) < 2:
        get_usage()
        return
    source_obj = args[0]
    dest_obj = args[1]
    logger.info("get\t" + source_obj +"\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('get', source_obj, dest_obj, r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def put_usage():
    logger.info(sys.argv[0] + "\t put \t[ store://folder/.../object ] [ store2://folderX/obj2] ")

def put_cmd(cfg, loop, args, r):
    if len(args) < 2:
        put_usage()
        return
    source_obj = args[0]
    dest_obj = args[1]
    logger.info("put\t" + source_obj +"\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('put', source_obj, dest_obj, r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)

def gend_usage():
    logger.info(sys.argv[0] + "\t gend \t[ store://folder/.../object ] [ store2://folderX/obj2] ")

def gend_cmd(cfg, loop, args, r):
    if len(args) < 1:
        gend_usage()
        return
    dest_obj = args[0]
    logger.info("gend\t" + dest_obj)
    try:
        eda = EdgexDataAccess(cfg, loop)
        eda.create_task('gend', dest_obj, "", r)
        eda.execute()
    except Exception as exp:
        logger.exception(exp)


def command(cmd, cfg, loop, args, r):

    if cmd == "copy":
        copy_cmd(cfg, loop, args, r)
    elif cmd == "move":
        move_cmd(cfg, loop, args, r)
    elif cmd == "delete":
        delete_cmd(cfg, loop, args, r)
    elif cmd == "store":
        store_cmd(cfg, loop, args, r)
    elif cmd == "meta":
        meta_cmd(cfg, loop, args, r)
    elif cmd == "ls":
        ls_cmd(cfg, loop, args, r)
    elif cmd == "get":
        get_cmd(cfg, loop, args, r)
    elif cmd == "ls":
        put_cmd(cfg, loop, args, r)
    elif cmd == "info":
        info_cmd(cfg, loop, args, r)
    elif cmd == "exists":
        exists_cmd(cfg, loop, args, r)
    elif cmd == "gend":
        gend_cmd(cfg, loop, args, r)
    else:
        logger.error("Unknown Command " + cmd)

    loop.close()


def main():

    # TODO: location of edgex_access directory for the package
    #HERE = path.abspath(path.dirname(__file__))
    #VPATH = os.path.join(HERE, '../edgex_access', 'version.py')
    #__version__ = eval(open(VPATH).read())
    __version__ = '0.0.14'

    parser = argparse.ArgumentParser(
        description="S3/Posix data ls/put/get/delete/copy/move",
                    epilog="Manage data the same way on all data store platforms")

    parser.add_argument('-d', '--debug', type=int, help='debug value', required=False)
    parser.add_argument('-r', action='store_true', help='recursive run')
    parser.add_argument('--version', action='version', version=__version__)

    parser.add_argument("--ls", help="Listing of this object or folder", nargs=argparse.REMAINDER)
    parser.add_argument("--exists", help="Listing of this object or folder", nargs=argparse.REMAINDER)
    parser.add_argument("--info", help="Listing of this object or folder", nargs=argparse.REMAINDER)
    parser.add_argument("--put", help="Put this object or the folder", nargs=argparse.REMAINDER)
    parser.add_argument("--get", help="Get this object or the folder", nargs=argparse.REMAINDER)
    parser.add_argument("--delete", help="Remove this object or the folder", nargs=argparse.REMAINDER)

    parser.add_argument("--copy", help="Copy one object or folder to another store", nargs=argparse.REMAINDER)
    parser.add_argument("--move", help="Move this object or folder to another store", nargs=argparse.REMAINDER)

    parser.add_argument("--config", help="Configure this utility", nargs=argparse.REMAINDER)
    parser.add_argument("--store", help="Create and Show existing stores", nargs=argparse.REMAINDER)
    parser.add_argument("--meta", help="MetaData store configuration", nargs=argparse.REMAINDER)
    parser.add_argument("--gend", help="Generate random data ", nargs=argparse.REMAINDER)

    results = parser.parse_args()

    DEBUG_LEVEL = 5
    if results.debug != DEBUG_LEVEL:
        DEBUG_LEVEL = results.debug

    if DEBUG_LEVEL == 0:
        log_format = '%(color)s[%(levelname)1.1s %(asctime)s \
                %(module)s:%(lineno)d]%(end_color)s %(message)s'
        logfile = sys.argv[0] + ".log"
        logzero.logfile(logfile, maxBytes=1048576, backupCount=3, \
                        loglevel=logging.DEBUG, formatter=log_format)
        formatter = logzero.LogFormatter(fmt=log_format)
        logzero.setup_default_logger(level=logging.DEBUG, formatter=formatter)
    else:
        log_format = '%(message)s'
        formatter = logzero.LogFormatter(fmt=log_format)
        logzero.setup_default_logger(level=logging.INFO, formatter=formatter)


    if results.config is not None:
        cmd = "config"
        args = results.config
        config_cmd(args[0], args[1:])
        sys.exit(0)


    cfg_file = expanduser("~") + DEFAULT_CONFIG
    if not path.isfile(cfg_file) or not os.access(cfg_file, os.R_OK):
        logger.error(str("Unable to access " + cfg_file))
        sys.exit(2)
    cfg = EdgexConfig(cfg_file)


    recursive = results.r
    loop = asyncio.get_event_loop()

    if results.ls is not None:
        cmd = "ls"
        args = results.ls
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.exists is not None:
        cmd = "exists"
        args = results.exists
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.info is not None:
        cmd = "info"
        args = results.info
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.put is not None:
        cmd = "put"
        args = results.put
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.get is not None:
        cmd = "get"
        args = results.get
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.delete is not None:
        cmd = "delete"
        args = results.delete
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.copy is not None:
        cmd = "copy"
        args = results.copy
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.move is not None:
        cmd = "move"
        args = results.move
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.store is not None:
        cmd = "store"
        args = results.store
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.meta is not None:
        cmd = "meta"
        args = results.meta
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    if results.gend is not None:
        cmd = "gend"
        args = results.gend
        command(cmd, cfg, loop, args, recursive)
        sys.exit(0)

    parser.print_help()

if __name__ == "__main__":
    main()
