#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Processor functions
"""
from logging import getLogger

from .utils import IdentitySet

from .rules import Rule, RemoveMatch

log = getLogger(__name__).log

DEFAULT = '__default__'

POST_PROCESS = -2048
PRE_PROCESS = 2048


def _default_conflict_solver(match, conflicting_match):
    """
    Default conflict solver for matches, shorter matches if they conflicts with longer ones

    :param conflicting_match:
    :type conflicting_match:
    :param match:
    :type match:
    :return:
    :rtype:
    """
    if len(conflicting_match.initiator) < len(match.initiator):
        return conflicting_match
    if len(match.initiator) < len(conflicting_match.initiator):
        return match
    return None


class ConflictSolver(Rule):
    """
    Remove conflicting matches.
    """
    priority = PRE_PROCESS

    consequence = RemoveMatch

    @property
    def default_conflict_solver(self):
        """
        Default conflict solver to use.
        """
        return _default_conflict_solver

    def when(self, matches, context):
        # pylint:disable=too-many-nested-blocks
        to_remove_matches = IdentitySet()

        public_matches = [match for match in matches if not match.private]
        public_matches.sort(key=len)

        for match in public_matches:
            conflicting_matches = matches.conflicting(match)

            if conflicting_matches:
                # keep the match only if it's the longest
                conflicting_matches = [conflicting_match for conflicting_match in conflicting_matches if
                                       not conflicting_match.private]
                conflicting_matches.sort(key=len)

                for conflicting_match in conflicting_matches:
                    conflict_solvers = [(self.default_conflict_solver, False)]

                    if match.conflict_solver:
                        conflict_solvers.append((match.conflict_solver, False))
                    if conflicting_match.conflict_solver:
                        conflict_solvers.append((conflicting_match.conflict_solver, True))

                    for conflict_solver, reverse in reversed(conflict_solvers):
                        if reverse:
                            to_remove = conflict_solver(conflicting_match, match)
                        else:
                            to_remove = conflict_solver(match, conflicting_match)
                        if to_remove == DEFAULT:
                            continue
                        if to_remove and to_remove not in to_remove_matches:
                            both_matches = [match, conflicting_match]
                            both_matches.remove(to_remove)
                            to_keep = both_matches[0]

                            if to_keep not in to_remove_matches:
                                log(self.log_level, "Conflicting match %s will be removed in favor of match %s",
                                    to_remove, to_keep)

                                to_remove_matches.add(to_remove)
                        break
        return to_remove_matches


class PrivateRemover(Rule):
    """
    Removes private matches rule.
    """
    priority = POST_PROCESS

    consequence = RemoveMatch

    def when(self, matches, context):
        return [match for match in matches if match.private]
