class RegionSheet(GeounitsSheet):
    label = u'REGPJ'
    model = Region
    ignore_superfluous_columns = True

    columns = Columns(
        # {{{
        pk=TextColumn(
            u'RSUJ3',
            # Merge duplicate rows; see process_rows()
            max_length=32,
            field=Field(),
        ),
        name=TextColumn(
            u'NAZKRJ = NAZRSUJ3',
            # Check that names have unique slugs; see process_rows()
            max_length=255,
            field=Field(),
        ),
        # }}}
    )

    def process_rows(self, rows):
        rows = super(RegionSheet, self).process_rows(rows)

        # Merge duplicate rows
        rows = self.merge_duplicate_rows(rows)

        # Check that names have unique slugs
        rows = self.check_unique_slugs(rows, self.columns.name)

        return rows
class ObligeeGroupSheet(Sheet):
    label = u'Hierarchia'
    model = ObligeeGroup

    columns = Columns(
            # {{{
            pk=IntegerColumn(u'ID',
                unique=True, min_value=1,
                field=Field(),
                ),
            key=TextColumn(u'Kod',
                # Checked that every subgroup has its parent group; See process_rows()
                unique=True, max_length=255, regex=re.compile(r'^[\w-]+(/[\w-]+)*$'),
                field=Field(confirm_changed=True),
                ),
            name=TextColumn(u'Nazov v hierarchii',
                unique_slug=True, max_length=255,
                field=Field(),
                ),
            description=TextColumn(u'Popis',
                blank=True,
                field=Field(),
                ),
            # }}}
            )

    def process_rows(self, rows):
        rows = super(ObligeeGroupSheet, self).process_rows(rows)
        errors = 0

        # Check that every subgroup has its parent group
        keys = set()
        for values in rows.values():
            key = values[self.columns.key.label]
            keys.add(key)
        for row_idx, values in rows.items():
            key = values[self.columns.key.label]
            if u'/' not in key:
                continue
            parent_key = key.rsplit(u'/', 1)[0]
            if parent_key not in keys:
                self.cell_error(u'no_parent_group', row_idx, self.columns.key,
                        u'Group {} has no parent; Group {} not found',
                        self.columns.key.coerced_repr(key),
                        self.columns.key.coerced_repr(parent_key))
                errors += 1

        if errors:
            raise RollingError(errors)
        return rows
class NeighbourhoodSheet(GeounitsSheet):
    label = u'REGPJ'
    model = Neighbourhood
    ignore_superfluous_columns = True

    columns = Columns(
        # {{{
        pk=TextColumn(
            u'ICZSJ',
            # Skip duplicate rows ignoring inconsistencies; see process_rows()
            max_length=32,
            field=Field(),
        ),
        name=TextColumn(
            u'NAZZSJ',
            max_length=255,
            field=Field(),
        ),
        cadastre=TextColumn(
            u'NAZUTJ',
            max_length=255,
            field=Field(),
        ),
        municipality=ForeignKeyColumn(
            u'LSUJ2',
            Municipality,
            field=ForeignKeyField(),
        ),
        district=ForeignKeyColumn(
            u'LSUJ1',
            District,
            field=ForeignKeyField(),
        ),
        region=ForeignKeyColumn(
            u'RSUJ3',
            Region,
            field=ForeignKeyField(),
        ),
        # }}}
    )

    def process_rows(self, rows):
        rows = super(NeighbourhoodSheet, self).process_rows(rows)

        # Skip duplicate rows ignoring inconsistencies
        rows = self.merge_duplicate_rows(rows, check_columns=[])

        return rows
class ObligeeAliasSheet(Sheet):
    label = u'Aliasy'
    model = ObligeeAlias

    columns = Columns(
            # {{{
            pk=IntegerColumn(u'ID',
                unique=True, min_value=1,
                field=Field(),
                ),
            obligee=ForeignKeyColumn(u'ID institucie', Obligee,
                field=ForeignKeyField(confirm_changed=True),
                ),
            obligee_name=TextColumn(u'Rozlisovaci nazov institucie',
                # Checked that obligee_name is obligee.name; See process_row()
                ),
            name=TextColumn(u'Alternativny nazov',
                unique_slug=True, max_length=255,
                field=Field(),
                ),
            description=TextColumn(u'Vysvetlenie',
                blank=True,
                field=Field(),
                ),
            notes=TextColumn(u'Poznamka',
                blank=True,
                field=Field(),
                ),
            # }}}
            )

    def process_row(self, row_idx, row):
        values = super(ObligeeAliasSheet, self).process_row(row_idx, row)

        # Check that obligee_name is obligee.name
        value = values[self.columns.obligee_name.label]
        obligee = values[self.columns.obligee.label]
        if value != obligee.name:
            self.cell_error(u'obligee_name', row_idx, self.columns.obligee_name,
                    u'Expecting {} but found {}',
                    self.columns.obligee_name.coerced_repr(obligee.name),
                    self.columns.obligee_name.coerced_repr(value))
            raise RollingError

        return values
class ObligeeTagSheet(Sheet):
    label = u'Tagy'
    model = ObligeeTag

    columns = Columns(
            # {{{
            pk=IntegerColumn(u'ID',
                unique=True, min_value=1,
                field=Field(),
                ),
            key=TextColumn(u'Kod',
                unique=True, max_length=255, regex=re.compile(r'^[\w-]+$'),
                field=Field(confirm_changed=True),
                ),
            name=TextColumn(u'Nazov',
                unique_slug=True, max_length=255,
                field=Field(),
                ),
            # }}}
            )
class MunicipalitySheet(GeounitsSheet):
    label = u'REGPJ'
    model = Municipality
    ignore_superfluous_columns = True

    columns = Columns(
        # {{{
        pk=TextColumn(
            u'LSUJ2',
            # Merge duplicate rows; see process_rows()
            max_length=32,
            field=Field(),
        ),
        name=TextColumn(
            u'NAZZUJ = NAZLSUJ2',
            # Append district names to ambiguous names; see process_rows()
            # Check that names have unique slugs; see process_rows()
            max_length=255,
            field=Field(),
        ),
        district=ForeignKeyColumn(
            u'LSUJ1',
            District,
            field=ForeignKeyField(),
        ),
        region=ForeignKeyColumn(
            u'RSUJ3',
            Region,
            field=ForeignKeyField(),
        ),
        # }}}
    )

    def make_names_unique(self, rows):
        groups = defaultdict(list)
        for row_idx, values in rows.items():
            name = values[self.columns.name.label]
            slug = slugify(name)
            groups[slug].append(row_idx)
        for group in groups.values():
            if len(group) > 1:
                for row_idx in group:
                    name = rows[row_idx][self.columns.name.label]
                    district = rows[row_idx][self.columns.district.label]
                    new_name = u'{}, okres {}'.format(name, district.name)
                    rows[row_idx][self.columns.name.label] = new_name
        return rows

    def process_rows(self, rows):
        rows = super(MunicipalitySheet, self).process_rows(rows)

        # Merge duplicate rows
        rows = self.merge_duplicate_rows(rows)

        # Append district names to ambiguous names
        rows = self.make_names_unique(rows)

        # Check that names have unique slugs
        rows = self.check_unique_slugs(rows, self.columns.name)

        return rows
class ObligeeSheet(Sheet):
    label = u'Obligees'
    model = Obligee
    delete_omitted = False

    columns = Columns(
            # {{{
            pk=IntegerColumn(u'ID',
                unique=True, min_value=1,
                field=Field(),
                ),
            official_name=TextColumn(u'Oficialny nazov',
                max_length=255,
                field=Field(confirm_changed=True),
                ),
            name=TextColumn(u'Rozlisovaci nazov nominativ',
                unique_slug=True, max_length=255,
                field=Field(confirm_unchanged_if_changed=u'official_name'),
                ),
            name_genitive=TextColumn(u'Rozlisovaci nazov genitiv',
                max_length=255,
                field=Field(confirm_unchanged_if_changed=u'name'),
                ),
            name_dative=TextColumn(u'Rozlisovaci nazov dativ',
                max_length=255,
                field=Field(confirm_unchanged_if_changed=u'name'),
                ),
            name_accusative=TextColumn(u'Rozlisovaci nazov akuzativ',
                max_length=255,
                field=Field(confirm_unchanged_if_changed=u'name'),
                ),
            name_locative=TextColumn(u'Rozlisovaci nazov lokal',
                max_length=255,
                field=Field(confirm_unchanged_if_changed=u'name'),
                ),
            name_instrumental=TextColumn(u'Rozlisovaci nazov instrumental',
                max_length=255,
                field=Field(confirm_unchanged_if_changed=u'name'),
                ),
            gender=FieldChoicesColumn(u'Rod', Obligee.GENDERS,
                choices={
                    u'muzsky': Obligee.GENDERS.MASCULINE,
                    u'zensky': Obligee.GENDERS.FEMININE,
                    u'stredny': Obligee.GENDERS.NEUTER,
                    u'pomnozny': Obligee.GENDERS.PLURALE,
                    },
                field=FieldChoicesField(Obligee.GENDERS),
                ),
            ico=TextColumn(u'ICO',
                blank=True, max_length=32,
                field=Field(),
                ),
            street=TextColumn(u'Adresa: Ulica s cislom',
                max_length=255,
                field=Field(),
                ),
            city=TextColumn(u'Adresa: Obec',
                max_length=255,
                field=Field(),
                ),
            zip=TextColumn(u'Adresa: PSC',
                max_length=10, regex=re.compile(r'^\d\d\d \d\d$'),
                field=Field(),
                ),
            iczsj=ForeignKeyColumn(u'ICZSJ', Neighbourhood,
                field=ForeignKeyField(),
                ),
            emails=TextColumn(u'Adresa: Email',
                # Overridden with dummy emails for local and dev server modes; See process_row()
                blank=True, max_length=1024, validators=validate_comma_separated_emails,
                field=Field(),
                ),
            latitude=FloatColumn(u'Lat',
                min_value=-90.0, max_value=90.0,
                field=FloatField(),
                ),
            longitude=FloatColumn(u'Lon',
                min_value=-180.0, max_value=180.0,
                field=FloatField(),
                ),
            tags=ManyToManyColumn(u'Tagy', ObligeeTag,
                to_field=u'key', blank=True,
                field=ManyToManyField(),
                ),
            groups=ManyToManyColumn(u'Hierarchia', ObligeeGroup,
                to_field=u'key',
                field=ManyToManyField(),
                ),
            type=FieldChoicesColumn(u'Typ', Obligee.TYPES,
                choices={
                    u'odsek 1': Obligee.TYPES.SECTION_1,
                    u'odsek 2': Obligee.TYPES.SECTION_2,
                    u'odsek 3': Obligee.TYPES.SECTION_3,
                    u'odsek 4': Obligee.TYPES.SECTION_4,
                    },
                field=FieldChoicesField(Obligee.TYPES),
                ),
            official_description=TextColumn(u'Oficialny popis',
                blank=True,
                field=Field(),
                ),
            simple_description=TextColumn(u'Zrozumitelny popis',
                blank=True,
                field=Field(),
                ),
            status=FieldChoicesColumn(u'Stav', Obligee.STATUSES,
                choices={
                    u'aktivny': Obligee.STATUSES.PENDING,
                    u'neaktivny': Obligee.STATUSES.DISSOLVED,
                    },
                field=FieldChoicesField(Obligee.STATUSES, confirm_changed=True),
                ),
            notes=TextColumn(u'Poznamka',
                blank=True,
                field=Field(),
                ),
            # }}}
            )

    def do_reset(self):
        count = Inforequest.objects.count()
        if count:
            inputed = self.importer.input_yes_no(squeeze(u"""
                    Discarding current obligees will discard all existing inforequests as well.
                    There are {} inforequests.
                    """),
                    u'Are you sure, you want to discard them?', count, default=u'N')
            if inputed != u'Y':
                raise CommandError(squeeze(u"""
                        Existing inforequests prevented us from discarding current obligees.
                        """))
        self.reset_model(Obligee)
        self.reset_model(HistoricalObligee)
        self.reset_model(Inforequest)

    def process_row(self, row_idx, row):
        values = super(ObligeeSheet, self).process_row(row_idx, row)

        # Dummy emails for local and dev server modes
        if hasattr(settings, u'OBLIGEE_DUMMY_MAIL'):
            name = values[self.columns.name.label]
            dummy_email = Obligee.dummy_email(name, settings.OBLIGEE_DUMMY_MAIL)
            values[self.columns.emails.label] = dummy_email

        return values