# Copyright (C) 2008 Michael Homer <=mwh>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

class Update(object):
    """Represents a program update.

    The `program`, `version`, `revision`, `type, and `url` fields are
    as in a `CheckDependencies` tuple. Only these are considered for
    equality or hashing.

    `enabledFlags` and `disabledFlags` are populated for recipes, and
    may be updated after the creation of the update.

    `activeFlags` is a set of the flags causing a dependency to be
    pulled in. It is equivalent to the activeflags entry of a rule dict
    from CheckDependencies.

    >>> tup = ('Freshen', '3.0.3', 'r1', 'recipe', '/F/C/R/Freshen/3.0.3')
    >>> u = Update(tup)
    >>> v = Update(tup, intBy='Freshen')
    >>> w = Update(('Nehserf',) + tup[1:], intBy='Nehserf')
    >>> v.enabledFlags = frozenset(['awesomeness'])
    >>> u == v
    True
    >>> hash(u) == hash(v)
    True
    >>> u != v
    False
    >>> u == w
    False
    >>> v.tuple9() # doctest: +NORMALIZE_WHITESPACE
    ('Freshen', '3.0.3', 'r1', 'recipe', '/F/C/R/Freshen/3.0.3', 'Freshen',
     frozenset(['awesomeness']), frozenset([]), frozenset([]))
    """

    def __init__(self, tup, intBy=None, activeFlags=frozenset(),
                enabledFlags=frozenset(), disabledFlags=frozenset()):
        self.program, self.version, self.revision, self.type, self.url = tup
        self.introducedBy = intBy if intBy else self.program
        self.activeFlags = activeFlags
        self.flagsEngine = None
        self.enabledFlags = enabledFlags
        self.disabledFlags = disabledFlags
        if ':' in self.program:
            self.type = 'alien'
        self._hash = hash((self.program, self.version,
                           self.revision, self.type))

    def tuple9(self):
        """Return an equivalent nine-element tuple, as in the old API"""
        return (self.program, self.version, self.revision, self.type, self.url,
                self.introducedBy, self.enabledFlags, self.disabledFlags,
                self.activeFlags)

    def initialiseFlagsEngine(self, engine=None):
        if engine:
            self.flagsEngine = engine
        self.enabledFlags = self.flagsEngine.flags()
        # Another stopgap to work with older Scripts. To remove after 2.9.6
        try:
            self.disabledFlags = self.flagsEngine.disabledflags()
        except AttributeError:
            self.disabledFlags = self.flagsEngine.potentialflags() - self.flagsEngine.flags()

    def __eq__(self, other):
        if self.program != other.program:
            return False
        if self.version != other.version:
            return False
        if self.revision != other.revision:
            return False
        if self.type != other.type:
            return False
        return True

    def __ne__(self, other):
        return not (self == other)

    def __hash__(self):
        return self._hash

    def __getstate__(self):
        # This is a stopgap to handle unserialisable pre-2.9.6 UFE instances
        self.flagsEngine = None
        return self.__dict__

if __name__ == '__main__':
    import doctest
    if doctest.testmod()[0]:
        exit(1)
