from __future__ import absolute_import

# Copyright (c) 2010-2018 Andrew Dalke Scientific, AB (Sweden)
# See the contents of "chemfp/__init__.py" for full license details.

import os
import sys
import _chemfp
from _chemfp import (hex_isvalid, hex_popcount, hex_intersect_popcount,
                     hex_tanimoto, hex_contains, hex_contains_bit,
                     hex_encode, hex_encode_as_bytes, hex_decode,
                     hex_from_bitlist, hex_to_bitlist,
                     hex_intersect, hex_union, hex_difference)
                    

from _chemfp import (byte_popcount, byte_intersect_popcount,
                     byte_tanimoto, byte_contains, byte_contains_bit,
                     byte_hex_tanimoto,
                     byte_from_bitlist, byte_to_bitlist,
                     byte_intersect, byte_union, byte_difference)

__all__ = ["byte_popcount", "byte_intersect_popcount",
           "byte_tanimoto", "byte_contains", "byte_contains_bit",
           "byte_to_bitlist", "byte_from_bitlist",
           "hex_isvalid", "hex_popcount", "hex_intersect_popcount", 
           "hex_tanimoto", "hex_contains",
           "hex_to_bitlist", "hex_from_bitlist",
           "hex_encode", "hex_encode_as_bytes", "hex_decode"
           # Don't export the method and alignment-related functions
               ]


def get_methods():
    return [_chemfp.get_method_name(i) for i in range(_chemfp.get_num_methods())]

def get_alignments():
    return [_chemfp.get_alignment_name(i) for i in range(_chemfp.get_num_alignments())]

def get_alignment_methods():
    settings = {}
    for alignment in range(_chemfp.get_num_alignments()):
        method = _chemfp.get_alignment_method(alignment)
        settings[_chemfp.get_alignment_name(alignment)] = _chemfp.get_method_name(method)
    return settings

def get_alignment_method(alignment):
    try:
        alignment_i = get_alignments().index(alignment)
    except ValueError:
        raise ValueError("Unknown alignment %r" % (alignment,))
    return _chemfp.get_method_name(_chemfp.get_alignment_method(alignment_i))

def set_alignment_method(alignment, method):
    try:
        alignment_i = get_alignments().index(alignment)
    except ValueError:
        raise ValueError("Unknown alignment %r" % (alignment,))

    try:
        method_i = get_methods().index(method)
    except ValueError:
        raise ValueError("Unknown method %r" % (method,))

    _chemfp.set_alignment_method(alignment_i, method_i)

def select_fastest_method(repeat=10000):
    if repeat > 100000:
        raise ValueError("repeat size is meaninglessly large")
    if repeat < 1:
        raise ValueError("repeat size must be 1 or larger (values under 1000 are likely useless)")
    
    for alignment_i, name in enumerate(get_alignments()):
        _chemfp.select_fastest_method(alignment_i, repeat)


def get_options():
    return [_chemfp.get_option_name(i) for i in range(_chemfp.get_num_options())]

def get_option(option):
    _chemfp.get_option(option)

def set_option(option, value):
    _chemfp.set_option(option, value)

def print_report(out=sys.stdout):
    from . import SOFTWARE
    print >>out, "== Configuration report for", SOFTWARE, "=="
    print >>out, "Number of available threads:", _chemfp.get_num_threads()
    print >>out, "Available methods:", " ".join(get_methods())
    print >>out, "Alignment methods:"
    for alignment in get_alignments():
        method = get_alignment_method(alignment)
        print >>out, "  %s: %s" % (alignment, method)
    print >>out, "Option settings:"
    for option in get_options():
        print >>out, "  %s: %s" % (option, _chemfp.get_option(option))

def use_environment_variables(environ=None):
    if environ is None:
        environ = os.environ

    known = set()
    for alignment in get_alignments():
        name = "CHEMFP_" + alignment.upper().replace("-", "_")
        known.add(name)
        try:
            value = environ[name]
        except KeyError:
            pass
        else:
            try:
                set_alignment_method(alignment, value)
            except ValueError, err:
                print >>sys.stderr, "WARNING: Unable to use $%s = %r: %s" % (
                    (name, value, err))

    for option in get_options():
        name = "CHEMFP_" + option.upper().replace("-", "_")
        known.add(name)
        try:
            value = environ[name]
        except KeyError:
            pass
        else:
            try:
                set_option(option, int(value))
            except ValueError, err:
                print >>sys.stderr, "WARNING: Unable to use $%s = %r: %s" % (
                    (name, value, err))

    known.add("CHEMFP_REPORT")
    report = environ.get("CHEMFP_REPORT", "0") == "1"

    if report:
        set_option("report-popcount", 1)
        set_option("report-intersect", 1)

    
    known.add("CHEMFP_PRINT_CONFIG")
    if (environ.get("CHEMFP_PRINT_CONFIG", "0") == "1" or report):
        print_report(sys.stderr)


    for k in environ:
        if not k.startswith("CHEMFP_"):
            continue
        if k not in known:
            print >>sys.stderr, "WARNING: Unknown chemfp environment variable %r" % (k,)
