--DX Material WireParameter SAVE/Load TEST. by zhangy 11/9/06
-- Beta V1.0 based on the xml io sample by Ravi. Special thanks Larry Minton.
-- notes: only 1 way connect and only for dx material now
--supported: all kind of nodes, environment color, global shadow.
--V3-1 try to use less execute hack and using string converted name
--v4 use filterstring to split the items
--v4.1 change the filter for only tracks have the same subname 3/12/07
--v5.0 add automatic hook up feature  3/14/07
global PMWireUIRollout 
(
--forward declarations
local DXMatXMLToolRoll
struct sxmlIODX
(
	m_xmlDoc,
	ErrorMsg	  = "",
	DxProps1	 = 	#("ToObj","ObjName","ObjClass","SubAni"),
	wireProps1    = #("CtrlClass","ClassID","NumWires","SlaveAnim"), --attributes for wire controller
	wireProps2 	  = #("BlockNum","class_of","FromObj","SubAni","ExprText"), --attributes inside a wire block
	wireCtrlType  = #(Scale_Wire,Point3_Wire,Point4_Wire,Float_Wire,Position_Wire,Rotation_Wire),
	specialTrack  =#(RenderEnvironment,shadowMap),
	splitStr    ="\t",
	------------------------------------------------------------------------------------
	-- general purpose functions
	------------------------------------------------------------------------------------
	--function to filter out xml quat characters..etc
	--function to find the sub-animation path string. findNode should be a string
	fn subAnimPath findNode findName=
	(
	 	 local NodeSubCol=#(findNode as string)
	
		 for i in NodeSubCol do
		 (
		 	local findObj = execute i
			if findObj !=undefined do
			(
				local curNodeSubs = getSubAnimNames findObj
				if curNodeSubs!=undefined do
				(
					if (finditem curNodeSubs findName)!=0 do return i
					--convert all prop name into string
					if curNodeSubs.count >0 do
					(
						for j=1 to curNodeSubs.count do curNodeSubs[j]=i+"[#"+(curNodeSubs[j] as string) +"]"
						join NodeSubCol curNodeSubs
					)
				)
			)
		 )
		return ""
	),
	
-- wireparameter 2 xml design for dx materials - zhangy
	fn wire2xml wireCtrl ctrlElem = 
	(
		--Create an element for the controller
		local wireElem =  m_xmlDoc.createElement "WireParameter"
		--the controller type
		ctrlElem.appendChild wireElem
		wireElem.setAttribute  wireProps1[1] ((classOf wireCtrl) as string)
		--wireElem.setAttribute  wireProps1[2] (wireCtrl.classid as string )
		wireElem.setAttribute  wireProps1[3] (wireCtrl.numWires as string)
		wireElem.setAttribute  wireProps1[4] (wireCtrl.slaveAnimation as string)
		
		for i in 1 to wireCtrl.numWires do 
		(
			local wireBlock=m_xmlDoc.createElement "WireBlock"
			wireElem.appendChild wireBlock
			wireBlock.setAttribute wireProps2[1]  (i as string)
			--set from object
			local parent = wireCtrl.getWireParent i
			local parent_owner=(refs.dependents parent)[1]
			local parentO_class=classof parent_owner
			local parent_class=classof parent		
			local param_name = getSubAnimName parent (wireCtrl.getWireSubnum i)
			local findParent = finditem specialTrack parent_class
			local findParentO = finditem specialTrack parentO_class
			local realIndex = findParent+ findParentO
			--local objCreatable =(classof parent_owner).creatable

			wireBlock.setAttribute wireProps2[2] ((classof parent) as string)
			if realIndex !=0 then
			(
				--if it's a max env global var. we can't find it's from object , we have to convert it to the global var
				wireBlock.setAttribute wireProps2[3] ("(getclassinstances "+(specialTrack[realIndex] as string)+")[1]")
			)
			else
			(
				local MaxPath=exprForMAXObject parent_owner
				local realPath=subAnimPath MaxPath param_name
				wireBlock.setAttribute wireProps2[3] (realPath as string)

			)
			
			wireBlock.setAttribute wireProps2[4] (param_name as string)
			--set expression text part
			expString= wireCtrl.getExprText i
 			result=wireBlock.setAttribute wireProps2[5] expString	
			
		)
	),

	--Dx Material output - zhangy
	fn 	dxWire2xml obj parentElem=
	(	
	
		--go though material anisubs
		local objProps=getPropNames obj
		 
		for i in objProps do
		(
			-- if contoller is a wire type , then output it
			if obj[i]!=undefined and (findItem  wireCtrlType (classof  obj[i].controller))!=0 do
			(
				local nodeElem = m_xmlDoc.createElement "WireTo"
				parentElem.appendChild nodeElem
				nodeElem.setAttribute DxProps1[1] ((exprForMAXObject obj)+"\t")
				nodeElem.setAttribute DxProps1[2] (obj.name)
				nodeElem.setAttribute DxProps1[3] ((classof obj) as string)
				nodeElem.setAttribute DxProps1[4] (i as string)
				wire2xml obj[i].controller nodeElem 
			)
		)
	),

	fn doConnect WireToObj ctrlElem NumWires= 
	(
		--scan the wires inside this controller
		local WireBlockElms=ctrlElem.SelectNodes "WireBlock"
		for i=0 to NumWires-1 do 
		(
			local WireBlockElm=WireBlockElms.item i
			local FromClass = WireBlockElm.getAttribute wireProps2[2]
			local FromObj = WireBlockElm.getAttribute wireProps2[3]
			local FromSubAni ="[#"+ WireBlockElm.getAttribute wireProps2[4]+"]"
			local ExprText= WireBlockElm.getAttribute wireProps2[5]
			local WireFromObj =  execute (FromObj +FromSubAni)
			--if the object and property doesn't existing at all , quit
			if WireFromObj == undefined do 
			(
				print ("Can't find the From Object!:"+FromObj +FromSubAni)
				return false
			)
			--create the actual wire link
			format "From:% Exp:%\n" (FromObj +FromSubAni)  ExprText
			if (paramWire.connect WireFromObj WireToObj ExprText) then
				print "Wire Successful!"
			else 
				print "Wire Failed!"
		)
	),

	fn xml2dxWire nodeElem chkController:false =
	(
		local WireToObj = nodeElem.getAttribute DxProps1[1]
		local WireToName = nodeElem.getAttribute DxProps1[2]
		local WireToClass = nodeElem.getAttribute DxProps1[3]
		local WireToSub = "[#"+nodeElem.getAttribute DxProps1[4]+"]"
		--split the to objs
		local toObjCol= filterString  WireToObj splitStr
		for i in toObjCol do
		(
			local WireToPath =execute (i+ WireToSub)
			--if the object and property doesn't existing at all , quit
			if WireToPath== undefined do 
			(
				errorMsg="Can't find the To Object!:"+WireToObj+WireToSub
				return false
			)
			format "To:% "  (WireToObj+WireToSub)
			--get the wire parameter block attribute
			local wireElem =nodeElem.SelectSingleNode "WireParameter"
			/*
			local ctrlClass = wireElem.getAttribute wireProps1[1]
			local ClassID = wireElem.getAttribute wireProps1[2]
			local SlaveAnim=wireElem.getAttribute wireProps1[4]
			*/
			local NumWires = (wireElem.getAttribute wireProps1[3]) as integer
			doConnect WireToPath wireElem NumWires
		)
	),
	
	fn	getConnections =
	(
		local connCol=#()
		local objs = gXmlIO.m_xmlDoc.selectNodes "//WireTo"
		for i=0 to (objs.count-1) do
		(
			--local WireToObj = (objs.item i).getAttribute DxProps1[1]
			local WireToName =(objs.item i).getAttribute DxProps1[2]
			append connCol WireToName
			
		)
		connCol 
	),
	
	fn removeConnection connIndex=
	(
		if connIndex!=undefined do
		(
			local objs = m_xmlDoc.selectNodes "//WireTo"
			local worldElm = gXmlIO.m_xmlDoc.SelectSingleNode "//world"
			for i=0 to (objs.count-1) do
			(
				if i==connIndex do worldElm.RemoveChild (objs.item i)
			)
		)
	),
	fn getWireTargets ConnIndex=
	(
		local nameCol=""
		if ConnIndex !=-1 do
		(
			local objs = m_xmlDoc.selectNodes "//WireTo"
			if objs.count!=0 do
			(
				local WireToObj = (objs.item ConnIndex).getAttribute DxProps1[1]		
				nameCol=filterString WireToObj splitStr
			)
		)
		nameCol
	),
	fn getWireSubname ConnIndex=
	(
		local WireSubname=""
		if ConnIndex!=-1 then
		(
			local objs = m_xmlDoc.selectNodes "//WireTo"
			if objs.count!=0 do WireSubName = (objs.item ConnIndex).getAttribute DxProps1[4]
		)
		WireSubname
		
	),
	
	fn Targets2Str inArray=
	(
		local outStr=""
		for i in inArray do
			outStr+=i+"\t"
		outStr
	),
	fn addWireTarget ConnIndex TargetName=
	(
		if ConnIndex!=-1 do
		(
			local objs = m_xmlDoc.selectNodes "//WireTo"
			local oldTargets=getWireTargets ConnIndex
			--only add the name not in the list
			if (finditem oldTargets TargetName)==0 do append oldTargets TargetName
			(objs.item ConnIndex).setAttribute DxProps1[1] (Targets2Str oldTargets)
		)
		
	),
	
	
	fn removeTarget ConnIndex TargetIndex=
	(
		if ConnIndex!=-1 and TargetIndex!=0 do
		(
			local objs = m_xmlDoc.selectNodes "//WireTo"
			local oldTargets=getWireTargets ConnIndex
			deleteItem oldTargets TargetIndex
			(objs.item ConnIndex).setAttribute DxProps1[1] (Targets2Str oldTargets)
		)
		
	),
	fn clearTarget ConnIndex=
	(
		if ConnIndex!=-1 do
		(
			local objs = m_xmlDoc.selectNodes "//WireTo"
			(objs.item ConnIndex).setAttribute DxProps1[1] ""
		)
		
	),
	fn StartConnect =
	(
		local objs = m_xmlDoc.selectNodes "//WireTo"				 	
		undo "PW XML Connections" on
		(
			for i=0 to (objs.count-1) do
				xml2dxWire (objs.item i)
		)
	),
	--init fn
	fn init force:false = 
	(	
		dotnet.LoadAssembly "system.xml.dll"		
		m_xmlDoc = dotNetObject "System.Xml.XmlDocument" 
		
		local cpi = m_xmlDoc.createProcessingInstruction ("xml") ("version=\"1.0\" encoding = \"gb2312\"")
		m_xmlDoc.AppendChild cpi
		
		local sceneElem = m_xmlDoc.createElement "scene"
		m_xmlDoc.appendChild sceneElem
		local worldElem = m_xmlDoc.createElement "world"
		sceneElem.appendChild worldElem
		
	),
	
	-- loads an xml document into memory
	function load xmlDocName =
	(
		m_xmlDoc.load xmlDocName
	),
	
	-- save the in-memory xml document to file 
	function save xmlDocName =
	(
		m_xmlDoc.save xmlDocName
	)	
)
-- declare a global instance 
gXmlIO = sxmlIODX()
DxMPW_Floater=newRolloutFloater "DX PW XML Tool:beta 1" 170 160

--UI Part
rollout PMWireUIRollout "PMWire Interface" width:330 height:342
(
	local lvops = ListViewOps()
	GroupBox grp1 "ParameterWire Connections" pos:[2,2] width:325 height:158
	dotNetControl WiresElements "Listview" pos:[5,23] width:280 height:110
	--button btn1 "Add" pos:[288,23] width:36 height:20
	button btn2 "Del" pos:[288,43] width:36 height:20
	
	GroupBox grp2 "Wire Targets" pos:[2,163] width:325 height:137	
	dotNetControl TargetsElements "Listview" pos:[5,183] width:280 height:110
	button btn3 "Add" pos:[288,183] width:36 height:20
	button btn4 "Del" pos:[288,205] width:36 height:20
	
	button btn5 "Connect!" pos:[68,307] width:60 height:20
	button btn6 "Cancel" pos:[178,306] width:60 height:20
	button btn7 "Save" pos:[287,308] width:32 height:16

	label lbl1 "" pos:[287,307] enabled:false visible:false
	--AutoWire
	checkbox chk1 "AutoWire" pos:[11,140] width:85 height:14
	button  btn8 "Scan Targets" pos:[102,139] width:70 height:16
	button  btn9 "Delete Targets" pos:[190,139] width:70 height:16
	fn initListView =
	(
		--init the wireelements listview
		lvops.InitListView WiresElements pInitColumns:#("Wire No.","Wire Name") pInitColWidths:#(80,200)
		WiresElements .fullRowSelect = true
		WiresElements .hideSelection = false
		WiresElements .LabelEdit = false
		WiresElements .multiselect = false
		--WiresElements .sorting = (dotnetclass "System.Windows.Forms.SortOrder").none
		lvops.RefreshListView WiresElements 
		
		--init the wireTarget listview
		lvops.InitListView TargetsElements pInitColumns:#("Target No.","Target Name") pInitColWidths:#(80,200) 
		TargetsElements.fullRowSelect = true
		TargetsElements.hideSelection = false
		TargetsElements.LabelEdit = false
		TargetsElements.multiselect = false
		--TargetsElements.sorting = (dotnetclass "System.Windows.Forms.SortOrder").none
		lvops.RefreshListView TargetsElements
		
	)

	fn updateConnectionsList = 
	(	
		
		if gXmlIO.m_xmlDoc.BaseURI==""  do return false
		--get data for connectiosn
		local PW_Connections =gXmlIO.getConnections()
		
		lvops.ClearLvItems WiresElements 
		local LVAdd = lvops.AddLvItem
		
		for i=1 to PW_Connections.count do
		(
			LVAdd WiresElements pTextItems: #((i as string),PW_Connections[i]) 
		)
		lvops.SelectLvItem WiresElements 0
	)
	
	fn updateWireTarget ConnID=
	(
		if ConnID!=undefined do
		(
			local PW_TargetsList =gXmlIO.getWireTargets ConnID
			lvops.ClearLvItems TargetsElements 
			local LVAdd = lvops.AddLvItem
			for i=1 to PW_TargetsList.count do
				LVAdd TargetsElements pTextItems: #((i as string),(PW_TargetsList[i] as string))
			lvops.SelectLvItem TargetsElements 0
		)
	)
	
	on PMWireUIRollout open do
	(
		initListView()
	)
	
	on WiresElements SelectedIndexChanged arg do
	(
		--the arg returned here is useless
		local selectedLVItems=lvops.GetLvSelection WiresElements
		
		if (selectedLVItems.count > 0) then
		(
			local lastIndex = selectedLVItems.count
			updateWireTarget selectedLVItems[lastIndex].index
		)
	)
	on btn2 pressed  do
	(		
		--remove the selected wire connections
		gXmlIO.removeConnection (lvops.GetSelectedIndex WiresElements)
		updateConnectionsList()
		updateWireTarget 0
	)
	
	--the filter fn for the following trackview
	fn tvFilterFN arg=
	(
		if ((classof arg.anim)==DirectX_9_Shader) and (hasProperty arg.anim lbl1.text)do true

	)
	
	--add current scene materials to the list
	on btn3 pressed  do
	(
		local selectedConnID = lvops.GetSelectedIndex WiresElements
		local subName=gXmlIO.getWireSubname selectedConnID
		lbl1.text=subName
		local tvp=trackView.pickTrackDlg #multiple tvFilterFN
		if tvp!=undefined  do
		(
			for i=1 to tvp.count do
				gXmlIO.addWireTarget selectedConnID (exprForMAXObject (tvp[i].anim))
		)
		updateWireTarget selectedConnID
	)
	on btn4 pressed do
	(
		--remove the selected wire target
		local selectedConnID = lvops.GetSelectedIndex WiresElements
		local selectedTargetID = lvops.GetSelectedIndex TargetsElements
		
		gXmlIO.removeTarget selectedConnID (selectedTargetID+1)
		updateWireTarget selectedConnID
	)
	--connect the current xml
	on btn5 pressed do
	(
		gXmlIO.startConnect()
	)
	on btn6 pressed  do
	(		
		--remove the current UI and add the new one
		removeRollout PMWireUIRollout DxMPW_Floater
		DxMPW_Floater.size = [170,150]
		addRollout DXMatXMLToolRoll DxMPW_Floater
		
	)
	on btn7 pressed  do
	(		
		--save the current xmlIo in to a new file
		local FileSaveTemp=getSaveFileName caption:"Select The XML File To Save As" types:"WireParameter XML(*.XML)|*.XML"
		if FileSaveTemp!=Undefined do
		(
			--Save xml part
			gXmlIO.save FileSaveTemp
		)
		
	)
	--process all material in on scene
	fn returnDxMat MatSource paraName=
	(
		local sceneDX=#()
		local sceneMat=#(MatSource)
		for i in sceneMat do 
		(
			if (iskindof i DirectX_9_Shader) and (hasProperty i paraName) do
				append sceneDX i
			if (superclassof i)==material or i==sceneMaterials do for j=1 to i.numsubs do append sceneMat i[j]
		)
		sceneDX
	)
	fn refreshDx ScanMaterials=
	(
			local PW_Connections =gXmlIO.getConnections()
			for i=0 to PW_Connections.count-1 do
			(
				local subName=gXmlIO.getWireSubname i

				for j in (returnDxMat ScanMaterials subName) do
					gXmlIO.addWireTarget i (exprForMAXObject j)
				updateWireTarget i
			)
			--job done, update
			lvops.SelectLvItem WiresElements 0
			lvops.SelectLvItem TargetsElements 0
			updateConnectionsList()
			updateWireTarget 0
	)
	fn clearTarget=
	(
		local PW_Connections =gXmlIO.getConnections()
		for i=0 to PW_Connections.count-1 do
			gXmlIO.clearTarget i
		
		lvops.SelectLvItem WiresElements 0
		lvops.SelectLvItem TargetsElements 0
		updateConnectionsList()
		updateWireTarget 0
		)
		
	fn AutoWireCall = 
	(
		WireNode=Callbacks.notificationParam()
		if WireNode!=undefined do
		(	print "callllllllllllll"
			refreshDx WireNode.material
			)
	)
	on chk1 changed theState do 
	(
		if theState then
			callbacks.addScript #nodePostMaterial "PMWireUIRollout.AutoWireCall()" id:#autoCaller
		else
			callbacks.removeScripts #nodePostMaterial id:#autoCaller
	)
	on btn8 pressed do
	(
		clearTarget()
		refreshDx scenematerials
	)
	on btn9 pressed do
	(
	clearTarget()
	)

)

rollout DXMatXMLToolRoll "DXMatXMLTool-Save/Load" width:162 height:131
(
	button btn1 "Save" pos:[45,28] width:70 height:30
	button btn2 "Load" pos:[45,75] width:70 height:30
	groupBox grp1 "Save/Load" pos:[10,6] width:142 height:112
	on btn1 pressed  do
	(		
		local FileSaveTemp=getSaveFileName caption:"Select The XML File To Save" types:"WireParameter XML(*.XML)|*.XML"
		if FileSaveTemp!=Undefined do
		(
			--Save xml part
			gXmlIO.init()
			local worldElemsList = gxmlIO.m_xmlDoc.GetElementsByTagName "world"
			local worldElem = worldElemsList.item[0]
			--save all the dx materials
			for ob in meditMaterials do if classof ob==DirectX_9_Shader do gXmlIO.dxWire2xml ob worldElem
			gXmlIO.save FileSaveTemp
		)
		
	)
	on btn2 pressed  do
	(
		--load xml part
		local FileLoadTemp=getOpenFileName caption:"Select The XML File To Load" types:"WireParameter XML(*.XML)|*.XML"
		if FileLoadTemp!=Undefined do
		(		
			
			gXmlIO.init()
			gXmlIO.load FileLoadTemp

			--remove the current UI and add the new one
			removeRollout DXMatXMLToolRoll DxMPW_Floater
			DxMPW_Floater.size = [340,365]
			addRollout PMWireUIRollout DxMPW_Floater
			PMWireUIRollout.updateConnectionsList()
		)
	)
)

--add the rollout 

addRollout DXMatXMLToolRoll DxMPW_Floater
clearlistener()
)