# copyright 2016-2017 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr -- mailto:contact@logilab.fr
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 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 Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.

from . import generated


def _extract_title(annotation):
    """Return the first line in the annotation to use as a title"""
    annotation = annotation.strip()
    assert annotation
    return annotation.splitlines()[0]


class SEDAArchiveTransfer(generated.SEDAArchiveTransfer):

    def dc_title(self):
        return self.title

    @property
    def formats_compat(self):
        if self.compat_list is None:
            return set()
        return set(self.compat_list.split(', '))

    @property
    def archival_agreement(self):
        if self.reverse_seda_archival_agreement:
            return self.reverse_seda_archival_agreement[0]
        return None

    @property
    def comments(self):
        return self.reverse_seda_comment

    @property
    def archive_units(self):
        return self.reverse_seda_archive_unit

    @property
    def physical_data_objects(self):
        return self.reverse_seda_physical_data_object

    @property
    def binary_data_objects(self):
        return self.reverse_seda_binary_data_object


class SEDAArchiveUnit(generated.SEDAArchiveUnit):

    def dc_title(self):
        return _extract_title(self.user_annotation)

    @property
    def is_archive_unit_ref(self):
        """Return true if this is a 'reference' archive unit, else false for 'description' archive
        unit.
        """
        return not bool(self.first_level_choice.content_sequence)

    @property
    def first_level_choice(self):
        """Return the choice element of an archive unit (SEDAAltArchiveUnitArchiveUnitRefId),
        holding either a reference or descriptive content
        """
        return self.related('seda_alt_archive_unit_archive_unit_ref_id', 'subject').one()


class SEDABinaryDataObject(generated.SEDABinaryDataObject):

    def dc_title(self):
        return _extract_title(self.user_annotation)

    @property
    def format_id(self):
        return self.reverse_seda_format_id_from[0] if self.reverse_seda_format_id_from else None

    @property
    def encoding(self):
        return self.reverse_seda_encoding_from[0] if self.reverse_seda_encoding_from else None

    @property
    def mime_type(self):
        return self.reverse_seda_mime_type_from[0] if self.reverse_seda_mime_type_from else None

    @property
    def date_created_by_application(self):
        if self.reverse_seda_date_created_by_application:
            return self.reverse_seda_date_created_by_application[0]
        return None

    @property
    def referenced_by(self):
        """Return an iterator on archive unit's content sequences referencing this data-object."""
        for ref in self.reverse_seda_data_object_reference_id:
            for seq in ref.seda_data_object_reference:
                yield seq


class SEDAPhysicalDataObject(generated.SEDAPhysicalDataObject):

    def dc_title(self):
        return _extract_title(self.user_annotation)


class SEDAAltArchiveUnitArchiveUnitRefId(generated.SEDAAltArchiveUnitArchiveUnitRefId):

    @property
    def reference(self):
        """Return the reference element for an archive unit which has no content"""
        rset = self.related('seda_archive_unit_ref_id_from', 'object')
        if rset:
            return rset.one()
        return None

    @property
    def content_sequence(self):
        """Return the sequence element holding content for an archive unit which is not a reference
        """
        rset = self.related('seda_seq_alt_archive_unit_archive_unit_ref_id_management', 'subject')
        if rset:
            return rset.one()
        return None


class SEDASeqAltArchiveUnitArchiveUnitRefIdManagement(
        generated.SEDASeqAltArchiveUnitArchiveUnitRefIdManagement):

    @property
    def title(self):
        return self.reverse_seda_title[0]

    @property
    def keywords(self):
        return self.reverse_seda_keyword

    @property
    def custodial_history_items(self):
        return self.reverse_seda_custodial_history_item

    @property
    def type(self):
        return self.reverse_seda_type_from[0] if self.reverse_seda_type_from else None

    @property
    def language(self):
        return self.reverse_seda_language_from[0] if self.reverse_seda_language_from else None

    @property
    def description_level_concept(self):
        return self.seda_description_level[0] if self.seda_description_level else None

    @property
    def description(self):
        return self.reverse_seda_description[0] if self.reverse_seda_description else None

    @property
    def start_date(self):
        return self.reverse_seda_start_date[0] if self.reverse_seda_start_date else None

    @property
    def end_date(self):
        return self.reverse_seda_end_date[0] if self.reverse_seda_end_date else None

    @property
    def system_id(self):
        return self.reverse_seda_system_id[0] if self.reverse_seda_system_id else None

    @property
    def transferring_agency_archive_unit_identifier(self):
        if self.reverse_seda_transferring_agency_archive_unit_identifier:
            return self.reverse_seda_transferring_agency_archive_unit_identifier[0]
        return None

    @property
    def originating_agency(self):
        if self.reverse_seda_originating_agency_from:
            return self.reverse_seda_originating_agency_from[0]
        return None


class SEDAKeyword(generated.SEDAKeyword):

    @property
    def reference(self):
        return (self.reverse_seda_keyword_reference_from[0]
                if self.reverse_seda_keyword_reference_from else None)

    @property
    def type(self):
        return (self.reverse_seda_keyword_type_from[0]
                if self.reverse_seda_keyword_type_from else None)


class SEDAKeywordReference(generated.SEDAKeywordReference):

    @property
    def scheme(self):
        return (self.seda_keyword_reference_to_scheme[0] if self.seda_keyword_reference_to_scheme
                else None)

    @property
    def concept(self):
        return self.seda_keyword_reference_to[0] if self.seda_keyword_reference_to else None


class SEDAKeywordType(generated.SEDAKeywordType):

    @property
    def concept(self):
        return self.seda_keyword_type_to[0] if self.seda_keyword_type_to else None


class RuleMixIn(object):

    @property
    def _rule_type(self):
        return self.cw_etype[4:-4].lower()

    @property
    def rules(self):
        return getattr(self, 'seda_seq_{0}_rule_rule'.format(self._rule_type))

    @property
    def inheritance_control(self):
        alt = getattr(self, 'seda_alt_{0}_rule_prevent_inheritance'.format(self._rule_type))
        return alt[0] if alt else None


class SEDAAccessRule(RuleMixIn, generated.SEDAAccessRule):
    pass


class SEDAAppraisalRule(RuleMixIn, generated.SEDAAppraisalRule):

    @property
    def final_action_concept(self):
        if self.seda_final_action:
            return self.seda_final_action[0]
        return None


class SEDAClassificationRule(RuleMixIn, generated.SEDAClassificationRule):
    pass


class SEDADisseminationRule(RuleMixIn, generated.SEDADisseminationRule):
    pass


class SEDAReuseRule(RuleMixIn, generated.SEDAReuseRule):
    pass


class SEDAStorageRule(RuleMixIn, generated.SEDAStorageRule):

    @property
    def final_action_concept(self):
        if self.seda_final_action:
            return self.seda_final_action[0]
        return None


class RuleRuleMixIn(object):

    @property
    def start_date(self):
        return self.reverse_seda_start_date[0] if self.reverse_seda_start_date else None

    @property
    def rule_concept(self):
        return self.seda_rule[0] if self.seda_rule else None


class SEDASeqAccessRuleRule(RuleRuleMixIn, generated.SEDASeqAccessRuleRule):
    pass


class SEDASeqAppraisalRuleRule(RuleRuleMixIn, generated.SEDASeqAppraisalRuleRule):
    pass


class SEDASeqClassificationRuleRule(RuleRuleMixIn, generated.SEDASeqClassificationRuleRule):
    pass


class SEDASeqDisseminationRuleRule(RuleRuleMixIn, generated.SEDASeqDisseminationRuleRule):
    pass


class SEDASeqReuseRuleRule(RuleRuleMixIn, generated.SEDASeqReuseRuleRule):
    pass


class SEDASeqStorageRuleRule(RuleRuleMixIn, generated.SEDASeqStorageRuleRule):
    pass


class SEDAFormatId(generated.SEDAFormatId):

    @property
    def concept(self):
        return self.seda_format_id_to[0] if self.seda_format_id_to else None


class SEDAEncoding(generated.SEDAEncoding):

    @property
    def concept(self):
        return self.seda_encoding_to[0] if self.seda_encoding_to else None


class SEDAMimeType(generated.SEDAMimeType):

    @property
    def concept(self):
        return self.seda_mime_type_to[0] if self.seda_mime_type_to else None


class SEDAType(generated.SEDAType):

    @property
    def concept(self):
        return self.seda_type_to[0] if self.seda_type_to else None


class SEDALanguage(generated.SEDALanguage):

    @property
    def concept(self):
        return self.seda_language_to[0] if self.seda_language_to else None


class SEDAOriginatingAgency(generated.SEDAOriginatingAgency):

    @property
    def agency(self):
        return self.seda_originating_agency_to[0] if self.seda_originating_agency_to else None


class SEDACustodialHistoryItem(generated.SEDACustodialHistoryItem):

    @property
    def when(self):
        return self.reverse_seda_when[0] if self.reverse_seda_when else None
