#!/usr/bin/env python
"""
stagecache

Given a path to a resource (usually a file),

 * look for file in local chache
 * copy file to cache if missing
 * return path to cached file

Caches to ~/.cache by default, but a new location can be configured:
    * with command line options (see below)
    * in local config file: .stagecache.yaml
    * in user config file: ~/.config/stagecache.yaml
    * in global config file: ${SCRIPT_PATH}/../etc/stagecache.yaml

Limited support for groups of files:
    * formated lastdb database
    * formatted bwa index
    * generic prefix
    * taxdump (names.dmp, nodes.dmp in given folder)
    * define your own in a config file (see config.py and types.py)

default cache root and cache lifetimes are configurable (see config.py).
Fallback values are: ~/.cache and one day (1-0:00).

Lifetime can be negative. This will free the file up to be purge immediately,
but not delete it. Add the purge option to delete the file from the cache.

Use bash magic to embed in a command. EG:
    lastal $(stagecache -t last /path/to/db) /path/to/query.fasta

Run with no TARGET_PATH to get the number of files and free space in cache. Add
--verbose or --debug (or -v or -d) to get list of files in cache. Use purge
with no TARGET_PATH to delete all expired files.

Usage:
    stagecache [options] TARGET_PATH
    stagecache [options] [ --yaml | --json ]
    stagecache -h | --help
    stagecache -V | --version

Options:
    -h --help                Show this screen.
    -V --version             Show version.
    -v --verbose             Print more messages.
    -d --debug               Print even more messages.
    --dry_run                Just report what will be copied and/or deleted
    --force                  Delete any write_locks, and re-run rsync
    --purge                  Delete expired file(s)
    -a ATYPE, --atype ATYPE  Asset type [default: file]
    -c CACHE, --cache CACHE  Cache root
    -t TIME, --time TIME     Keep in cache for at least this time
"""

import logging
import json
import time
import yaml
from docopt import docopt
from jme.stagecache.main import cache_target, query_cache
from jme.stagecache import VERSION
from jme.stagecache.util import human_readable_bytes, get_time_string

def main(arguments):
    """ The starting point for command line operation

    Takes arguments from docopt (see 'if' block at end)

    Arguments from docopt like:
    {
          "--help": false,
          "--verbose": true,
          "--time": false,
          "--version": false,
          "--cache": None,
          "--atype": None,
          "TARGET_PATH": "/path/to/target.ext",
    }
    """

    # help and version options handled by docopt

    # collect arguments that affect function
    target_path = arguments['TARGET_PATH']
    kwargs = {k:arguments["--"+k] \
              for k in ['time', 'cache', 'atype', 'force', 'dry_run', 'purge']}

    # logging
    if arguments['--debug']:
        log_level = logging.DEBUG
        ll_text = 'debug'
    elif arguments['--verbose']:
        log_level = logging.INFO
        ll_text = 'verbose'
    else:
        log_level = logging.WARNING
        ll_text = 'quiet'
    logging.basicConfig(level=log_level)
    logging.debug("Log level set to %s (%s)", log_level, ll_text)

    logging.debug(arguments)

    if target_path is not None:
        try:
            print(cache_target(target_path, **kwargs))
        except Exception as e:
            # If anything fails, print the target_url before quitting
            print(target_path)
            raise e
    else:
        cache_data = query_cache(**kwargs)
        if arguments['--json']:
            print(json.dumps(cache_data, indent=1))
        elif arguments['--yaml']:
            print(yaml.dump(cache_data, indent=1))
        else:
            print("{} used and {} available in {}".format(
                human_readable_bytes(cache_data['used']),
                human_readable_bytes(cache_data['free']),
                cache_data['root']))

            # print file details if verbose or debugging
            if log_level <= logging.INFO:
                for target, file_data in cache_data['files'].items():
                    file_date = file_data['lock']
                    if isinstance(file_date, int):
                        if file_date > time.time():
                            status = "until " + get_time_string(file_date)
                        else:
                            status = "EXPIRED on " + get_time_string(file_date)
                    elif file_date is None:
                        status = "(missing)"
                    else:
                        status = file_date
                    print("{} ({}) uses {} {}".format(
                        target,
                        file_data['type'],
                        human_readable_bytes(file_data['size']),
                        status
                    ))

if __name__ == '__main__':
    arguments = docopt(__doc__, version=VERSION)
    main(arguments)
