from django.core.validators import RegexValidator
from django.db import models


# TODO for int'l
# Update phone to 20
# Update state to "state/providence/region"


class Address(models.Model):

    COUNTRIES = (
        ('US', 'United States'),
        ('MX', 'Mexico'),
        ('PR', 'Puerto Rico'),
    )

    address_line_1 = models.CharField(max_length=60)
    address_line_2 = models.CharField(max_length=60, blank=True, null=True)
    city = models.CharField(max_length=50)
    state = models.CharField(max_length=50)  # "state/providence/region"
    postal_code = models.CharField(max_length=20)
    country = models.CharField(max_length=100, choices=COUNTRIES, default='US')

    def __str__(self):
        state_line = self.city + ', ' + self.state + ' ' + self.postal_code
        address = (
            self.address_line_1,
            self.address_line_2,
            state_line,
            self.country
        )
        return ', '.join(address)

    def as_json(self):

        return dict(
            address_line_1=self.address_line_1,
            address_line_2=self.address_line_2,
            city=self.city,
            state=self.state,
            postal_code=self.postal_code,
            country=self.country,
        )


class EPAEntity(models.Model):

    sig_statement_default = "I hereby declare that the contents \
        of this consignment are fully and \
        accurately described above by the proper shipping name, and are \
        classified, packaged, marked and labeled/placarded, and are in all \
        respects in proper condition for transport according to applicable \
        international and national governmental regulations. If export \
        shipment and I am the Primary Exporter, I certify that the \
        contents of this consignment conform to the terms of the \
        attached EPA Acknowledgment of Consent. I certify that the waste \
        minimization statement identified in 40 CFR 262.27(a) (if I am a \
        large quantity generator) or (b) (if I am a small quantity \
        generator) is true."

    name = models.CharField(max_length=200)

    # TODO: EPA ID: XXX123456789
    epa_id = models.CharField(max_length=200)

    # TODO: Validate address & phone for designated facility
    address = models.ForeignKey('Address', null=True, blank=True)
    phone = models.CharField(max_length=12, null=True, blank=True)

    signature_name = models.CharField(max_length=200, null=True, blank=True)
    certification_statments = models.TextField(default=sig_statement_default,
                                               null=True, blank=True)
    signature_date = models.DateField(null=True, blank=True)
    signature = models.CharField(max_length=200, null=True, blank=True)

    def __str__(self):
        return ', '.join([self.name, self.epa_id])

    def as_json(self):
        try:
            address = self.address.as_json()
        except AttributeError:
            address = {}

        return dict(
            name=self.name,
            phone=self.phone,
            address=address,
            epa_id=self.epa_id,
        )


# The way that addresses are handled here should be thought out better.
# This is a quick hack for demo purposes.
class Generator(models.Model):
    name = models.CharField(max_length=40)
    phone = models.CharField(max_length=12)
    address = models.ForeignKey('Address')
    mailing_address = models.ForeignKey('Address',
                                        related_name='mailing_address',
                                        null=True, blank=True)
    mailing_and_address_same = models.BooleanField()

    def as_json(self):
        address = self.address.as_json()
        mailing_address = self.mailing_address.as_json()

        return dict(
            name=self.name,
            phone=self.phone,
            address=address,
            mailing_and_address_are_the_same=self.mailing_and_address_same,
            mailing_address=mailing_address,
        )


class International(models.Model):  # 16
    import_to_us = models.BooleanField()
    export_from_us = models.BooleanField()
    port = models.CharField(max_length=200)
    date_at_port = models.DateField()
    # transporter_signature = ??

    def as_json(self):

        international_dict = dict(
            import_to_us=self.import_to_us,
            export_to_us=self.export_to_us,
            port=self.port,
            date_at_port=self.date_at_port,
        )

        print(type(international_dict))

        return international_dict


class Manifest(models.Model):
    # "ManifestTrackingNumber":"3 Letters  9 numbers",
    tracking_number = models.CharField(max_length=12)  # 4

    generator = models.ForeignKey('Generator')  # 1

    # TODO: How to validate -- emergency numbers internationally?
    # django local flavor -- validate the number by locality
    # "23 alphanumberic string accounting for international numbers
    # e.g. +001 1234321234, to be honest this is just a safety feature,
    # most will be standard 10 digit"
    # # 3
    phone_help = "Phone number 9-15 digits, entered in the format: '999999999'"
    phone_regex = RegexValidator(regex=r'^\d{9,15}$', message=phone_help)
    emergency_phone = models.CharField(validators=[phone_regex], max_length=15)

    international = models.ForeignKey('International', null=True, blank=True)
    designated_facility = models.ForeignKey('EPAEntity')  # 'DesinatedFacility'

    special_instructions = models.TextField(blank=True)
    # TODO: Compare these to sample data. Can we parse at this time?
    # special handling -- TextField
    # tracking instructions -- TextField
    # waste profile number -- 9 Charater pattern value=([0-9])+
    # container number -- 20 char
    # response guide number - 4 Alphanumeric pattern value=[0-9,a-z,A-Z](0-9)+

    # This is included, b/c maybe it could be used as a way to validate
    number_of_pages = models.IntegerField()  # 2

    def __str__(self):
        return self.tracking_number

    def as_json(self):
        generator = self.generator.as_json()

        try:
            international = self.international.as_json()
        except AttributeError:
            international = {}

        designated_facility = self.designated_facility.as_json()

        transporters = Transporter.objects.filter(manifest_id=self.id)
        transporters = [t.transporter.as_json() for t in transporters]

        waste = ManifestedWaste.objects.filter(manifest_id=self.id)
        print(waste)
        waste = [w.as_json() for w in waste]

        return dict(
            tracking_number=self.tracking_number,
            generator=generator,
            emergency_phone=self.emergency_phone,
            international=international,
            designated_facility=designated_facility,
            special_instructions=self.special_instructions,
            number_of_pages=self.number_of_pages,
            transporters=transporters,
            waste=waste,
        )


class Transporter(models.Model):
    manifest = models.ForeignKey('Manifest')  # 6, 7
    transporter = models.ForeignKey('EPAEntity')  # "transporter"
    # aknowledgement_name = models.CharField(max_length=200)
    # aknowledgement = ?? signature
    # aknowledgement_date = models.DateField()


class WasteCode(models.Model):
    WASTE_CODE_TYPES = (
        ('Federal', 'Federal'),
        ('State', 'State'),
    )

    # if the code is federal then max length = 4
    # if the code it state, then max length = 8
    code = models.CharField(max_length=10, null=True, blank=True)
    code_type = models.CharField(max_length=10, choices=WASTE_CODE_TYPES)

    def as_json(self):

        return dict(
            code=self.code,
            code_type=self.code_type,
        )


class ManifestedWaste(models.Model):

    DOT_GROUPS = (
        ("", "None"),
        ("I", "I"),
        ("II", "II"),
        ("III", "III"),
    )

    CONTAINER_TYPES = (
        ("BA", "Burlap, cloth, paper, or plastic bags"),
        ("CF", "Fiber or plastic boxes, cartons, cases"),
        ("CM", "Metal boxes, cartons, cases (including roll-offs"),
        ("CW", "Wooden boxes, cartons, cases"),
        ("CY", "Cylinders"),
        ("DF", "Fiberboard or plastic drums, barrels, kegs"),
        ("DM", "Metal drums, barrels, kegs"),
        ("DW", "Wooden drums, barrels, kegs"),
        ("HG", "Hopper or gondola cars"),
        ("TC", "Tank cars"),
        ("TP", "Portable tanks"),
        ("TT", "Cargo tanks (tank trucks)."),
    )

    UNITS_OF_MEASURE = (
        ("G", "Gallons (liquids only)"),
        ("N", "Cubic Meters"),
        ("K", "Kilograms P = Pounds"),
        ("L", "Liters (liquids only)"),
        ("T", "Tons (2000 Pounds)"),
        ("M", "Metric Tons (1000 Kilograms)"),
        ("Y", "Cubic Yards"),
    )

    manifest = models.ForeignKey('Manifest')

    hazardous_waste = models.BooleanField()  # 9a HM
    # description = models.TextField(null=True, blank=True)
    dot_description = models.TextField(null=True, blank=True)
    dot_shipping_name = models.CharField(max_length=255, null=True, blank=True)
    dot_hazard_class = models.CharField(max_length=300, null=True, blank=True)
    dot_id = models.CharField(max_length=6, null=True, blank=True)
    dot_packing_group = models.CharField(max_length=6, choices=DOT_GROUPS,
                                         blank=True, default='')

    # (including Proper Shipping Name, Hazard Class, ID Number, and
    # Packing Group (if any))

    container_quantity = models.IntegerField()
    container_type = models.CharField(max_length=2, choices=CONTAINER_TYPES)

    total_quantity = models.IntegerField()      # total quantity # 11
    units_of_measure = models.CharField(max_length=1, choices=UNITS_OF_MEASURE)
    # 12

    waste_codes = models.ForeignKey('WasteCode', null=True, blank=True)  # 13

    def as_json(self):
        waste_codes = self.waste_codes.as_json()

        description = dict(
            description=self.dot_description,
            shipping_name=self.dot_shipping_name,
            hazard_class=self.dot_hazard_class,
            dot_id=self.dot_id,
            packing_group=self.dot_packing_group,
        )

        return dict(
            hazardous_waste=self.hazardous_waste,
            dot_description=description,
            container_quantity=self.container_quantity,
            container_type=self.container_type,
            total_quantity=self.total_quantity,
            units_of_measure=self.units_of_measure,
            waste_codes=waste_codes,
        )

4cc320492342119f12c43b4c5f1021a583a097a2
<mask token>


class International(models.Model):
    <mask token>
    <mask token>
    <mask token>
    <mask token>

    def as_json(self):
        international_dict = dict(import_to_us=self.import_to_us,
            export_to_us=self.export_to_us, port=self.port, date_at_port=
            self.date_at_port)
        print(type(international_dict))
        return international_dict


class Manifest(models.Model):
    tracking_number = models.CharField(max_length=12)
    generator = models.ForeignKey('Generator')
    phone_help = "Phone number 9-15 digits, entered in the format: '999999999'"
    phone_regex = RegexValidator(regex='^\\d{9,15}$', message=phone_help)
    emergency_phone = models.CharField(validators=[phone_regex], max_length=15)
    international = models.ForeignKey('International', null=True, blank=True)
    designated_facility = models.ForeignKey('EPAEntity')
    special_instructions = models.TextField(blank=True)
    number_of_pages = models.IntegerField()

    def __str__(self):
        return self.tracking_number

    def as_json(self):
        generator = self.generator.as_json()
        try:
            international = self.international.as_json()
        except AttributeError:
            international = {}
        designated_facility = self.designated_facility.as_json()
        transporters = Transporter.objects.filter(manifest_id=self.id)
        transporters = [t.transporter.as_json() for t in transporters]
        waste = ManifestedWaste.objects.filter(manifest_id=self.id)
        print(waste)
        waste = [w.as_json() for w in waste]
        return dict(tracking_number=self.tracking_number, generator=
            generator, emergency_phone=self.emergency_phone, international=
            international, designated_facility=designated_facility,
            special_instructions=self.special_instructions, number_of_pages
            =self.number_of_pages, transporters=transporters, waste=waste)


class Transporter(models.Model):
    manifest = models.ForeignKey('Manifest')
    transporter = models.ForeignKey('EPAEntity')


class WasteCode(models.Model):
    WASTE_CODE_TYPES = ('Federal', 'Federal'), ('State', 'State')
    code = models.CharField(max_length=10, null=True, blank=True)
    code_type = models.CharField(max_length=10, choices=WASTE_CODE_TYPES)

    def as_json(self):
        return dict(code=self.code, code_type=self.code_type)


class ManifestedWaste(models.Model):
    DOT_GROUPS = ('', 'None'), ('I', 'I'), ('II', 'II'), ('III', 'III')
    CONTAINER_TYPES = ('BA', 'Burlap, cloth, paper, or plastic bags'), ('CF',
        'Fiber or plastic boxes, cartons, cases'), ('CM',
        'Metal boxes, cartons, cases (including roll-offs'), ('CW',
        'Wooden boxes, cartons, cases'), ('CY', 'Cylinders'), ('DF',
        'Fiberboard or plastic drums, barrels, kegs'), ('DM',
        'Metal drums, barrels, kegs'), ('DW', 'Wooden drums, barrels, kegs'), (
        'HG', 'Hopper or gondola cars'), ('TC', 'Tank cars'), ('TP',
        'Portable tanks'), ('TT', 'Cargo tanks (tank trucks).')
    UNITS_OF_MEASURE = ('G', 'Gallons (liquids only)'), ('N', 'Cubic Meters'
        ), ('K', 'Kilograms P = Pounds'), ('L', 'Liters (liquids only)'), ('T',
        'Tons (2000 Pounds)'), ('M', 'Metric Tons (1000 Kilograms)'), ('Y',
        'Cubic Yards')
    manifest = models.ForeignKey('Manifest')
    hazardous_waste = models.BooleanField()
    dot_description = models.TextField(null=True, blank=True)
    dot_shipping_name = models.CharField(max_length=255, null=True, blank=True)
    dot_hazard_class = models.CharField(max_length=300, null=True, blank=True)
    dot_id = models.CharField(max_length=6, null=True, blank=True)
    dot_packing_group = models.CharField(max_length=6, choices=DOT_GROUPS,
        blank=True, default='')
    container_quantity = models.IntegerField()
    container_type = models.CharField(max_length=2, choices=CONTAINER_TYPES)
    total_quantity = models.IntegerField()
    units_of_measure = models.CharField(max_length=1, choices=UNITS_OF_MEASURE)
    waste_codes = models.ForeignKey('WasteCode', null=True, blank=True)

    def as_json(self):
        waste_codes = self.waste_codes.as_json()
        description = dict(description=self.dot_description, shipping_name=
            self.dot_shipping_name, hazard_class=self.dot_hazard_class,
            dot_id=self.dot_id, packing_group=self.dot_packing_group)
        return dict(hazardous_waste=self.hazardous_waste, dot_description=
            description, container_quantity=self.container_quantity,
            container_type=self.container_type, total_quantity=self.
            total_quantity, units_of_measure=self.units_of_measure,
            waste_codes=waste_codes)

<mask token>


class Generator(models.Model):
    name = models.CharField(max_length=40)
    phone = models.CharField(max_length=12)
    address = models.ForeignKey('Address')
    mailing_address = models.ForeignKey('Address', related_name=
        'mailing_address', null=True, blank=True)
    mailing_and_address_same = models.BooleanField()

    def as_json(self):
        address = self.address.as_json()
        mailing_address = self.mailing_address.as_json()
        return dict(name=self.name, phone=self.phone, address=address,
            mailing_and_address_are_the_same=self.mailing_and_address_same,
            mailing_address=mailing_address)


class International(models.Model):
    import_to_us = models.BooleanField()
    export_from_us = models.BooleanField()
    port = models.CharField(max_length=200)
    date_at_port = models.DateField()

    def as_json(self):
        international_dict = dict(import_to_us=self.import_to_us,
            export_to_us=self.export_to_us, port=self.port, date_at_port=
            self.date_at_port)
        print(type(international_dict))
        return international_dict


class Manifest(models.Model):
    tracking_number = models.CharField(max_length=12)
    generator = models.ForeignKey('Generator')
    phone_help = "Phone number 9-15 digits, entered in the format: '999999999'"
    phone_regex = RegexValidator(regex='^\\d{9,15}$', message=phone_help)
    emergency_phone = models.CharField(validators=[phone_regex], max_length=15)
    international = models.ForeignKey('International', null=True, blank=True)
    designated_facility = models.ForeignKey('EPAEntity')
    special_instructions = models.TextField(blank=True)
    number_of_pages = models.IntegerField()

    def __str__(self):
        return self.tracking_number

    def as_json(self):
        generator = self.generator.as_json()
        try:
            international = self.international.as_json()
        except AttributeError:
            international = {}
        designated_facility = self.designated_facility.as_json()
        transporters = Transporter.objects.filter(manifest_id=self.id)
        transporters = [t.transporter.as_json() for t in transporters]
        waste = ManifestedWaste.objects.filter(manifest_id=self.id)
        print(waste)
        waste = [w.as_json() for w in waste]
        return dict(tracking_number=self.tracking_number, generator=
            generator, emergency_phone=self.emergency_phone, international=
            international, designated_facility=designated_facility,
            special_instructions=self.special_instructions, number_of_pages
            =self.number_of_pages, transporters=transporters, waste=waste)


class Transporter(models.Model):
    manifest = models.ForeignKey('Manifest')
    transporter = models.ForeignKey('EPAEntity')


class WasteCode(models.Model):
    WASTE_CODE_TYPES = ('Federal', 'Federal'), ('State', 'State')
    code = models.CharField(max_length=10, null=True, blank=True)
    code_type = models.CharField(max_length=10, choices=WASTE_CODE_TYPES)

    def as_json(self):
        return dict(code=self.code, code_type=self.code_type)


class ManifestedWaste(models.Model):
    DOT_GROUPS = ('', 'None'), ('I', 'I'), ('II', 'II'), ('III', 'III')
    CONTAINER_TYPES = ('BA', 'Burlap, cloth, paper, or plastic bags'), ('CF',
        'Fiber or plastic boxes, cartons, cases'), ('CM',
        'Metal boxes, cartons, cases (including roll-offs'), ('CW',
        'Wooden boxes, cartons, cases'), ('CY', 'Cylinders'), ('DF',
        'Fiberboard or plastic drums, barrels, kegs'), ('DM',
        'Metal drums, barrels, kegs'), ('DW', 'Wooden drums, barrels, kegs'), (
        'HG', 'Hopper or gondola cars'), ('TC', 'Tank cars'), ('TP',
        'Portable tanks'), ('TT', 'Cargo tanks (tank trucks).')
    UNITS_OF_MEASURE = ('G', 'Gallons (liquids only)'), ('N', 'Cubic Meters'
        ), ('K', 'Kilograms P = Pounds'), ('L', 'Liters (liquids only)'), ('T',
        'Tons (2000 Pounds)'), ('M', 'Metric Tons (1000 Kilograms)'), ('Y',
        'Cubic Yards')
    manifest = models.ForeignKey('Manifest')
    hazardous_waste = models.BooleanField()
    dot_description = models.TextField(null=True, blank=True)
    dot_shipping_name = models.CharField(max_length=255, null=True, blank=True)
    dot_hazard_class = models.CharField(max_length=300, null=True, blank=True)
    dot_id = models.CharField(max_length=6, null=True, blank=True)
    dot_packing_group = models.CharField(max_length=6, choices=DOT_GROUPS,
        blank=True, default='')
    container_quantity = models.IntegerField()
    container_type = models.CharField(max_length=2, choices=CONTAINER_TYPES)
    total_quantity = models.IntegerField()
    units_of_measure = models.CharField(max_length=1, choices=UNITS_OF_MEASURE)
    waste_codes = models.ForeignKey('WasteCode', null=True, blank=True)

    def as_json(self):
        waste_codes = self.waste_codes.as_json()
        description = dict(description=self.dot_description, shipping_name=
            self.dot_shipping_name, hazard_class=self.dot_hazard_class,
            dot_id=self.dot_id, packing_group=self.dot_packing_group)
        return dict(hazardous_waste=self.hazardous_waste, dot_description=
            description, container_quantity=self.container_quantity,
            container_type=self.container_type, total_quantity=self.
            total_quantity, units_of_measure=self.units_of_measure,
            waste_codes=waste_codes)

<mask token>


class EPAEntity(models.Model):
    sig_statement_default = (
        'I hereby declare that the contents         of this consignment are fully and         accurately described above by the proper shipping name, and are         classified, packaged, marked and labeled/placarded, and are in all         respects in proper condition for transport according to applicable         international and national governmental regulations. If export         shipment and I am the Primary Exporter, I certify that the         contents of this consignment conform to the terms of the         attached EPA Acknowledgment of Consent. I certify that the waste         minimization statement identified in 40 CFR 262.27(a) (if I am a         large quantity generator) or (b) (if I am a small quantity         generator) is true.'
        )
    name = models.CharField(max_length=200)
    epa_id = models.CharField(max_length=200)
    address = models.ForeignKey('Address', null=True, blank=True)
    phone = models.CharField(max_length=12, null=True, blank=True)
    signature_name = models.CharField(max_length=200, null=True, blank=True)
    certification_statments = models.TextField(default=
        sig_statement_default, null=True, blank=True)
    signature_date = models.DateField(null=True, blank=True)
    signature = models.CharField(max_length=200, null=True, blank=True)

    def __str__(self):
        return ', '.join([self.name, self.epa_id])

    def as_json(self):
        try:
            address = self.address.as_json()
        except AttributeError:
            address = {}
        return dict(name=self.name, phone=self.phone, address=address,
            epa_id=self.epa_id)


class Generator(models.Model):
    name = models.CharField(max_length=40)
    phone = models.CharField(max_length=12)
    address = models.ForeignKey('Address')
    mailing_address = models.ForeignKey('Address', related_name=
        'mailing_address', null=True, blank=True)
    mailing_and_address_same = models.BooleanField()

    def as_json(self):
        address = self.address.as_json()
        mailing_address = self.mailing_address.as_json()
        return dict(name=self.name, phone=self.phone, address=address,
            mailing_and_address_are_the_same=self.mailing_and_address_same,
            mailing_address=mailing_address)


class International(models.Model):
    import_to_us = models.BooleanField()
    export_from_us = models.BooleanField()
    port = models.CharField(max_length=200)
    date_at_port = models.DateField()

    def as_json(self):
        international_dict = dict(import_to_us=self.import_to_us,
            export_to_us=self.export_to_us, port=self.port, date_at_port=
            self.date_at_port)
        print(type(international_dict))
        return international_dict


class Manifest(models.Model):
    tracking_number = models.CharField(max_length=12)
    generator = models.ForeignKey('Generator')
    phone_help = "Phone number 9-15 digits, entered in the format: '999999999'"
    phone_regex = RegexValidator(regex='^\\d{9,15}$', message=phone_help)
    emergency_phone = models.CharField(validators=[phone_regex], max_length=15)
    international = models.ForeignKey('International', null=True, blank=True)
    designated_facility = models.ForeignKey('EPAEntity')
    special_instructions = models.TextField(blank=True)
    number_of_pages = models.IntegerField()

    def __str__(self):
        return self.tracking_number

    def as_json(self):
        generator = self.generator.as_json()
        try:
            international = self.international.as_json()
        except AttributeError:
            international = {}
        designated_facility = self.designated_facility.as_json()
        transporters = Transporter.objects.filter(manifest_id=self.id)
        transporters = [t.transporter.as_json() for t in transporters]
        waste = ManifestedWaste.objects.filter(manifest_id=self.id)
        print(waste)
        waste = [w.as_json() for w in waste]
        return dict(tracking_number=self.tracking_number, generator=
            generator, emergency_phone=self.emergency_phone, international=
            international, designated_facility=designated_facility,
            special_instructions=self.special_instructions, number_of_pages
            =self.number_of_pages, transporters=transporters, waste=waste)


class Transporter(models.Model):
    manifest = models.ForeignKey('Manifest')
    transporter = models.ForeignKey('EPAEntity')


class WasteCode(models.Model):
    WASTE_CODE_TYPES = ('Federal', 'Federal'), ('State', 'State')
    code = models.CharField(max_length=10, null=True, blank=True)
    code_type = models.CharField(max_length=10, choices=WASTE_CODE_TYPES)

    def as_json(self):
        return dict(code=self.code, code_type=self.code_type)


class ManifestedWaste(models.Model):
    DOT_GROUPS = ('', 'None'), ('I', 'I'), ('II', 'II'), ('III', 'III')
    CONTAINER_TYPES = ('BA', 'Burlap, cloth, paper, or plastic bags'), ('CF',
        'Fiber or plastic boxes, cartons, cases'), ('CM',
        'Metal boxes, cartons, cases (including roll-offs'), ('CW',
        'Wooden boxes, cartons, cases'), ('CY', 'Cylinders'), ('DF',
        'Fiberboard or plastic drums, barrels, kegs'), ('DM',
        'Metal drums, barrels, kegs'), ('DW', 'Wooden drums, barrels, kegs'), (
        'HG', 'Hopper or gondola cars'), ('TC', 'Tank cars'), ('TP',
        'Portable tanks'), ('TT', 'Cargo tanks (tank trucks).')
    UNITS_OF_MEASURE = ('G', 'Gallons (liquids only)'), ('N', 'Cubic Meters'
        ), ('K', 'Kilograms P = Pounds'), ('L', 'Liters (liquids only)'), ('T',
        'Tons (2000 Pounds)'), ('M', 'Metric Tons (1000 Kilograms)'), ('Y',
        'Cubic Yards')
    manifest = models.ForeignKey('Manifest')
    hazardous_waste = models.BooleanField()
    dot_description = models.TextField(null=True, blank=True)
    dot_shipping_name = models.CharField(max_length=255, null=True, blank=True)
    dot_hazard_class = models.CharField(max_length=300, null=True, blank=True)
    dot_id = models.CharField(max_length=6, null=True, blank=True)
    dot_packing_group = models.CharField(max_length=6, choices=DOT_GROUPS,
        blank=True, default='')
    container_quantity = models.IntegerField()
    container_type = models.CharField(max_length=2, choices=CONTAINER_TYPES)
    total_quantity = models.IntegerField()
    units_of_measure = models.CharField(max_length=1, choices=UNITS_OF_MEASURE)
    waste_codes = models.ForeignKey('WasteCode', null=True, blank=True)

    def as_json(self):
        waste_codes = self.waste_codes.as_json()
        description = dict(description=self.dot_description, shipping_name=
            self.dot_shipping_name, hazard_class=self.dot_hazard_class,
            dot_id=self.dot_id, packing_group=self.dot_packing_group)
        return dict(hazardous_waste=self.hazardous_waste, dot_description=
            description, container_quantity=self.container_quantity,
            container_type=self.container_type, total_quantity=self.
            total_quantity, units_of_measure=self.units_of_measure,
            waste_codes=waste_codes)

<mask token>


class Address(models.Model):
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>

    def __str__(self):
        state_line = self.city + ', ' + self.state + ' ' + self.postal_code
        address = (self.address_line_1, self.address_line_2, state_line,
            self.country)
        return ', '.join(address)

    def as_json(self):
        return dict(address_line_1=self.address_line_1, address_line_2=self
            .address_line_2, city=self.city, state=self.state, postal_code=
            self.postal_code, country=self.country)


class EPAEntity(models.Model):
    sig_statement_default = (
        'I hereby declare that the contents         of this consignment are fully and         accurately described above by the proper shipping name, and are         classified, packaged, marked and labeled/placarded, and are in all         respects in proper condition for transport according to applicable         international and national governmental regulations. If export         shipment and I am the Primary Exporter, I certify that the         contents of this consignment conform to the terms of the         attached EPA Acknowledgment of Consent. I certify that the waste         minimization statement identified in 40 CFR 262.27(a) (if I am a         large quantity generator) or (b) (if I am a small quantity         generator) is true.'
        )
    name = models.CharField(max_length=200)
    epa_id = models.CharField(max_length=200)
    address = models.ForeignKey('Address', null=True, blank=True)
    phone = models.CharField(max_length=12, null=True, blank=True)
    signature_name = models.CharField(max_length=200, null=True, blank=True)
    certification_statments = models.TextField(default=
        sig_statement_default, null=True, blank=True)
    signature_date = models.DateField(null=True, blank=True)
    signature = models.CharField(max_length=200, null=True, blank=True)

    def __str__(self):
        return ', '.join([self.name, self.epa_id])

    def as_json(self):
        try:
            address = self.address.as_json()
        except AttributeError:
            address = {}
        return dict(name=self.name, phone=self.phone, address=address,
            epa_id=self.epa_id)


class Generator(models.Model):
    name = models.CharField(max_length=40)
    phone = models.CharField(max_length=12)
    address = models.ForeignKey('Address')
    mailing_address = models.ForeignKey('Address', related_name=
        'mailing_address', null=True, blank=True)
    mailing_and_address_same = models.BooleanField()

    def as_json(self):
        address = self.address.as_json()
        mailing_address = self.mailing_address.as_json()
        return dict(name=self.name, phone=self.phone, address=address,
            mailing_and_address_are_the_same=self.mailing_and_address_same,
            mailing_address=mailing_address)


class International(models.Model):
    import_to_us = models.BooleanField()
    export_from_us = models.BooleanField()
    port = models.CharField(max_length=200)
    date_at_port = models.DateField()

    def as_json(self):
        international_dict = dict(import_to_us=self.import_to_us,
            export_to_us=self.export_to_us, port=self.port, date_at_port=
            self.date_at_port)
        print(type(international_dict))
        return international_dict


class Manifest(models.Model):
    tracking_number = models.CharField(max_length=12)
    generator = models.ForeignKey('Generator')
    phone_help = "Phone number 9-15 digits, entered in the format: '999999999'"
    phone_regex = RegexValidator(regex='^\\d{9,15}$', message=phone_help)
    emergency_phone = models.CharField(validators=[phone_regex], max_length=15)
    international = models.ForeignKey('International', null=True, blank=True)
    designated_facility = models.ForeignKey('EPAEntity')
    special_instructions = models.TextField(blank=True)
    number_of_pages = models.IntegerField()

    def __str__(self):
        return self.tracking_number

    def as_json(self):
        generator = self.generator.as_json()
        try:
            international = self.international.as_json()
        except AttributeError:
            international = {}
        designated_facility = self.designated_facility.as_json()
        transporters = Transporter.objects.filter(manifest_id=self.id)
        transporters = [t.transporter.as_json() for t in transporters]
        waste = ManifestedWaste.objects.filter(manifest_id=self.id)
        print(waste)
        waste = [w.as_json() for w in waste]
        return dict(tracking_number=self.tracking_number, generator=
            generator, emergency_phone=self.emergency_phone, international=
            international, designated_facility=designated_facility,
            special_instructions=self.special_instructions, number_of_pages
            =self.number_of_pages, transporters=transporters, waste=waste)


class Transporter(models.Model):
    manifest = models.ForeignKey('Manifest')
    transporter = models.ForeignKey('EPAEntity')


class WasteCode(models.Model):
    WASTE_CODE_TYPES = ('Federal', 'Federal'), ('State', 'State')
    code = models.CharField(max_length=10, null=True, blank=True)
    code_type = models.CharField(max_length=10, choices=WASTE_CODE_TYPES)

    def as_json(self):
        return dict(code=self.code, code_type=self.code_type)


class ManifestedWaste(models.Model):
    DOT_GROUPS = ('', 'None'), ('I', 'I'), ('II', 'II'), ('III', 'III')
    CONTAINER_TYPES = ('BA', 'Burlap, cloth, paper, or plastic bags'), ('CF',
        'Fiber or plastic boxes, cartons, cases'), ('CM',
        'Metal boxes, cartons, cases (including roll-offs'), ('CW',
        'Wooden boxes, cartons, cases'), ('CY', 'Cylinders'), ('DF',
        'Fiberboard or plastic drums, barrels, kegs'), ('DM',
        'Metal drums, barrels, kegs'), ('DW', 'Wooden drums, barrels, kegs'), (
        'HG', 'Hopper or gondola cars'), ('TC', 'Tank cars'), ('TP',
        'Portable tanks'), ('TT', 'Cargo tanks (tank trucks).')
    UNITS_OF_MEASURE = ('G', 'Gallons (liquids only)'), ('N', 'Cubic Meters'
        ), ('K', 'Kilograms P = Pounds'), ('L', 'Liters (liquids only)'), ('T',
        'Tons (2000 Pounds)'), ('M', 'Metric Tons (1000 Kilograms)'), ('Y',
        'Cubic Yards')
    manifest = models.ForeignKey('Manifest')
    hazardous_waste = models.BooleanField()
    dot_description = models.TextField(null=True, blank=True)
    dot_shipping_name = models.CharField(max_length=255, null=True, blank=True)
    dot_hazard_class = models.CharField(max_length=300, null=True, blank=True)
    dot_id = models.CharField(max_length=6, null=True, blank=True)
    dot_packing_group = models.CharField(max_length=6, choices=DOT_GROUPS,
        blank=True, default='')
    container_quantity = models.IntegerField()
    container_type = models.CharField(max_length=2, choices=CONTAINER_TYPES)
    total_quantity = models.IntegerField()
    units_of_measure = models.CharField(max_length=1, choices=UNITS_OF_MEASURE)
    waste_codes = models.ForeignKey('WasteCode', null=True, blank=True)

    def as_json(self):
        waste_codes = self.waste_codes.as_json()
        description = dict(description=self.dot_description, shipping_name=
            self.dot_shipping_name, hazard_class=self.dot_hazard_class,
            dot_id=self.dot_id, packing_group=self.dot_packing_group)
        return dict(hazardous_waste=self.hazardous_waste, dot_description=
            description, container_quantity=self.container_quantity,
            container_type=self.container_type, total_quantity=self.
            total_quantity, units_of_measure=self.units_of_measure,
            waste_codes=waste_codes)

from django.core.validators import RegexValidator
from django.db import models


# TODO for int'l
# Update phone to 20
# Update state to "state/providence/region"


class Address(models.Model):

    COUNTRIES = (
        ('US', 'United States'),
        ('MX', 'Mexico'),
        ('PR', 'Puerto Rico'),
    )

    address_line_1 = models.CharField(max_length=60)
    address_line_2 = models.CharField(max_length=60, blank=True, null=True)
    city = models.CharField(max_length=50)
    state = models.CharField(max_length=50)  # "state/providence/region"
    postal_code = models.CharField(max_length=20)
    country = models.CharField(max_length=100, choices=COUNTRIES, default='US')

    def __str__(self):
        state_line = self.city + ', ' + self.state + ' ' + self.postal_code
        address = (
            self.address_line_1,
            self.address_line_2,
            state_line,
            self.country
        )
        return ', '.join(address)

    def as_json(self):

        return dict(
            address_line_1=self.address_line_1,
            address_line_2=self.address_line_2,
            city=self.city,
            state=self.state,
            postal_code=self.postal_code,
            country=self.country,
        )


class EPAEntity(models.Model):

    sig_statement_default = "I hereby declare that the contents \
        of this consignment are fully and \
        accurately described above by the proper shipping name, and are \
        classified, packaged, marked and labeled/placarded, and are in all \
        respects in proper condition for transport according to applicable \
        international and national governmental regulations. If export \
        shipment and I am the Primary Exporter, I certify that the \
        contents of this consignment conform to the terms of the \
        attached EPA Acknowledgment of Consent. I certify that the waste \
        minimization statement identified in 40 CFR 262.27(a) (if I am a \
        large quantity generator) or (b) (if I am a small quantity \
        generator) is true."

    name = models.CharField(max_length=200)

    # TODO: EPA ID: XXX123456789
    epa_id = models.CharField(max_length=200)

    # TODO: Validate address & phone for designated facility
    address = models.ForeignKey('Address', null=True, blank=True)
    phone = models.CharField(max_length=12, null=True, blank=True)

    signature_name = models.CharField(max_length=200, null=True, blank=True)
    certification_statments = models.TextField(default=sig_statement_default,
                                               null=True, blank=True)
    signature_date = models.DateField(null=True, blank=True)
    signature = models.CharField(max_length=200, null=True, blank=True)

    def __str__(self):
        return ', '.join([self.name, self.epa_id])

    def as_json(self):
        try:
            address = self.address.as_json()
        except AttributeError:
            address = {}

        return dict(
            name=self.name,
            phone=self.phone,
            address=address,
            epa_id=self.epa_id,
        )


# The way that addresses are handled here should be thought out better.
# This is a quick hack for demo purposes.
class Generator(models.Model):
    name = models.CharField(max_length=40)
    phone = models.CharField(max_length=12)
    address = models.ForeignKey('Address')
    mailing_address = models.ForeignKey('Address',
                                        related_name='mailing_address',
                                        null=True, blank=True)
    mailing_and_address_same = models.BooleanField()

    def as_json(self):
        address = self.address.as_json()
        mailing_address = self.mailing_address.as_json()

        return dict(
            name=self.name,
            phone=self.phone,
            address=address,
            mailing_and_address_are_the_same=self.mailing_and_address_same,
            mailing_address=mailing_address,
        )


class International(models.Model):  # 16
    import_to_us = models.BooleanField()
    export_from_us = models.BooleanField()
    port = models.CharField(max_length=200)
    date_at_port = models.DateField()
    # transporter_signature = ??

    def as_json(self):

        international_dict = dict(
            import_to_us=self.import_to_us,
            export_to_us=self.export_to_us,
            port=self.port,
            date_at_port=self.date_at_port,
        )

        print(type(international_dict))

        return international_dict


class Manifest(models.Model):
    # "ManifestTrackingNumber":"3 Letters  9 numbers",
    tracking_number = models.CharField(max_length=12)  # 4

    generator = models.ForeignKey('Generator')  # 1

    # TODO: How to validate -- emergency numbers internationally?
    # django local flavor -- validate the number by locality
    # "23 alphanumberic string accounting for international numbers
    # e.g. +001 1234321234, to be honest this is just a safety feature,
    # most will be standard 10 digit"
    # # 3
    phone_help = "Phone number 9-15 digits, entered in the format: '999999999'"
    phone_regex = RegexValidator(regex=r'^\d{9,15}$', message=phone_help)
    emergency_phone = models.CharField(validators=[phone_regex], max_length=15)

    international = models.ForeignKey('International', null=True, blank=True)
    designated_facility = models.ForeignKey('EPAEntity')  # 'DesinatedFacility'

    special_instructions = models.TextField(blank=True)
    # TODO: Compare these to sample data. Can we parse at this time?
    # special handling -- TextField
    # tracking instructions -- TextField
    # waste profile number -- 9 Charater pattern value=([0-9])+
    # container number -- 20 char
    # response guide number - 4 Alphanumeric pattern value=[0-9,a-z,A-Z](0-9)+

    # This is included, b/c maybe it could be used as a way to validate
    number_of_pages = models.IntegerField()  # 2

    def __str__(self):
        return self.tracking_number

    def as_json(self):
        generator = self.generator.as_json()

        try:
            international = self.international.as_json()
        except AttributeError:
            international = {}

        designated_facility = self.designated_facility.as_json()

        transporters = Transporter.objects.filter(manifest_id=self.id)
        transporters = [t.transporter.as_json() for t in transporters]

        waste = ManifestedWaste.objects.filter(manifest_id=self.id)
        print(waste)
        waste = [w.as_json() for w in waste]

        return dict(
            tracking_number=self.tracking_number,
            generator=generator,
            emergency_phone=self.emergency_phone,
            international=international,
            designated_facility=designated_facility,
            special_instructions=self.special_instructions,
            number_of_pages=self.number_of_pages,
            transporters=transporters,
            waste=waste,
        )


class Transporter(models.Model):
    manifest = models.ForeignKey('Manifest')  # 6, 7
    transporter = models.ForeignKey('EPAEntity')  # "transporter"
    # aknowledgement_name = models.CharField(max_length=200)
    # aknowledgement = ?? signature
    # aknowledgement_date = models.DateField()


class WasteCode(models.Model):
    WASTE_CODE_TYPES = (
        ('Federal', 'Federal'),
        ('State', 'State'),
    )

    # if the code is federal then max length = 4
    # if the code it state, then max length = 8
    code = models.CharField(max_length=10, null=True, blank=True)
    code_type = models.CharField(max_length=10, choices=WASTE_CODE_TYPES)

    def as_json(self):

        return dict(
            code=self.code,
            code_type=self.code_type,
        )


class ManifestedWaste(models.Model):

    DOT_GROUPS = (
        ("", "None"),
        ("I", "I"),
        ("II", "II"),
        ("III", "III"),
    )

    CONTAINER_TYPES = (
        ("BA", "Burlap, cloth, paper, or plastic bags"),
        ("CF", "Fiber or plastic boxes, cartons, cases"),
        ("CM", "Metal boxes, cartons, cases (including roll-offs"),
        ("CW", "Wooden boxes, cartons, cases"),
        ("CY", "Cylinders"),
        ("DF", "Fiberboard or plastic drums, barrels, kegs"),
        ("DM", "Metal drums, barrels, kegs"),
        ("DW", "Wooden drums, barrels, kegs"),
        ("HG", "Hopper or gondola cars"),
        ("TC", "Tank cars"),
        ("TP", "Portable tanks"),
        ("TT", "Cargo tanks (tank trucks)."),
    )

    UNITS_OF_MEASURE = (
        ("G", "Gallons (liquids only)"),
        ("N", "Cubic Meters"),
        ("K", "Kilograms P = Pounds"),
        ("L", "Liters (liquids only)"),
        ("T", "Tons (2000 Pounds)"),
        ("M", "Metric Tons (1000 Kilograms)"),
        ("Y", "Cubic Yards"),
    )

    manifest = models.ForeignKey('Manifest')

    hazardous_waste = models.BooleanField()  # 9a HM
    # description = models.TextField(null=True, blank=True)
    dot_description = models.TextField(null=True, blank=True)
    dot_shipping_name = models.CharField(max_length=255, null=True, blank=True)
    dot_hazard_class = models.CharField(max_length=300, null=True, blank=True)
    dot_id = models.CharField(max_length=6, null=True, blank=True)
    dot_packing_group = models.CharField(max_length=6, choices=DOT_GROUPS,
                                         blank=True, default='')

    # (including Proper Shipping Name, Hazard Class, ID Number, and
    # Packing Group (if any))

    container_quantity = models.IntegerField()
    container_type = models.CharField(max_length=2, choices=CONTAINER_TYPES)

    total_quantity = models.IntegerField()      # total quantity # 11
    units_of_measure = models.CharField(max_length=1, choices=UNITS_OF_MEASURE)
    # 12

    waste_codes = models.ForeignKey('WasteCode', null=True, blank=True)  # 13

    def as_json(self):
        waste_codes = self.waste_codes.as_json()

        description = dict(
            description=self.dot_description,
            shipping_name=self.dot_shipping_name,
            hazard_class=self.dot_hazard_class,
            dot_id=self.dot_id,
            packing_group=self.dot_packing_group,
        )

        return dict(
            hazardous_waste=self.hazardous_waste,
            dot_description=description,
            container_quantity=self.container_quantity,
            container_type=self.container_type,
            total_quantity=self.total_quantity,
            units_of_measure=self.units_of_measure,
            waste_codes=waste_codes,
        )
