#!/usr/bin/env python3.4
#-*- coding: utf-8 -*-

class TableField:
    def __init__(self, id, label, options):
        self._id = id
        self._label = label
        self._options = options

    def id(self): return self._id
    def label(self): return self._label
    def options(self): return self._options

class TableData:
    def __init__(self, fields):
        self._rows = []
        self._fields = fields

    def addLine(self):
        self._rows.append('line')

    def addDoubleLine(self):
        self._rows.append('double-line')

    def addHeader(self):
        self._rows.append('header')

    def fields(self):
        return self._fields

    def add(self, **kwargs):
        found = False
        for key, value in kwargs.items():
            found = False
            for field in self._fields:
                if field.id() == key:
                    found = True
            # if not found:
            #     raise BaseException('field not found: ' + key)

        self._rows.append(kwargs)

    def rawData(self):
        return self._rows

class AsciiTable:
    def __init__(self, data, separator='|'):
        self._data = data
        self._separator = separator
        self._fieldList = data.fields()
        self._fields = {}
        for field in self._fieldList:
            self._fields[field.id()] = field

    def _fieldWidth(self, field):
        return field.options()['ascii']['width']

    def _formatField(self, field, value):
        if isinstance(value, str):
            lines = value.split('\n')
        else:
            lines = [value]

        result = []
        for s in lines:
            align = field.options()['ascii']['align']
            precision = field.options()['ascii']['precision']
            width = field.options()['ascii']['width']

            if isinstance(value, int):
                s = '%d' % value

            if isinstance(value, float):
                s = ('%.'+str(precision)+'f') % value

            if align == 'RIGHT':
                s = ('%-'+str(width)+'s') % s

            else:
                s = ('%'+str(width)+'s') % s

            result.append(s)

        return result

    def printLine(self):
        print(self._separator, end='')
        for field in self._fieldList:
            str = '-' * self._fieldWidth(field)
            print(str+self._separator, end='')
        print()

    def printDoubleLine(self):
        print(self._separator, end='')
        for field in self._fieldList:
            str = '=' * self._fieldWidth(field)
            print(str+self._separator, end='')
        print()

    def printValues(self, values):
        maxLen = 1
        for value in values:
            maxLen = max(maxLen, len(value))

        for i in range(0, maxLen):
            print(self._separator, end='')
            for value in values:
                fieldWidth = len(value[0])

                if i < len(value): print(value[i]+self._separator, end='')
                else:              print(' '*fieldWidth+self._separator, end='')
            print()


    def printHeader(self):
        self.printLine()
        values = []
        for field in self._fieldList:
            values.append(self._formatField(field, field.label()))
        self.printValues(values)
        self.printDoubleLine()

    def print(self):
        data = self._data
        for ent in data.rawData():
            if ent == 'line': self.printLine()
            elif ent == 'double-line': self.printDoubleLine()
            elif ent == 'header': self.printHeader()
            else:
                values = []
                for field in self._fieldList:
                    if field.id() in ent:    value = ent[field.id()]
                    else:                    value = ''
                    if value is None:        value = ''

                    values.append(self._formatField(field, value))
                self.printValues(values)

#!/usr/bin/env python3.4
#-*- coding: utf-8 -*-

class TableField:
    def __init__(self, id, label, options):
        self._id = id
        self._label = label
        self._options = options

    def id(self): return self._id
    def label(self): return self._label
    def options(self): return self._options

class TableData:
    def __init__(self, fields):
        self._rows = []
        self._fields = fields

    def addLine(self):
        self._rows.append('line')

    def addDoubleLine(self):
        self._rows.append('double-line')

    def addHeader(self):
        self._rows.append('header')

    def fields(self):
        return self._fields

    def add(self, **kwargs):
        found = False
        for key, value in kwargs.items():
            found = False
            for field in self._fields:
                if field.id() == key:
                    found = True
            # if not found:
            #     raise BaseException('field not found: ' + key)

        self._rows.append(kwargs)

    def rawData(self):
        return self._rows

class AsciiTable:
    def __init__(self, data, separator='|'):
        self._data = data
        self._separator = separator
        self._fieldList = data.fields()
        self._fields = {}
        for field in self._fieldList:
            self._fields[field.id()] = field

    def _fieldWidth(self, field):
        return field.options()['ascii']['width']

    def _formatField(self, field, value):
        if isinstance(value, str):
            lines = value.split('\n')
        else:
            lines = [value]

        result = []
        for s in lines:
            align = field.options()['ascii']['align']
            precision = field.options()['ascii']['precision']
            width = field.options()['ascii']['width']

            if isinstance(value, int):
                s = '%d' % value

            if isinstance(value, float):
                s = ('%.'+str(precision)+'f') % value

            if align == 'RIGHT':
                s = ('%-'+str(width)+'s') % s

            else:
                s = ('%'+str(width)+'s') % s

            result.append(s)

        return result

    def printLine(self):
        print(self._separator, end='')
        for field in self._fieldList:
            str = '-' * self._fieldWidth(field)
            print(str+self._separator, end='')
        print()

    def printDoubleLine(self):
        print(self._separator, end='')
        for field in self._fieldList:
            str = '=' * self._fieldWidth(field)
            print(str+self._separator, end='')
        print()

    def printValues(self, values):
        maxLen = 1
        for value in values:
            maxLen = max(maxLen, len(value))

        for i in range(0, maxLen):
            print(self._separator, end='')
            for value in values:
                fieldWidth = len(value[0])

                if i < len(value): print(value[i]+self._separator, end='')
                else:              print(' '*fieldWidth+self._separator, end='')
            print()


    def printHeader(self):
        self.printLine()
        values = []
        for field in self._fieldList:
            values.append(self._formatField(field, field.label()))
        self.printValues(values)
        self.printDoubleLine()

    def print(self):
        data = self._data
        for ent in data.rawData():
            if ent == 'line': self.printLine()
            elif ent == 'double-line': self.printDoubleLine()
            elif ent == 'header': self.printHeader()
            else:
                values = []
                for field in self._fieldList:
                    if field.id() in ent:    value = ent[field.id()]
                    else:                    value = ''
                    if value is None:        value = ''

                    values.append(self._formatField(field, value))
                self.printValues(values)

#!/usr/bin/env python3.4 #-*- coding: utf-8 -*- # if not found: #     raise BaseException('field not found: ' + key)