import maya.cmds as mc
from functools import partial

#check if UI is already open
if mc.window('spaceMatchUI', query=True, exists=True):
    mc.deleteUI('spaceMatchUI', window=True)
    
def warningMsg(msg, arg=None):
    mc.confirmDialog(title='Warning', message=msg, button='ok') 
    
#parenting functions
objects = None
world = None
driver1 = None
driver2 = None

def assignObjects(arg=None):
    global objects
    objects = mc.ls(sl=True)
    if not objects:
        warningMsg('Please select at least one object')
    
def assignWorld(arg=None):
    global world
    world = mc.ls(sl=True)
    if not world:
        warningMsg('Please select world')
        
def assignDriver1(arg=None):
    global driver1
    driver1 = mc.ls(sl=True)
    if not driver1:
        warningMsg('Please select driver')
    
def assignDriver2(arg=None):
    global driver2
    driver2 = mc.ls(sl=True)
    if not driver2:
        warningMsg('Please select driver')


def parentObjects(arg=None):
    #Crates  a locator  parent for each object. Constraints locators to world/driver1/driver2 and sets set driven key
    if objects and world and driver1:
        for obj in objects:
            #create locator
            loc = mc.spaceLocator(name=obj+'_loc')
            #parent constraint to object
            constraint = mc.parentConstraint( obj, loc )
            #break constraint
            mc.delete(constraint)
            #parent object to locator
            mc.parent( obj, loc )
            #freeze transforms
            mc.makeIdentity(apply=True, t=1, r=1, s=1, n=0)
            #turn locator display off
            mc.select(loc)
            loc_shape = mc.listRelatives(s=True)
            mc.setAttr(loc_shape[0]+'.visibility',0)
    
            #create constraints
            loc_parentConstraint = mc.parentConstraint( world[0], loc, w=1.0, mo=True )
            mc.parentConstraint(driver1[0], loc, w=0.0, mo=True )
            if driver2:
                mc.parentConstraint(driver2[0] , loc, w=0.0, mo=True)
            #add attribute 'follow'
            mc.select(obj)
            enumNames = ''
            if driver2:
                enumNames = str(world[0])+':'+str(driver1[0])+':'+str(driver2[0])
            else:
                enumNames = str(world[0])+':'+str(driver1[0])
            
            mc.addAttr( ln='follow', at='enum', enumName=enumNames, k=True )
            #set set driven keys
            #world
            mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + str(world[0]) + 'W0', cd= obj + '.follow' )
            mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + str(driver1[0]) + 'W1', cd= obj + '.follow' )
            if driver2:
                mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + str(driver2[0]) + 'W2', cd= obj + '.follow' )
            #driver1
            mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + str(world[0]) + 'W0', v=0.0, cd= obj + '.follow', dv=1 )
            mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + str(driver1[0]) + 'W1',v=1.0, cd= obj + '.follow', dv=1 )
            if driver2:
                mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + str(driver2[0]) + 'W2',v=0.0, cd= obj + '.follow', dv=1 )
            #driver2
            if driver2:
                mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + world[0] + 'W0', v=0.0, cd= obj + '.follow', dv=2 )
                mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + driver1[0] + 'W1',v=0.0, cd= obj + '.follow', dv=2 )
                mc.setDrivenKeyframe( loc_parentConstraint[0] + '.' + driver2[0] + 'W2', v=1.0, cd= obj + '.follow', dv=2 )
    else:
       warningMsg('Please select at least one object, one world and one driver') 
             
    
#space matching functions    
obj = None   
layoutList = []
driverList = []
driversChannel = 'follow'

def clearButtons(arg=None):
    global layoutList
    for ly in layoutList:
        mc.deleteUI(ly)
    layoutList = []   
    
    
def assignObj(arg=None):
    clearButtons()
    global layoutList
    global obj
    global driverList
    sel = mc.ls(sl=True)
    if sel:
        obj = sel[0]
        mc.text(objSelected, e=True, l=str(obj)) 
       
        #find drivers
        driverStr = mc.attributeQuery(str(driversChannel), node= obj, le=True)
        driverList = driverStr[0].split(':')
        
        #add buttons to layout
        for driver in driverList:
            mc.setParent( win )
            ly = mc.columnLayout(adjustableColumn=True)
            layoutList.append(ly)
            mc.button(label=str(driver), command= partial(spaceMatch, driver))
            mc.setParent( win )
    else:
        warningMsg('Please select object')
            
def assignChannel(arg=None):
    global driversChannel
    driversChannel = mc.textField(chanName, q=True, tx=True)
    print(driversChannel)
    
            
def spaceMatch(drv, arg=None):
    global obj
    global driverList
    #get ws tranlation and rotation
    tValues = mc.xform( obj, ws=True, q=True, t=True)
    rValues = mc.xform( obj, ws=True, q=True, ro=True)
    tx,ty,tz = tValues[0],tValues[1],tValues[2]
    rx,ry,rz = rValues[0],rValues[1],rValues[2]  
    
    #switch space
    enumIndex = driverList.index(drv)
    mc.setAttr(str(obj)+'.'+ str(driversChannel), enumIndex )
    
    #set ws trans and rot
    mc.xform( obj, a=True, ws=True, t=tValues)
    mc.xform( obj, a=True, ws=True, ro=rValues)
    
######## GUI    
win = mc.window('spaceMatchUI', title='Dynamic parenting & Space Matching')
mc.columnLayout( adjustableColumn=True )

#Dynamic parent frame
mc.frameLayout( label='DYNAMIC PARENTING', borderStyle='out' )
mc.rowColumnLayout(numberOfColumns=4, columnWidth=[(1, 100), (2, 100), (3, 100), (4, 100)])
mc. button(label='Object(s)', command= partial(assignObjects))
mc. button(label='World', command= partial(assignWorld))
mc. button(label='Driver1', command= partial(assignDriver1))
mc. button(label='Driver2', command= partial(assignDriver2))
mc.setParent( '..' )
mc.setParent( '..' )
mc. button(label='PARENT OBJECTS', command= partial(parentObjects))

#Space switch frame
mc.frameLayout( label='SPACE MATCHING', borderStyle='in' )
mc.rowColumnLayout(numberOfColumns=3, columnWidth=[(1, 100), (2, 200), (3, 100)])
mc.text(label='Selected object:', align='left')
objSelected = mc.text('select object', font='obliqueLabelFont', align='left')
mc. button(label='assign', command= partial(assignObj))
mc.text(label='Channel name:', align='left')
chanName = mc.textField(tx='follow')
mc. button(label='assign', command= partial(assignChannel))
mc.setParent( '..' )
mc.setParent( '..' )
#Drivers list
mc.frameLayout( label='Drivers list', borderStyle='out' )
#Show
mc.showWindow('spaceMatchUI')