#
# Copyright © 2020 MSC.Software Corporation
#  
# Permission to use Scripts
#  
# Permission is granted to MSC.Software customers with valid licenses of the MSC Apex™ software 
# to use script files posted on this page (collectively “Scripts”) solely for customers’ own authorized 
# internal use in conjunction with licensed use of the MSC Apex software.  
# No other use is permitted.  No license to MSC Apex or other software is granted under this Permission.
#  
# SCRIPTS ARE PROVIDED ON AN "AS-IS" BASIS, WITH NO WARRANTIES OF ANY KIND.  USE OF THE SCRIPTS IS AT CUSTOMER'S SOLE RISK.
#  
# IN NO EVENT SHALL MSC.SOFTWARE CORPORATION, ITS AFFILIATES, SUBSIDIARIES, SUPPLIERS, AGENTS, REPRESENTATIVES OR EMPLOYEES BE LIABLE FOR ANY 
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, 
# STRICT LIABILITY, OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION USE OF THE SCRIPTS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
#  
# Customer shall indemnify, defend and hold MSC.Software Corporation, its affiliates, subsidiaries, suppliers, agents, 
# employees or representatives (collectively, “Indemnified Parties”) harmless from and against any third-party claims 
# brought against Indemnified Parties rising out of or in connection with Customer’s use of the Scripts.
#
''' Module to add simple ply stack to top of existing plies
panel must already exist. Only one material is used, thickness and ply angles sequence can be specified with / between layers '''

# coding: utf-8
# V1.0
import ctypes
import apex


def main(dict={}):
    # apex.disableShowOutput()
    apex.enableShowOutput()
    # print(type(apex.selection.getCurrentSelection()[0]))
    # return
    ''' main function called from ui module.
    dict contains all inputs '''
    model = apex.currentModel()
    parts = model.getParts(recursive = True)

    # Convert angle and thickness sequence to list
    angle_string = dict.get("Angles")
    angles = angle_string.split('/')

    thickness_string = dict.get("Thickness")
    thicknesses = thickness_string.split('/')
    if len(thicknesses) == 1: thicknesses = len(angles)*thicknesses
    if len(thicknesses) == 1:
        print("Inconsistent number of plies between Angles and Thicknesses.")
        return 150

    # Convert list of strings to floats:
    for i, _angle in enumerate(angles):
        try:
            angles[i] = float(_angle)
        except:
            message_box("Add Ply Stack", "Angle input format incorrect!", 48, 0)
            print("Angle input format incorrect!")
            return 100
    for i, _thickness in enumerate(thicknesses):
        try:
            thicknesses[i] = float(_thickness)
        except:
            message_box("Add Ply Stack", "Thickness input format incorrect!", 48, 0)
            print("Thickness input format incorrect!")
            return 125

    material = apex.catalog.getMaterial(name=dict.get("Material"))

# get selected coverage region
    if dict.get("Test") == True:
        myModel = apex.currentModel()
        Parts = myModel.getParts(True)
        _selected = apex.entityCollection()
        for part in Parts:
            _selected += part.getSurfaces()
    else:
        _selected = apex.selection.getCurrentSelection()
    # print("No Selected: " + str(len(_selected)))
    #selection check
    if False:
        faces = []
        surfaces = []
        zones = []
        _geoms = apex.EntityCollection()
        for sel in _selected:
    #        selected_type = type(sel)
            selected_type = sel.getEntityType()
    #        print(f"Type: {selected_type}")
    #        print ('Zone type = ', apex.EntityType.Zone)
            if selected_type == apex.EntityType.Face:
                faces.append(sel)
                # print("Geoms: "+str(_geoms))
                _geoms.append(sel)
            elif selected_type == apex.EntityType.Surface:
                surfaces.append(sel)
                _geoms.extend(sel.getFaces(ids=""))
            elif selected_type == apex.EntityType.Zone:
                zones.append(sel)
        print(str(len(surfaces)) + " Surfaces selected")
        print(str(len(faces)) + " Faces selected")
    #    print(str(len(zones)) + " Zones selected")
        print("Geoms number: "+str(len(_geoms)))

    panels = apex.EntityCollection()
    if apex.getApplicationInfo()['release'] == '2021':
        panels = apex.attribute.getLayeredPanels([{}])     
    else:
        panels = apex.attribute.getLayeredPanels([{"path":apex.currentModel().name}]) # API change after 2021

    # Identify the panel by the selected object:
    if len(_selected) == 0:
        message_box("Add Ply Stack", "No entities selected.", 48, 0)
        return 350
    if type(_selected[0]) == apex.geometry.Face:
        faces = apex.entityCollection()
        # faces = [face for face in surface.getFaces() for surface in part.getSurfaces() for part in parts ]
        for part in parts:
            surfaces = part.getSurfaces()
            for surf in surfaces:
                faces = surf.getFaces()
                for face in faces:
                    if _selected[0] == face:
                        my_surf = surf
                        print(my_surf)
                        break
        for panel in panels:
            if panel.path == my_surf.path:
                my_panel = panel
                # print(my_panel.name)
                # print(my_panel.path, my_surf.path)
                panel_exists = True
                print(my_panel.path)
                break
        if not panel_exists:
            message_box("Add Ply Stack", "No Panel for this surface. Create one to apply the stack.", 16, 0)
            return 200
    elif type(_selected[0]) == apex.geometry.Surface:
        for panel in panels:
            if panel.path == _selected[0].path:
                my_panel = panel
                # print(my_panel.name)
                # print(my_panel.path, my_surf.path)
                break
    elif type(_selected[0]) == apex.attribute.Zone:   #these types are not supported yet
        one_face = _selected[0].getRegions()[0]
        faces = apex.entityCollection()
        for part in parts:
            surfaces = part.getSurfaces()
            for surf in surfaces:
                faces = surf.getFaces()
                for face in faces:
                    if one_face == face:
                        my_surf = surf
                        break
        for panel in panels:
            if panel.path == _selected[0].path:
                my_panel = panel
                # print(my_panel.name)
                # print(my_panel.path, my_surf.path)
                break
    elif type(_selected[0]) == apex.attribute.LayeredPanel:
        my_panel = _selected[0]

    # Check if there are more than one panel in the part:
    # n = 0
    # for panel in panels:
    #     if panel.path == my_panel.path: n += 1
    #     if n > 1:
    #         message_box("Add Ply Stack", "There are more than one panel in the same part.", 48, 0)
    #         return 375

    # Apply Stack
    for _angle, _thickness in zip(angles, thicknesses):
        try:
            myply = my_panel.createAddPlyUsingProjectedVector(material = material,
                thickness = _thickness,
                angle = _angle,
                coverageRegion = _selected,)
            if -22.5 <= _angle < 22.5:
                myply.update(color=[254, 0, 0])
            else:
                if 67.5 <= _angle < 112.5:
                    myply.update(color=[0, 254, 0])
                else:
                    myply.update(color=[0, 0, 127])
        except:
            message_box("Add Ply Stack", "Error creating ply. Please select only one connected region.", 48, 0)
            return 400

        print(f"Ply Mat: {material.name} Thick: {_thickness} Angle {_angle}")


def get_materials(self):
    '''get all materials used in model and return as a dictionary
    of material objects'''
    apex.disableShowOutput()
    my_model = apex.currentModel()
    matls = apex.catalog.getMaterials([{"path": my_model.getName()+"/Materials"}])
#    print(f"matls: {matls}")
    matl_names = []
    for matl in matls:
        matl_names.append(matl.getName())

    if len(matl_names) == 0:
        matl_names.append("None")

    ret_dict = {}
    ret_dict["matlList"] = matl_names

    return ret_dict


def message_box(title, text, icon, style):
    # Force to top
    if style < 4095:
        style += 4096
    messageBox = ctypes.windll.user32.MessageBoxW
    returnValue = messageBox(None, text, title, icon | style)
    return returnValue

# Icon
# 16 Stop-sign icon
# 32 Question-mark icon
# 48 Exclamation-point icon
# 64 Information-sign icon consisting of an 'i' in a circle
#  Styles:
#  0 : OK
#  1 : OK | Cancel
#  2 : Abort | Retry | Ignore
#  3 : Yes | No | Cancel
#  4 : Yes | No
#  5 : Retry | No
#  6 : Cancel | Try Again | Continue
