#
# 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.
#
import apex

import os




###
# this function gets an array of lines from the abaqus file
# it returns a list of point objects, that have the entries
# 'nodeID', 'adamsID', 'x', 'y', 'z' and 'markerLabel'
###
def getNodes(fileLines):
    nodes = []
    detectedPointEntries = False
    positionInPointEntries = 0
    for line in fileLines:
        # detect start of point entries
        if "(Global Reference Frame)" in line and not detectedPointEntries:
            detectedPointEntries = True

        # if start detected, wait until header lines are skipped and then process
        if positionInPointEntries >= 3:
            # detect end of point entries
            if line.strip() == "**":
                break
                
            # process line
            node = {}
            node['nodeID'] = int(line[3:11])
            node['adamsID'] = int(line[12:20])
            node['x'] = float(line[21:33])
            node['y'] = float(line[34:46])
            node['z'] = float(line[47:59])
            node['markerLabel'] = line[60:72].strip()
            nodes.append(node)

        # increase counter from beginning of point entries, to count header lines without values
        if detectedPointEntries:
            positionInPointEntries += 1

    return nodes


###
# this function gets an array of lines from the abaqus file
# it returns a list of forceAndMoment objects, that have the entries
# 'ID', 'forceX', 'forceY', 'forceZ', 'momentX', 'momentY' and 'momentZ'
###
def getForceAndMoments(fileLines):
    forceAndMoments = []
    detectedForceAndMomentEntries = False
    
    forceAndMomentIndex = -1
    for line in fileLines:
        if detectedForceAndMomentEntries:
            # detect end of forces and moments
            if line.strip() == "*END STEP":
                break

            # process line
            lineArr = line.split(',')
            forceAndMomentID = int(lineArr[0])
#            forceAndMomentIndex = forceAndMomentID - 1
            component = ""

            numberToComponentAssignment = {
                "1" : "forceX", 
                "2" : "forceY",
                "3" : "forceZ",
                "4" : "momentX",
                "5" : "momentY",
                "6" : "momentZ"
            }

            component = numberToComponentAssignment.get(lineArr[1].strip())
            value = float(lineArr[2])

            # initialize the first element
            if forceAndMomentIndex == -1:
                forceAndMoments.append({
                    'ID' : -1,
                    'forceX' : 0.0,
                    'forceY' : 0.0,
                    'forceZ' : 0.0,
                    'momentX' : 0.0,
                    'momentY' : 0.0,
                    'momentZ' : 0.0,
                })
                forceAndMomentIndex += 1
                forceAndMoments[forceAndMomentIndex]['ID'] = forceAndMomentID
                forceAndMoments[forceAndMomentIndex][component] = value
                
            # initialize next element
            if forceAndMomentID != forceAndMoments[forceAndMomentIndex]['ID']:
                forceAndMoments.append({
                    'ID' : -1,
                    'forceX' : 0.0,
                    'forceY' : 0.0,
                    'forceZ' : 0.0,
                    'momentX' : 0.0,
                    'momentY' : 0.0,
                    'momentZ' : 0.0,
                })
                forceAndMomentIndex += 1
            # overwrite values from list with the given values in processed line
            forceAndMoments[forceAndMomentIndex]['ID'] = forceAndMomentID
            forceAndMoments[forceAndMomentIndex][component] = value
                


        # detect beginning of forces and moments
        if line.strip() == "*CLOAD":
            detectedForceAndMomentEntries = True

        

    return forceAndMoments

def main(InputDict={}):

    #abaqusFileName = "AdamsLoads"
    abaqusFileName = InputDict['filePath']

    # Read abaqus file line by line
    fh_abaqusFile = open(abaqusFileName, 'r')
    Lines = fh_abaqusFile.readlines()

    nodes=getNodes(Lines)
    print("found" , len(nodes) , "nodes:", "\n")

    print(nodes, "\n")

    forceAndMoments = getForceAndMoments(Lines)

    print("found" , len(forceAndMoments) , "forces and moments:", "\n")
    print(forceAndMoments)

    ##########################import the values in Apex GD ##########################
    import gendes_package as apex
    from apex.construct import Point3D, Point2D

    apex.setScriptUnitSystem(unitSystemName = r'''mm-kg-s-N-K''')
    applicationSettingsGeometry = apex.setting.ApplicationSettingsGeometry()
    applicationSettingsGeometry.createGeometryInNewPart = apex.setting.CreateGeometryInNewPart.CurrentPart
    applicationSettingsGeometry.geometryTessellationIsWatertight = True
    applicationSettingsGeometry.geometryEdgeTesselationTolerance = apex.setting.GeometryTessellationTolerance.VeryFine
    applicationSettingsGeometry.geometryFaceTesselationTolerance = apex.setting.GeometryTessellationTolerance.VeryFine
    apex.setting.setApplicationSettingsGeometry(applicationSettingsGeometry = applicationSettingsGeometry)
    model_1 = apex.currentModel()


    ## Create part for the new loads
    part_loads = apex.createPart()
    updatedPartName = part_loads.update( name = "LoadCollector")



    ## define method for the scetch 
    def doSketch_loads():
        
    #    if part_loads is None:
     #       part_loads = model_1.createPart()
        sketch_loads = part_loads.createSketchOnGlobalPlane(
            name = 'Sketch load surface',
            plane = apex.construct.GlobalPlane.XY,
            alignSketchViewWithViewport = True 
        )


        rectangle_loads = sketch_loads.createRectangle2Point(
            name = "Rectangle loads",
            location = Point2D( 0.0, 0.0 ),
            diagonal = Point2D( 1.000000000000000e+02, 1.000000000000000e+02 )
        )

        return sketch_loads.completeSketch( fillSketches = True )


    ## create a sruface in the load collector part
    LoadCollectorEntities = doSketch_loads()
    #print(LoadCollectorEntities[0].name)
         
     
    ######### Ceate forces and moments####################

    surface_loads = LoadCollectorEntities[0]
    attachmentRegionFix =surface_loads.faces

    #print(nodes[1]['markerLabel'])
    #print(nodes[1]['x'])
     
    for entry in nodes:
        remotePt = apex.attribute.createRemotePointEntity(
        x = entry['x'] , 
        y = entry['y'] , 
        z = entry['z'] , 
        )
     #   x = nodes[i]['X'], 
     #   y = nodes[i]['Y'], 
     #   z = nodes[i]['Z'], 
     #   )
        target_temp = apex.EntityCollection()
        target_temp.append(remotePt)
        
        forceFound = False
        for entry2 in forceAndMoments:
            if entry2['ID'] == entry['nodeID']:
                tempX = entry2['forceX']
                tempY = entry2['forceY']
                tempZ = entry2['forceZ']
                
                forceMomentRep_temp = apex.environment.createForceMomentStaticRepByComponent(
                    name = "Static Force - Moment Rep 1",
                    forceX = entry2['forceX'],
                    forceY = entry2['forceY'],
                    forceZ = entry2['forceZ'],
                    momentX = entry2['momentX'],
                    momentY = entry2['momentY'],
                    momentZ = entry2['momentZ'],
                    description = ""   #defaults to " "
                )
            
                forcemoment_1 = apex.environment.createForceMoment(
                    name = entry['markerLabel'],
                    forceMomentRep = forceMomentRep_temp,
                    applicationMethod = apex.attribute.ApplicationMethod.Remote,
                    target = target_temp,
                    attachmentRegion = attachmentRegionFix,
                    attachmentDistributionType = apex.attribute.DistributionType.Rigid,
                    description = ""   #defaults to " "
                )
                
                forceFound = True
                break
        if forceFound == False:
            print('Not all nodes have corresponding forces')