"""
HB_ConvertSymmetry V1.0

Last Modified: 6/28/2017
Works with CINEMA 4D R16.050 and up.
Copyright: Holger Biebrach, www.c4dstuff.com

Name-US: HB_ConvertSymmetry
Description-US: Converts the Clip Symmetry Object to a Polygonal Object

Usage:
You need to Select a HB_ClipSymmetry-object and run the Script to convert the Symmetry Setup
to a Polygonal Object.

Video Tutorial:
https://youtu.be/G9XVCcOe6jQ?t=22m31s

ChangeLog:

6/28/2017 
Release Version v1.0

"""

import c4d
from c4d import gui, utils

def InvertPolygonSelection(obj):
    selection = obj.GetPolygonS()
    poly_count = obj.GetPolygonCount()


    for i in range(poly_count):
        if selection.IsSelected(i):
            
            selection.Deselect(i)
        else:
            selection.Select(i)
            
def SelectChildrensPolygons(obj):
    
    while obj:
       
     
        if obj.GetType()==c4d.Opolygon:

            selection = obj.GetPolygonS()
            selection.DeselectAll()
            poly_count = obj.GetPolygonCount()
        
            for i in range(poly_count):
                selection.Select(i)
            
            obj = walker(obj)
            continue

        obj = walker(obj)
        

def walker(obj):
    if not obj: return

    elif obj.GetDown():
        
        return obj.GetDown()
    while obj.GetUp() and not obj.GetNext():
        obj = obj.GetUp()
    return obj.GetNext()


def SelectObjects(objlist):

    for obj in objlist:
        doc.AddUndo(c4d.UNDOTYPE_BITS, obj)
        obj.SetBit(c4d.BIT_ACTIVE)

    return


###################      MAIN

def main():
    doc.StartUndo()
    
    selobj=doc.GetActiveObject()
    

    if not doc.GetActiveObject() or selobj.GetType() != c4d.Osymmetry:
        gui.MessageDialog("Select a HB_ClipSymmetry Object!")
        return

    objPos=selobj.GetMg()
   
    
    if selobj.GetName() == "HB_ClipSymmetry":
        objName=selobj.GetDown().GetDown().GetDown().GetName()
        RootObj = selobj.GetDown().GetDown()
       
        CSsettings = c4d.BaseContainer()                 
        ConvertedObj=utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                            list = [RootObj],
                            mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                            bc = CSsettings,
                            doc = doc,
                            )
        
        ConvertedObj[0].InsertAfter(RootObj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, ConvertedObj[0])
        
        doc.AddUndo(c4d.UNDOTYPE_DELETE,RootObj)
        RootObj.Remove()
        
        NewRootObj= ConvertedObj[0]
        
        doc.AddUndo(c4d.UNDOTYPE_BITS, NewRootObj)
        NewRootObj.SetBit(c4d.BIT_ACTIVE)
        
        doc.AddUndo(c4d.UNDOTYPE_BITS, selobj)
        selobj.DelBit(c4d.BIT_ACTIVE)
        
        
        SelectChildrensPolygons(NewRootObj)
        c4d.EventAdd()
        
        
        doc.AddUndo(c4d.UNDOTYPE_BITS, NewRootObj)
        NewRootObj.DelBit(c4d.BIT_ACTIVE)
        
        doc.SetMode(c4d.Mpolygons)

        
        BooleObj= NewRootObj.GetUp()
        ConvertedBoole=utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                            list = [BooleObj],
                            mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                            bc = CSsettings,
                            doc = doc,
                            )
        
        ConvertedBoole[0].InsertAfter(BooleObj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, ConvertedBoole[0])
        
        Converted=ConvertedBoole[0]
        doc.AddUndo(c4d.UNDOTYPE_DELETE, BooleObj)
        BooleObj.Remove()
        
        
        if Converted.GetType()==c4d.Onull:
            ConvertedObjChild=Converted.GetDown()
            InvertPolygonSelection(ConvertedObjChild)
            ### Delete Polygons
            c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_DELETE,
                                      list=[ConvertedObjChild],
                                      mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                      doc=doc,
                                      flags = c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)
            

            
        else:
            InvertPolygonSelection(Converted)

            ### Delete Inverted Polygons
            c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_DELETE,
                                      list=[Converted],
                                      mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                      doc=doc,
                                      flags = c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)

        
        ConvertedSym=utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                            list = [selobj],
                            mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                            bc = CSsettings,
                            doc = doc,
                            )
         
        if ConvertedSym[0].GetDown().GetDown():
            finalMesh=ConvertedSym[0].GetDown().GetDown()
           
        else:

            finalMesh=ConvertedSym[0].GetDown()
        
        finalMesh.InsertAfter(selobj)
        doc.AddUndo(c4d.UNDOTYPE_NEW,finalMesh)
        doc.AddUndo(c4d.UNDOTYPE_DELETE,selobj)
        selobj.Remove()
        doc.AddUndo(c4d.UNDOTYPE_BITS,finalMesh)
        finalMesh.SetBit(c4d.BIT_ACTIVE)
  
        doc.SetMode(c4d.Mmodel)
        
        doc.AddUndo(c4d.UNDOTYPE_CHANGE,finalMesh)
        finalMesh.SetMg(objPos)
        finalMesh.SetName(objName)
        
        return

    
    if selobj[0].GetName()=="HB_SymmetryCenter":

        selobj=selobj[0].GetUp()
        
    return

    children = selobj.GetChildren()
    selobjpos=selobj.GetMg()
    CSsettings = c4d.BaseContainer()                 
    ConvertedObj=utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                            list = [children],
                            mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                            bc = CSsettings,
                            doc = doc,
                            )
                         
    
    if ConvertedObj[0].GetType()==c4d.Onull:
        ConvertedObjChild=ConvertedObj[0].GetDown()
        ConvertedObjChild.InsertAfter(selobj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, ConvertedObjChild)
    else:
        ConvertedObjChild=ConvertedObj[0]
        ConvertedObjChild.InsertAfter(selobj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, ConvertedObjChild)
        RemoveChildren(ConvertedObjChild.GetChildren())
    
    doc.AddUndo(c4d.UNDOTYPE_DELETE, selobj)
    selobj.Remove()

    InsertChildren(children,ConvertedObjChild)              
    deletetags(ConvertedObjChild)
    doc.AddUndo(c4d.UNDOTYPE_BITS, ConvertedObjChild)
    ConvertedObjChild.SetBit(c4d.BIT_ACTIVE)

    c4d.EventAdd()
    doc.EndUndo()



if __name__=='__main__':
    main()
