#!/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/>.
##
###########################################################################

"""
TaurusGUI configuration file used to convert Taurus into VACCA

This file should be NOT modified.

.. toctree::
   :maxdepth: 4

h2. Usage
=========

This configuration file determines the default, permanent, pre-defined
contents of the GUI. While the user may add/remove more elements at run
time and those customizations will also be stored, this file defines what a
user will find when launching the GUI for the first time.

Don't modify this file, use default.py to do a simple setup of your
facility and paths and a CONFIG.py file (based on default.py format) to 
construct a VACCA gui for each subsystem.

h3. Contents
------------

This file mainly defines two kinds of objects:

 * Panel descriptors: the panels to be shown.
   To define a panel, instantiate a PanelDescription object (see documentation
   for the gblgui_utils module)
 * Panels will be TREE, JDRAW_FILE, DEVICE, ...
   
 * QSignals (managed by Taurus Shared Data Manager):
  * SelectedInstrument: goes from taurusgui and tree into panel/synoptic
  * SelectionMultiple: goes from panic/finder/... to synoptic to display multiple elements
  * JDrawIn/JDrawOut: used only if JDRAW_HOOK defined, to transform data between synoptic and selection
  * lastWindowClosed: signal will close all opened widgets and dialogs on application exit

h3. Extending Taurus GUI
------------------------

We will differentiate between:

 - Tools (applications launched in a separate process)
 - Panels (widgets embeddable in the application)
 - Applets (widgets or applications launched from the right-side bar)
 - Widgets (widgets not instantiated, but added to the catalog when adding a new panel).
 
The config variables to include new Tools/Panels/Apps/Widgets are:

Use EXTRA_WIDGETS to add new widgets to the catalog and the right-side toolbar.
They will be added to EXTRA_CATALOG_WIDGETS, that contains default extra widgets.

Use EXTRA_PANELS to force new Panels always at startup.
They will be instantiated and running in background.

Use EXTRA_APPS to add launchers to the toolbar.
Creates new AppletDescription objects to add elements to the right-side toolbar.

Use EXTRA_TOOLS to add launchers to the "External Apps" toolbar.
Creates new ExternalApp objects to add elements to the top menu and toolbar.

Use TOOLBARS to add new Toolbars: 
  TOOLBARS = [('Sectors','SR.sector.get_sectors_toolbar')]
Creates new ToolBarDescription objects.


h2. Config Variables
====================

Described below. All of them can be overriden in TangoDB(VACCA free properties) or
using environment variables (adding the VACCA_ preffix).

"""

#==============================================================================
# Import section. You probably want to keep this line. Don't edit this block 
# unless you know what you are doing

import time,os,sys,traceback,imp,inspect
import fandango as fn,taurus
import vacca,vacca.utils
from .doc import get_autodoc,get_vars_docs
from fandango import partial,FakeLogger as FL
from taurus.external.qt import Qt
from taurus.external.qt.Qt import SIGNAL
from taurus.qt.qtgui.taurusgui.utils import \
  PanelDescription, ExternalApp, ToolBarDescription, AppletDescription
from vacca.panel import VaccaAction,VaccaSplash
from vacca.utils import *

# (end of import section)
#==============================================================================

VACCA_CONFIG = os.getenv('VACCA_CONFIG')
PROPS = get_config_properties(VACCA_CONFIG)
VACCA_DIR = WDIR = PROPS.get('VACCA_DIR',VACCA_DIR)

print('-'*80)
print('In vacca.config(done=%s,vacca_dir=%s)'%(globals().get('CONFIG_DONE',False),VACCA_DIR))

try:

    if VACCA_DIR:
        print('Changing directory to VACCA_DIR:%s' %(VACCA_DIR))
        os.chdir(os.environ['VACCA_DIR'])
        sys.path.append(os.environ['VACCA_DIR'])

    try:
        app = Qt.QApplication.instance()
        assert app,'QApplication not running!'
        splash = VaccaSplash()
    except:
        print("QApplication Instance do not exist!")
        app = None

    try:
        import default
    except:
        try:
            default = get_config_file(imp.find_module('vacca')[1]+'/default.py')
        except:
            traceback.print_exc()

    #===============================================================================
    # Loading of Config Files
    #===============================================================================

    #: Config file where perspectives will be saved
    SETTINGS = '/home/$USER/.config/$ORGANIZATION/$GUI_NAME'

    #: Default options are set in default.py file and later customized in a config file.
    #: This CONFIG can be a .py file passed as argument or a TANGO_HOST.py file in
    #: vacca folder.
    CONFIG = get_config_file()

    #: ALL Variables that can be defined in CONFIG FILE
    OPTION_LISTS = [
        ('General Info', ['GUI_NAME','URL_HELP','URL_LOGBOOK','VACCA_LOGO','ORGANIZATION','ORGANIZATION_LOGO',]),
        ('Installation', ['WDIR','SETTINGS']),
        ('Sub systems', ['DOMAIN','TARGET','COMPOSER',]),
        ('Device Tree', ['USE_DEVICE_TREE','CUSTOM_TREE','DEVICES','EXTRA_DEVICES']),
        ('Synoptics', ['JDRAW_FILE','JDRAW_TREE','JDRAW_HOOK','GRID',]),
        ('Device Panel', ['USE_DEVICE_PANEL','DEVICE','PANEL_COMMAND','AttributeFilters','CommandFilters','IconMap',]),
        ('Plot', ['GAUGES']),
        ('Widgets', ['EXTRA_WIDGETS','EXTRA_PANELS','TOOLBARS','MENUS','EXTRA_APPS','EXTRA_CATALOG_WIDGETS']),]

    OPTIONS = [o for c,l in OPTION_LISTS for o in l]
    
    for c,l in OPTION_LISTS:
        __doc__ += get_vars_docs(__name__,title=c+' Options',module_vars=l,subtitle=False)
    
    if CONFIG:
        print('\n%s Config Options:\n'%VACCA_CONFIG)

        #Check renamed variables
        if getattr(CONFIG,'EXTRA_DEVICES',[]) and not getattr(CONFIG,'DEVICES',None):
            CONFIG.DEVICES = CONFIG.EXTRA_DEVICES
        if not getattr(CONFIG,'DEVICE',None) and getattr(CONFIG,'COMPOSER',None):
            CONFIG.DEVICE = CONFIG.COMPOSER

        varpatch = lambda old,new: (
          setattr(CONFIG,new,getattr(CONFIG,old)) 
          if getattr(CONFIG,old,None) and not getattr(CONFIG,new,None) 
          else none)
          
        #Variable replacement (update config ->  update default -> load default)
        for op in OPTIONS:
            limit = 800
            if 'VACCA_'+op in os.environ:
                print('%s.%s overriden by OS'%(VACCA_CONFIG,op))
                setattr(CONFIG,op,os.getenv('VACCA_'+op))
                
            elif op in PROPS:
                print('%s.%s overriden by TangoDB'%(VACCA_CONFIG,op))
                setattr(CONFIG,op,replace_env(PROPS[op]))
                
            if hasattr(CONFIG,op):
                v = replace_env(getattr(CONFIG,op))
                print('\t%s: \t%s = %s'%(CONFIG.__name__,op,str(v).replace('\n',',')[:limit]))
                setattr(default,op,v)
    
    #Adding all variables to Namespace where taurusgui can found them
    try:
        for k,v in vars(default).items():
            if not any((k.startswith('_'),inspect.ismodule(v))): #inspect.isfunction(v)
                vars()[k] = v
    except:
        traceback.print_exc()
    
    #===============================================================================
    # General info.
    #===============================================================================
    #: GUI_NAME will be used on application title and settings filenames
    GUI_NAME = '%s-%s-%s'%(GUI_NAME,VACCA_CONFIG.split('/')[-1].split('.')[0],DB_HOST)
    #: Name to be shown in right-side bar
    ORGANIZATION = ORGANIZATION
    #: Logo to be shown in right-side bar
    ORGANIZATION_LOGO = ORGANIZATION_LOGO
    
    print('\nConfig loaded, Perspectives will be saved/loaded from %s'%(
        SETTINGS.replace('$USER',get_env_variable('USER')
          ).replace('$ORGANIZATION',ORGANIZATION
          ).replace('$GUI_NAME',GUI_NAME)))
    
    SINGLE_INSTANCE = False

    #: CUSTOM_LOGO. It can be an absolute path,or relative to the app dir or a
    #: resource path. If commented out, ":/taurus.png" will be used
    CUSTOM_LOGO = VACCA_LOGO

    #: You can provide an URI for a manual in html format
    #: (comment out or make MANUAL_URI=None to skip creating a Manual panel)
    MANUAL_URI = URL_HELP #'http://packages.python.org/taurus'
    
    print('\n'+'#'*80+'\n')
    print('In vacca.config(%s): loading classes\n'%VACCA_CONFIG)

    #===============================================================================
    # Define panels to be shown.
    # To define a panel, instantiate a PanelDescription object (see documentation
    # for the gblgui_utils module)
    #===============================================================================
    
    print('\t>>> Loading Trend panel ... %s'%','.join(GAUGES))
    
    #: If defined, the default trend will be shown in logarithmic scale
    GAUGES=GAUGES
    if GAUGES:
        trend = PanelDescription('Gauges',
            classname = 'vacca.plot.PressureTrend',
            model = GAUGES)

    trends = PanelDescription('Trends',
        classname = 'vacca.plot.VaccaTrend',
        model = '')

    #: USE_DEVICE_TREE:  True or False, To Show by default the Device_Tree
    USE_DEVICE_TREE = USE_DEVICE_TREE
    #print('\t>>> Parsing DEVICES: %s ...'%(str(DEVICES)[:80]))
    
    try:
        DEVICES = expand_device_list(DEVICES)
        DEVICES.extend(expand_device_list(EXTRA_DEVICES))
        if DEVICE and DEVICE.lower() not in DEVICES:
          DEVICES.append(DEVICE.lower())
        if DEVICES and not DEVICE: 
          DEVICE = DEVICES[0]
        DEVICES = sorted(set(DEVICES))
    except: 
        traceback.print_exc()

    if any((USE_DEVICE_TREE,JDRAW_FILE,len(DEVICES)>1)):
        print('\t>>> Loading Tree panel(%s) ...'%(len(DEVICES)))
        from tree import *
        try:
            # The lastWindowClosed() signal will close all opened widgets and dialogs on application exit
            assert Qt.QApplication.instance(),'QApplication not running!'
            panelclass = VaccaPanel #VaccaAction(default=PANEL_COMMAND)
            Qt.QObject.connect(Qt.QApplication.instance(), Qt.SIGNAL(
             "lastWindowClosed()"), panelclass.kill )
            VaccaTree.setDefaultPanelClass(panelclass)
        except:
            print("Cannot instance Device Tree")
        logger = fn.Logger()
        printf = logger.info

        def filterMatching(a,dct=AttributeFilters,p=printf):
            match = False
            if a.lower().endswith('/state'): return True
            elif a.lower().endswith('/status'): return False
            for k,l in dct.items():
                if fn.searchCl(k,a.rsplit('/',1)[0]):
                    for t in l: #T is every declared Tab for panel (TabName,[attrlist]); or just attrname when not using tabs
                        p((k,t))
                        f = t[-1] if all(map(fn.isSequence,(t,t[-1]))) else [t]
                        if any(fn.matchCl(v,a.rsplit('/',1)[-1]) for v in f): 
                            match =True
            return match
        VaccaTree.setDefaultAttrFilter(filterMatching)
        if IconMap: VaccaTree.setIconMap(IconMap)
        
        tree = PanelDescription('Tree',
            classname = 'vacca.VaccaTree',#'vacca.VaccaTree',#'TaurusDevTree',
            model = CUSTOM_TREE or ','.join(DEVICES),
            sharedDataRead={'LoadItems':'addModels',
                ##DISABLED BECAUSE TRIGGERED RECURSIVE SELECTION, TO BE AVOIDED IN TREE
                #'SelectedInstrument':'findInTree',
                }, #It will load devices from synoptic
            sharedDataWrite={'SelectedInstrument':'deviceSelected(QString)'}
            )

    #: USE_DEVICE_PANEL:  True or False, To Show by default the DevicePanel
    USE_DEVICE_PANEL = USE_DEVICE_PANEL
    if USE_DEVICE_PANEL:
        print('\t>>> Loading Device panel (%s)...' % DEVICE)
        from vacca.panel import VaccaPanel
        m = DEVICE if DEVICE and fn.check_device(DEVICE) else None
        panel = VaccaPanel.getPanelDescription('Device',model=m)
        
    from vacca.panel import VaccaPanel
    if AttributeFilters: VaccaPanel.setAttributeFilters(AttributeFilters)
    if IconMap: VaccaPanel.setIconMap(IconMap)
    if CommandFilters: VaccaPanel.setCommandFilters(CommandFilters)

    #: JDRAW_FILE:  The JDRAW file to create the Synoptic, 
    #: it can be .jdw or .svg but the second option will require the svgsynoptic module from maxlab.
    JDRAW_FILE = JDRAW_FILE

    if JDRAW_FILE:
        print('\t>>> Loading Synoptic panel new ... %s, %s, %s'%(JDRAW_FILE,
                                                         JDRAW_HOOK, JDRAW_TREE))
        from vacca.synoptics import VaccaSynoptic
        try:
            synoptic = VaccaSynoptic.getPanelDescription('Synoptic',JDRAW_FILE,JDRAW_HOOK,JDRAW_TREE)
        except:
            traceback.print_exc()
            sys.exit()

    #: GRID:  True/False to show by default ehe GRID Panel.
    GRID = GRID

    if GRID:
        print('\t>>> Loading Grid panels ...')
        
        GRID['frames'] = False
        GRID['labels'] = False
        GRID['units'] = False
        
        from vacca.grid import VaccaGrid, VaccaVerticalGrid

        try:
            assert Qt.QApplication.instance(),'QApplication not running!'
            grid = VaccaGrid.getGridPanelDescription(GRID)
        except:
            print('\t>>> Unable to create Grid')

        ##VGRID disabled, the Vertical layout should be added as option to common GRID
        #try:
            #assert Qt.QApplication.instance(),'QApplication not running!'
            #vgrid = VaccaVerticalGrid.getVerticalGridPanelDescription(GRID)
        #except:
            #print 'Unable to create VerticalGrid'

    #: COMPOSER:  True/False to show by default the COMPOSER Panel.
    COMPOSER = COMPOSER

    if COMPOSER:
        def VacuumProfile():
            print('\t>>> Loading VacuumProfile()')
            from . import plot
            p = plot.VaccaProfilePlot()
            p.setModel(COMPOSER)
            return p
        try:
            print('\t>>> Loading Profile panel ...')
            profile = PanelDescription('Profile',
                            classname = 'vacca.plot.VaccaProfilePlot',
                            model = COMPOSER,
                            )
        except:
            print('\t>>> Unable to create ProfilePlot')
            
    import vacca.properties
    properties = vacca.properties.VaccaPropTable.getPanelDescription('Properties',model=DEVICE or '')


    #: EXTRA_PANELS:  dictionary of Extra Panels to be shown by default.
    #: Each element may be a PanelDescription object or a tuple with its arguments.
    #:
    #: The dictionary will be defined like:
    #:  * key: Panel name
    #:  * value: list of arguments to PanelDescription
    #:  * value[0]: panel name
    #:  * value[1]: class name
    #:  * value[2]: default model
    #:  * value[3]: shared data read signal
    #:  * value[4]: shared data write signal
    #:
    #: As example, to add PANIC as extra panel use:
    #: EXTRA_PANELS['PANIC'] = ('PANIC','panic.gui.AlarmGUI','',{},{'HighlightInstruments':'devicesSelected'})
    EXTRA_PANELS = EXTRA_PANELS

    if EXTRA_PANELS:
        print('\t>>> Loading Extra panels ... %s'%str(EXTRA_PANELS))
        if not hasattr(EXTRA_PANELS,'items'):
            EXTRA_PANELS = dict(('extra%d'%(i+1),p) for i,p in enumerate(EXTRA_PANELS))
            
        def get_panel(i):
            pargs = EXTRA_PANELS[i]
            if not fn.isSequence(pargs): return pargs
            elif len(pargs)==3: return PanelDescription(pargs[0],classname=pargs[1],model=pargs[2])
            else: return PanelDescription(pargs[0],classname=pargs[1],model=pargs[2],sharedDataRead=pargs[3],sharedDataWrite=pargs[4])

        for k,p in EXTRA_PANELS.items():
            try:
                vars()[k] = get_panel(k)
            except:
                traceback.print_exc()

    #===============================================================================
    #: EXTRA_WIDGETS: The Dictionary of EXTRA_WIDGETS Panels
    #:
    #: Adding other widgets to the catalog of the "new panel" dialog.
    #: pass a tuple of (classname,screenshot)
    #:
    #: - classname may contain the module name.
    #: - screenshot can either be a file name relative to the application dir or
    #:   a resource URL or None
    #:
    #: examples:
    #:
    #:    ('vacca.properties.VaccaPropTable',wdir('vacca/image/widgets/Properties.png')),
    #:    ('vacca.panel.VaccaPanel',wdir('vacca/image/widgets/Panel.png')),
    EXTRA_WIDGETS = EXTRA_WIDGETS

    #: EXTRA_CATALOG_WIDGETS: The Dictionary of EXTRA_CATALOG_WIDGETS Panels to Show by
    #: default.
    #:Is the Sum of EXTRA_WIDGETS and the custom Widgets defined in config.py
    EXTRA_CATALOG_WIDGETS = []
    EXTRA_CATALOG_WIDGETS = EXTRA_WIDGETS+[
        #('vacca.VacuumProfile',WDIR+'image/ProfilePlot.jpg'),
        #('vacca.plot.PressureTrend',WDIR+'image/PressureTrend.jpg'),
        #('vacca.VacuumGrid',WDIR+'image/BLGrid.jpg'),
        #('vacca.VerticalGrid',WDIR+'image/VerticalGrid.jpg'),
        ('vacca.properties.VaccaPropTable',vpath('image/widgets/Properties.png')),
        ('fandango.qt.QEvaluator',':/snapshot/large/snapshot/TaurusShell.png'),
        ]

    #===============================================================================
    #: TOOLBARS
    #:
    #: Define custom toolbars to be shown. To define a toolbar, instantiate a
    #: ToolbarDescription object (see documentation for the gblgui_utils module)
    #===============================================================================
    
    #dummytoolbar = ToolBarDescription('Empty Toolbar',
                            #classname = 'QToolBar',
                            #modulename = 'PyQt4.Qt')
    
    #panictoolbar = ToolBarDescription('Panic Toolbar',
    #                        classname = 'PanicToolbar',
    #                        modulename = 'tangopanic')
    
    toolbars = []
    for name,obj in (TOOLBARS or []):
        toolbars.append(ToolBarDescription(name,
            classname = obj.split('.')[-1],
            modulename = obj.rsplit('.',1)[0],
            #sharedDataWrite={'selectedPerspective':'blabla'}
            ))
        toolbar = toolbars[-1]
        
    try:
        for menu,actions in MENUS:
            vacca.utils.add_menu(menu,actions)
    except:
        traceback.print_exc()
        
    #===============================================================================
    # Define custom applets to be shown in the applets bar (the wide bar that
    # contains the logos). To define an applet, instantiate an AppletDescription
    # object (see documentation for the gblgui_utils module)
    #===============================================================================
    
    # ALREADY LOADED FROM vacca.default.EXTRA_APPS
    
    #xmambo = AppletDescription('Mambo',classname = 'vacca.panel.VaccaAction',
    # model=["Archiving",wdir('vacca/image/widgets/ProfilePlot.png'),'mambo'],)
    
    #===============================================================================
    # Define which External Applications are to be inserted.
    # To define an external application, instantiate an ExternalApp object
    # See TaurusMainWindow.addExternalAppLauncher for valid values of ExternalApp
    #===============================================================================

    # ALREADY LOADED FROM vacca.default.EXTRA_TOOLS
    
    #xvacca = ExternalApp(cmdargs=['konqueror',URL_HELP], text="Alba VACuum Controls Application", icon=WDIR+'image/icons/cow-tux.png')
    #DEFAULT_APPS = 
    
    EXTRA_TOOLS = EXTRA_TOOLS
    for name,cmdargs,icon in EXTRA_TOOLS:
        locals()['x'+name] = ExternalApp(cmdargs=cmdargs,text=name,icon=icon or None)
    
    #xjive = ExternalApp(cmdargs=['jive'], text="Jive")#, icon=WDIR+'image/icons/cow-tux.png')
    #xastor = ExternalApp(cmdargs=['astor'], text="Astor")#, icon=WDIR+'image/icons/cow-tux.png')
    
    #===============================================================================
    # POOL RELATED OPTIONS
    #===============================================================================
    
    # Set INSTRUMENTS_FROM_POOL to True for enabling auto-creation of
    # instrument panels based on the Pool Instrument info
    #MACROSERVER_NAME = 
    #DOOR_NAME = 
    #MACROEDITORS_PATH = 
    INSTRUMENTS_FROM_POOL = False
    
    #===============================================================================
    # THIS SYNOPTIC OPTION IS POOL-related; IT'S NOT THE MAIN APPLICATION SYNOPTIC!!!
    # If you want an instrument selection synoptic, set the SYNOPTIC variable
    # to the file name of a jdraw file. If a relative path is given, the directory
    # containing this configuration file will be used as root
    # (comment out or make SYNOPTIC=None to skip creating a synoptic panel)
    #===============================================================================
    SYNOPTIC = [] #'images/example01.jdw','images/syn2.jdw']    
    
    #===============================================================================

    #: 
    
    #Forcing nesting of dock widgets
    if app:
        try:
            main = vacca.utils.get_main_window(app)
            main.setDockNestingEnabled(True)
        except:
            traceback.print_exc()
            
    EXTRA_APPS = EXTRA_APPS
    """ The Vacca Panels to show in the JogsBar. Use EXTRA_APPS to add launchers to the toolbar.
    It will create new AppletDescription objects to add elements to the right-side toolbar.

    Examples:
     * EXTRA_APPS['Properties'] = {'class' : vacca.VaccaPropTable}
     * EXTRA_APPS['DevicePanel'] = {'class' : vacca.VaccaPanel}
     * EXTRA_APPS['Panic']= {'class' : vacca.VaccaPanic       }
     * EXTRA_APPS['ExtraDock']= {'class' : Qt.QMainWindow       }
    """
    adder = vacca.addCustomPanel2Gui(EXTRA_APPS)            

    print('\n\t>>> Config Finished ...')
    globals()['CONFIG_DONE'] = True
    print('-'*80 + '\n\n\n')

except:
    print(traceback.format_exc())

