# -*- coding: utf-8 -*-

from cwr.acknowledgement import AcknowledgementRecord, MessageRecord
from cwr.agreement import AgreementRecord, AgreementTerritoryRecord, \
    InterestedPartyForAgreementRecord
from cwr.group import Group, GroupHeader, GroupTrailer
from cwr.info import AdditionalRelatedInfoRecord
from cwr.parser.decoder.common import Decoder
from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, \
    PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord
from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, \
    NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, \
    NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, \
    NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord
from cwr.transmission import Transmission, TransmissionTrailer, \
    TransmissionHeader
from cwr.work import RecordingDetailRecord, ComponentRecord, \
    AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, \
    InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, \
    WorkRecord
from cwr.file import CWRFile, FileTag
from cwr.other import AVIKey, VISAN
from cwr.table_value import MediaTypeValue, TableValue, InstrumentValue

"""
Classes for transforming dictionaries into instances of the CWR model.

There is a decoder for each of the model classes, and all of them expect a
dictionary having at least one key for each field, having the same name as the
field, which will refer to a valid value.

As said, the values on the dictionary should be valid values, for example if
an integer is expected, then the dictionary contains an integer. The values
contained in the dictionary entries should not need to be parsed.

These decoders are useful for handling JSON transmissions or Mongo databases.
"""

__author__ = 'Bernardo Martínez Garrido'
__license__ = 'MIT'
__status__ = 'Development'


class TransactionRecordDictionaryDecoder(Decoder):
    def __init__(self):
        super(TransactionRecordDictionaryDecoder, self).__init__()
        self._decoders = {}

        self._decoders['ACK'] = AcknowledgementDictionaryDecoder()
        self._decoders['AGR'] = AgreementDictionaryDecoder()
        self._decoders['TER'] = AgreementTerritoryDictionaryDecoder()
        self._decoders['ARI'] = AdditionalRelatedInformationDictionaryDecoder()
        self._decoders['ALT'] = AlternateTitleDictionaryDecoder()
        self._decoders['EWT'] = AuthoredWorkDictionaryDecoder()
        self._decoders['VER'] = AuthoredWorkDictionaryDecoder()
        self._decoders['COM'] = ComponentDictionaryDecoder()
        self._decoders['IPA'] = InterestedPartyForAgreementDictionaryDecoder()
        self._decoders['SPT'] = IPTerritoryOfControlDictionaryDecoder()
        self._decoders['SWT'] = IPTerritoryOfControlDictionaryDecoder()
        self._decoders['IND'] = InstrumentationDetailDictionaryDecoder()
        self._decoders['INS'] = InstrumentationSummaryDictionaryDecoder()
        self._decoders['MSG'] = MessageDictionaryDecoder()
        self._decoders['PER'] = PerformingArtistDictionaryDecoder()
        self._decoders['PWR'] = PublisherForWriterDictionaryDecoder()
        self._decoders['REC'] = RecordingDetailDictionaryDecoder()
        self._decoders['EXC'] = WorkDictionaryDecoder()
        self._decoders['ISW'] = WorkDictionaryDecoder()
        self._decoders['NWR'] = WorkDictionaryDecoder()
        self._decoders['REV'] = WorkDictionaryDecoder()
        self._decoders['ORN'] = WorkOriginDictionaryDecoder()
        self._decoders['SWR'] = WriterRecordDictionaryDecoder()
        self._decoders['OWR'] = WriterRecordDictionaryDecoder()
        self._decoders['OWR'] = WriterRecordDictionaryDecoder()
        self._decoders[
            'NPA'] = NonRomanAlphabetAgreementPartyDictionaryDecoder()
        self._decoders['NOW'] = NonRomanAlphabetOtherWriterDictionaryDecoder()
        self._decoders[
            'NPR'] = NonRomanAlphabetPerformanceDataDictionaryDecoder()
        self._decoders['NPN'] = NonRomanAlphabetPublisherNameDictionaryDecoder()
        self._decoders['NAT'] = NonRomanAlphabetTitleDictionaryDecoder()
        self._decoders['NET'] = NonRomanAlphabetWorkDictionaryDecoder()
        self._decoders['NCT'] = NonRomanAlphabetWorkDictionaryDecoder()
        self._decoders['NVT'] = NonRomanAlphabetWorkDictionaryDecoder()
        self._decoders['NWN'] = NonRomanAlphabetWriterNameDictionaryDecoder()
        self._decoders['SPU'] = PublisherRecordDictionaryDecoder()
        self._decoders['OPU'] = PublisherRecordDictionaryDecoder()

    def decode(self, data):
        return self._decoders[data['record_type']].decode(data)


class AcknowledgementDictionaryDecoder(Decoder):
    def __init__(self):
        super(AcknowledgementDictionaryDecoder, self).__init__()

    def decode(self, data):
        return AcknowledgementRecord(record_type=data['record_type'],
                                     transaction_sequence_n=data[
                                         'transaction_sequence_n'],
                                     record_sequence_n=data[
                                         'record_sequence_n'],
                                     original_group_id=data[
                                         'original_group_id'],
                                     original_transaction_sequence_n=data[
                                         'original_transaction_sequence_n'],
                                     original_transaction_type=data[
                                         'original_transaction_type'],
                                     transaction_status=data[
                                         'transaction_status'],
                                     creation_date_time=data[
                                         'creation_date_time'],
                                     processing_date=data['processing_date'],
                                     creation_title=data['creation_title'],
                                     submitter_creation_n=data[
                                         'submitter_creation_n'],
                                     recipient_creation_n=data[
                                         'recipient_creation_n'])


class AgreementDictionaryDecoder(Decoder):
    def __init__(self):
        super(AgreementDictionaryDecoder, self).__init__()

    def decode(self, data):
        return AgreementRecord(record_type=data['record_type'],
                               transaction_sequence_n=data[
                                   'transaction_sequence_n'],
                               record_sequence_n=data['record_sequence_n'],
                               submitter_agreement_n=data[
                                   'submitter_agreement_n'],
                               agreement_type=data['agreement_type'],
                               agreement_start_date=data[
                                   'agreement_start_date'],
                               prior_royalty_status=data[
                                   'prior_royalty_status'],
                               post_term_collection_status=data[
                                   'post_term_collection_status'],
                               number_of_works=data['number_of_works'],
                               society_assigned_agreement_n=data[
                                   'society_assigned_agreement_n'],
                               international_standard_code=data[
                                   'international_standard_code'],
                               sales_manufacture_clause=data[
                                   'sales_manufacture_clause'],
                               agreement_end_date=data['agreement_end_date'],
                               date_of_signature=data['date_of_signature'],
                               retention_end_date=data['retention_end_date'],
                               prior_royalty_start_date=data[
                                   'prior_royalty_start_date'],
                               post_term_collection_end_date=data[
                                   'post_term_collection_end_date'],
                               shares_change=data['shares_change'],
                               advance_given=data['advance_given'])


class AgreementTerritoryDictionaryDecoder(Decoder):
    def __init__(self):
        super(AgreementTerritoryDictionaryDecoder, self).__init__()

    def decode(self, data):
        return AgreementTerritoryRecord(record_type=data['record_type'],
                                        transaction_sequence_n=data[
                                            'transaction_sequence_n'],
                                        record_sequence_n=data[
                                            'record_sequence_n'],
                                        tis_numeric_code=data[
                                            'tis_numeric_code'],
                                        inclusion_exclusion_indicator=data[
                                            'inclusion_exclusion_indicator'])


class AdditionalRelatedInformationDictionaryDecoder(Decoder):
    def __init__(self):
        super(AdditionalRelatedInformationDictionaryDecoder, self).__init__()

    def decode(self, data):
        return AdditionalRelatedInfoRecord(record_type=data['record_type'],
                                           transaction_sequence_n=data[
                                               'transaction_sequence_n'],
                                           record_sequence_n=data[
                                               'record_sequence_n'],
                                           society_n=data['society_n'],
                                           type_of_right=data['type_of_right'],
                                           work_n=data['work_n'],
                                           subject_code=data['subject_code'],
                                           note=data['note'])


class AlternateTitleDictionaryDecoder(Decoder):
    def __init__(self):
        super(AlternateTitleDictionaryDecoder, self).__init__()

    def decode(self, data):
        return AlternateTitleRecord(record_type=data['record_type'],
                                    transaction_sequence_n=data[
                                        'transaction_sequence_n'],
                                    record_sequence_n=data['record_sequence_n'],
                                    alternate_title=data['alternate_title'],
                                    title_type=data['title_type'],
                                    language_code=data['language_code'])


class AuthoredWorkDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(AuthoredWorkDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        ipi_base_1 = self._ipi_base_decoder.decode(data[
                                                       'writer_1_ipi_base_n'])
        ipi_base_2 = self._ipi_base_decoder.decode(data[
                                                       'writer_2_ipi_base_n'])

        return AuthoredWorkRecord(record_type=data['record_type'],
                                  transaction_sequence_n=data[
                                      'transaction_sequence_n'],
                                  record_sequence_n=data['record_sequence_n'],
                                  title=data['title'],
                                  submitter_work_n=data['submitter_work_n'],
                                  writer_1_first_name=data[
                                      'writer_1_first_name'],
                                  writer_1_last_name=data['writer_1_last_name'],
                                  writer_2_first_name=data[
                                      'writer_2_first_name'],
                                  writer_2_last_name=data['writer_2_last_name'],
                                  writer_1_ipi_base_n=ipi_base_1,
                                  writer_1_ipi_name_n=data[
                                      'writer_1_ipi_name_n'],
                                  writer_2_ipi_base_n=ipi_base_2,
                                  writer_2_ipi_name_n=data[
                                      'writer_2_ipi_name_n'],
                                  source=data['source'],
                                  language_code=data['language_code'],
                                  iswc=data['iswc'])


class ComponentDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(ComponentDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        ipi_base_1 = self._ipi_base_decoder.decode(data['writer_1_ipi_base_n'])
        ipi_base_2 = self._ipi_base_decoder.decode(data['writer_2_ipi_base_n'])

        return ComponentRecord(record_type=data['record_type'],
                               transaction_sequence_n=data[
                                   'transaction_sequence_n'],
                               record_sequence_n=data['record_sequence_n'],
                               title=data['title'],
                               submitter_work_n=data['submitter_work_n'],
                               writer_1_last_name=data['writer_1_last_name'],
                               writer_1_first_name=data['writer_1_first_name'],
                               writer_2_last_name=data['writer_2_last_name'],
                               writer_2_first_name=data['writer_2_first_name'],
                               writer_1_ipi_base_n=ipi_base_1,
                               writer_1_ipi_name_n=data['writer_1_ipi_name_n'],
                               writer_2_ipi_base_n=ipi_base_2,
                               writer_2_ipi_name_n=data['writer_2_ipi_name_n'],
                               iswc=data['iswc'],
                               duration=data['duration'])


class GroupHeaderDictionaryDecoder(Decoder):
    def __init__(self):
        super(GroupHeaderDictionaryDecoder, self).__init__()

    def decode(self, data):
        return GroupHeader(record_type=data['record_type'],
                           group_id=data['group_id'],
                           transaction_type=data['transaction_type'],
                           version_number=data['version_number'],
                           batch_request_id=data['batch_request_id'])


class GroupTrailerDictionaryDecoder(Decoder):
    def __init__(self):
        super(GroupTrailerDictionaryDecoder, self).__init__()

    def decode(self, data):
        total_monetary_value = None
        if 'total_monetary_value' in data:
            total_monetary_value = data['total_monetary_value']

        currency_indicator = None
        if 'currency_indicator' in data:
            currency_indicator = data['currency_indicator']

        return GroupTrailer(record_type=data['record_type'],
                            group_id=data['group_id'],
                            transaction_count=data['transaction_count'],
                            record_count=data['record_count'],
                            currency_indicator=currency_indicator,
                            total_monetary_value=total_monetary_value,
                            )


class InterestedPartyForAgreementDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(InterestedPartyForAgreementDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        ipi_base = self._ipi_base_decoder.decode(data['ipi_base_n'])

        return InterestedPartyForAgreementRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            ip_n=data['ip_n'],
            ip_last_name=data['ip_last_name'],
            agreement_role_code=data['agreement_role_code'],
            ip_writer_first_name=data['ip_writer_first_name'],
            ipi_name_n=data['ipi_name_n'], ipi_base_n=ipi_base,
            pr_society=data['pr_society'], pr_share=data['pr_share'],
            mr_society=data['mr_society'], mr_share=data['mr_share'],
            sr_society=data['sr_society'], sr_share=data['sr_share'])


class IPTerritoryOfControlDictionaryDecoder(Decoder):
    def __init__(self):
        super(IPTerritoryOfControlDictionaryDecoder, self).__init__()

    def decode(self, data):
        record = IPTerritoryOfControlRecord(record_type=data['record_type'],
                                            transaction_sequence_n=data[
                                                'transaction_sequence_n'],
                                            record_sequence_n=data[
                                                'record_sequence_n'],
                                            ip_n=data['ip_n'],
                                            inclusion_exclusion_indicator=data[
                                                'inclusion_exclusion_indicator'],
                                            tis_numeric_code=data[
                                                'tis_numeric_code'],
                                            sequence_n=data['sequence_n'],
                                            pr_collection_share=data[
                                                'pr_collection_share'],
                                            mr_collection_share=data[
                                                'mr_collection_share'],
                                            shares_change=data['shares_change'])

        if 'sr_collection_share' in data:
            record.sr_collection_share = data['sr_collection_share']

        return record


class InstrumentationDetailDictionaryDecoder(Decoder):
    def __init__(self):
        super(InstrumentationDetailDictionaryDecoder, self).__init__()

    def decode(self, data):
        return InstrumentationDetailRecord(record_type=data['record_type'],
                                           transaction_sequence_n=data[
                                               'transaction_sequence_n'],
                                           record_sequence_n=data[
                                               'record_sequence_n'],
                                           instrument_code=data[
                                               'instrument_code'],
                                           number_players=data[
                                               'number_players'])


class InstrumentationSummaryDictionaryDecoder(Decoder):
    def __init__(self):
        super(InstrumentationSummaryDictionaryDecoder, self).__init__()

    def decode(self, data):
        return InstrumentationSummaryRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            number_voices=data['number_voices'],
            standard_instrumentation_type=data['standard_instrumentation_type'],
            instrumentation_description=data['instrumentation_description'])


class MessageDictionaryDecoder(Decoder):
    def __init__(self):
        super(MessageDictionaryDecoder, self).__init__()

    def decode(self, data):
        return MessageRecord(record_type=data['record_type'],
                             transaction_sequence_n=data[
                                 'transaction_sequence_n'],
                             record_sequence_n=data['record_sequence_n'],
                             message_type=data['message_type'],
                             message_text=data['message_text'],
                             original_record_sequence_n=data[
                                 'original_record_sequence_n'],
                             message_record_type=data['message_record_type'],
                             message_level=data['message_level'],
                             validation_n=data['validation_n'])


class PerformingArtistDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(PerformingArtistDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        ipi_base = None
        if 'performing_artist_ipi_base_n' in data:
            ipi_base = self._ipi_base_decoder.decode(data['performing_artist_ipi_base_n'])

        performing_artist_first_name = None
        if 'performing_artist_first_name' in data:
            performing_artist_first_name = data['performing_artist_first_name']

        performing_artist_ipi_name_n = None
        if 'performing_artist_ipi_name_n' in data:
            performing_artist_ipi_name_n = data['performing_artist_ipi_name_n']

        return PerformingArtistRecord(record_type=data['record_type'],
                                      transaction_sequence_n=data[
                                          'transaction_sequence_n'],
                                      record_sequence_n=data[
                                          'record_sequence_n'],
                                      performing_artist_last_name=data[
                                          'performing_artist_last_name'],
                                      performing_artist_first_name=performing_artist_first_name,
                                      performing_artist_ipi_name_n=performing_artist_ipi_name_n,
                                      performing_artist_ipi_base_n=ipi_base)


class PublisherForWriterDictionaryDecoder(Decoder):
    def __init__(self):
        super(PublisherForWriterDictionaryDecoder, self).__init__()

    def decode(self, data):
        publisher_name = None
        if 'publisher_name' in data:
            publisher_name = data['publisher_name']
        return PublisherForWriterRecord(record_type=data['record_type'],
                                        transaction_sequence_n=data[
                                            'transaction_sequence_n'],
                                        record_sequence_n=data[
                                            'record_sequence_n'],
                                        publisher_ip_n=data['publisher_ip_n'],
                                        publisher_name=publisher_name,
                                        writer_ip_n=data['writer_ip_n'],
                                        submitter_agreement_n=data[
                                            'submitter_agreement_n'],
                                        society_assigned_agreement_n=data[
                                            'society_assigned_agreement_n'])


class RecordingDetailDictionaryDecoder(Decoder):
    def __init__(self):
        super(RecordingDetailDictionaryDecoder, self).__init__()

    def decode(self, data):
        media_type = None
        if 'media_type' in data:
            media_type = data['media_type']

        return RecordingDetailRecord(record_type=data['record_type'],
                                     transaction_sequence_n=data[
                                         'transaction_sequence_n'],
                                     record_sequence_n=data[
                                         'record_sequence_n'],
                                     first_release_date=data[
                                         'first_release_date'],
                                     first_release_duration=data[
                                         'first_release_duration'],
                                     first_album_title=data[
                                         'first_album_title'],
                                     first_album_label=data[
                                         'first_album_label'],
                                     first_release_catalog_n=data[
                                         'first_release_catalog_n'],
                                     ean=data['ean'],
                                     isrc=data['isrc'],
                                     recording_format=data['recording_format'],
                                     recording_technique=data[
                                         'recording_technique'],
                                     media_type=media_type)


class FileDictionaryDecoder(Decoder):
    def __init__(self):
        super(FileDictionaryDecoder, self).__init__()

        self._tag_decoder = FileTagDictionaryDecoder()
        self._transmission_decoder = TransmissionDictionaryDecoder()

    def decode(self, data):
        tag = data['tag']
        if isinstance(tag, dict):
            tag = self._tag_decoder.decode(tag)

        transmission = data['transmission']
        if isinstance(transmission, dict):
            transmission = self._transmission_decoder.decode(transmission)

        return CWRFile(tag, transmission)


class TransmissionDictionaryDecoder(Decoder):
    def __init__(self):
        super(TransmissionDictionaryDecoder, self).__init__()

        self._header_decoder = TransmissionHeaderDictionaryDecoder()
        self._trailer_decoder = TransmissionTrailerDictionaryDecoder()
        self._group_decoder = GroupDictionaryDecoder()

    def decode(self, data):
        header = data['header']
        if isinstance(header, dict):
            header = self._header_decoder.decode(header)

        trailer = data['trailer']
        if isinstance(trailer, dict):
            trailer = self._trailer_decoder.decode(trailer)

        groups = []
        if len(data['groups']) > 0:
            if isinstance(data['groups'][0], dict):
                for group in data['groups']:
                    groups.append(self._group_decoder.decode(group))
            else:
                groups = data['groups']

        return Transmission(header, trailer, groups)


class GroupDictionaryDecoder(Decoder):
    def __init__(self):
        super(GroupDictionaryDecoder, self).__init__()

        self._header_decoder = GroupHeaderDictionaryDecoder()
        self._trailer_decoder = GroupTrailerDictionaryDecoder()
        self._transaction_decoder = TransactionRecordDictionaryDecoder()

    def decode(self, data):
        header = data['group_header']
        if isinstance(header, dict):
            header = self._header_decoder.decode(header)

        trailer = data['group_trailer']
        if isinstance(trailer, dict):
            trailer = self._trailer_decoder.decode(trailer)

        transactions = []
        if len(data['transactions']) > 0:
            if isinstance(data['transactions'][0][0], dict):
                for transaction in data['transactions']:
                    transaction_records = []
                    for record in transaction:
                        transaction_records.append(
                            self._transaction_decoder.decode(record))
                    transactions.append(transaction_records)
            else:
                transactions = data['transactions']

        return Group(header, trailer, transactions)


class TransmissionHeaderDictionaryDecoder(Decoder):
    def __init__(self):
        super(TransmissionHeaderDictionaryDecoder, self).__init__()

    def decode(self, data):
        header = TransmissionHeader(record_type=data['record_type'],
                                    sender_id=data['sender_id'],
                                    sender_name=data['sender_name'],
                                    sender_type=data['sender_type'],
                                    creation_date_time=data[
                                        'creation_date_time'],
                                    transmission_date=data['transmission_date'],
                                    edi_standard=data['edi_standard'])
        if 'character_set' in data:
            header.character_set = data['character_set']

        return header


class TransmissionTrailerDictionaryDecoder(Decoder):
    def __init__(self):
        super(TransmissionTrailerDictionaryDecoder, self).__init__()

    def decode(self, data):
        return TransmissionTrailer(record_type=data['record_type'],
                                   group_count=data['group_count'],
                                   transaction_count=data['transaction_count'],
                                   record_count=data['record_count'])


class WorkDictionaryDecoder(Decoder):
    def __init__(self):
        super(WorkDictionaryDecoder, self).__init__()

    def decode(self, data):

        catalogue_number = None
        if 'catalogue_number' in data:
            catalogue_number = data['catalogue_number']

        exceptional_clause = None
        if 'exceptional_clause' in data:
            exceptional_clause = data['exceptional_clause']

        opus_number = None
        if 'opus_number' in data:
            opus_number = data['opus_number']

        priority_flag = None
        if 'priority_flag' in data:
            priority_flag = data['priority_flag']

        return WorkRecord(record_type=data['record_type'],
                          transaction_sequence_n=data['transaction_sequence_n'],
                          record_sequence_n=data['record_sequence_n'],
                          submitter_work_n=data['submitter_work_n'],
                          title=data['title'],
                          version_type=data['version_type'],
                          musical_work_distribution_category=data[
                              'musical_work_distribution_category'],
                          date_publication_printed_edition=data[
                              'date_publication_printed_edition'],
                          text_music_relationship=data[
                              'text_music_relationship'],
                          language_code=data['language_code'],
                          copyright_number=data['copyright_number'],
                          copyright_date=data['copyright_date'],
                          music_arrangement=data['music_arrangement'],
                          lyric_adaptation=data['lyric_adaptation'],
                          excerpt_type=data['excerpt_type'],
                          composite_type=data['composite_type'],
                          composite_component_count=data[
                              'composite_component_count'],
                          iswc=data['iswc'],
                          work_type=data['work_type'],
                          duration=data['duration'],
                          catalogue_number=catalogue_number,
                          opus_number=opus_number,
                          contact_id=data['contact_id'],
                          contact_name=data['contact_name'],
                          recorded_indicator=data['recorded_indicator'],
                          priority_flag=priority_flag,
                          exceptional_clause=exceptional_clause,
                          grand_rights_indicator=data['grand_rights_indicator'])


class WorkOriginDictionaryDecoder(Decoder):
    def __init__(self):
        super(WorkOriginDictionaryDecoder, self).__init__()

    def decode(self, data):
        return WorkOriginRecord(record_type=data['record_type'],
                                transaction_sequence_n=data[
                                    'transaction_sequence_n'],
                                record_sequence_n=data['record_sequence_n'],
                                intended_purpose=data['intended_purpose'],
                                production_title=data['production_title'],
                                cd_identifier=data['cd_identifier'],
                                cut_number=data['cut_number'],
                                library=data['library'],
                                bltvr=data['bltvr'],
                                visan=data['visan'],
                                production_n=data['production_n'],
                                episode_title=data['episode_title'],
                                episode_n=data['episode_n'],
                                year_production=data['year_production'],
                                audio_visual_key=data['audio_visual_key'])


class WriterDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(WriterDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        ipi_base_n = self._ipi_base_decoder.decode(data['ipi_base_n'])

        return Writer(ip_n=data['ip_n'],
                      personal_number=data['personal_number'],
                      ipi_base_n=ipi_base_n,
                      writer_first_name=data['writer_first_name'],
                      writer_last_name=data['writer_last_name'],
                      tax_id=data['tax_id'],
                      ipi_name_n=data['ipi_name_n'])


class WriterRecordDictionaryDecoder(Decoder):
    def __init__(self):
        super(WriterRecordDictionaryDecoder, self).__init__()
        self._writer_decoder = WriterDictionaryDecoder()

    def decode(self, data):
        writer = self._writer_decoder.decode(data['writer'])

        usa_license = None
        if 'usa_license' in data:
            usa_license = data['usa_license']

        return WriterRecord(record_type=data['record_type'],
                            transaction_sequence_n=data[
                                'transaction_sequence_n'],
                            record_sequence_n=data['record_sequence_n'],
                            writer=writer,
                            writer_designation=data['writer_designation'],
                            work_for_hire=data['work_for_hire'],
                            writer_unknown=data['writer_unknown'],
                            reversionary=data['reversionary'],
                            first_recording_refusal=data[
                                'first_recording_refusal'],
                            usa_license=usa_license,
                            pr_society=data['pr_society'],
                            pr_ownership_share=data['pr_ownership_share'],
                            mr_society=data['mr_society'],
                            mr_ownership_share=data['mr_ownership_share'],
                            sr_society=data['sr_society'],
                            sr_ownership_share=data['sr_ownership_share'])


class NonRomanAlphabetAgreementPartyDictionaryDecoder(Decoder):
    def __init__(self):
        super(NonRomanAlphabetAgreementPartyDictionaryDecoder, self).__init__()

    def decode(self, data):
        return NonRomanAlphabetAgreementPartyRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            ip_name=data['ip_name'],
            ip_writer_name=data['ip_writer_name'],
            ip_n=data['ip_n'],
            language_code=data['language_code'])


class NonRomanAlphabetOtherWriterDictionaryDecoder(Decoder):
    def __init__(self):
        super(NonRomanAlphabetOtherWriterDictionaryDecoder, self).__init__()

    def decode(self, data):
        return NonRomanAlphabetOtherWriterRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            writer_first_name=data['writer_first_name'],
            writer_name=data['writer_name'],
            position=data['position'],
            language_code=data['language_code'])


class NonRomanAlphabetPerformanceDataDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(NonRomanAlphabetPerformanceDataDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        ipi_base = self._ipi_base_decoder.decode(
            data['performing_artist_ipi_base_n'])

        return NonRomanAlphabetPerformanceDataRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            performing_artist_first_name=data['performing_artist_first_name'],
            performing_artist_name=data['performing_artist_name'],
            performing_artist_ipi_name_n=data['performing_artist_ipi_name_n'],
            performing_artist_ipi_base_n=ipi_base,
            language_code=data['language_code'],
            performance_language=data['performance_language'],
            performance_dialect=data['performance_dialect'])


class NonRomanAlphabetPublisherNameDictionaryDecoder(Decoder):
    def __init__(self):
        super(NonRomanAlphabetPublisherNameDictionaryDecoder, self).__init__()

    def decode(self, data):
        return NonRomanAlphabetPublisherNameRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            publisher_sequence_n=data['publisher_sequence_n'],
            ip_n=data['ip_n'],
            publisher_name=data['publisher_name'],
            language_code=data['language_code'])


class NonRomanAlphabetTitleDictionaryDecoder(Decoder):
    def __init__(self):
        super(NonRomanAlphabetTitleDictionaryDecoder, self).__init__()

    def decode(self, data):
        return NonRomanAlphabetTitleRecord(record_type=data['record_type'],
                                           transaction_sequence_n=data[
                                               'transaction_sequence_n'],
                                           record_sequence_n=data[
                                               'record_sequence_n'],
                                           title=data['title'],
                                           title_type=data['title_type'],
                                           language_code=data['language_code'])


class NonRomanAlphabetWorkDictionaryDecoder(Decoder):
    def __init__(self):
        super(NonRomanAlphabetWorkDictionaryDecoder, self).__init__()

    def decode(self, data):
        return NonRomanAlphabetWorkRecord(record_type=data['record_type'],
                                          transaction_sequence_n=data[
                                              'transaction_sequence_n'],
                                          record_sequence_n=data[
                                              'record_sequence_n'],
                                          title=data['title'],
                                          language_code=data['language_code'])


class NonRomanAlphabetWriterNameDictionaryDecoder(Decoder):
    def __init__(self):
        super(NonRomanAlphabetWriterNameDictionaryDecoder, self).__init__()

    def decode(self, data):
        return NonRomanAlphabetWriterNameRecord(record_type=data['record_type'],
                                                transaction_sequence_n=data[
                                                    'transaction_sequence_n'],
                                                record_sequence_n=data[
                                                    'record_sequence_n'],
                                                writer_first_name=data[
                                                    'writer_first_name'],
                                                writer_last_name=data[
                                                    'writer_last_name'],
                                                ip_n=data['ip_n'],
                                                language_code=data[
                                                    'language_code'])


class PublisherDictionaryDecoder(Decoder):
    def __init__(self, ipi_base_decoder=None):
        super(PublisherDictionaryDecoder, self).__init__()

        if ipi_base_decoder:
            self._ipi_base_decoder = ipi_base_decoder
        else:
            self._ipi_base_decoder = IPIBaseDictionaryDecoder()

    def decode(self, data):
        if 'ipi_base_n' in data:
            ipi_base = self._ipi_base_decoder.decode(data['ipi_base_n'])
        else:
            ipi_base = None

        return Publisher(ip_n=data['ip_n'],
                         publisher_name=data['publisher_name'],
                         ipi_name_n=data['ipi_name_n'],
                         ipi_base_n=ipi_base,
                         tax_id=data['tax_id'])


class PublisherRecordDictionaryDecoder(Decoder):
    def __init__(self):
        super(PublisherRecordDictionaryDecoder, self).__init__()
        self._publisher_decoder = PublisherDictionaryDecoder()

    def decode(self, data):
        publisher = self._publisher_decoder.decode(data['publisher'])

        special_agreements = None
        if 'special_agreements' in data:
            special_agreements = data['special_agreements']

        first_recording_refusal = None
        if 'first_recording_refusal' in data:
            first_recording_refusal = data['first_recording_refusal']

        agreement_type = None
        if 'agreement_type' in data:
            agreement_type = data['agreement_type']

        usa_license = None
        if 'usa_license' in data:
            usa_license = data['usa_license']

        international_standard_code = None
        if 'international_standard_code' in data:
            international_standard_code = data['international_standard_code']

        society_assigned_agreement_n = None
        if 'society_assigned_agreement_n' in data:
            society_assigned_agreement_n = data['society_assigned_agreement_n']

        return PublisherRecord(
            record_type=data['record_type'],
            transaction_sequence_n=data['transaction_sequence_n'],
            record_sequence_n=data['record_sequence_n'],
            publisher=publisher,
            publisher_sequence_n=data['publisher_sequence_n'],
            submitter_agreement_n=data['submitter_agreement_n'],
            publisher_type=data['publisher_type'],
            publisher_unknown=data['publisher_unknown'],
            pr_society=data['pr_society'],
            pr_ownership_share=data['pr_ownership_share'],
            mr_society=data['mr_society'],
            mr_ownership_share=data['mr_ownership_share'],
            sr_society=data['sr_society'],
            sr_ownership_share=data['sr_ownership_share'],
            special_agreements=special_agreements,
            first_recording_refusal=first_recording_refusal,
            international_standard_code=international_standard_code,
            society_assigned_agreement_n=society_assigned_agreement_n,
            agreement_type=agreement_type,
            usa_license=usa_license)


class TableValueDictionaryDecoder(Decoder):
    def __init__(self):
        super(TableValueDictionaryDecoder, self).__init__()

    def decode(self, data):
        return TableValue(code=data['code'],
                          name=data['name'],
                          description=data['description'])


class MediaTypeValueDictionaryDecoder(Decoder):
    def __init__(self):
        super(MediaTypeValueDictionaryDecoder, self).__init__()

    def decode(self, data):
        return MediaTypeValue(code=data['code'],
                              name=data['name'],
                              media_type=data['media_type'],
                              duration_max=data['duration_max'],
                              works_max=data['works_max'],
                              fragments_max=data['fragments_max'])


class InstrumentValueDictionaryDecoder(Decoder):
    def __init__(self):
        super(InstrumentValueDictionaryDecoder, self).__init__()

    def decode(self, data):
        return InstrumentValue(code=data['code'],
                               name=data['name'],
                               family=data['family'],
                               description=data['description'])


class FileTagDictionaryDecoder(Decoder):
    def __init__(self):
        super(FileTagDictionaryDecoder, self).__init__()

    def decode(self, data):
        return FileTag(data['year'],
                       data['sequence_n'],
                       data['sender'],
                       data['receiver'],
                       data['version'])


class AVIKeyDictionaryDecoder(Decoder):
    def __init__(self):
        super(AVIKeyDictionaryDecoder, self).__init__()

    def decode(self, data):
        return AVIKey(data['society_code'],
                      data['av_number'])


class IPIBaseDictionaryDecoder(Decoder):
    def __init__(self):
        super(IPIBaseDictionaryDecoder, self).__init__()

    def decode(self, data):
        if data:
            result = data
        else:
            result = None

        return result


class ISWCDictionaryDecoder(Decoder):
    def __init__(self):
        super(ISWCDictionaryDecoder, self).__init__()

    def decode(self, data):
        if data:
            result = data
        else:
            result = None

        return result


class VISANDictionaryDecoder(Decoder):
    def __init__(self):
        super(VISANDictionaryDecoder, self).__init__()

    def decode(self, data):
        return data

[(97, 'cwr.acknowledgement.AcknowledgementRecord', 'AcknowledgementRecord', False, 'from cwr.acknowledgement import AcknowledgementRecord, MessageRecord\n'), (125, 'cwr.agreement.AgreementRecord', 'AgreementRecord', False, 'from cwr.agreement import AgreementRecord, AgreementTerritoryRecord, InterestedPartyForAgreementRecord\n'), (161, 'cwr.agreement.AgreementTerritoryRecord', 'AgreementTerritoryRecord', False, 'from cwr.agreement import AgreementRecord, AgreementTerritoryRecord, InterestedPartyForAgreementRecord\n'), (177, 'cwr.info.AdditionalRelatedInfoRecord', 'AdditionalRelatedInfoRecord', False, 'from cwr.info import AdditionalRelatedInfoRecord\n'), (194, 'cwr.work.AlternateTitleRecord', 'AlternateTitleRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (218, 'cwr.work.AuthoredWorkRecord', 'AuthoredWorkRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (254, 'cwr.work.ComponentRecord', 'ComponentRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (277, 'cwr.group.GroupHeader', 'GroupHeader', False, 'from cwr.group import Group, GroupHeader, GroupTrailer\n'), (297, 'cwr.group.GroupTrailer', 'GroupTrailer', False, 'from cwr.group import Group, GroupHeader, GroupTrailer\n'), (318, 'cwr.agreement.InterestedPartyForAgreementRecord', 'InterestedPartyForAgreementRecord', False, 'from cwr.agreement import AgreementRecord, AgreementTerritoryRecord, InterestedPartyForAgreementRecord\n'), (337, 'cwr.interested_party.IPTerritoryOfControlRecord', 'IPTerritoryOfControlRecord', False, 'from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord\n'), (365, 'cwr.work.InstrumentationDetailRecord', 'InstrumentationDetailRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (381, 'cwr.work.InstrumentationSummaryRecord', 'InstrumentationSummaryRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (395, 'cwr.acknowledgement.MessageRecord', 'MessageRecord', False, 'from cwr.acknowledgement import AcknowledgementRecord, MessageRecord\n'), (430, 'cwr.work.PerformingArtistRecord', 'PerformingArtistRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (450, 'cwr.interested_party.PublisherForWriterRecord', 'PublisherForWriterRecord', False, 'from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord\n'), (473, 'cwr.work.RecordingDetailRecord', 'RecordingDetailRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (512, 'cwr.file.CWRFile', 'CWRFile', False, 'from cwr.file import CWRFile, FileTag\n'), (540, 'cwr.transmission.Transmission', 'Transmission', False, 'from cwr.transmission import Transmission, TransmissionTrailer, TransmissionHeader\n'), (572, 'cwr.group.Group', 'Group', False, 'from cwr.group import Group, GroupHeader, GroupTrailer\n'), (580, 'cwr.transmission.TransmissionHeader', 'TransmissionHeader', False, 'from cwr.transmission import Transmission, TransmissionTrailer, TransmissionHeader\n'), (599, 'cwr.transmission.TransmissionTrailer', 'TransmissionTrailer', False, 'from cwr.transmission import Transmission, TransmissionTrailer, TransmissionHeader\n'), (627, 'cwr.work.WorkRecord', 'WorkRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (666, 'cwr.work.WorkOriginRecord', 'WorkOriginRecord', False, 'from cwr.work import RecordingDetailRecord, ComponentRecord, AlternateTitleRecord, AuthoredWorkRecord, InstrumentationDetailRecord, InstrumentationSummaryRecord, PerformingArtistRecord, WorkOriginRecord, WorkRecord\n'), (696, 'cwr.interested_party.Writer', 'Writer', False, 'from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord\n'), (717, 'cwr.interested_party.WriterRecord', 'WriterRecord', False, 'from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord\n'), (742, 'cwr.non_roman_alphabet.NonRomanAlphabetAgreementPartyRecord', 'NonRomanAlphabetAgreementPartyRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (757, 'cwr.non_roman_alphabet.NonRomanAlphabetOtherWriterRecord', 'NonRomanAlphabetOtherWriterRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (780, 'cwr.non_roman_alphabet.NonRomanAlphabetPerformanceDataRecord', 'NonRomanAlphabetPerformanceDataRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (798, 'cwr.non_roman_alphabet.NonRomanAlphabetPublisherNameRecord', 'NonRomanAlphabetPublisherNameRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (813, 'cwr.non_roman_alphabet.NonRomanAlphabetTitleRecord', 'NonRomanAlphabetTitleRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (828, 'cwr.non_roman_alphabet.NonRomanAlphabetWorkRecord', 'NonRomanAlphabetWorkRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (842, 'cwr.non_roman_alphabet.NonRomanAlphabetWriterNameRecord', 'NonRomanAlphabetWriterNameRecord', False, 'from cwr.non_roman_alphabet import NonRomanAlphabetAgreementPartyRecord, NonRomanAlphabetOtherWriterRecord, NonRomanAlphabetPerformanceDataRecord, NonRomanAlphabetPublisherNameRecord, NonRomanAlphabetTitleRecord, NonRomanAlphabetWorkRecord, NonRomanAlphabetWriterNameRecord\n'), (871, 'cwr.interested_party.Publisher', 'Publisher', False, 'from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord\n'), (910, 'cwr.interested_party.PublisherRecord', 'PublisherRecord', False, 'from cwr.interested_party import IPTerritoryOfControlRecord, Publisher, PublisherRecord, Writer, PublisherForWriterRecord, WriterRecord\n'), (938, 'cwr.table_value.TableValue', 'TableValue', False, 'from cwr.table_value import MediaTypeValue, TableValue, InstrumentValue\n'), (948, 'cwr.table_value.MediaTypeValue', 'MediaTypeValue', False, 'from cwr.table_value import MediaTypeValue, TableValue, InstrumentValue\n'), (961, 'cwr.table_value.InstrumentValue', 'InstrumentValue', False, 'from cwr.table_value import MediaTypeValue, TableValue, InstrumentValue\n'), (972, 'cwr.file.FileTag', 'FileTag', False, 'from cwr.file import CWRFile, FileTag\n'), (984, 'cwr.other.AVIKey', 'AVIKey', False, 'from cwr.other import AVIKey, VISAN\n')]