import csv
from enum import Enum
from io import StringIO


class PanelDataColumn(Enum):
    Handle = 'HANDLE'
    Blockname = 'BLOCKNAME'
    Subarray = 'SUBARRAY'
    PanelType = 'POS'
    WindZone = 'WIND'
    Ballast = 'BAL'
    LinkTray = 'LT_CALCULATED'
    CrossTray = 'XTRAY'
    WindAnchor = 'ANC'
    SeismicAnchor = 'SEISMIC'
    Coordinate = 'COORDINATE'
    Pressure = 'PSF'
    Id = 'ID'
    PresentedLinkTray = 'LTRAY'
    Xcoord = 'XCOORD'
    Ycoord = 'YCOORD'
    Rotation = 'ANGLE'
    FuzzyWindZone = 'FUZZYWINDZONE'


class CSVDataColumn(Enum):
    PresentedAnchors = "ANC"


class CsvBuilder(object):
    def build_cad_output(self, panels):
        panels.sort(key=lambda x: x.id)


        output_columns = [
            PanelDataColumn.Handle, PanelDataColumn.Blockname, PanelDataColumn.WindZone, PanelDataColumn.PanelType,
            PanelDataColumn.Subarray, PanelDataColumn.Pressure, PanelDataColumn.Ballast,
            PanelDataColumn.PresentedLinkTray, PanelDataColumn.CrossTray, CSVDataColumn.PresentedAnchors,
            PanelDataColumn.Id, PanelDataColumn.Xcoord, PanelDataColumn.Ycoord, PanelDataColumn.Rotation
        ]
        use_fuzzy_wind_zone = False
        for panel in panels:
            if panel.fuzzy_wind_zone:
                output_columns.append(PanelDataColumn.FuzzyWindZone)
                use_fuzzy_wind_zone = True
                break

        header_row = [col.value for col in output_columns]
        matrix = [self.format_panel_for_csv(panel, include_fuzzy_wind_zone=use_fuzzy_wind_zone) for panel in panels]

        return self.output_csv(header_row, matrix)

    def build_bom_output(self, rows):
        headers = ['Part #', 'Description', 'Total']
        return self.output_csv(headers, rows)

    def output_csv(self, headers, rows):
        output = StringIO()
        writer = csv.writer(output, dialect='excel-tab', quoting=csv.QUOTE_NONE, quotechar='')

        writer.writerow(headers)
        writer.writerows(rows)
        return output.getvalue()

    def format_panel_for_csv(self, panel, include_fuzzy_wind_zone=False):
        row = [
            panel.handle or "",
            panel.blockname or "",
            self.int_to_wind_zone(panel.wind_zone),
            panel.panel_type.number() if panel.panel_type else "",
            panel.subarray,
            round(panel.pressure, 2) if panel.pressure else "",
            self.present_value(panel.ballast),
            self.present_value(panel.presented_link_tray) or '-',
            self.present_value(panel.cross_tray) or '-',
            self.present_anchors(panel.wind_anchors, panel.seismic_anchors),
            panel.id,
            round(panel.original_coordinate.x, 14),
            round(panel.original_coordinate.y, 14),
            round(panel.original_coordinate.rotation, 14)
        ]
        if include_fuzzy_wind_zone:
            row.append(int(panel.fuzzy_wind_zone))
        return row

    def round_two_digits(self, value):
        return round(value, 2)

    def zero_to_dash(self, value):
        return int(value) or '-'

    def int_to_wind_zone(self, value):
        if value is None:
            return ""
        return ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"][value]

    def present_value(self, value, default=''):
        if value is None:
            return default
        return int(value)

    def present_anchors(self, wind, seismic):
        if not wind and not seismic:
            return '-'
        wind_string = str(int(wind)) if wind != 0 else ''
        return wind_string + 'S' * int(seismic)
