

from typing import List
import FreeCAD as App
import Part
import Mesh
import Part
import MeshPart
import os
import json
import FreeCADGui as Gui

class FS:
    def readJSON(path: str):
        return json.loads((open(path)).read())

    def writeFile(data, filePath, fileName):
        file_to_open = filePath + fileName

        f = open(file_to_open, 'w', encoding='utf-8',
                 errors='ignore')
        f.write(data)
        f.close()
    def createFolder(path: str):
        if (not os.path.exists(path)):
            return os.mkdir(path)



class SimpleCopyPartModel:
    id = None
    copyLink = None
    label = None
    part = None

    def getPart(self):
        return self.part

    def __init__(self, part) -> None:
        try:
            from random import randrange
            self.id = str(randrange(1000000))
            childObj = part
            print(part)
            __shape = Part.getShape(
                childObj, '', needSubElement=False, refine=False)
            obj = App.ActiveDocument.addObject('Part::Feature', self.id)
            obj.Shape = __shape
            self.part = obj
            self.label = obj.Label
            App.ActiveDocument.recompute()
        except Exception as e:
            print(e)

    def remove(self):
        App.ActiveDocument.removeObject(self.label)

class MeshPartModel:
    id = None
    mesh = None

    def __init__(self, part) -> None:
        try:
            from random import randrange
            self.id = 'mesh' + str(randrange(1000000))
            document = App.ActiveDocument
            mesh = document.addObject("Mesh::Feature", self.id)
            shape = Part.getShape(part, "")
            mesh.Mesh = MeshPart.meshFromShape(
                Shape=shape, LinearDeflection=20, AngularDeflection=0.1, Relative=False)
            mesh.Label = self.id
            self.mesh = mesh
        except Exception as e:
            print(e)
        pass

    def remove(self):
        try:
            App.ActiveDocument.removeObject(self.mesh.Label)
        except Exception as e:
            print(e)



class JoinMeshModel:
    id = None
    mesh = None

    def __init__(self, meshesPartModels: list['MeshPartModel']) -> None:
        meshes = []
        from random import randrange
        for el in meshesPartModels:
            meshes.append(el.mesh.Mesh)

        self.id = 'MergedMesh' + str(randrange(1000000))
        doc = App.ActiveDocument
        merged_mesh = Mesh.Mesh()
        for el in meshes:
            merged_mesh.addMesh(el)

        new_obj = doc.addObject("Mesh::Feature", self.id)
        new_obj.Mesh = merged_mesh
        new_obj.ViewObject.DisplayMode = "Flat Lines"  
        self.mesh = new_obj

    def remove(self):
        try:
            App.ActiveDocument.removeObject(self.id)
        except Exception as e:
            print(e)


class ExportAssemblyThemAllUseCase:

    def call(self, path:str, assemblys:list[str]):
        assembly = assemblys
        asmStructure = {}
        inc = 0
        for el in assembly:
            if (inc != 0):
                asmStructure[inc] = {
                    "child": el,
                    "parents": assembly[0:inc]
                }
            inc += 1
        objectsFreeCad = App.ActiveDocument.Objects
        asmSolids = {}
        for k, v in asmStructure.items():
            assemblyParentList = v['parents']
            assemblyChild = v['child']
            for el in assemblyParentList:
                for solid in objectsFreeCad:
                    if (el == solid.Label):
                        if (asmSolids.get(k) is None):

                            asmSolids[k] = {'parents': [], 'child': list(
                                filter(lambda x: x.Label == assemblyChild, objectsFreeCad))[0]}

                        asmSolids[k]['parents'].append(solid)

        inc = 0
        for k, v in asmSolids.items():
            geometry = {"0": [], "1": []}
            if (k != 0):
                App.activeDocument().addObject("Part::Compound", "Compound")

                copyLinks = list(
                    map(lambda el:  SimpleCopyPartModel(el), v['parents']))

                if copyLinks != None:
                    App.activeDocument().Compound.Links = list(
                        map(lambda el: el.getPart(), copyLinks))

                    object = App.activeDocument().getObject('Compound')
                    boundBox = object.Shape.BoundBox
                    geometry['0'].append(boundBox.XMax)
                    geometry['0'].append(boundBox.YMax)
                    geometry['0'].append(boundBox.ZMax)

                    boundBoxChild = v['child'].Shape.BoundBox
                    geometry['1'].append(boundBoxChild.XMax)
                    geometry['1'].append(boundBoxChild.YMax)
                    geometry['1'].append(boundBoxChild.ZMax)
                    meshParents = []

                    for el in v['parents']:
                        meshParents.append(MeshPartModel(el))
                    joinMesh = JoinMeshModel(meshParents)
                    for el in meshParents:
                        el.remove()
                    import importOBJ
                    importOBJ.export(joinMesh.mesh, path + str(1) + '.obj')
                    joinMesh.remove()
                    importOBJ.export(v['child'], path + str(0) + '.obj')
                    FS.writeFile(json.dumps(geometry), path, 'translation.json')

                    App.ActiveDocument.removeObject("Compound")
                    for el in copyLinks:
                        el.remove()
                    App.activeDocument().recompute()
            inc += 1

def main():

    env = FS.readJSON('./env.json')
    env.get('cadDoc')
    aspDir = env.get('aspDir')
    sequences = FS.readJSON(env.get('sequences')).get('sequences')
    App.openDocument(env.get('cadDoc'))
    for sequencyNumber in range(len(sequences)):
        FS.createFolder(aspDir + 'assemblys/')
        mainFolder = aspDir + 'assemblys/' + str(sequencyNumber) + '/'
        FS.createFolder(mainFolder)
        for subSequenceNumber in  range(len(sequences[sequencyNumber])):
            if(subSequenceNumber != 0):
                subFolder = aspDir + 'assemblys/' + \
                        str(sequencyNumber) + '/' + str(subSequenceNumber) + '/'

                FS.createFolder(subFolder)
                ExportAssemblyThemAllUseCase().call(path=subFolder,assemblys=sequences[sequencyNumber][0:subSequenceNumber+1])

    App.closeDocument(App.ActiveDocument.Name)
    freecadQTWindow  = Gui.getMainWindow()
    freecadQTWindow.close()
main()