import wx
import telnetlib
import win32gui

import win32com.client
import os
import sys
import time
import traceback
 
def process_is_running(proc_name):
	#From Adam Pletcher's "Python for Tech Artsts" (http://www.volition-inc.com/gdc/)

	import win32pdh
 
	proc_name = os.path.splitext(proc_name)[0].lower()
 
	junk, instances = win32pdh.EnumObjectItems(None,None,'Process', win32pdh.PERF_DETAIL_WIZARD)
 
	for proc_inst in instances:
		if (proc_inst.lower() == proc_name):
			return True

 
	return False
 
class MB_Sub_Frame(wx.Frame):
        #This comes from Adam Pletcher's "Python for Tech Artsts", and FeindishVegan's Maya Python post here:
        #http://forums.cgsociety.org/showpost.php?p=4215205&postcount=19
	_top_mb_window_handle = None
 
	def __init__(self, parent, app, id=-1, title="Motion Builder Tool", pos=(60, 120), size=(350, 200), name='frame', resize=True, style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_NO_TASKBAR):

 
		wx.Frame.__init__(self, parent, id, title, pos, size, style)
 
		self.app = app
		self.panel = None
 
		self.initialPosOffset = pos
		self._runningModal = False
 
		# resizable windows is the default in wxPython, but we allow caller to override that.
		if (not resize):
			wx.Frame.ToggleWindowStyle(self, wx.RESIZE_BORDER)

 
		# Tool window's background color.  This should be made to match the user's BG color in Max.
		bg_color = (197, 197, 197)
 
		self.SetBackgroundStyle(wx.BG_STYLE_COLOUR)
		self.SetBackgroundColour(wx.Color(bg_color[0], bg_color[1], bg_color[2]))
 
		# Event Bindings
		self.Bind(wx.EVT_CLOSE, self.on_close)
 
	@classmethod
	def create(cls, *args, **kw):
		"""
		Call this static class method to create a new instance of your subframe.
		This will use the 3dsmax window as a parent for the current frame.
		Limitation: If > 1 copy of 3dsmax is open, uses the first one it finds.
		Could probably be fixed, however.
		"""

		if (not process_is_running('motionbuilder.exe')):
			raise WindowsError('*** ERROR: MotionBuilder is not running')
		else:
			app = wx.GetApp()
 

			if (app == None):
				app = wx.App(redirect=False)
 
			val = MB_Sub_Frame._get_top_mb_window()
			topHandle = val[0]
 
			if (topHandle == None):
				raise WindowsError('*** ERROR: Motion Builder window handle not found.')
			else:
				windowPos = val[1]

 
				toolFrame = wx.PreFrame()
				toolFrame.AssociateHandle(topHandle)
				toolFrame.PostCreate(toolFrame)
				app.SetTopWindow(toolFrame)
 
				try:
					frame = cls(toolFrame, app, *args, **kw)
					frame.Show(True)
 
				except:
					print cls.__name__
					print traceback.format_exc()
					frame = None

 
				toolFrame.DissociateHandle()
 
				return frame
 
	@staticmethod
	def _get_top_mb_window():
		if MB_Sub_Frame._top_mb_window_handle is not None:
			return MB_Sub_Frame._top_mb_window_handle

 
		# EnumWindows requires a callback function
		def callback(handle, winList):
			winList.append(handle)
			return True
 
		# Get list of open windows
		windows = []
		win32gui.EnumWindows(callback, windows)
 
		# Find window belonging to 3ds Max

		for handle in windows:
			title = win32gui.GetWindowText(handle)
			if ('MotionBuilder 7.5' in title):
				# Maximize the window if it's minimized
				import win32con
				window = win32gui.ShowWindow(handle, win32con.SW_MAXIMIZE)

 
				# Get upper left desktop coords of MB window
				pos = win32gui.GetWindowRect(handle)[:2]
 
				# Set handle id in our instance
				MB_Sub_Frame._top_mb_window_handle = handle
 
				return (handle, pos)
		# MB window not found
		return None

 
	def on_close(self, evt):
		"""
		Event handler for EVT_CLOSE event.
		"""
		self.Show(False)
		self.Destroy()
		win32gui.DestroyWindow(self.GetHandle())
 
		# Regular wx Destroy waits for the application to destroy the window.
		# Since there is no wxApp running, we do it ourselves.
		win32gui.SetFocus(MB_Sub_Frame._top_mb_window_handle)

 
	def show_modal_dialog(self, dlg):
		"""
		Method to display a modal dialog that also disables the 3dsmax window.
		"""
		mb_disabled = self._runningModal					# Save enabled state, so we can restore it when this modal dialog is done
 
		if (not mb_disabled):
			self._runningModal = True
			top = MB_Sub_Frame._top_mb_window_handle	# get MB window handle

			win32gui.EnableWindow(top, False)				# disable it
 
		ret_val = dlg.ShowModal()								# show our dialog - won't continue until dialog is closed
 
		if (not mb_disabled):									# enables 3dsmax window again, if it was enabled when this dialog started
			win32gui.EnableWindow(top, True)
			self._runningModal = False

 
		return ret_val
 
host = telnetlib.Telnet("127.0.0.1", 4242)
 
def mbPipe(command):
	host.read_until('>>>', .01)
	#write the command
	host.write(command + '\n')
	#read all data returned

	raw = str(host.read_until('>>>', .1))
	#removing garbage i don't want
	raw = raw.replace('\n\r>>>','')
	raw = raw.replace('\r','')
	rawArr = raw.split('\n')
	#cleanArr = [item.replace('\r', '') for item in rawArr]

	return rawArr
 
class MyFrame(MB_Sub_Frame):
 
    def __init__(self,parent,app):
        # create a frame, no parent, default to wxID_ANY
        MB_Sub_Frame.__init__(self, parent, app, id=-1, title='mbUI test',pos=(200, 150),size=(175,280))

 
        #create listbox
        self.selListBox = wx.ListBox(self, -1, choices=[],pos=(8,38),size=(150, 145))
        self.selListBox.Bind(wx.EVT_LISTBOX, self.selListBoxChange)
 
        #create model metadata
        self.translationLabel = wx.StaticText(self,-1,'Pos:',pos=(8,185))
        self.rotationLabel = wx.StaticText(self,-1,'Rot:',pos=(8,200))
 
        #make buttons

        self.selItems = wx.Button(self, id=-1,label='Get Selected Items',pos=(8, 8),size=(150, 28))
        self.selItems.Bind(wx.EVT_BUTTON, self.selItemsClick)
        self.selItems.SetToolTip(wx.ToolTip("Gets all 'models' selected in Motion Builder"))
 
        self.delItems = wx.Button(self, id=-1,label='Delete This Model',pos=(8, 217),size=(150, 28))
        self.delItems.Bind(wx.EVT_BUTTON, self.delItemsClick)
        self.delItems.SetToolTip(wx.ToolTip("Will delete selected models"))
 
        # show the frame
        #self.Show(True)

 
    def selItemsClick(self,event):
        mbPipe("selectedModels = FBModelList()")
        mbPipe("FBGetSelectedModels(selectedModels,None,True)")
        self.selListBox.Set([])
        for item in (mbPipe("for item in selectedModels: print item.Name")):
                self.selListBox.Append(item)

 
    def delItemsClick(self,event):
        mbPipe('FBFindModelByName("' + str(self.selListBox.GetStringSelection()) + '").FBDelete()')
        mbPipe("selectedModels = FBModelList()")
        mbPipe("FBGetSelectedModels(selectedModels,None,True)")
        self.selListBox.Set([])
        for item in (mbPipe("for item in selectedModels: print item.Name")):
                self.selListBox.Append(item)

 
    def selListBoxChange(self,event):
        trans = mbPipe('FBFindModelByName("' + str(self.selListBox.GetStringSelection()) + '").Translation')
        rot = mbPipe('FBFindModelByName("' + str(self.selListBox.GetStringSelection()) + '").Rotation')
        self.translationLabel.SetLabel(('Pos: ' + trans[0]))
        self.rotationLabel.SetLabel(('Rot: ' + rot[0]))

 
    def on_close(self, event):
        #This method is bound by MB_Sub_Frame to the EVT_CLOSE event.
        print 'Shutting down...'
        self.user_exit = True
        self.Destroy()
 
application = wx.PySimpleApp()
window = MyFrame.create()
#window = MyFrame()
application.MainLoop()