from winnow.utils import deep_copy_dict as deepcopy
import jsonschema
from decimal import Decimal
import os

from winnow.options import OptionsSet
from winnow import inline
from winnow import utils
from winnow import validation
from winnow.exceptions import OptionsExceptionFailedValidation, OptionsExceptionReferenceError
from winnow.constants import *


def add_doc(target, doc, validation=True):
    _set_doc(target,  deepcopy(doc), validation=validation)


def allows(source_a, source_b):
    set_a = OptionsSet(inline.get_inlined_options(source_a))
    set_b = OptionsSet(inline.get_inlined_options(source_b))
    return set_a.allows(set_b)


def is_allowed_by(source_a, source_b):
    return allows(source_b, source_a)


def disallowed_keys(source_a, source_b):
    set_a = OptionsSet(inline.get_inlined_options(source_a))
    set_b = OptionsSet(inline.get_inlined_options(source_b))
    return set_b.disallowed_keys(set_a)


def filter_allows(filter_source, possible):
    return [p for p in possible if allows(filter_source, p)]


def filter_allowed_by(filter_source, possible):
    return [p for p in possible if is_allowed_by(filter_source, p)]




def merge(source_a, source_b, target, doc, validation=True):

    doc_a = source_a.get_doc()
    doc_b = source_b.get_doc()

    # get the options from bothe sources
    options_a = deepcopy(source_a.get_options_dict())
    options_b = deepcopy(source_b.get_options_dict())

    errors = []

    # carry any errors through
    errors_a = doc_a.get("errors")
    if errors_a:
        errors += errors_a

    errors_b = doc_b.get("errors")
    if errors_b:
        errors += errors_b

    merged_options = inline._merge_option_dicts(source_a, options_a, options_b, doc_a, doc_b, errors=errors)

    # put this merged options into a copy of the doc
    new_doc = deepcopy(doc)
    new_doc[OPTIONS_KEY] = merged_options
    if errors:
        new_doc["errors"] = errors

    target.clone_history_from(source_a)
    _add_start_if_needed(source_a, target)