"""pocli -- library and basic methods

Copyright (c) 2016, 2017
Florian Kaiser (fek@rzg.mpg.de), Klaus Reuter (khr@rzg.mpg.de)

Initial version based on the program "pyocclient.py" by Florian Kaiser.
"""


import os
import sys
import math
import json
import time
import locale
import argparse
import getpass
import owncloud


__version__ = '0.1.5'


def get_ocrc():
    home = os.path.expanduser('~')
    rcfile = os.path.join(home, '.ocrc')
    return rcfile


def init_ocrc():
    config = {}
    config['OC_USER'] = getpass.getuser()
    config['OC_SERVER'] = "https://datashare.mpcdf.mpg.de"
    config['OC_DEBUG'] = False
    rcfile = get_ocrc()
    with open(rcfile, 'w') as fp:
        fp.write( json.dumps(config, sort_keys=True, indent=4, separators=(',', ': ')) )
    print("created config file: " + rcfile)


"""Construct ownCloud client based on the configuration file."""
def _client():
    if 'OC_PASSWORD' in os.environ:
        password = os.environ['OC_PASSWORD']
    else:
        password = getpass.getpass()
    config = {}
    rcfile = get_ocrc()
    with open(rcfile, 'r') as fp:
        config = json.loads( fp.read() )
    config['OC_PASSWORD'] = password
    client = owncloud.Client(config['OC_SERVER'], debug=config['OC_DEBUG'])
    client.login(config['OC_USER'], config['OC_PASSWORD'])
    return client


def _filesizeformat(value):
    """
    Converts an integer representing of the size of a file-like object
    in bytes into human readable form (i.e. 13 KB, 4.1 MB, etc).
    """
    _FILESIZE_BASE = 1024
    _FILESIZE_SUFFIXES = ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z')
    if value is None or value == "":
        return ""
    if type(value) != int:
        try:
            value = float(value)
        except:
            return ""
    suffix_index = 0 if value==0 else int(math.log(value) / math.log(_FILESIZE_BASE))
    if suffix_index == 0:
        scaled_value = value
    elif suffix_index > len(_FILESIZE_SUFFIXES)-1:
        raise ValueError("number too big")
    else:
        scaled_value = round(float(value) / pow(_FILESIZE_BASE, suffix_index), 2)
    suffix = _FILESIZE_SUFFIXES[suffix_index]
    return "%g %s" % (scaled_value, suffix)


def _print_file_list(l):
    file_info_str = lambda x: "{:6s} {:10s} {:18s} {:s}".format(x.file_type, _filesizeformat(x.get_size()),
                                x.get_last_modified().strftime('%x %X'), x.path)
    for x in l:
        print(file_info_str(x))


# Code snippet adapted from:
# https://code.activestate.com/recipes/577058-query-yesno/
def _query_yes_no(question, default="yes"):
    """Ask a yes/no question via raw_input() and return their answer.
    """
    valid = {"yes":"yes", "y":"yes", "ye":"yes", "no":"no", "n":"no"}
    if default == None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [Y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '%s'" % default)
    while 1:
        sys.stdout.write(question + prompt)
        choice = raw_input().lower()
        if default is not None and choice == '':
            return default
        elif choice in valid.keys():
            return valid[choice]
        else:
            sys.stdout.write("Please respond with 'yes' or 'no' (or 'y' or 'n').\n")


# --- routines called by the cli interface (cli.py) below ---


def put(argparse_args):
    if (argparse_args.directory):
        directory = argparse_args.directory
    else:
        directory = '/'
    args = vars(argparse_args)
    file_list = args['files']
    if (len(file_list) > 0):
        client = _client()
        try:
            lst = client.list(directory)
        except:
            print("`%s': remote directory is not accessible" % directory)
        else:
            for file_name in file_list:
                if os.path.isfile(file_name):
                    size_mb = float(os.path.getsize(file_name))/float(1024*1024)
                    file_basename = os.path.basename(file_name)
                    if (size_mb > 100.0):
                        print("`%s': large file detected (%.2f MB), transfer may take some time ..." % (file_basename, size_mb))
                    t0 = time.time()
                    client.put_file(os.path.join(directory, file_basename), file_name)
                    t1 = time.time()
                    dt = t1 - t0
                    print("`%s': OK (%.2f MB/s)" % (file_basename, size_mb/dt))
                else:
                    print("`%s': skipping, not a regular file" % file_name)
        client.logout()


def get(argparse_args):
    if (argparse_args.directory):
        directory = argparse_args.directory
    else:
        directory = '.'
    args = vars(argparse_args)
    file_list = args['files']
    if (len(file_list) > 0):
        if os.path.isdir(directory):
            client = _client()
            for file_name in file_list:
                try:
                    file_info = client.file_info(file_name)
                except:
                    print("`%s': remote object is not accessible" % (file_name,))
                    continue
                else:
                    if file_info.is_dir():
                        print("`%s': skipping, download of remote directories is not supported" % (file_name,))
                        continue
                    else:
                        file_size_mb = float(file_info.get_size())/float(1024*1024)
                        file_basename = os.path.basename(file_name)
                        if (file_size_mb > 100.0):
                            print("`%s': large file detected (%.2f MB), transfer may take some time ..." % (file_basename, file_size_mb))
                        file_target = os.path.join(directory, file_basename)
                        t0 = time.time()
                        client.get_file(file_name, file_target)
                        t1 = time.time()
                        dt = t1 - t0
                        size_mb = float(os.path.getsize(file_target))/float(1024*1024)
                        print("`%s': OK (%.2f MB/s)" % (file_basename, size_mb/dt))
            client.logout()
        else:
            print("`%s': invalid local directory" % directory)


def ls(argparse_args):
    args = vars(argparse_args)
    directory_list = args['dir']
    if (len(directory_list) == 0):
        directory_list.append('/')
    client = _client()
    for directory in directory_list:
        try:
            lst = client.list(directory)
        except:
            print("`%s': remote directory is not accessible" % directory)
        else:
            _print_file_list(lst)
    client.logout()


def rm(argparse_args):
    args = vars(argparse_args)
    file_list = args['file']
    if (len(file_list) > 0):
        client = _client()
        for file_name in file_list:
            try:
                client.list(file_name)
            except:
                print("`%s': remote object is not accessible" % file_name)
            else:
                answer = _query_yes_no("`%s': remove remote object?" % file_name)
                if answer is "yes":
                    client.delete(file_name)
        client.logout()


def mkdir(argparse_args):
    args = vars(argparse_args)
    directory_list = args['dir']
    if (len(directory_list) > 0):
        client = _client()
        for directory in directory_list:
            client.mkdir(directory)
        client.logout()


def check(argparse_args):
    try:
        _client()
    except:
        raise
    else:
        print("OK!")
