# Path: pupa/scrape/base.py
# class BaseModel(object):
#     """
#     This is the base class for all the Open Civic objects. This contains
#     common methods and abstractions for OCD objects.
#     """
# 
#     # to be overridden by children. Something like "person" or "organization".
#     # Used in :func:`validate`.
#     _type = None
#     _schema = None
# 
#     def __init__(self):
#         super(BaseModel, self).__init__()
#         self._id = str(uuid.uuid1())
#         self._related = []
#         self.extras = {}
# 
#     # validation
# 
#     def validate(self, schema=None):
#         """
#         Validate that we have a valid object.
# 
#         On error, this will raise a `ScrapeValueError`
# 
#         This also expects that the schemas assume that omitting required
#         in the schema asserts the field is optional, not required. This is
#         due to upstream schemas being in JSON Schema v3, and not validictory's
#         modified syntax.
#         ^ TODO: FIXME
#         """
#         if schema is None:
#             schema = self._schema
# 
#         type_checker = Draft3Validator.TYPE_CHECKER.redefine(
#             "datetime", lambda c, d: isinstance(d, (datetime.date, datetime.datetime))
#         )
#         type_checker = type_checker.redefine(
#             "date", lambda c, d: (isinstance(d, datetime.date)
#                                   and not isinstance(d, datetime.datetime))
#         )
# 
#         ValidatorCls = jsonschema.validators.extend(Draft3Validator, type_checker=type_checker)
#         validator = ValidatorCls(schema, format_checker=FormatChecker())
# 
#         errors = [str(error) for error in validator.iter_errors(self.as_dict())]
#         if errors:
#             raise ScrapeValueError('validation of {} {} failed: {}'.format(
#                 self.__class__.__name__, self._id, '\n\t'+'\n\t'.join(errors)
#             ))
# 
#     def pre_save(self, jurisdiction_id):
#         pass
# 
#     def as_dict(self):
#         d = {}
#         for attr in self._schema['properties'].keys():
#             if hasattr(self, attr):
#                 d[attr] = getattr(self, attr)
#         d['_id'] = self._id
#         return d
# 
#     # operators
# 
#     def __setattr__(self, key, val):
#         if key[0] != '_' and key not in self._schema['properties'].keys():
#             raise ScrapeValueError('property "{}" not in {} schema'.format(key, self._type))
#         super(BaseModel, self).__setattr__(key, val)
# 
# class SourceMixin(object):
#     def __init__(self):
#         super(SourceMixin, self).__init__()
#         self.sources = []
# 
#     def add_source(self, url, *, note=''):
#         """ Add a source URL from which data was collected """
#         new = {'url': url, 'note': note}
#         self.sources.append(new)
# 
# class LinkMixin(object):
#     def __init__(self):
#         super(LinkMixin, self).__init__()
#         self.links = []
# 
#     def add_link(self, url, *, note=''):
#         self.links.append({"note": note, "url": url})
# 
# class ContactDetailMixin(object):
#     def __init__(self):
#         super(ContactDetailMixin, self).__init__()
#         self.contact_details = []
# 
#     def add_contact_detail(self, *, type, value, note=''):
#         self.contact_details.append({"type": type, "value": value, "note": note})
# 
# class OtherNameMixin(object):
#     def __init__(self):
#         super(OtherNameMixin, self).__init__()
#         self.other_names = []
# 
#     def add_name(self, name, *, start_date='', end_date='', note=''):
#         other_name = {'name': name}
#         if start_date:
#             other_name['start_date'] = start_date
#         if end_date:
#             other_name['end_date'] = end_date
#         if note:
#             other_name['note'] = note
#         self.other_names.append(other_name)
# 
# class IdentifierMixin(object):
#     def __init__(self):
#         super(IdentifierMixin, self).__init__()
#         self.identifiers = []
# 
#     def add_identifier(self, identifier, *, scheme=''):
#         self.identifiers.append({"identifier": identifier, "scheme": scheme})
# 
# Path: pupa/scrape/schemas/post.py

# 
# Path: pupa/scrape/schemas/person.py

# 
# Path: pupa/scrape/schemas/membership.py

# 
# Path: pupa/scrape/schemas/organization.py

# 
# Path: pupa/utils/generic.py
# def _make_pseudo_id(**kwargs):
#     """ pseudo ids are just JSON """
#     # ensure keys are sorted so that these are deterministic
#     return '~' + json.dumps(kwargs, sort_keys=True)
# 
# Path: pupa/exceptions.py
# class ScrapeValueError(PupaError, ValueError):
#     """ An invalid value was passed to a pupa scrape object. """


import copy
from .base import (BaseModel, SourceMixin, LinkMixin, ContactDetailMixin, OtherNameMixin,
                   IdentifierMixin)
from .schemas.post import schema as post_schema
from .schemas.person import schema as person_schema
from .schemas.membership import schema as membership_schema
from .schemas.organization import schema as org_schema
from ..utils import _make_pseudo_id
from pupa.exceptions import ScrapeValueError

# a copy of the org schema without sources
org_schema_no_sources = copy.deepcopy(org_schema)
org_schema_no_sources['properties'].pop('sources')


class Post(BaseModel, LinkMixin, ContactDetailMixin):
    """
    A popolo-style Post
    """

    _type = 'post'

# Path: pupa/scrape/base.py
# class BaseModel(object):
#     """
#     This is the base class for all the Open Civic objects. This contains
#     common methods and abstractions for OCD objects.
#     """
# 
#     # to be overridden by children. Something like "person" or "organization".
#     # Used in :func:`validate`.
#     _type = None
#     _schema = None
# 
#     def __init__(self):
#         super(BaseModel, self).__init__()
#         self._id = str(uuid.uuid1())
#         self._related = []
#         self.extras = {}
# 
#     # validation
# 
#     def validate(self, schema=None):
#         """
#         Validate that we have a valid object.
# 
#         On error, this will raise a `ScrapeValueError`
# 
#         This also expects that the schemas assume that omitting required
#         in the schema asserts the field is optional, not required. This is
#         due to upstream schemas being in JSON Schema v3, and not validictory's
#         modified syntax.
#         ^ TODO: FIXME
#         """
#         if schema is None:
#             schema = self._schema
# 
#         type_checker = Draft3Validator.TYPE_CHECKER.redefine(
#             "datetime", lambda c, d: isinstance(d, (datetime.date, datetime.datetime))
#         )
#         type_checker = type_checker.redefine(
#             "date", lambda c, d: (isinstance(d, datetime.date)
#                                   and not isinstance(d, datetime.datetime))
#         )
# 
#         ValidatorCls = jsonschema.validators.extend(Draft3Validator, type_checker=type_checker)
#         validator = ValidatorCls(schema, format_checker=FormatChecker())
# 
#         errors = [str(error) for error in validator.iter_errors(self.as_dict())]
#         if errors:
#             raise ScrapeValueError('validation of {} {} failed: {}'.format(
#                 self.__class__.__name__, self._id, '\n\t'+'\n\t'.join(errors)
#             ))
# 
#     def pre_save(self, jurisdiction_id):
#         pass
# 
#     def as_dict(self):
#         d = {}
#         for attr in self._schema['properties'].keys():
#             if hasattr(self, attr):
#                 d[attr] = getattr(self, attr)
#         d['_id'] = self._id
#         return d
# 
#     # operators
# 
#     def __setattr__(self, key, val):
#         if key[0] != '_' and key not in self._schema['properties'].keys():
#             raise ScrapeValueError('property "{}" not in {} schema'.format(key, self._type))
#         super(BaseModel, self).__setattr__(key, val)
# 
# class SourceMixin(object):
#     def __init__(self):
#         super(SourceMixin, self).__init__()
#         self.sources = []
# 
#     def add_source(self, url, *, note=''):
#         """ Add a source URL from which data was collected """
#         new = {'url': url, 'note': note}
#         self.sources.append(new)
# 
# class LinkMixin(object):
#     def __init__(self):
#         super(LinkMixin, self).__init__()
#         self.links = []
# 
#     def add_link(self, url, *, note=''):
#         self.links.append({"note": note, "url": url})
# 
# class ContactDetailMixin(object):
#     def __init__(self):
#         super(ContactDetailMixin, self).__init__()
#         self.contact_details = []
# 
#     def add_contact_detail(self, *, type, value, note=''):
#         self.contact_details.append({"type": type, "value": value, "note": note})
# 
# class OtherNameMixin(object):
#     def __init__(self):
#         super(OtherNameMixin, self).__init__()
#         self.other_names = []
# 
#     def add_name(self, name, *, start_date='', end_date='', note=''):
#         other_name = {'name': name}
#         if start_date:
#             other_name['start_date'] = start_date
#         if end_date:
#             other_name['end_date'] = end_date
#         if note:
#             other_name['note'] = note
#         self.other_names.append(other_name)
# 
# class IdentifierMixin(object):
#     def __init__(self):
#         super(IdentifierMixin, self).__init__()
#         self.identifiers = []
# 
#     def add_identifier(self, identifier, *, scheme=''):
#         self.identifiers.append({"identifier": identifier, "scheme": scheme})
# 
# Path: pupa/scrape/schemas/post.py

# 
# Path: pupa/scrape/schemas/person.py

# 
# Path: pupa/scrape/schemas/membership.py

# 
# Path: pupa/scrape/schemas/organization.py

# 
# Path: pupa/utils/generic.py
# def _make_pseudo_id(**kwargs):
#     """ pseudo ids are just JSON """
#     # ensure keys are sorted so that these are deterministic
#     return '~' + json.dumps(kwargs, sort_keys=True)
# 
# Path: pupa/exceptions.py
# class ScrapeValueError(PupaError, ValueError):
#     """ An invalid value was passed to a pupa scrape object. """


# Path: pupa/scrape/popolo.py
import copy
from .base import (BaseModel, SourceMixin, LinkMixin, ContactDetailMixin, OtherNameMixin,
                   IdentifierMixin)
from .schemas.post import schema as post_schema
from .schemas.person import schema as person_schema
from .schemas.membership import schema as membership_schema
from .schemas.organization import schema as org_schema
from ..utils import _make_pseudo_id
from pupa.exceptions import ScrapeValueError


# a copy of the org schema without sources
org_schema_no_sources = copy.deepcopy(org_schema)
org_schema_no_sources['properties'].pop('sources')


class Post(BaseModel, LinkMixin, ContactDetailMixin):
    """
    A popolo-style Post
    """

    _type = 'post'

    _schema = post_schema