from watsup.winGuiAuto import findControl,findControls,findTopWindow, \
                              WinGuiAutoError,getEditText,clickButton, \
                              activateMenuItem,getMenuInfo, \
                              getListboxItems,getComboboxItems, \
                              selectListboxItem,selectComboboxItem,\
                              setEditText,getTopMenu, setCheckBox,\
                              getCheckBox
                              
from watsup.launcher import launchApp,terminateApp
import win32gui
import win32con
#from watsup.Knowledge import getKnowledge
from types import ListType,TupleType
 
verbose=False

CONTROL_MAX_WAIT_SECS=3

def PLaunchApp(program,wantedText=None,wantedClass=None):
    hwnd=launchApp(program,wantedText,wantedClass,verbose) 
    return PWindow(hwnd=hwnd) 
  
class PWinControl(object): 
    """Abstract base class for PWindows and PControls"""    
    def __init__(self,parent):
        self.parent=parent
        
    def findPControl(self,hwnd=None,wantedText=None,wantedClass=None,selectionFunction=None):
        """Factory method returning a PControl instance, or a subclass thereof, 
        within a PWinControl instance,
        
        find a unique control - raises exception if non-unique
        """ 
        
        # if wantedClass is not given, let's try and find out what it is;
        # then we should be better able to assign the right PControl subclass
        # to it
        if wantedClass==None:
            #find the wantedClass anyway
            p=PControl(self.parent,hwnd,wantedText,wantedClass,selectionFunction)
            wantedClass=p.className
        else:
            p=None 
        
        # if this is a known class, return the instance of the specific
        # subclass of PControl               
        if KNOWN_CLASSES.has_key(wantedClass):
            if verbose:
                print KNOWN_CLASSES[wantedClass],(self.parent,hwnd,wantedText,wantedClass,selectionFunction)    
    
            return KNOWN_CLASSES[wantedClass](self.parent,hwnd,wantedText,wantedClass,selectionFunction)    

        # in all other cases, return a PControl (we may have already calculated it above)
        if p:
            return p 
        else:
            return PControl(self.parent,hwnd,wantedText,wantedClass,selectionFunction)
 
            
    def findPControls(self,wantedText=None,wantedClass=None,selectionFunction=None):
        # returns a list of PControl instances which match the criteria                
        hwnds=findControls(wantedText,wantedClass,selectionFunction)
        controlList=[]
        for hwnd in hwnds:
            controlList.append(self.findPControl(self,hwnd=hwnd))
        return controlList                     

##class Menu(object):
##    # container for menu items
##    def __init__(self,mwnd):
##        self.mwnd=mwnd
# not sure we need this entity, as we can address MenuItems directly
        
class MenuItem(object):
    def __init__(self,parentWindow,*menuItems):
        self.parentWindow=parentWindow
        #acceept either a tuple/list or *args-type values
        if type(menuItems[0]) in (ListType,TupleType):
            self.menuItemTuple=menuItems[0]
        else:
            self.menuItemTuple=menuItems
        
    def activate(self):
        activateMenuItem(self.parentWindow.hwnd,self.menuItemTuple)        
        
    #-------------------------------------------------------------------------------
    # accessors and properties
    
    def getInfo(self):
        return getMenuInfo(self.parentWindow.hwnd,self.menuItemTuple)
    
    def getName(self):
        return menuInfo.name
    
    def getItemCount(self):
        return menuInfo.itemCount
    
    def getIsChecked(self):
        return menuInfo.IsChecked
    
    def getIsSeparator(self):
        return menuInfo.IsSeparator
    
    def getIsDisabled(self):
        return menuInfo.IsDisabled
    
    def getIsGreyed(self):        
        return menuInfo.IsGreyed  
        
    name=property(getName)
    itemCount=property(getItemCount)
    isChecked=property(getIsChecked)
    isDisabled = property(getIsDisabled)
    isGreyed = property(getIsGreyed)
    isSeparator = property(getIsSeparator)
    
    menuInfo=property(getInfo)
    
    #-------------------------------------------------------------------------------
       
      
class PWindowError(Exception): pass    
class PWindow(PWinControl):  
    
    def __init__(self,hwnd=None,wantedText=None,wantedClass=None,selectionFunction=None,controlParameters=None):
        PWinControl.__init__(self,self)
        
        if hwnd:
            self.hwnd=hwnd
        else:    
            try:
                self.hwnd=findTopWindow(wantedText=wantedText,
                                        wantedClass=wantedClass,
                                        selectionFunction=selectionFunction)
            except WinGuiAutoError,e:
                raise PWindowError,e
        
        # controlParameters is the list of dictionaries with unique
        # definitions of the controls within this Window
        # eg controlParameters=[{'wantedClass':'TButton','wantedText':'Button1'},
        #                       {'wantedClass':'TRadioButton','selectionFunction':chooseIt}]
        self.controls=[]
        if controlParameters<>None:
            for cp in controlParameters:
                hwnd=cp.get('hwnd',None)
                wantedClass=cp.get('wantedClass',None)
                wantedText=cp.get('wantedTest',None)
                selectionFunction=cp.get('selectionFunction',None)
                clist=self.findControls(hwnd=hwnd,                                   
                                   wantedText=wantedText,
                                   wantedClass=wantedClass,
                                   selectionFunction=selectionFunction)
                                          
                self.controls.extend(clist)
         
        self._mainMenuHandle=None
                
    def activateMenuItem(self,menuItem):
        menuItem.activateMenuItem()
        
    def terminate(self):
        terminateApp(self.hwnd)    
    
#-------------------------------------------------------------------------------
#Accessors & properties
    
### top menu item
##   def getMainMenu(self):
##       if self._mainMenuHandle:
##           return self._mainMenuHandle
##       else:
##           return getTopMenu(self.hwnd)  
##      
##    mainMenu=property(getMainMenu)    
#-------------------------------------------------------------------------------
    
class PControlError(Exception): pass          
class PControl(PWinControl):    
    def __init__(self,parent,hwnd=None,wantedText=None,wantedClass=None,selectionFunction=None):
        "Constructor takes either hwnd directly, or others in a controlParameter set"
        PWinControl.__init__(self,parent)
        if hwnd:
            self.hwnd=hwnd
        else:               
            try:
                self.hwnd=findControl(parent.hwnd,
                                   wantedText=wantedText,
                                   wantedClass=wantedClass,
                                   selectionFunction=selectionFunction,
                                   maxWait=CONTROL_MAX_WAIT_SECS)
            except WinGuiAutoError,e:
                raise PControlError,e
            
            
##    def addKnowledge(self,attrName):
##        knowledge=getKnowledge()
##        knowledge.add(self.className,attrName)
                
    #-------------------------------------------------------------------------------
    # general winctrl actions which, if acted upon by a user, might tell us sth about 
    # this unknown control 
    
    def getItems(self):
        # This PControl of unknown class can get items
        # at least the user thinks so 
        #self.addKnowledge('getItems')
        res=getComboboxItems(self.hwnd)
        if not res:
            res=getListboxItems(self.hwnd)
            
        return res
    
    def selectItem(self,item):
        # This PControl of unknown class can select items
        # at least the user thinks so 
        #self.addKnowledge('selectItem')
        res= selectListboxItem(self.hwnd, item) 
        if not res:
            res=selectComboBoxItem(self.hwnd,item)
        return res       
       
    def click(self):
        # This PControl of unknown class is clickable
        # at least the user thinks so 
        #self.addKnowledge('click')
        clickButton(self.hwnd)
    
    def getCaption(self):
        # This PControl of unknown class has a caption,
        # at least the user thinks so  
        #self.addKnowledge('caption')
        return self.getEditText()
          
    def setCheckBox(self, state=3DTrue):
	setCheckBox(self.hwnd, state)
	
    def getCheckBox(self):
	return getCheckBox(self.hwnd)
                                
    #-------------------------------------------------------------------------------
    #Accessors and properties
     
    def getText(self):
        # returns a list of strings which make up the text
        return getEditText(self.hwnd)
    
    def setText(self,text,append=False):
        setEditText(text,append)
        
    def getClassName(self):
        return win32gui.GetClassName(self.hwnd)    
      
    text=property(getText)
    className=property(getClassName)
    caption=property(getCaption)
    items=property(getItems)    
    
    #-------------------------------------------------------------------------------
         
class PEdit(PControl): 
    def __init__(self,parent,hwnd=None,wantedText=None,wantedClass=None,selectionFunction=None):
        PControl.__init__(self,parent,hwnd,wantedText,wantedClass,selectionFunction)

    #-------------------------------------------------------------------------------
    #Accessors and properties        

    def getText(self):
        # returns a simple string - PEdit controls only have one value
        p=PControl.getText(self)
        if p:
            return p[0]
        else:
            return ''
        
    text=property(getText) 
    caption=None #undefine the caption property
    
    #-------------------------------------------------------------------------------

class PText(PControl):
    # multi-line text control
    caption=None
    
class PComboBox(PControl):
    
    def selectItem(self,item):
        selectComboboxItem(self.hwnd,item)
    
    #-------------------------------------------------------------------------------
    #Accessors and properties 
    
    def getItems(self):
        return getComboboxItems(self.hwnd)       
        
    items=property(getItems)
   
    
    #-------------------------------------------------------------------------------
            

class PDelphiComboBox(PComboBox): 
    # The Delphi Combo box has a control of class Edit within
    # it, which contains the text
    def __init__(self,parent,hwnd=None,wantedText=None,wantedClass=None,selectionFunction=None):
        PControl.__init__(self,parent,hwnd,wantedText,wantedClass,selectionFunction)
        self.editCtrl=self.findPControl(wantedClass='Edit')
    #-------------------------------------------------------------------------------
    #Accessors and properties        

    def getText(self):
        # get the content from the control Edit:
            
        return self.editCtrl.getText()
    
    text=property(getText)  
   
    
    #-------------------------------------------------------------------------------

class PButton(PControl): 
    
    def click(self):        
        clickButton(self.hwnd)
        
    #-------------------------------------------------------------------------------
    #Accessors and properties        
        
    caption=property(PControl.getText)    
    
    #-------------------------------------------------------------------------------
 
class PListBox(PControl):
    
    def selectItem(self,item):
        return selectListboxItem(self.hwnd, item)
    
    #-------------------------------------------------------------------------------
    #Accessors and properties 
    
    def getItems(self):
        return getListboxItems(self.hwnd)       
        
    items=property(getItems)
   
    
    #-------------------------------------------------------------------------------
        
class PCheckBox(PControl):
    
   
    #-------------------------------------------------------------------------------
    #Accessors and properties 
    
  
    caption=property(PControl.getText)
    
    def getCheckStatus(self):
    	return self.getCheckBox()
    	
    def isChecked(self):
    	return self.getCheckStatus()#=3D=3D win32con.BST_INDETERMINATE
    
    def isIndeterminate(self):
	return self.getCheckStatus() #=3D=3D win32con.BST_INDETERMINATE
	=20

    def isNotChecked(self):
	return self.getCheckStatus() #=3D=3D win32con.BST_UNCHECKED
	=20
   
    def setChecked(self):
	setCheckBox(hwnd, state = True)

    def setUnChecked(self):
	setCheckBox(hwnd, state = False)

    
    #-------------------------------------------------------------------------------        
KNOWN_CLASSES={'TEdit': PEdit,
               'TComboBox': PDelphiComboBox,
               'ComboBox': PComboBox,
               'TButton': PButton,
               'TListBox': PListBox,
               'ListBox': PListBox,
               'CheckBox': PCheckBox,
               'TCheckBox': PCheckBox,
               
               }       
    