# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2017 Continuum Analytics, Inc.
#
# All Rights Reserved.
# -----------------------------------------------------------------------------
import hashlib
import json
import os.path
import tarfile

CHUNK_SIZE = 16384


def extract_from_sh(infile):
    if isinstance(infile, str):
        f = open(infile, 'rb')
    else:
        f = infile
    text = f.read(100000)
    # Look for the start of the tarfile containing the main constructor
    # tarball, so the metadata can be extracted. In constructor 2, the
    # tarball started right after the @@END_HEADER@@. In version 3, we
    # added the standalone conda executable before that, so we need to
    # extract the offset and add that in.
    marker1 = b'@@END_HEADER@@'
    marker2 = b'boundary0 + '
    i1 = text.rfind(marker1) + len(marker1) + 1
    i2 = text.rfind(marker2)
    if i2 > 0:
        i2 += len(marker2)
        i2 = int(text[i2:i2 + 32].split()[0])
        i1 += i2
    f.seek(i1)
    tf = tarfile.open(fileobj=f, mode='r')
    efo = tf.extractfile('preconda.tar.bz2')
    tf2 = tarfile.open(fileobj=efo, mode='r:bz2')
    try:
        meta = json.loads(
            tf2.extractfile('pkgs/.constructor-build.info').read().decode())
    except KeyError:
        meta = {}
    meta['urls'] = tf2.extractfile('pkgs/urls').read().decode()
    return meta


def extract_from_ambari(infile):
    tf = tarfile.open(infile, mode='r:gz')
    _install_script = 'install.sh'
    for name in tf.getnames():
        if name.endswith(_install_script):
            break
    efo = tf.extractfile(name)
    return extract_from_sh(efo)


def extract_from_parcel(infile):
    tf = tarfile.open(infile, mode='r:gz')
    _install_script = 'meta/.constructor-build.info'
    for name in tf.getnames():
        if name.endswith(_install_script):
            break
    efo = tf.extractfile(name)
    meta = json.loads(efo.read().decode())
    return meta


def extract(infile):
    if infile.endswith('.sh'):
        out = extract_from_sh(infile)
        installer_format = 'constructor'
    elif infile.endswith('.parcel'):
        out = extract_from_parcel(infile)
        installer_format = 'parcel'
    elif infile.endswith('.tar.gz'):
        out = extract_from_ambari(infile)
        installer_format = 'mpack'
    else:
        raise ValueError('Installer type not known: %s' % infile)

    size = 0
    md5 = hashlib.md5()
    sha1 = hashlib.sha1()
    sha256 = hashlib.sha256()

    with open(infile, 'rb') as fd:
        for chunk in iter(lambda: fd.read(CHUNK_SIZE), b''):
            size += len(chunk)
            md5.update(chunk)
            sha1.update(chunk)
            sha256.update(chunk)

    return {
        'size': size,
        'md5': md5.hexdigest(),
        'sha1': sha1.hexdigest(),
        'sha256': sha256.hexdigest(),
        'filename': os.path.basename(infile),
        'manifest-attributes': out,
        'installer-format': installer_format,
    }
