# :coding: utf-8
# :copyright: Copyright (c) 2013 Martin Pengelly-Phillips
# :license: See LICENSE.txt.

import re

import clique.descriptor


class Collection(object):
    '''Represent group of items that differ only by numerical component.'''

    head = clique.descriptor.ReadOnly('head')
    tail = clique.descriptor.ReadOnly('tail')
    padding = clique.descriptor.ReadOnly('padding')

    def __init__(self, head, tail, padding, indexes=None):
        '''Initialise collection.

        *head* is the leading common part whilst *tail* is the trailing
        common part.

        *padding* specifies the "width" of the numerical component. An index
        will be padded with zeros to fill this width. A *padding* of zero
        implies no padding and width may be any size so long as no leading
        zeros are present.

        *indexes* can specify a set of numerical indexes to initially populate
        the collection with.

        '''
        super(Collection, self).__init__()
        self.__dict__.update({
            'head': head,
            'tail': tail,
            'padding': padding
        })
        self.indexes = set()
        if indexes is not None:
            self.indexes.update(indexes)

        self._pattern = re.compile('^{0}(?P<index>(?P<padding>0*)\d+?){1}$'
                                   .format(self.head, self.tail))

    def __iter__(self):
        '''Return iterator over items in collection.'''

    def __contains__(self, item):
        '''Return whether *item* is present in collection.'''

    def match(self, item):
        '''Return whether *item* matches this collection pattern.

        If a match is successful return data about the match otherwise return
        None.

        '''
        match = self._pattern.match(item)
        if not match:
            return None

        index = match.group('index')
        padded = False
        if match.group('padding'):
            padded = True

        if self.padding == 0:
            if padded:
                return None

        elif len(index) != self.padding:
            return None

        return match

    def add(self, item):
        '''Add *item* to collection.

        raise :py:class:`~clique.error.CollectionError` if *item* cannot be
        added to the collection.

        '''

    def remove(self, item):
        '''Remove *item* from collection.

        raise :py:class:`~clique.error.CollectionError` if *item* cannot be
        removed from the collection.

        '''

    def format(self, pattern):
        '''Return string representation as specified by *pattern*.'''

    def is_contiguous(self):
        '''Return whether entire collection is contiguous.'''

    def holes(self):
        '''Return holes in collection.

        Return :py:class:`~clique.collection.Collection` of missing indexes.

        '''

    def merge(self, collection):
        '''Merge *collection* into this collection.

        If the *collection* is compatible with this collection then update
        indexes with all indexes in *collection*.

        '''

    def separate(self):
        '''Return contiguous parts of collection as separate collections.

        Return as list of :py:class:`~clique.collection.Collection` instances.

        '''

@@ -134,16 +134,36 @@
 criptor%0A
+import clique.error%0A
 %0A%0Aclass 
@@ -2328,205 +2328,774 @@
 '''%0A
-%0A    def remove(self, item):%0A        '''Remove *item* from collection.%0A%0A        raise :py:class:%60~clique.error.CollectionError%60 if *item* cannot be%0A        removed from the collection.%0A%0A        '''
+        match = self.match(item)%0A        if match is None:%0A            raise clique.error.CollectionError(%0A                'Item does not match sequence pattern.'%0A            )%0A%0A        self.indexes.add(int(match.group('index')))%0A%0A    def remove(self, item):%0A        '''Remove *item* from collection.%0A%0A        raise :py:class:%60~clique.error.CollectionError%60 if *item* cannot be%0A        removed from the collection.%0A%0A        '''%0A        match = self.match(item)%0A        if match is None:%0A            raise clique.error.CollectionError('Item not present in sequence.')%0A%0A        index = int(match.group('index'))%0A        try:%0A            self.indexes.remove(index)%0A        except KeyError:%0A            raise clique.error.CollectionError('Item not present in sequence.')
 %0A%0A  

Implement Collection.add/Collection.remove methods.