# coding: utf-8
#
# 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.
#

try:
    import matplotlib.pyplot as plt
except:
    print("matplotlib not installed")
import apex
import materialsCDE
import classicalLaminateTheory as CLT
import failCDE
from apex.construct import Point3D, Point2D
try:
    import numpy
except:
    print("numpy not installed")
from operator import itemgetter
import os
# reload modules during development
from importlib import reload
reload(materialsCDE)
reload(CLT)
reload(failCDE)
global standalone
standalone = False


def main(CDE_dict={}):
    apex.disableShowOutput()

    # create utility specific material objects for all materials

    iret = materialsCDE.find_all_mat_properties()
    mat1_dict = iret[0]
    mat8_dict = iret[1]
    materialsCDE.createQ(mat1_dict, mat8_dict)

# create dictionary of zones and elements

    zoneDict = createZoneDict()  # returns dictionary of zone for each composite element

# convert tool settings to variables

    print(f"Tool settings: {dict}")
    failureTheory = CDE_dict.get("failureTheory")
    membraneStiffness = CDE_dict.get("membraneStiffness")
    bendingStiffness = CDE_dict.get("bendingStiffness")
    membraneStrength = CDE_dict.get("membraneStrength")
    bendingStrength = CDE_dict.get("bendingStrength")

# loop through selected elements and find which zones are used

    _selected = apex.selection.getCurrentSelection()
    if len(_selected) == 0:
        print("Nothing selected?")
        return
    model = apex.currentModel()
    usedZoneList = []

    elements = apex.entityCollection()
    for sel in _selected:
        if type(sel) == apex.mesh.Element:
            elements.append(sel)
    # print(f"Elements: {elements}")
    for element in elements:
        EID = element.getId()
        try:
            zone = zoneDict[str(EID)]
        except:
            print("Not Composite!")
        else:
            # is zone in usedZones?  If not add
            flag = 0
            for item in usedZoneList:
                test = (item == zone)
                if test:
                    flag = 1
            if flag == 0:
                usedZoneList.append(zone)


    for zone in usedZoneList:
        plies = zone.getPlies()
        ABDout = CLT.createABD(plies, mat1_dict, mat8_dict)
        a = ABDout[0]
        b = ABDout[1]
        d = ABDout[2]
        abdTop = numpy.concatenate((a, b), axis=1)
        abdBottom = numpy.concatenate((b.transpose(), d), axis=1)
        abd = numpy.concatenate((abdTop, abdBottom))
        abdInv = numpy.linalg.inv(abd)
        fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(ncols=2,
                                        nrows=2,
                                        subplot_kw=dict(projection='polar'),
                                        gridspec_kw=dict(left=0.2, right=0.8,
                                        bottom=0.2, top=0.8),
                                        constrained_layout=True)
        fig.suptitle('Composite Design Explorer', fontsize=20)
        if membraneStiffness == "True":
            plt_data = CLT.create_polar_stiffness(a, "Membrane Stiffness")
            angle_list = plt_data[0]
            k_list = plt_data[1]
            ax1.set_title('Membrane Stiffness')
            ax1.plot(angle_list, k_list, linewidth=2)
        if bendingStiffness == "True":
            plt_data = CLT.create_polar_stiffness(d, "Bending Stiffness")
            angle_list = plt_data[0]
            k_list = plt_data[1]
            ax2.set_title('Bending Stiffness')
            ax2.plot(angle_list, k_list, linewidth=2)
        if membraneStrength == "True":
            plt_data = failCDE.failureEnvelope(plies,
                                               abdInv,
                                               mat1_dict,
                                               mat8_dict,
                                               failureTheory,
                                               "membrane")
            angle_list = plt_data[0]
            SR_list = plt_data[1]
            ax3.set_title(f"Membrane failure, Theory= {failureTheory}")
            ax3.plot(angle_list, SR_list, linewidth=2)
        if bendingStrength == "True":
            plt_data = failCDE.failureEnvelope(plies,
                                               abdInv,
                                               mat1_dict,
                                               mat8_dict,
                                               failureTheory,
                                               "bending")
            angle_list = plt_data[0]
            SR_list = plt_data[1]
            ax4.set_title(f"Bending failure, Theory= {failureTheory}")
            ax4.plot(angle_list, SR_list, linewidth=2)
        plt.show()


def createZoneDict():
    # Creates dictionary of zones for each element in a zone.

    elementZoneDict = {}
    panels = apex.attribute.getLayeredPanels([{}])
    for panel in panels:
        zones = apex.entityCollection()
        zones = panel.getZones()
#   print("Zones:" + str(zones))
        for zone in zones:
            regions = apex.entityCollection()
            regions = zone.getRegions()
#     print ("Regions: "+ str(regions))
            for face in regions:
                elements = face.getElements()
                for element in elements:
                    EID = element.getId()
                    elementZoneDict[EID] = zone
    return elementZoneDict
