# /**********************************************************************
# *                                                                     *
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com>  *
# *                                                                     *
# * This program is free software; you can redistribute it and/or modify*
# * it under the terms of the GNU Lesser General Public License (LGPL)  *
# * as published by the Free Software Foundation; either version 2 of   *
# * the License, or (at your option) any later version.                 *
# * for detail see the LICENCE text file.                               *
# *                                                                     *
# * This program is distributed in the hope that it will be useful,     *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of      *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       *
# * GNU Library General Public License for more details.                *
# *                                                                     *
# * You should have received a copy of the GNU Library General Public   *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307*
# * USA                                                                 *
# *                                                                     *
# ***********************************************************************


import FreeCAD

if FreeCAD.GuiUp:
    import FreeCADGui, os
    from PySide import QtCore
    from PySide.QtCore import QT_TRANSLATE_NOOP
else:
    # \cond
    def translate(ctxt, txt):
        return txt
    def QT_TRANSLATE_NOOP(ctxt, txt):
        return txt
    # \endcond

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

import openpyxl
from openpyxl.styles import Alignment, Border, Side, PatternFill, Font
import PVPlantResources
import PVPlantSite

# Estilos:
thin = Side(border_style="thin", color="7DA4B8")
double = Side(border_style="double", color="ff0000")
border_thin = Border(top=thin, left=thin, right=thin, bottom=thin)
border_fat = Border(top=thin, left=thin, right=thin, bottom=thin)
# fill = PatternFill("solid", fgColor="DDDDDD")
# fill = GradientFill(stop=("000000", "FFFFFF"))

scale = 0.001 # milimeters to meter

def style_range(ws, cell_range, border=Border(), fill=None, font=None, alignment=None):
    """
    Apply styles to a range of cells as if they were a single cell.

    :param ws:  Excel worksheet instance
    :param range: An excel range to style (e.g. A1:F20)
    :param border: An openpyxl Border
    :param fill: An openpyxl PatternFill or GradientFill
    :param font: An openpyxl Font object
    """

    top = Border(top=border.top)
    left = Border(left=border.left)
    right = Border(right=border.right)
    bottom = Border(bottom=border.bottom)

    first_cell = ws[cell_range.split(":")[0]]
    if alignment:
        first_cell.alignment = alignment

    rows = ws[cell_range]
    if font:
        first_cell.font = font

    for cell in rows[0]:
        cell.border = cell.border + top
    for cell in rows[-1]:
        cell.border = cell.border + bottom

    for row in rows:
        l = row[0]
        r = row[-1]
        l.border = l.border + left
        r.border = r.border + right
        if fill:
            for c in row:
                c.fill = fill

def spreadsheetBOQFrames(sheet, sel):
    sheet['A1'] = 'Index'
    sheet['B1'] = 'Frame'
    sheet['C1'] = 'Frame Type'
    sheet['D1'] = 'X'
    sheet['E1'] = 'Y'
    sheet['F1'] = 'Z'
    sheet['G1'] = 'Angle N-S'
    sheet['H1'] = 'Angle L-W'
    sheet['I1'] = 'Nº Poles'

    sheet.column_dimensions['A'].width = 8
    sheet.column_dimensions['B'].width = 30
    sheet.column_dimensions['C'].width = 20
    sheet.column_dimensions['D'].width = 20
    sheet.column_dimensions['E'].width = 20
    sheet.column_dimensions['F'].width = 20
    sheet.column_dimensions['G'].width = 15
    sheet.column_dimensions['H'].width = 15
    sheet.column_dimensions['I'].width = 15
    sheet.row_dimensions[1].height = 40

    style_range(sheet, 'A1:I1',
                border=Border(top=thin, left=thin, right=thin, bottom=thin),
                fill=PatternFill("solid", fgColor="7DA4B8"),
                font=Font(name='Quicksand', size=10, b=True, color="FFFFFF"),
                alignment=Alignment(horizontal="center", vertical="center"))

    for ind in range(0, len(sel)):
        row = ind + 2
        sheet['A{0}'.format(row)] = ind + 1
        sheet['B{0}'.format(row)] = sel[ind].Label
        sheet['C{0}'.format(row)] = sel[ind].Setup.Label
        sheet['D{0}'.format(row)] = sel[ind].Placement.Base.x * scale
        sheet['E{0}'.format(row)] = sel[ind].Placement.Base.y * scale
        sheet['R{0}'.format(row)] = sel[ind].Placement.Base.z * scale
        sheet['G{0}'.format(row)] = sel[ind].Placement.Rotation.toEuler()[0]
        sheet['H{0}'.format(row)] = sel[ind].Placement.Rotation.toEuler()[1]
        sheet['I{0}'.format(row)] = sel[ind].Setup.NumberPole.Value
        style_range(sheet, 'A' + str(row) + ':I' + str(row),
                    border=Border(top=thin, left=thin, right=thin, bottom=thin),
                    font=Font(name='Quicksand', size=10),
                    alignment=Alignment(horizontal="center", vertical="center"))

def spreadsheetBOQPoles(sheet, sel):
    import MeshPart as mp
    from Mechanical.Frame import PVPlantFrame

    # Data:
    terrain = PVPlantSite.get().Terrain.Mesh  # Shape

    # Headers:
    sheet['A1'] = 'Frame'
    sheet['B1'] = 'Pole'
    sheet['C1'] = 'Pole Type'
    sheet['D1'] = 'X'
    sheet['E1'] = 'Y'
    sheet['F1'] = 'Z frame attach'
    sheet['G1'] = 'Z aerial head'
    sheet['H1'] = 'Pole length'
    sheet['I1'] = 'Pole aerial length'
    sheet['J1'] = 'Pole terrain enter length'

    sheet.column_dimensions['A'].width = 30
    sheet.column_dimensions['B'].width = 8
    sheet.column_dimensions['C'].width = 20
    sheet.column_dimensions['D'].width = 20
    sheet.column_dimensions['E'].width = 20
    sheet.column_dimensions['F'].width = 20
    sheet.column_dimensions['G'].width = 20
    sheet.column_dimensions['H'].width = 20
    sheet.column_dimensions['I'].width = 20
    sheet.column_dimensions['J'].width = 20
    sheet.row_dimensions[1].height = 40
    style_range(sheet, 'A1:J1',
                border=Border(top=thin, left=thin, right=thin, bottom=thin),
                fill=PatternFill("solid", fgColor="7DA4B8"),
                font=Font(name='Quicksand', size=11, b=True, color="FFFFFF"),
                alignment=Alignment(horizontal="center", vertical="center"))
    sheet['A2'] = ""
    sheet.row_dimensions[2].height = 5

    data = {"Frame": [],
            #"FrameType": [],
            "Pole": [],
            "PoleType": [],
            "PoleLength": [],
            "Center": [],
            "Head": []}

    cnt = 0
    for frame_ind, frame in enumerate(sel):
        poles = frame.Shape.SubShapes[1].SubShapes[0].SubShapes
        numpoles = int(frame.Setup.NumberPole.Value)
        seq = frame.Setup.PoleSequence
        if len(seq) < numpoles:
            seq = PVPlantFrame.getarray(frame.Setup.PoleSequence, numpoles)
        for pole_ind in range(numpoles):
            pole = poles[pole_ind]
            poletype = frame.Setup.PoleType[seq[pole_ind]]
            data["Frame"].append(frame.Label)
            #data["FrameType"].append(frame.Setup.Label)
            data["Pole"].append(pole_ind + 1)
            data["PoleType"].append(poletype.Label)
            data["PoleLength"].append(int(poletype.Height))
            data["Center"].append(pole.BoundBox.Center)
            data["Head"].append(pole.BoundBox.ZMax)
            cnt += 1

    pts = mp.projectPointsOnMesh(data["Center"], terrain, FreeCAD.Vector(0, 0, 1))
    #if cnt == len(pts):
    data["Soil"] = pts

    row = 3
    group_from = row
    f = data["Frame"][0]
    for i in range(0, len(data["Frame"])):
        if f != data["Frame"][i]:
            style_range(sheet, 'A' + str(group_from) + ':F' + str(row - 1),
                        border=Border(top=thin, left=thin, right=thin, bottom=thin),
                        font=Font(name='Quicksand', size=11, ),
                        alignment=Alignment(horizontal="center", vertical="center"))
            sheet.merge_cells('A' + str(group_from) + ':A' + str(row - 1))
            style_range(sheet, 'A' + str(group_from) + ':A' + str(row - 1),
                        border=Border(top=thin, left=thin, right=thin, bottom=thin),
                        font=Font(name='Quicksand', size=11, ),
                        alignment=Alignment(horizontal="center", vertical="center"))
            #sheet['A{0}'.format(row)] = ""
            sheet.row_dimensions[row].height = 5
            row += 1
            f = data["Frame"][i]
            group_from = row

        sheet['A{0}'.format(row)] = data['Frame'][i]
        sheet['B{0}'.format(row)] = data['Pole'][i]
        sheet['C{0}'.format(row)] = data['PoleType'][i]
        sheet['D{0}'.format(row)] = round(data['Center'][i].x, 0) * scale
        sheet['D{0}'.format(row)].number_format = "0.000"
        sheet['E{0}'.format(row)] = round(data['Center'][i].y, 0) * scale
        sheet['E{0}'.format(row)].number_format = "0.000"
        try:
            sheet['F{0}'.format(row)] = round(data['Soil'][i].z, 0) * scale
            sheet['F{0}'.format(row)].number_format = "0.000"
        except:
            pass
        sheet['G{0}'.format(row)] = round(data['Head'][i]) * scale
        sheet['G{0}'.format(row)].number_format = "0.000"
        sheet['H{0}'.format(row)] = data["PoleLength"][i] * scale
        sheet['H{0}'.format(row)].number_format = "0.000"
        sheet['I{0}'.format(row)] = '=G{0}-F{0}'.format(row)
        sheet['I{0}'.format(row)].number_format = "0.000"
        sheet['J{0}'.format(row)] = '=H{0}-I{0}'.format(row)
        sheet['J{0}'.format(row)].number_format = "0.000"

        style_range(sheet, 'A' + str(row) + ':J' + str(row),
                    border=Border(top=thin, left=thin, right=thin, bottom=thin),
                    font=Font(name='Quicksand', size=11,),
                    alignment=Alignment(horizontal="center", vertical="center"))
        row += 1

def spreadsheetBOQPanelCollision(sheet, sel):
    # Headers:
    sheet['A1'] = 'Frame'
    sheet['B1'] = 'Nombre'
    sheet['C1'] = 'X'
    sheet['D1'] = 'Y'
    sheet['E1'] = 'Z'
    sheet['G1'] = 'Ángulo E-O'
    sheet['H1'] = 'Nº Hincas'

    sheet.column_dimensions['A'].width = 30
    sheet.column_dimensions['B'].width = 8
    sheet.column_dimensions['C'].width = 20
    sheet.column_dimensions['D'].width = 20
    sheet.column_dimensions['E'].width = 20
    sheet.column_dimensions['F'].width = 20
    sheet.column_dimensions['G'].width = 20
    sheet.column_dimensions['H'].width = 20
    sheet.column_dimensions['I'].width = 20
    sheet.row_dimensions[1].height = 40
    style_range(sheet, 'A1:I1',
                border=Border(top=thin, left=thin, right=thin, bottom=thin),
                fill=PatternFill("solid", fgColor="7DA4B8"),
                font=Font(name='Quicksand', size=11, b=True, color="FFFFFF"),
                alignment=Alignment(horizontal="center", vertical="center"))
    sheet['A2'] = ""
    sheet.row_dimensions[2].height = 5

    # Data:
    for frame_ind in range(0, len(sel)):
        frame = sel[frame_ind]
        sheet['A{0}'.format(ind + 2)] = ind
        sheet['B{0}'.format(ind + 2)] = sel[ind].Label
        sheet['C{0}'.format(ind + 2)] = sel[ind].Placement.Base.x * scale
        sheet['D{0}'.format(ind + 2)] = sel[ind].Placement.Base.y * scale
        sheet['E{0}'.format(ind + 2)] = sel[ind].Placement.Base.z * scale
        sheet['F{0}'.format(ind + 2)] = sel[ind].Placement.Rotation.toEuler()[0]
        sheet['G{0}'.format(ind + 2)] = sel[ind].Placement.Rotation.toEuler()[1]
        sheet['H{0}'.format(ind + 2)] = sel[ind].NumberPole.Value

class _CommandBOQMechanical:
    def GetResources(self):
        return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "boqm.svg")),
                'Accel': "R, M",
                'MenuText': QT_TRANSLATE_NOOP("Placement", "BOQ Mecánico"),
                'ToolTip': QT_TRANSLATE_NOOP("Placement", "Calcular el BOQ de la")}

    def Activated(self):
        # make file global:
        #sel = FreeCAD.ActiveDocument.findObjects(Name="Tracker")
        sel = []
        for obj in FreeCAD.ActiveDocument.Objects:
            '''if not hasattr(obj, "Proxy"):
                continue
            if issubclass(obj.Proxy.__class__, PVPlantRack.Frame):
                objects.append(obj)'''
            if obj.Name.startswith("Tracker") and not obj.Name.startswith("TrackerSetup"):
                sel.append(obj)
        sel = sorted(sel, key=lambda x: x.Label)
        if len(sel) > 0:
            path = os.path.dirname(FreeCAD.ActiveDocument.FileName)
            filename = os.path.join(path, "BOQMechanical.xlsx")
            mywb = openpyxl.Workbook()
            sheet = mywb.active
            sheet.title = 'Frames information'
            spreadsheetBOQFrames(sheet, sel)

            sheet = mywb.create_sheet("Poles information")
            spreadsheetBOQPoles(sheet, sel)
            mywb.save(filename)

            print("Se ha generado el BOQMechanical: ")
            print(filename)
            '''import sys
            path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
            sys.path.append(path)'''

            import subprocess
            subprocess.Popen('explorer ' + path)

    def IsActive(self):
        if FreeCAD.ActiveDocument:
            return True
        else:
            return False

if FreeCAD.GuiUp:
    FreeCADGui.addCommand('BOQMechanical', _CommandBOQMechanical())
