"""Support for CSV files.

See README.txt and interfaces.py to learn more.
"""

import csv
import grok
from waeup.sirp.csvfile.interfaces import ICSVFile

class CSVFile(grok.Adapter):
    """A CSV file abstraction.
    """
    grok.context(basestring)
    grok.implements(ICSVFile)

    required_fields = []
    path = None
    
    def __init__(self, context):
        self.path = context
        self.checkFields()

    def checkFields(self):
        headers = self.getHeaderFields()
        missing = [x for x in self.required_fields
                   if x not in headers]
        if len(missing):
            raise TypeError('Missing columns in CSV file: %s' % missing)
        return
            
    def getDictReader(self):
        return csv.DictReader(open(self.path, 'rb'))
    
    def getData(self):
        reader = self.getDictReader()
        for row in reader:
            row = self.processRow(row)
            yield row

    def processRow(self, row):
        return row

    def getHeaderFields(self):
        path = self.path
        reader = self.getDictReader()
        reader.next()
        fields = reader.fieldnames
        return sorted(reader.fieldnames)

    
# The registry for CSV file wrappers...
csvwrappers = [CSVFile,]

def getScore(path, wrapperclass):
    """Compute a score for a certain wrapper related to a certain CSV
    file.
    """
    wrapper = None
    try:
        wrapper = wrapperclass(path)
    except:
        return -1
    required = wrapper.required_fields
    if required == []:
        return 0
    available_headers = wrapper.getHeaderFields()
    score = len([x for x in required if x in available_headers])
    if score < len(required):
        return -1
    return score
    
    
def getCSVFile(path):
    """Get a CSVFile instance for a path.
    """
    best_score = -1
    best_wrapper = None
    
    for wrapperclass in csvwrappers:
        score = getScore(path, wrapperclass)
        if score < best_score or score == -1:
            continue
        best_score, best_wrapper = score, wrapperclass
    if best_wrapper is not None:
        return best_wrapper(path)
    return None

