#!/usr/bin/env python3

#############################################################################
##
## $Author: Sergi Rubio Manrique, srubio@cells.es $
##
## $Revision: 2008 $
##
## copyleft :    ALBA Synchrotron Controls Section, CELLS
##               Bellaterra
##               Spain
##
#############################################################################
##
## This file is part of Tango Control System
##
## Tango Control System is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as published
## by the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## Tango Control System 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 General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
###########################################################################

import fandango
import fandango.log as log

__doc__ = """

Usage:

  fandango [qt] [-l] [-v] [--list] [-h/--help] [-x/--extra] [-n/--new-line] \
     [fandango_method_0] [fandango_method_1/argument_0] [key:=argument_key] [...]
  
  Execute python and fandango methods from shell

  Objects and Generators will not be allowed as arguments, \
     only python primitives, lists and tuples
  
  The --extra option will load PyTangoArchiving and Panic methods
  
Examples:

  fandango --help # prints this help

  fandango --list # lists available methods 
  
  fandango --quiet # do not print results
  
  fandango -v / --verbose # print exceptions

  fandango findModule fandango

  python $(fandango findModule fandango)/interface/CopyCatDS.py 1
  
  fandango get_tango_host
  
  fandango qt #Launch interactive Qt console
  
  fandango --help get_matching_devices | less
  
  fandango get_matching_devices "tango/admin/*"
  
  fandango get_matching_attributes "lab/ct/plctest16/*_af"
  
  fandango list | grep propert
  
  fandango get_matching_device_properties "lab/ct/plctest16" "*modbus*"
  
  fandango read_attribute "tango/admin/pctest/status"
  
  for attr in $(fandango get_matching_attributes "tango/admin/pctest/*"); \
    do echo "$attr : $(fandango read_attribute ${attr})" ; done
  
"""

"""
A launcher like this can't be created as a function, because generic imports 
with wildcards are allowed only at module level.

If it is problem is solved in the future, then will be moved to fandango.linos
"""

if __name__ == '__main__':
  import sys
  cmd, r = '', None
  try:
    #comms = sys.argv[sys.argv.index('-c')+1:]
    comms,opts = fandango.sysargs_to_dict(split=True,cast=False,lazy=False)
    
    from fandango.functional import *
    try:
        from fandango.tango import *
        from fandango.servers import *
    except:
        print('Unable to import Tango modules')

    from fandango.linos import *
    from fandango.objects import *

    assert any((comms,opts)) and comms != ['help']
    # go to exit()

    if comms and comms[0] in ('help','list'):
        opts[comms[0]],comms = 1, comms[1:]
    
    if opts.get('x',opts.get('extra',0)):
      try: 
        import PyTangoArchiving
        from PyTangoArchiving import Reader
        from PyTangoArchiving.files import LoadArchivingConfiguration
        locals()['pta'] = locals()['PyTangoArchiving'] = PyTangoArchiving
      except: pass
      try: 
        import panic
      except: pass
    
    if opts.get('list') is not None or opts.get('h',opts.get('help',0)):
      # Executing HELP
      import inspect
      
      _locals=locals()
      def get_module_name(o):
          o = inspect.getmodule(o)
          return getattr(o,'__name__','')
      _locals['get_module_name'] = get_module_name
      
      target = comms[0] if comms else (opts.get('help') or '')

      if target and isString(target):
        cmd = 'inspect.getsource(%s)'%target
        
      else:
        cmd = ("sorted(m for m in [('%s.%s'%(get_module_name(o),k)).strip('.') "
               " for k,o in locals().items() if not k.startswith('_')"
               " and hasattr(o,'__call__')] if not m.startswith('_'))")
        
      r = evalX(cmd,_locals=_locals)
      if isSequence(r):
        r = list2str(r,'\n')
      for c in ('"""',"'''"):
        if c in r:
          r = c.join(r.split(c)[:2])+c
      if not target: 
        r = '\nAvailable methods:\n\n'+r
      
    ###########################################################################  
    else:
      assert comms
      
      if 'qt' in comms[:1] or opts.get('qt'):
        # LAUNCHING QT SHELL
        args = comms['qt' in comms:]
        print('Launching the interactive Qt console ... %s' % args)
        import fandango.qt
        fandango.qt.QEvaluator.main(args)
        
      elif '(' in comms[0]:
        ## SINGLE STRING COMMAND
        _locals = locals()
        for c in comms:
          cmd = c
          r = evalX(c,_locals=_locals)
          
    ###########################################################################
      else:
        ## MULTIPLE ARGS COMMAND
        str2evalstr = lambda c: (
            str(c) if isNumber(c) or isBool(c) else ("'%s'" if "'" not in c else '"%s"')%c)
        kwargs = [c for c in comms[1:] if c.count(':=')==1]
        args = [c for c in comms[1:] if c not in kwargs]
        
        kwargs = ','.join("'%s':%s"%(k,str2evalstr(v)) for k,v in 
                          (c.split(':=') for c in kwargs))
        args = ','.join(str2evalstr(c) for c in args)
        cmd = '%s(*[%s],**{%s})'%(comms[0],args,kwargs)
        log.debug(cmd)
        r = evalX(cmd,_locals=locals())
        
    if opts.get('v') or opts.get('verbose'): 
        print(cmd)
        
    if r is not None:
        linesep = '\n' if opts.get('l') else ';'
        s = obj2str(r,sep=' ',linesep=linesep)
        if opts.get('l') and '\n' not in s:
            s = '\n'.join(s.split())
        if not opts.get('quiet'):
            print(s)
 
  except AssertionError as e:
    print(__doc__)

  except:
    if opts.get('v') or opts.get('verbose'):
        print(cmd)
        import traceback
        traceback.print_exc()
    sys.exit(1)
    
  sys.exit(0)
