def __init__(self, src_path, dst_path, photoHandler, dirFilter=None,
 fileFilter=None):
     self.src_path = src_path
     self.dst_path = dst_path
     self.dirFilter = dirFilter
     self.fileFilter = fileFilter
     self.photoHandler = photoHandler
     self.stat_collector = StatCollector()
class PhotoBackuper(object):
    def __init__(self, src_path, dst_path, photoHandler, dirFilter=None,
    fileFilter=None):
        self.src_path = src_path
        self.dst_path = dst_path
        self.dirFilter = dirFilter
        self.fileFilter = fileFilter
        self.photoHandler = photoHandler
        self.stat_collector = StatCollector()
        
    def _join_path(self, pre_path, post_path):
        if type(post_path) == list:
            return map(lambda x: os.path.join(pre_path, x), post_path)
        else:
            return os.path.join(pre_path, post_path)
            
    def _remove_base_path(full_path, base):
        return full_path.split(base)[1]
    
    def _make_dir(self, dir_path):
        if not os.path.genericpath.exists(dir_path): # dir not exists yet
            os.makedirs(dir_path)
        else:
            print 'directory %s already exists.' % dir_path
    
    def _update_stat(self, stat_value, stat_type):
        self.stat_collector.update_stat(stat_value, stat_type)
    
    def print_stat(self):
        print self.stat_collector

    def _make_new_path(self, root_path):
        added_path = os.path.relpath(root_path, self.src_path)
        return self._join_path(self.dst_path, added_path)

    def _filter(self, data_list, filter_type):
        try:
            filter_inst = getattr(self, filter_type + 'Filter')
        except AttributeError as err:
            raise NotImplementedError
            return data_list
        if filter_inst is not None:
            filter_stat, output = filter_inst(data_list)
            self._update_stat(filter_stat, filter_type)
            return output
        else:
            return data_list
    
    def get_dirs_list(self):
        # content of top hierarchy dir (src_path dir)
        src_dir_content = self._join_path(self.src_path, os.listdir(self.src_path))
        full_dir_list = filter(os.path.isdir, src_dir_content)
        # filter top hierarchy dirs only
        allowed_dirs = self._filter(full_dir_list, 'dir')
        dirs_list = []
        for i in allowed_dirs: # collect dirs inside allowed dirs
            dirs_list.extend([root for root, dirs, files in os.walk(i)])
        if dirs_list:
            return dirs_list
        else: 
            # if src_path directory has no dirs inside,
            # return this path itself to find some files inside
            return [self.src_path,]

    def get_files_list(self, dir_path):
        # file names from dir_path
        files_names = os.listdir(dir_path)
        files_list = filter(os.path.isfile, self._join_path(dir_path, files_names))
        filtered_files = self._filter(files_list, 'file')
        return filtered_files        

    def process_image(self, file_path, dst_file_path):
        is_processed = self.photoHandler(file_path, dst_file_path)
        if is_processed:
            self._update_stat(1, 'processed')
        else:
            self._update_stat(1, 'failed')

    @timer
    def backup(self):
        for dir_path in self.get_dirs_list():
            new_dir_path = self._make_new_path(dir_path)
            files_list = self.get_files_list(dir_path)
            if files_list:
                self._make_dir(new_dir_path)    
            for file_path in files_list:
                dst_file_path = self._make_new_path(file_path)
                print "converting: %s -> %s" % (file_path, dst_file_path)
                self.process_image(file_path, dst_file_path)
        self.print_stat()