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

# Author: Larry Pearce
# Revised by: Larry Pearce
# Revision History
# Date         Change                                 By
# 2020-10-13   Original code (1.1)                    Larry Pearce

import apex

import os


def formatString(rval):
    s = "%7.4f" % rval
    if s.find(".") == -1 and s.find("e") == -1: s = s+"."

    return s


def normalizeVector(v):
    vx = v.getX()
    vy = v.getY()
    vz = v.getZ()

    vv = v.getLength()

    v = apex.construct.Vector3D(x = vx/vv, y = vy/vv, z = vz/vv)

    return v


def main(dict={}):
    #apex.disableShowOutput()
    myModel = apex.currentModel()

    print("DATA ENTERED")
    outputFile = dict["fspec"]
    coordName  = dict["coordName"]
    rforceVal  = dict["rforceVal"]

    print("Filespec: "+outputFile)
    print("Coordinate Frame: "+coordName)
    print("Angular Velocity: "+rforceVal)

    if outputFile == "":
        print("Output filename is BLANK!")
        return

    if os.path.splitext(outputFile)[1] == "":
        outputFile = outputFile+".bdf"
        print("Filespec has been renamed as: "+outputFile)

    coordSys  = None
    if coordName == "Global":
        coordSys = None
        coordId = 0
    else:
        coords = apex.getCoordinateSystems([{"path":myModel.getName()+"/Coordinate System"}])
        for coord in coords:
            if coord.getName() == coordName:
                coordSys = coord
                coordId = int(coordSys.getName().split(" ")[-1])
                break

    if rforceVal == "":
        print("RFORCE is BLANK!")
        return

    rforceVal = float(rforceVal)
    if rforceVal == 0.0:
        print("RFORCE is equal to ZERO!")
        return

    rforceVal = formatString(rforceVal)

    _selected = apex.selection.getCurrentSelection()

    if _selected.len() == 0:
        print("No Part was selected!")
        return

    if _selected.len() > 1:
        print("Only one Part of Assembly may be selected!")
        return

    isPart = isAssembly = False
    if _selected[0].getEntityType() == apex.EntityType.Part:     isPart = True
    if _selected[0].getEntityType() == apex.EntityType.Assembly: isAssembly = True

    sel = _selected[0]

    dispConstraints = apex.environment.getDisplacementConstraints()
    if dispConstraints.len() < 1:
        print("No displacement constraints applied to the model!")
        return

    # ADD GRAVITY
    # This will be deleted.  This is to make sure that Apex exports the constraints to the bdf
    orientation_ = apex.construct.createOptionOrientation()
    orientation_.GlobalNZ = True
    gravity = apex.environment.createGravityByG(
       name = "TEMP Gravity",
       gravConstant = 386.08858268,
       orientation = orientation_,
       gravConstantMultiplier = 1.0,
       description = "description")


    _entities = apex.EntityCollection()
    _entities.append(sel)
    _entities.showOnly()

    context_ = sel
    study = apex.getPrimaryStudy()
    study.createScenarioByModelRep( context = context_, simulationType = apex.studies.SimulationType.Static )

    scenarioName = "Static Scenario "+sel.getName()

    study = apex.getPrimaryStudy()
    scenario1 = study.getScenario( name = scenarioName )
    scenario1.exportFEModel(
        filename = outputFile,
        unitSystem = "in-slinch-s-lbf-degF-deg",
        exportWideFormat = False,
        exportHierarchicalFiles = False,
        resultOutputType = apex.attribute.NastranResultOutputType.Hdf5,
        renumberMethod = apex.attribute.ExportRenumberMethod.Internal,
        apexEngineeringAbstractions = False)

    # now delete GRAVITY after the bdf has been exported
    _entities = apex.EntityCollection()
    _gravity = apex.environment.getGravity( name = "TEMP Gravity" )
    _entities.append(_gravity)
    apex.deleteEntities(_entities)

    # check to make sure a bdf was exported
    if not os.path.exists(outputFile):
        print("Error exporting bdf")
        return

    # + read the bdf
    # + looking for the max grid id
    # + also looking to see if the selected coordinate frame was exported.  only referenced
    #  coordinate frames are exported
    ff = open(outputFile, "r")
    allData = ff.readlines()

    loadId   = 0  # i am going to assign the load id later
    gridIds  = []
    coordIds = []

    for data in allData:
        if data[0:8].lstrip().rstrip().upper() == "GRID*":
            gridIds.append(int(data[8:24]))
        elif data[0:8].lstrip().rstrip().upper() == "GRID":
            gridIds.append(int(data[8:16]))
        elif data.find("LOAD =") > -1:
            loadId = int(data.split("=")[1])
            loadId = 3
        elif data[0:4].upper() == "CORD":   # i may need to also consider large field format
            coordIds.append(int(data[8:16]))

    if loadId == 0: loadId = 3 # I am hardcoding the load id to 3

    # i am closing and renaming the original bdf
    ff.close()
    if os.path.exists(outputFile + ".bkup"): os.remove(outputFile + ".bkup")
    os.rename(outputFile, outputFile+".bkup")
    #os.remove(outputFile)

    maxGridId = max(gridIds)
    addCoord = False
    if coordId != 0 and coordId not in coordIds:
        addCoord = True
        print("Adding coordinate frame ID = "+str(coordId)+" as the RFORCE coordinate frame to the bdf")
    else:
        print("Using existing coordinate frame ID = "+str(coordId)+" as the RFORCE coordinate frame")

    if coordSys is None:
        rforceCoord = "0"
        a1 = "0.0"
        a2 = "0.0"
        a3 = "0.0"
        _cordCard = ""
    else:
        origin = coordSys.getOrigin()
        xAxis  = coordSys.getXAxis()
        zAxis  = coordSys.getZAxis()
        xx = normalizeVector(xAxis)
        zz = normalizeVector(zAxis)

        a1 = formatString(origin.getX())
        a2 = formatString(origin.getY())
        a3 = formatString(origin.getZ())

        if addCoord:
            b1 = formatString(origin.getX() + zz.getX())
            b2 = formatString(origin.getY() + zz.getY())
            b3 = formatString(origin.getZ() + zz.getZ())

            c1 = formatString(origin.getX() + xx.getX())
            c2 = formatString(origin.getY() + xx.getY())
            c3 = formatString(origin.getZ() + xx.getZ())

    ff = open(outputFile, "w")
    gravDoublePrecision = False
    for data in allData:
        if gravDoublePrecision:
            gravDoublePrecision = False
            continue

        if data[0:4].upper() == "GRAV":
            if data.find("*") > -1: gravDoublePrecision = True
            continue
        elif data.find("SUBCASE") > -1:
            ff.write(data)
            ff.write(" LOAD = "+str(loadId)+"\n")
        elif data.find("LOAD =") > -1:
            continue
        elif data[0:7].upper() == "ENDDATA":
            ff.write("$\n")
            ff.write("$ Data added for RFORCE support\n")
            ff.write("$\n")
            ff.write("$ GRID and RFORCE added ...\n")
            rforceCoord = str(coordId)
            rforceGrid  = str(maxGridId+1)
            _gridCard   = "GRID, "+rforceGrid+", , "+a1+", "+a2+", "+a3+"\n"
            ff.write(_gridCard)
            print("RFORCE GRID = "+str(rforceGrid)+" added at the end of the bdf")
            _rforceCard = "RFORCE, "+str(loadId)+", "+rforceGrid+", "+rforceCoord+", "+rforceVal+", 0.0, 0.0, 1.0\n"
            ff.write(_rforceCard)
            print("RFORCE entry added at the end of the bdf")
            if addCoord:
                _coordCard = "CORD2R, "+rforceCoord+", , "+a1+", "+a2+", "+a3+", "+b1+", "+b2+", "+b3+"\n"+", "+c1+", "+c2+", "+c3+"\n"
                ff.write("$Added coordinate frame: "+str(rforceCoord)+"\n")
                ff.write(_coordCard)
                print("RFORCE coordinate frame added at the end of the bdf")
            else:
                print("Using existing coordinate frame for RFORCE.  CID = "+str(rforceCoord))
            ff.write(data)
        else:
            ff.write(data)
    ff.close()

    print("RFORCE data has been added to: "+outputFile)



