#!/usr/bin/env python3
# -*- coding: utf-8 -*- vim60:fdm=marker
#
# Copyright: 2016, Maximiliano Curia <maxy@debian.org>
#
# License: ISC
#  Permission to use, copy, modify, and/or distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#  .
#  THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
#  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
#  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
#  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#  PERFORMANCE OF THIS SOFTWARE.

''' Miscelaneous data types '''

try:
    import regex as re
except ImportError:
    import re

from collections import namedtuple

ReSub = namedtuple('ReSub', ('pattern', 'repl'))
ReFlags = namedtuple('ReFlags', ('re', 'flags'))
ReFlags.__new__.__defaults__ = (None, re.IGNORECASE)
ReLicense = namedtuple('ReLicense', ('re', 'license', 'get_detail', 're_flags'))
ReLicense.__new__.__defaults__ = (None, None, None, re.IGNORECASE)

UNKNOWN = 'Unknown'
UNKNOWN_COPYRIGHTED = 'UnknownCopyrighted'


class License(object):

    __slots__ = ('name', 'stored')

    licenses = {}

    def __init__(self, name):
        self.name = name
        self.stored = None

    def __str__(self):
        if self.stored:
            return self.stored.dump().rstrip('\n')
        return ('License: {name}\n'
                'Comment: Add the corresponding license text here'.format(
                    name=self.name))

    @staticmethod
    def get(name):
        if name not in License.licenses:
            License.licenses[name] = License(name)

        return License.licenses[name]


class YearRange(object):

    __slots__ = ('low', 'high')

    def __init__(self, low=None, high=None):
        if low is None:
            low_value = 0
        else:
            low_value = int(low)

        if high is None:
            high_value = low_value
        else:
            high_value = int(high)

        if low_value > high_value:
            low_value, high_value = high_value, low_value
        self.low = low_value
        self.high = high_value

    def __in__(self, year):
        value = int(year)
        return self.low <= value <= self.high

    def add(self, year):
        value = int(year if year is not None else 0)
        if not value:
            return self
        if not self.low or value < self.low:
            self.low = value
        if not self.high or self.high < value:
            self.high = value
        return self

    def newer(self, other):
        if self.high and other.high:
            return other.high > self.high
        return not self.high and other.high

    def merge(self, other):
        self.add(other.low)
        self.add(other.high)
        return self

    def __bool__(self):
        return bool(self.low)

    def __str__(self):
        if not self.low:
            return ''
        if self.low == self.high:
            return str(self.low)
        return str(self.low) + '-' + str(self.high)


class CopyrightHolder(object):

    __slots__ = ('name', 'email', 'years')

    def __init__(self, name, email, years):
        self.name = name
        self.email = email
        self.years = years if years is not None else YearRange()

    def merge(self, other):
        if other.name and self.years.newer(other.years):
            self.name = other.name
        self.years.merge(other.years)
        return self

    @property
    def person(self):
        result = self.name
        if self.name and self.email:
            result += ' '
        if self.email:
            result += '<{}>'.format(self.email)
        return result

    def __str__(self):
        result = str(self.years)
        result += ', ' if result else ''
        result += self.person
        return result

    def __repr__(self):
        return str(self)
