# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

# Code come from python-Levenshtein

__all__ = ['StringMatcher', 'StringPartitioned', 'LazyString']

from warnings import warn

try:
    from Levenshtein import distance, editops, matching_blocks, opcodes, ratio

    class StringMatcher:
        """A SequenceMatcher-like class built on the top of Levenshtein"""

        def _reset_cache(self):
            self._ratio = self._distance = None
            self._opcodes = self._editops = self._matching_blocks = None

        def __init__(self, isjunk=None, seq1='', seq2=''):
            if isjunk:
                warn("isjunk not NOT implemented, it will be ignored")
            self._str1, self._str2 = seq1, seq2
            self._reset_cache()

        def set_seqs(self, seq1, seq2):
            self._str1, self._str2 = seq1, seq2
            self._reset_cache()

        def set_seq1(self, seq1):
            self._str1 = seq1
            self._reset_cache()

        def set_seq2(self, seq2):
            self._str2 = seq2
            self._reset_cache()

        def get_opcodes(self):
            if not self._opcodes:
                if self._editops:
                    self._opcodes = opcodes(
                        self._editops, self._str1, self._str2)
                else:
                    self._opcodes = opcodes(self._str1, self._str2)
            return self._opcodes

        def get_editops(self):
            if not self._editops:
                if self._opcodes:
                    self._editops = editops(
                        self._opcodes, self._str1, self._str2)
                else:
                    self._editops = editops(self._str1, self._str2)
            return self._editops

        def get_matching_blocks(self):
            if not self._matching_blocks:
                self._matching_blocks = matching_blocks(self.get_opcodes(),
                                                        self._str1, self._str2)
            return self._matching_blocks

        def ratio(self):
            if not self._ratio:
                self._ratio = ratio(self._str1, self._str2)
            return self._ratio

        def quick_ratio(self):
            # This is usually quick enough :o)
            if not self._ratio:
                self._ratio = ratio(self._str1, self._str2)
            return self._ratio

        def real_quick_ratio(self):
            len1, len2 = len(self._str1), len(self._str2)
            return 2.0 * min(len1, len2) / (len1 + len2)

        def distance(self):
            if not self._distance:
                self._distance = distance(self._str1, self._str2)
            return self._distance
except ImportError:
    from difflib import SequenceMatcher as StringMatcher


class StringPartitioned(str):
    "A string subclass that stores parts that composes itself."
    __slots__ = ('_parts',)

    def __init__(self, base):
        super().__init__()
        if isinstance(base, StringPartitioned):
            self._parts = base._parts
        else:
            self._parts = (base,)

    def __iter__(self):
        return iter(self._parts)

    def __add__(self, other):
        new = self.__class__(str(self) + other)
        new._parts = self._parts + (other,)
        return new

    def __radd__(self, other):
        new = self.__class__(other + str(self))
        new._parts = (other,) + self._parts
        return new


class LazyString():
    def __init__(self, func, *args, **kwargs):
        self._func = func
        self._args = args
        self._kwargs = kwargs

    def __str__(self):
        return self._func(*self._args, **self._kwargs)

    def __add__(self, other):
        return str(self) + other

    def __radd__(self, other):
        return other + str(self)
