<commit_before># -*- coding: utf-8 -*-
#    Copyright 2015 Mirantis, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import networkx

from solar.core.log import log
from solar.events.api import add_events
from solar.events.controls import Dependency
from solar.interfaces import orm


def guess_mapping(emitter, receiver):
    """Guess connection mapping between emitter and receiver.

    Suppose emitter and receiver have common inputs:
    ip, ssh_key, ssh_user

    Then we return a connection mapping like this:

    {
        'ip': '<receiver>.ip',
        'ssh_key': '<receiver>.ssh_key',
        'ssh_user': '<receiver>.ssh_user'
    }

    :param emitter:
    :param receiver:
    :return:
    """
    guessed = {}
    for key in emitter.args:
        if key in receiver.args:
            guessed[key] = key

    return guessed


def location_and_transports(emitter, receiver, orig_mapping):

    # XXX: we didn't agree on that reverse thign there

    def _remove_from_mapping(single):
        if single in orig_mapping:
            if isinstance(orig_mapping, dict):
                del orig_mapping[single]
            elif isinstance(orig_mapping, set):
                orig_mapping.remove(single)

    def _single(single, inps_emitter, inps_receiver):
        if inps_emitter and inps_receiver:
            log.debug("location and transports different, skipping")
            return
        emitter_single = emitter.db_obj.meta_inputs[single]
        receiver_single = receiver.db_obj.meta_inputs[single]
        emitter_single_reverse = emitter_single.get('reverse')
        receiver_single_reverse = receiver_single.get('reverse')
        # connect in other direction
        if emitter_single_reverse:
            if receiver_single_reverse:
                connect_single(receiver, single, emitter, single)
                _remove_from_mapping(single)
                return
        if receiver_single_reverse:
            connect_single(receiver, single, emitter, single)
            _remove_from_mapping(single)
            return
        if isinstance(orig_mapping, dict):
            orig_mapping[single] = single

    # XXX: that .args is slow on current backend
    # would be faster or another
    inps_emitter = emitter.args
    inps_receiver = receiver.args
    # XXX: should be somehow parametrized (input attribute?)
    for single in ('transports_id', 'location_id'):
        _single(single, inps_emitter[single], inps_receiver[single])
    return


def connect(emitter, receiver, mapping=None, events=None):
    mapping = mapping or guess_mapping(emitter, receiver)

    # XXX: we didn't agree on that "reverse" there
    location_and_transports(emitter, receiver, mapping)

    if isinstance(mapping, set):
        mapping = {src: src for src in mapping}

    for src, dst in mapping.items():
        if not isinstance(dst, list):
            dst = [dst]

        for d in dst:
            connect_single(emitter, src, receiver, d)

    events_to_add = [
        Dependency(emitter.name, 'run', 'success', receiver.name, 'run'),
        Dependency(emitter.name, 'update', 'success', receiver.name, 'update')
    ]
    if isinstance(events, dict):
        for k, v in events.items():
            if v is not False:
                events_to_add = filter(lambda x: x.parent_action == k, events_to_add)
        add_events(emitter.name, events_to_add)
    elif events is not False:
        add_events(emitter.name, events_to_add)


def connect_single(emitter, src, receiver, dst):
    if ':' in dst:<commit_msg>Guess mapping only if it is None<commit_after># -*- coding: utf-8 -*-
#    Copyright 2015 Mirantis, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import networkx

from solar.core.log import log
from solar.events.api import add_events
from solar.events.controls import Dependency
from solar.interfaces import orm


def guess_mapping(emitter, receiver):
    """Guess connection mapping between emitter and receiver.

    Suppose emitter and receiver have common inputs:
    ip, ssh_key, ssh_user

    Then we return a connection mapping like this:

    {
        'ip': '<receiver>.ip',
        'ssh_key': '<receiver>.ssh_key',
        'ssh_user': '<receiver>.ssh_user'
    }

    :param emitter:
    :param receiver:
    :return:
    """
    guessed = {}
    for key in emitter.args:
        if key in receiver.args:
            guessed[key] = key

    return guessed


def location_and_transports(emitter, receiver, orig_mapping):

    # XXX: we didn't agree on that reverse thign there

    def _remove_from_mapping(single):
        if single in orig_mapping:
            if isinstance(orig_mapping, dict):
                del orig_mapping[single]
            elif isinstance(orig_mapping, set):
                orig_mapping.remove(single)

    def _single(single, inps_emitter, inps_receiver):
        if inps_emitter and inps_receiver:
            log.debug("location and transports different, skipping")
            return
        emitter_single = emitter.db_obj.meta_inputs[single]
        receiver_single = receiver.db_obj.meta_inputs[single]
        emitter_single_reverse = emitter_single.get('reverse')
        receiver_single_reverse = receiver_single.get('reverse')
        # connect in other direction
        if emitter_single_reverse:
            if receiver_single_reverse:
                connect_single(receiver, single, emitter, single)
                _remove_from_mapping(single)
                return
        if receiver_single_reverse:
            connect_single(receiver, single, emitter, single)
            _remove_from_mapping(single)
            return
        if isinstance(orig_mapping, dict):
            orig_mapping[single] = single

    # XXX: that .args is slow on current backend
    # would be faster or another
    inps_emitter = emitter.args
    inps_receiver = receiver.args
    # XXX: should be somehow parametrized (input attribute?)
    for single in ('transports_id', 'location_id'):
        _single(single, inps_emitter[single], inps_receiver[single])
    return


def connect(emitter, receiver, mapping=None, events=None):
    if mapping is None:
        mapping = guess_mapping(emitter, receiver)

    # XXX: we didn't agree on that "reverse" there
    location_and_transports(emitter, receiver, mapping)

    if isinstance(mapping, set):
        mapping = {src: src for src in mapping}

    for src, dst in mapping.items():
        if not isinstance(dst, list):
            dst = [dst]

        for d in dst:
            connect_single(emitter, src, receiver, d)

    events_to_add = [
        Dependency(emitter.name, 'run', 'success', receiver.name, 'run'),
        Dependency(emitter.name, 'update', 'success', receiver.name, 'update')
    ]
    if isinstance(events, dict):
        for k, v in events.items():
            if v is not False:
                events_to_add = filter(lambda x: x.parent_action == k, events_to_add)
        add_events(emitter.name, events_to_add)
    elif events is not False:
        add_events(emitter.name, events_to_add)


def connect_single(emitter, src, receiver, dst):
    if ':' in dst:
{'fraction_non_alphanumeric': 0.0847395451210565, 'fraction_numerical': 0.0022010271460014674, 'mean_word_length': 2.7501146263182026, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3921878', 'n_tokens_mistral': 2347, 'n_tokens_neox': 2214, 'n_words': 731}