import _csv
from _csv import Error, __version__
from _csv import QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE

__all__ = [ "QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE",
            "Error", "Dialect", "excel", "excel_tab", "reader", "writer",
            "register_dialect", "get_dialect", "list_dialects",
            "unregister_dialect", "__version__" ]

_dialects = {}

def register_dialect(name, dialect):
    if not issubclass(dialect, Dialect):
        raise TypeError, "dialect not a subclass of Dialect"
    if dialect == Dialect:
        raise ValueError, "Dialect is an abstract class"
    d = dialect()
    dialect._name = name
    _dialects[name] = d

def get_dialect(name):
    return _dialects[name]

def list_dialects():
    return _dialects.keys()

def unregister_dialect(name):
    del _dialects[name]

class Dialect:
    _name = ""
    _valid = False
    # placeholders
    delimiter = None
    quotechar = None
    escapechar = None
    doublequote = None
    skipinitialspace = None
    lineterminator = None
    quoting = None

    def __init__(self):
        if self.__class__ != Dialect:
            self._valid = True
        errors = self._validate()
        if errors != []:
            raise Error, "Dialect did not validate: %s" % ", ".join(errors)

    def _validate(self):
        errors = []
        if not self._valid:
            errors.append("can't directly instantiate Dialect class")
        if self.delimiter is None:
            errors.append("delimiter not set")
        if self.quotechar is None:
            errors.append("quotechar not set")
        if self.lineterminator is None:
            errors.append("lineterminator not set")
        if self.doublequote not in (True, False):
            errors.append("doublequote setting must be True or False")
        if self.skipinitialspace not in (True, False):
            errors.append("skipinitialspace setting must be True or False")
        return errors

class excel(Dialect):
    delimiter = ','
    quotechar = '"'
    doublequote = True
    skipinitialspace = False
    lineterminator = '\r\n'
    quoting = QUOTE_MINIMAL
register_dialect("excel", excel)

class excel_tab(excel):
    delimiter = '\t'
register_dialect("excel-tab", excel_tab)

class _OCcsv:
    def __init__(self, dialect, **options):
        if isinstance(dialect, Dialect):
            dialect_obj = dialect
        else:
            try:
                dialect_obj = _dialects[dialect]
            except KeyError:
                raise Error('Unknown dialect')
        parser_options = {}
        for attr in dir(dialect_obj):
            if attr.startswith('_'):
                continue
            parser_options[attr] = getattr(dialect_obj, attr)
        parser_options.update(options)
        self.parser = _csv.parser(**parser_options)

class reader(_OCcsv):
    def __init__(self, iterobj, dialect = 'excel',
                 fieldnames=None, restfield=None,
                 **options):
        self.iterobj = iter(iterobj)
        self.fieldnames = fieldnames
        self.restfield = restfield
        _OCcsv.__init__(self, dialect, **options)

    def __iter__(self):
        return self

    def next(self):
        while 1:
            fields = self.parser.parse(self.iterobj.next())
            if fields:
                if self.fieldnames is not None:
                    lf = len(self.fieldnames)
                    result = dict(zip(self.fieldnames, fields))
                    if (lf < len(fields) and
                        self.restfield is not None):
                        result[self.restfield] = fields[lf:]
                    return result
                return fields

class writer(_OCcsv):
    def __init__(self, fileobj, dialect='excel', fieldnames=None, **options):
        self.fileobj = fileobj
        self.fieldnames = fieldnames
        _OCcsv.__init__(self, dialect, **options)

    def writerow(self, fields):
        # if fields is a dict, we need a valid fieldnames list
        # if self.fieldnames is None we'll get a TypeError in the for stmt
        # if fields is not a dict we'll get an AttributeError on .get()
        try:
            flist = []
            for k in self.fieldnames:
                flist.append(fields.get(k, ""))
            fields = flist
        except (TypeError, AttributeError):
            pass
        self.fileobj.write(self.parser.join(fields))

    def writerows(self, lines):
        for fields in lines:
            self.writerow(fields)

# An alternate way of populating the dialects dictionary...
#def _init_dialects():
#    global _dialects
#    mod = sys.modules[__name__]
#    for name in dir(mod):
#        attr = getattr(mod, name)
#        try:
#            if issubclass(attr, Dialect) and attr is not Dialect:
#                dialect = attr()
#                _dialects[dialect.name] = dialect
#        except TypeError:
#            pass
#
#_init_dialects()
