#
# 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
from apex.construct import Point3D, Point2D



import os
import sys
import importlib

pathDir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

print("pathDir",pathDir)
if not pathDir in sys.path:
	sys.path.insert(0, pathDir)
	print('inserted ' + pathDir + ' into sys.path')	

from utils_subprocess_v106 import *
importlib.reload(sys.modules['utils_subprocess_v106'])
from utils_subprocess_v106 import *

def getAllParts():
	#get and return all solids from current model
	model_1 = apex.currentModel()
	parts = model_1.getParts(True)
	return parts
	
def getAllSolids():
	solids = apex.entityCollection()
	parts=getAllParts()
	for part in parts:
		solids += part.getSolids()
	return solids

def getAllSurfs():
	surfs = apex.entityCollection()
	parts=getAllParts()
	for part in parts:
		surfs += part.getSurfaces()
	return surfs

def getAllMeshIndepTies():
	outTies=apex.EntityCollection()
	model_1 = apex.currentModel()
	entities=model_1.getNamedEntities()	
	for entity in entities:
		if isinstance(entity, apex.attribute.MeshIndependentTie):
			#print(entity.getName())
			outTies.append(entity)
	print("Found:", len(outTies)," Mesh Indpep Ties")
	return outTies



def main(dict={}):

	model_1 = apex.currentModel()
	
	# Dict to transfer settings regarding model specifics, such as settings per contact body, event settings et.c.
	OptionsD={}
	

	settings_file=dict["xml_file"]
	
	
	#settings_file = file_path + "/res/UtilityUserSettings.xml"
	#settings_file=
	
	try:
		if os.path.isfile(settings_file):
			pass
		else:
			print("Settings file not selected")
			return
	except:
		print("Something is wrong the settings file: " + settings_file + " doesn't seem to exist")
		return


	
	try:
		SettingsD=read_settings(settings_file)
	except:
		print("reading of Settings file failed... exit")
		return
		
	# create a variable that we can later access	
	SettingsD['System']['SettingsFile']=settings_file	
		
	Scenario=dict["Scenario"]
	
	# check filename
	filename, file_extension = os.path.splitext(dict["bdf_file"])
	bdf_full_name=filename + '.bdf'
	
	if bdf_full_name.replace('.bdf','') == "":
		print("***Warning***No export filename given")
		return
	
	#===Settings=== "
	
	SettingsD['NASTRAN_JOB_SETUP']['NonLinearSolver']=dict["Solver"]
	SettingsD['NASTRAN_JOB_SETUP']['ContactMethod']=dict["contactMethod"]
	
	#====Analysis Options ==================
	
	AnalysisType=dict["AnalysisType"]
	
	print("AnalysisType",AnalysisType)
	
	if AnalysisType == "Nastran SOL101":
		exportOptionFlag= "sol101"
	elif AnalysisType == "Nastran SOL400":
		exportOptionFlag= "sol400"
	elif  AnalysisType == "Nastran SOL106":
		exportOptionFlag= "sol106"
	elif  AnalysisType == "Marc Mentat":
		exportOptionFlag= "mentat"
	elif  AnalysisType ==  "Abaqus .inp":	
		exportOptionFlag= "inp_"
		#override dedfaults
		SettingsD['NASTRAN_JOB_SETUP']['RunNastran']="False"
		SettingsD['System']['CreatePatranGroups']="False"
	else:
		exportOptionFlag="None"
		
	SettingsD['System']['ExportUnitSystem']=dict['ExportUnitSystem']


	
	
	#=========Manage Load Steps====================
	#try:
	if 1==1:
		OptionsD['eventStepL']=dict['eventSteps'].split(',')
		OptionsD['eventEpspL']=dict['eventEpsp'].split(',')
		OptionsD['eventEpsuL']=dict['eventEpsu'].split(',')
		OptionsD['eventConvCrit']=dict['eventConvCrit'].split(',')
	#except:
	#	print('No event info in dict')
	
	#========================================
	
	if dict["RunNastran"] == "Run Analysis":
		RunNastran="True"
	else:
		RunNastran="False"
		
	if dict["PostOption"] == "Post using Patran":
		StartPatran="True"
	else:
		#SettingsD['System']['CreatePatranGroups']="False"
		StartPatran="False"
	
	# Update SettingsD for the utils suprocess Step
	SettingsD['NASTRAN_JOB_SETUP']['SOL400StartPatranPost']=StartPatran
		
	# Options for ["Run-Ready input deck", "Bulk data only", "Run Analysis"]
	
	
	if  dict["RunNastran"] == "Run-Ready input deck":
		pass
	elif dict["RunNastran"] == "Run Analysis":
		if dict["bdf_file"].find(" ") > -1:
			print("*** Warning: There are blanks in the file path and Nastran can not be automatically executed. A run ready deck will be exported")
			dict["RunNastran"]="Run-Ready input deck"
	else:
		exportOptionFlag="None"
	
	# Settings from GUI
	SettingsD['NASTRAN_JOB_SETUP']['RunNastran']=dict["RunNastran"].replace("Run Analysis","True").replace("Run-Ready input deck","False").replace("Bulk data only","False")

	SettingsD['RBEX_CBUSH']['ZeroLength']=dict['ZeroLength']
	SettingsD['System']['CreatePatranGroups']=dict['PatranGroups']

	SettingsD['NASTRAN_JOB_SETUP']['LargeDisp']=dict['LargeDisp']
	SettingsD['NASTRAN_JOB_SETUP']['FollowerForce']=dict['FollowerForce']
	SettingsD['NASTRAN_JOB_SETUP']['AnalyticContact']=dict['AnalyticContact']
	
	#SettingsD['System']['MergeTieRbars']=dict['MergeTieRbars']
	SettingsD['System']['MergeTieRbars']="False"

	SettingsD['System']['AUTOMSET']=dict['AutoMset']
	SettingsD['NASTRAN_JOB_SETUP']['AUTOSPCEPS']=dict['AutoSpcEps']
	
	
	#SettingsD['BoltPreLoad']['CombineLoadSteps']=dict['combinePreLoadSteps']
	#SettingsD['NASTRAN_JOB_SETUP']['EditContactTable']=dict['editContactTable']

	#SettingsD['NASTRAN_JOB_SETUP']['SOL400Mode']=dict['sol400Mode'].replace("FAST","FasterThanFast")
	
	#SettingsD['NASTRAN_JOB_SETUP']['SOL101EPSP']=dict['sol400Epsp']
	#SettingsD['NASTRAN_JOB_SETUP']['SOL101EPSU']=dict['sol400Epsu']
	#SettingsD['NASTRAN_JOB_SETUP']['SOL106EPSP']=dict['sol400Epsp']
	#SettingsD['NASTRAN_JOB_SETUP']['SOL400EPSU']=dict['sol400Epsu']
	#SettingsD['NASTRAN_JOB_SETUP']['SOL400EPSP']=dict['sol400Epsp']
	#SettingsD['NASTRAN_JOB_SETUP']['SOL400EPSU']=dict['sol400Epsu']
		

	# Read Contact default settings

	
	SettingsD['NASTRAN_JOB_SETUP']['DefaultContactType']=dict["contactType"]
	
	
	SettingsD['NASTRAN_JOB_SETUP']['AnalyticContact']=dict['AnalyticContact']
	SettingsD['NASTRAN_JOB_SETUP']['RetainGapOverlaps']=dict['RetainGapOverlaps']
	SettingsD['NASTRAN_JOB_SETUP']['StressFreeInitialContact']=dict['StressFreeInitial']
	
	if AnalysisType == "Nastran SOL101":
		SettingsD['NASTRAN_JOB_SETUP']['SOL101DefaultContactType']=dict["contactMethod"]
		SettingsD['NASTRAN_JOB_SETUP']['SOL101TouchingContactError']=dict['DefaultTouchingTol']
		SettingsD['NASTRAN_JOB_SETUP']['SOL101GlueContactError']=dict['DefaultGlueTol']
		SettingsD['NASTRAN_JOB_SETUP']['SOL101DefaultContactType']=dict["contactType"]
	
	elif AnalysisType =="Nastran SOL106":
		SettingsD['NASTRAN_JOB_SETUP']['SOL106TouchingContactError']=dict['DefaultTouchingTol']
		SettingsD['NASTRAN_JOB_SETUP']['SOL106GlueContactError']=dict['DefaultGlueTol']
	
	else:
		SettingsD['NASTRAN_JOB_SETUP']['SOL400DefaultContactType']=dict["contactMethod"]
		SettingsD['NASTRAN_JOB_SETUP']['SOL400TouchingContactError']=dict['DefaultTouchingTol']
		SettingsD['NASTRAN_JOB_SETUP']['SOL400GlueContactError']=dict['DefaultGlueTol']
		SettingsD['NASTRAN_JOB_SETUP']['SOL400DefaultFriction']=dict['DefaultFriction']
		SettingsD['NASTRAN_JOB_SETUP']['SOL400DefaultContactType']=dict["contactType"]


		
	print("RunNastran:     " + SettingsD['NASTRAN_JOB_SETUP']['RunNastran'] )
	print("Scenario:       " + Scenario )
	print("Start Patran:   " + StartPatran )
	print("bdf_file:       " + bdf_full_name )	
	print("settings file:  " + settings_file )	
	
	#print("nodeThicknessLo:        " + SettingsD['System']['NodeThicknessToPshellsLower_T'])
	#print("nodeThicknessUp:        " + SettingsD['System']['NodeThicknessToPshellsUpper_T'])
	#print("ThicknessRangeInc:        " + SettingsD['System']['NodeThicknessToPshellsInc'])
	
	
	
	#===Contact pair settings===
	attrib_names=['contactType','Friction','StressFreeInitial','RetainGapOverlaps','Tolerance','Bias']
	#attrib_names=['contactType','Tolerance','Friction']
	# get all mesh indep ties
	ties=getAllMeshIndepTies()
	tieD={}
	for tie in ties:
		GoFlag=True
		attD={}
		for attrib_name in attrib_names:
			tmp_attributes=tie.getUserAttributes([attrib_name])
			for attrib in tmp_attributes:
				attD[attrib.getAttributeName()]=attrib.getStringValue()
			tieD[tie.getName()]=attD
		
	OptionsD['contactPairSettings']=tieD	
	
	bodies=apex.entityCollection()
	attrib_names=['contactBodyType']
	bodies.extend(getAllSolids())
	bodies.extend(getAllSurfs())

	bodyD={}
	for body in bodies:
		GoFlag=True
		attD={}
		for attrib_name in attrib_names:
			tmp_attributes=body.getUserAttributes([attrib_name])
			for attrib in tmp_attributes:
				attD[attrib.getAttributeName()]=attrib.getStringValue()
			bodyD[body.getName()]=attD
		
	OptionsD['contactBodyType']=bodyD
	
	
	
	#print(OptionsD)
	


	# Checks
	
	if bdf_full_name=="":
		# Use User Home
		#bdf_full_name=os.environ.get('HOMEPATH') + "\\" + Scenario.replace(" ","_") + ".bdf"
		print("***Fail*** Please specify output file")
		return
				
	try:
		export_units=SettingsD['System']['ExportUnitSystem']
		print("*** Exporting using:",export_units)
		print("*** Important! It is the users responsibility to ensure any material used are consistent with export unti system. Check the bdf")
	except:
		print("Could not obtain default units from settings file")
		return
	
	
	#["Run-Ready input deck", "Bulk data only", "Run Analysis"]
	
	# Export options
	if SettingsD['System']['CreatePatranGroups'].upper() == "TRUE":
		hierarchy_flag=True
	else:
		hierarchy_flag=False
		
	
	if Scenario == "Entire Model- Default Loadcase":
		top_assys=model_1.getAssemblies(False)
		top_parts=model_1.getParts(False)
		if (len(top_assys) + len(top_parts) ) > 1:
			print("###Fail### There can be exact ONE Part or ONE Assembly in  top level for the 'Export Entire Model' option")
			return
		top_assy_elems=[]
		top_part_elems=[]			
		if len(top_assys)==1:
			top_assy_elems=top_assys[0].getElements()
		if len(top_parts)==1:
			top_part_elems=top_parts[0].getElements()	
			
		if len(top_assy_elems) ==0 and len(top_part_elems)==0:
			print("###Fail### There are no vaild meshes")
			return

		model_1.exportFEModel(
			filename = bdf_full_name,
			unitSystem = export_units,
			exportWideFormat = False,
			exportHierarchicalFiles = hierarchy_flag,
			resultOutputType = apex.attribute.NastranResultOutputType.Hdf5,
			# meshDependentTieRenderStyle = apex.attribute.MeshDependentTieRenderStyle.AsRBARS,
			renumberMethod = apex.attribute.ExportRenumberMethod.Internal,
			apexEngineeringAbstractions = False,
		 )
	
	else:
		# There seem to be a problem with patran groups generation in the case there is just one part and no top Assy
		assies=model_1.getAssemblies(False)
		if len(assies) != 1:
			# Do not generate Patran groups and do not export hierarchic
			SettingsD['System']['CreatePatranGroups']="False"
			hierarchy_flag=False
			print("Patran groups are not created if there is not exactly one top level assembly")
			
		# need to validate units system later + add more export options later
		
		
		# try to retrieve Scenario from Name, export bdf
		study = apex.getPrimaryStudy()
		scenario1 = study.getScenario( name = Scenario )
		
		AssyRep=False

		try:
			_temp_rep=scenario1.getScenarioModelRep().asAssemblyRep()
			tmp_name=_temp_rep.getName()
			print(tmp_name)
			_temp_rep_parts=_temp_rep.getParts()
			#_temp_rep_parts=_temp_rep.getTargets()
			#print(len(_temp_rep_parts))
			#if len(_temp_rep_parts)==0:
			#	print("###Fail### Selected Assembly contains no parts")
			#	return
			#else:
			#	print("OK-",_temp_rep.getName())
			AssyRep=True
		except:
			pass
		
		if AssyRep==False:
			try:
				print("I am in 2")
				_temp_rep=scenario1.getScenarioModelRep().asPartRep()
				print(_temp_rep.getName() )
				_tmp_meshes=_temp_rep.getMeshes()
				if len(_tmp_meshes) == 0:
					print("###Fail### Selected part contains no meshes")
					return
			except:
				pass
		
		try:
			print("Model Rep Name: ",_temp_rep.getName())
		except:
			print("###Fail### Associate a Model representation to the Study before exporting")
			return
		
		print("")
		print("bdf_full_name",bdf_full_name)
		
		scenario1.exportFEModel(
			filename = bdf_full_name,
			unitSystem = export_units,
			exportWideFormat = False,
			exportHierarchicalFiles = hierarchy_flag,
			resultOutputType = apex.attribute.NastranResultOutputType.Hdf5,
			# meshDependentTieRenderStyle = apex.attribute.MeshDependentTieRenderStyle.AsRBARS,
			renumberMethod = apex.attribute.ExportRenumberMethod.Internal,
			#apexEngineeringAbstractions = False,
		)
	
	
	# Check so that SPCs exist in model
	bdf_h=open(bdf_full_name,'r')
	bdf_lines=bdf_h.readlines()
	bdf_h.close()
	
	n=0
	N=len(bdf_lines)
	goFlag=False
	if Scenario != "Entire Model- Default Loadcase":

		# make sure this is a static scenario1
		steps=scenario1.getSteps()
		print("Steps")
		for step in steps:
			print(step.getName())
	
	
		# make sure there are SPCs in model
		while n < N:
			if bdf_lines[n].replace(' ','').find('SPC=') == 0:
				print("*** Information *** Checking for constraints...Pass")
				goFlag=True
				break
			elif bdf_lines[n].find('BEGIN BULK') ==0:
				print("***Fail*** No constraints in SPC ")
				return
				break
			n+=1
		if goFlag==False:
			print("***Fail*** No SPCs in SUBCASES ")
			return
	
	else:
		while n < N:
			if bdf_lines[n].find('SPC') == 0:
				print("*** Information *** Checking for constraints...Pass")
				goFlag=True
				break
			n+=1
			
		if goFlag==False:
			print("***Fail*** No SPCs in exported model ")
			return
	
	
	
	
	
	ProcessSettingsFileOptions(bdf_full_name,SettingsD,exportOptionFlag,OptionsD)
		

	print("Done exporting")


		

##main()


