"""Utilities to help with developing using bcbio inside of docker.
"""
import copy
import datetime
import glob
import math
import os
import shutil
import subprocess
import sys

import boto
import numpy
import yaml

from bcbio import utils
from bcbio.distributed import objectstore
from bcbio.pipeline import genome
from bcbio.provenance import do

from bcbiovm.aws import common
from bcbiovm.docker import defaults, install, manage, mounts

# default information about docker container
DOCKER = {"port": 8085,
          "biodata_dir": "/usr/local/share/bcbio-nextgen",
          "work_dir": "/mnt/work",
          "image_url": "https://s3.amazonaws.com/bcbio_nextgen/bcbio-nextgen-docker-image.gz"}

def add_biodata_args(parser):
    """Add standard arguments for preparing biological data to a command line arg parser.
    """
    parser.add_argument("--genomes", help="Genomes to download",
                        action="append", default=[],
                        choices=["GRCh37", "hg19", "mm10", "mm9", "rn5", "canFam3", "dm3", "Zv9", "phix",
                                 "sacCer3", "xenTro3", "TAIR10", "WBcel235"])
    parser.add_argument("--aligners", help="Aligner indexes to download",
                        action="append", default=[],
                        choices=["bowtie", "bowtie2", "bwa", "novoalign", "star", "ucsc"])
    return parser

def setup_cmd(subparsers):
    parser = subparsers.add_parser("devel", help="Utilities to help with develping using bcbion inside of docker")
    psub = parser.add_subparsers(title="[devel commands]")

    iparser = psub.add_parser("setup_install", help="Run a python setup.py install inside of the current directory")
    iparser.add_argument("-i", "--image", help="Image name to write updates to",
                         default=install.DEFAULT_IMAGE)
    iparser.set_defaults(func=_run_setup_install)

    sparser = psub.add_parser("system", help="Update bcbio system file with a given core and memory/core target")
    sparser.add_argument("cores", help="Target cores to use for multi-core processes")
    sparser.add_argument("memory", help="Target memory per core, in Mb (1000 = 1Gb)")
    sparser.set_defaults(func=_run_system_update)

    dparser = psub.add_parser("biodata", help="Upload pre-prepared biological data to cache")
    dparser.add_argument("--prepped", help="Start with an existing set of cached data to output directory.")
    dparser = add_biodata_args(dparser)
    dparser.set_defaults(func=_run_biodata_upload)

    dbparser = psub.add_parser("dockerbuild", help="Build docker image and export to S3")
    dbparser.add_argument("-b", "--bucket", default="bcbio_nextgen",
                          help="S3 bucket to upload the gzipped docker image to")
    dbparser.add_argument("-t", "--buildtype", default="full", choices=["full", "code"],
                          help=("Type of docker build to do. full is all code and third party tools. "
                                "code is only bcbio-nextgen code."))
    dbparser.add_argument("-d", "--rundir", default="/tmp/bcbio-docker-build",
                          help="Directory to run docker build in")
    parser.add_argument("-q", "--quiet", dest="verbose", action="store_false", default=True,
                        help="Quiet output when running Ansible playbooks")
    dbparser.set_defaults(func=_run_docker_build)

# ## Install code to docker image

def _run_setup_install(args):
    """Install python code from a bcbio-nextgen development tree inside of docker.
    """
    bmounts = ["-v", "%s:%s" % (os.getcwd(), "/tmp/bcbio-nextgen")]
    cmd = ["docker", "run", "-i", "-d", "--net=host"] + bmounts + [args.image] + \
          ["bash", "-l", "-c",
           ("rm -rf /usr/local/share/bcbio-nextgen/anaconda/lib/python2.7/site-packages/bcbio && "
            "cd /tmp/bcbio-nextgen && "
            "/usr/local/share/bcbio-nextgen/anaconda/bin/python setup.py install")]
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    cid = process.communicate()[0].strip()
    do.run(["docker", "attach", "--no-stdin", cid], "Running in docker container: %s" % cid,
           log_stdout=True)
    subprocess.check_call(["docker", "commit", cid, args.image])
    subprocess.check_call(["docker", "rm", cid], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    print("Updated bcbio-nextgen install in docker container: %s" % args.image)

# ## Update bcbio_system.yaml

def _run_system_update(args):
    """Update bcbio_system.yaml file with a given target of cores and memory.
    """
    mem_types = set(["memory", "jvm_opts"])
    args = defaults.update_check_args(args, "Could not do upgrade of bcbio_system.yaml")
    system_file = os.path.join(args.datadir, "galaxy", "bcbio_system.yaml")
    with open(system_file) as in_handle:
        config = yaml.safe_load(in_handle)
    out = copy.deepcopy(config)
    mems = []
    for attrs in config.get("resources", {}).itervalues():
        for key, value in attrs.iteritems():
            if key in mem_types:
                mems.append((key, value))
    common_mem = _calculate_common_memory(mems)
    for prog, attrs in config.get("resources", {}).iteritems():
        for key, value in attrs.iteritems():
            if key == "cores":
                out['resources'][prog][key] = int(args.cores)
            elif key in mem_types:
                out["resources"][prog][key] = _update_memory(key, value, args.memory,
                                                             common_mem)
    bak_file = system_file + ".bak%s" % datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
    shutil.move(system_file, bak_file)
    with open(system_file, "w") as out_handle:
        yaml.safe_dump(out, out_handle, default_flow_style=False, allow_unicode=False)

def _get_cur_mem(key, val):
    if key == "memory":
        cur_mem = val
    elif key == "jvm_opts":