'''
Created on Dec 10, 2012

@author: steger
'''
from threading import RLock
from DataProcessing.DataError import DataError, SamplerError
#FIXME: import dependency problem, circular reference
#from DataProcessing.DataReader import DataReader

class DataSource(object):
    '''
#FIXME: docs
    @summary: a template to represent any data generated by a tool or derived via various operations on data
    @ivar source: pointer to the origin of the data
    @note: DataSource instances reference their ancestor via the source property, in a recursive manner, the last item needs to implement a read and a write lock
    @ivar data: pointer to the actual data container
    @note: results of operations on data yield their result in the container referenced by the data property, the original data generator's data and source properties are meant to be the same
    @ivar name: a name for the data source class
    @ivar um: reference to the unit model of the ancient data source
    '''
    PASS = 0
    CLEARED = 1
    EXPANDED = 2

    def __init__(self, dependency = None):
        self._readers = set()
        if dependency is None:
            self._inputreader = None
        else:
            self._inputreader = self.readerClass(dependency)
        self._processlock = RLock()
        self._data = None

#FIXME: import error
    def registerReader(self, reader):
        '''
        @summary: registers a reader to catch clear and update events
        @param reader: data consumer
        @type reader: DataReader 
        @raise DataError: wrong argument
        '''
        try:
#        if isinstance(reader, DataReader):
            self._readers.add(reader)
            if len(self):
                reader.sourceexpanded()
            else:
                reader.sourcecleared()
#        else:
        except SamplerError:
            pass
        except:
            raise
            raise DataError("Expecting a DataReader, got %s" % reader)
    
    def deregisterReader(self, reader):
        '''
        @summary: removes a registered reader
        @param reader: data consumer
        @type reader: DataReader 
        '''
        try:
            self._readers.remove(reader)
        except KeyError:
            pass
    
    def __len__(self):
        raise DataError("%s must implement __len__ method" % self)

    def __getitem__(self, k):
        raise DataError("%s must implement __getitem__ method" % self)

    @property
    def name(self):
        raise DataError("%s must implement name property" % self)

    @property
    def readerClass(self):
        raise DataError("%s must implement readerClass property" % self)

    @property
    def data(self):
        self.process()
        return self._data

    def process(self):
        '''
        @summary: recursively process data records of the source chain
        @return: status of the data processing
        @rtype: int
        '''
        with self._processlock:
            if self._inputreader:
#                print "PROC SRC", self, self._inputreader.source
                self._inputreader.source.process()
#            print "PROC", self
            status = self._process()
            if status & self.CLEARED:
#                print "SRC cleared", self
                self._sourcecleared()
            if status & self.EXPANDED:
#                print "SRC expanded", self
                self._sourceexpanded()
            return status

    def _process(self):
        raise DataError("%s must implement _process method returning process status" % self)

    def _sourcecleared(self):
        for r in self._readers:
            r.sourcecleared()

    def _sourceexpanded(self):
        for r in self._readers:
            r.sourceexpanded()
