#!/usr/bin/env python

#############################################################################
##
## This file is part of Taurus, a Tango User Interface Library
## 
## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html
##
## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
## 
## Taurus is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
## 
## Taurus is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU Lesser General Public License for more details.
## 
## You should have received a copy of the GNU Lesser General Public License
## along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################

"""
search.py: methods for getting matching device/attribute/alias names from Tango database

These methods have been borrowed from fandango modules.
"""

import re
import taurus

###############################################################################
# Utils

def searchCl(regexp,target): 
    return re.search(regexp.lower(),target.lower())

def matchCl(regexp,target): 
    return re.match(regexp.lower(),target.lower())

def is_regexp(s):
    return any(c in s for c in '.*[]()+?')

def extend_regexp(s):
    s = str(s).strip()
    if '.*' not in s: 
        s = s.replace('*','.*')
    if '.*' not in s:
        if ' ' in s: s = s.replace(' ','.*')
        if '/' not in s: s = '.*'+s+'.*'
    else:
        if not s.startswith('^'): s = '^'+s
        if not s.endswith('$'): s = s+'$'
    return s

def isString(s):
    typ = s.__class__.__name__.lower()
    return not hasattr(s,'__iter__') and 'str' in typ and 'list' not in typ

def isCallable(obj):
    return hasattr(obj,'__call__')

def isMap(obj):
    return hasattr(obj,'has_key') or hasattr(obj,'items')

def isDictionary(obj):
    return isMap(obj)

def isSequence(obj):
    typ = obj.__class__.__name__.lower()
    return (hasattr(obj,'__iter__') or 'list' in typ) and not isString(obj) and not isMap(obj)
        
def split_model_list(modelNames):
    '''convert str to list if needed (commas and whitespace are considered as separators)'''
    if isString(modelNames): #isinstance(modelNames,(basestring,Qt.QString)): 
        modelNames = str(modelNames).replace(',',' ')
        modelNames = modelNames.split()
    if isSequence(modelNames): #isinstance(modelNames,(list.Qt.QStringList)): 
        modelNames = [str(s) for s in modelNames]
    return modelNames 
    
def get_matching_devices(expressions,limit=0,exported=False):
    """ 
    Searches for devices matching expressions, if exported is True only running devices are returned 
    """
    db = taurus.Database()
    all_devs = [s.lower() for s in db.get_device_name('*','*')]
    #This code is used to get data from multiples hosts
    #if any(not fun.matchCl(rehost,expr) for expr in expressions): all_devs.extend(get_all_devices(exported))
    #for expr in expressions:
        #m = fun.matchCl(rehost,expr) 
        #if m:
            #host = m.groups()[0]
            #print 'get_matching_devices(%s): getting %s devices ...'%(expr,host)
            #odb = PyTango.Database(*host.split(':'))
            #all_devs.extend('%s/%s'%(host,d) for d in odb.get_device_name('*','*'))
    result = [e for e in expressions if e.lower() in all_devs]
    expressions = [extend_regexp(e) for e in expressions if e not in result]
    result.extend(filter(lambda d: any(matchCl(extend_regexp(e),d) for e in expressions),all_devs))
    return result

def get_device_for_alias(alias):
    db = taurus.Database()
    try: return db.get_device_alias(alias)
    except Exception,e:
        if 'no device found' in str(e).lower(): return None
        return None #raise e

def get_alias_for_device(dev):
    db = taurus.Database()
    try: 
        result = db.get_alias(dev) #.get_database_device().DbGetDeviceAlias(dev)
        return result
    except Exception,e:
        if 'no alias found' in str(e).lower(): return None
        return None #raise e

def get_alias_dict(exp='*'):
    tango = taurus.Database()
    return dict((k,tango.get_device_alias(k)) for k in tango.get_device_alias_list(exp))