# -*- coding: utf-8 -*-
#
#  -------------------------------------------------------------------------
#  pyCGNS - Python package for CFD General Notation System - 
#  See license.txt file in the root directory of this Python module source  
#  -------------------------------------------------------------------------
#
from __future__ import unicode_literals
from builtins import (str, bytes, range, dict)

import shutil
import os
import os.path as op
import sys
import imp
import tempfile

from time import gmtime, strftime
from CGNS.pyCGNSconfig import version as __vid__
from CGNS.pyCGNSconfig import HAS_MSW 

WINOPTS = HAS_MSW

import CGNS.PAT.cgnskeywords as CGK

from qtpy.QtGui import QFont, QFontDatabase, QTextCursor

# User file paths:
conf_path = op.join(op.expanduser('~'), ".CGNS.NAV")
tmp_path = "/tmp"
if sys.platform == 'win32':
    tmp_path = os.environ['TEMP']


# -----------------------------------------------------------------
def removeSubDirAndFiles(path):
    shutil.rmtree(path)


def copyOneFile(src, dst):
    f1 = open(src, 'r')
    l1 = f1.readlines()
    f1.close()
    if op.exists(dst):
        os.remove(dst)
    f2 = open(dst, 'w')
    f2.writelines(l1)
    f2.close()


# -----------------------------------------------------------------
class Q7OptionContext(object):
    Q_VAR_NODE = 'NODE'
    Q_VAR_PARENT = 'PARENT'
    Q_VAR_NAME = 'NAME'
    Q_VAR_VALUE = 'VALUE'
    Q_VAR_CGNSTYPE = 'SIDSTYPE'
    Q_VAR_CHILDREN = 'CHILDREN'
    Q_VAR_TREE = 'TREE'
    Q_VAR_PATH = 'PATH'
    Q_VAR_LINKS = 'LINKS'
    Q_VAR_SKIPS = 'SKIPS'
    Q_VAR_RESULT = 'RESULT'
    Q_VAR_USER = 'ARGS'
    Q_VAR_SELECTED = 'SELECTED'
    Q_VAR_RESULT_LIST = '__Q7_QUERY_RESULT__'

    Q_SCRIPT_PRE = """
import CGNS.PAT.cgnskeywords as CGK
import CGNS.PAT.cgnsutils as CGU
import CGNS.PAT.cgnslib as CGL
import numpy
"""

    Q_FILE_PRE = """
import CGNS.PAT.cgnskeywords as CGK
import CGNS.PAT.cgnsutils as CGU
import CGNS.PAT.cgnslib as CGL
import CGNS.NAV.moption as CGO
import numpy
"""

    Q_SCRIPT_POST = """
try:
  %s[0]=%s
except NameError:
  %s[0]=None
""" % (Q_VAR_RESULT_LIST, Q_VAR_RESULT, Q_VAR_RESULT_LIST)

    _depends = {
        'MaxDisplayDataSize': ['DoNotDisplayLargeData'],
        'MaxLoadDataSize': ['DoNotLoadLargeArrays'],
        'MaxRecursionLevel': ['RecursiveTreeDisplay'],
    }
    _HasProPackage = True
    CHLoneTrace = False
    QueryNoException = False
    ActivateMultiThreading = False
    NAVTrace = False
    AutoExpand = False
    RecursiveTreeDisplay = False
    OneViewPerTreeNode = False
    ShowTableIndex = True
    RecursiveSIDSPatternsLoad = True
    DoNotDisplayLargeData = False
    CheckOnTheFly = False
    FollowLinksAtLoad = True
    DoNotFollowLinksAtSave = True
    AddCurrentDirInSearch = True
    AddRootDirInSearch = True
    DoNotLoadLargeArrays = True
    ShowSIDSStatusColumn = True
    ForceSIDSLegacyMapping = False
    ForceFortranFlag = True
    FilterCGNSFiles = True
    FilterHDFFiles = True
    FilterOwnFiles = True
    FileUpdateRemovesChildren = True
    TransposeArrayForView = True
    Show1DAsPlain = True
    ShowSIDSColumn = True
    ShowLinkColumn = True
    ShowSelectColumn = True
    ShowUserColumn = True
    ShowCheckColumn = True
    ShowShapeColumn = True
    ShowDataTypeColumn = True
    UserCSS = ""
    SelectionListDirectory = op.normpath(op.join(conf_path, 'selections'))
    QueriesDirectory = op.normpath(op.join(conf_path, 'queries'))
    FunctionsDirectory = op.normpath(op.join(conf_path, 'functions'))
    SnapShotDirectory = op.normpath(op.join(conf_path, 'snapshots'))
    _HistoryFileName = op.normpath(op.join(conf_path, 'historyfile.py'))
    _OptionsFileName = op.normpath(op.join(conf_path, 'optionsfile.py'))
    _QueriesDefaultFile = 'default.py'
    _FunctionsDefaultFile = 'default.py'
    IgnoredMessages = []
    LinkSearchPathList = []
    ProfileSearchPathList = []
    GrammarSearchPathList = []
    ValKeyList = ['sample']
    CGNSFileExtension = ['.cgns', '.adf']
    HDFFileExtension = ['.hdf', '.hdf5']
    OwnFileExtension = ['.cgh']
    MaxLoadDataSize = 1000
    MaxDisplayDataSize = 1000
    MaxRecursionLevel = 7
    ADFConversionCom = 'cgnsconvert'
    TemporaryDirectory = op.normpath(tmp_path)
    _ConvertADFFiles = True
    _ToolName = 'CGNS.NAV'
    _ToolVersion = '%s' % __vid__

    _CopyrightNotice = u"""
Copyright (c) Marc Poinot <br>
Copyright (c) Safran - www.safran-group.com<br><br>
Copyright (c) Onera - www.onera.fr<br><br>
<b>all other copyrights and used versions listed below</b>

<hr>
<h3>Contributors (alphabetic order)</h3>
<table>
<tr><td>Florent Cayré</td><td>-SNECMA, France</td></tr>
<tr><td>Alexandre Fayolle</td><td>-LOGILAB, France</td></tr>
<tr><td>Xavier Garnaud</td><td>-SAFRAN, France</td></tr>
<tr><td>Loic Hauchard</td><td>-ONERA (Student INSA Rouen, France)</td></tr>
<tr><td>Elise Hénaux</td><td>-ONERA (Student FIIFO Orsay, France)</td></tr>
<tr><td>Grégory Laheurte</td><td>-ONERA, France</td></tr>
<tr><td>Pierre-Jacques Legay</td><td>-BERTIN, France</td></tr>
<tr><td>Bill Perkins</td><td>-Pacific Northwest Ntl Lab, U.S.A.</td></tr>
<tr><td>Mickael Philit</td><td>-SAFRAN, France</td></tr>
<tr><td>Jérôme Regis</td><td>-STILOG, France</td></tr>
<tr><td>Benoit Rodriguez</td><td>-ONERA, France</td></tr>
<tr><td>Tristan Soubrié</td><td>-ANDHEO, France</td></tr>
<tr><td>Francois Thirifays</td><td>-CENAERO, Belgique</td></tr>
<tr><td>Simon Verley</td><td>-ONERA, France</td></tr>
<tr><td>Ching-Yang Wang</td><td>-U.S.A.</td></tr>
</table>

<h2>Copyrights & Versions</h2>
<hr>
%(pycgnsversion)s<br>
All <b>pyCGNS</b> 
rights reserved in accordance with GPL v2 <br><br>
<b>NO WARRANTY :</b><br>
Check GPL v2 sections 15 and 16
about <font color=red>loss of data or corrupted data</font><br>
<hr>
%(pyqtversion)s<br>
PyQt Copyright (c) Riverbank Computing Limited. <br>
Usage within the terms of the GPL v2.<br>
All Rights Reserved.<br>
<hr>
%(qtversion)s<br>
Qt Copyright (c)<br>
The Qt4 Library is (c) 2011 Nokia Corporation and/or its subsidiary(-ies),
and is licensed under the GNU Lesser General Public License version 2.1
with Nokia Qt LGPL exception version 1.1. <br>
<hr>
%(pythonversion)s<br>
Python Copyright (c)<br>
Copyright (c) 2001-2011 Python Software Foundation.<br>
All Rights Reserved.<br>
<br>
Copyright (c) 2000 BeOpen.com.<br>
All Rights Reserved.<br>
<br>
Copyright (c) 1995-2001 Corporation for National Research Initiatives.<br>
All Rights Reserved.<br>
<br>
Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.<br>
All Rights Reserved.<br>
<br>
<hr>
%(numpyversion)s<br>
Numpy Copyright (c)<br>
Copyright (c) 2005, NumPy Developers<br>
<hr>
%(hdf5version)s<br>
HDF5 Copyright (c)<br>
HDF5 (Hierarchical Data Format 5) Software Library and Utilities<br>
Copyright 2006-2013 by The HDF Group.<br>
NCSA HDF5 (Hierarchical Data Format 5) Software Library and Utilities<br>
Copyright 1998-2006 by the Board of Trustees of the University of Illinois.<br>
<hr>
%(vtkversion)s<br>
VTK Copyright (c)<br>
Copyright (c) 1993-2008 Ken Martin, Will Schroeder, Bill Lorensen <br>
All rights reserved.<br>
<hr>
%(cythonversion)s<br>
Cython Copyright (c)<br>
(c) Copyright 2012, Stefan Behnel, Robert Bradshaw, Dag Sverre Seljebotn,
Greg Ewing, William Stein, Gabriel Gellner, et al.
<hr>
Icons Copyright (c)<br>
All these nice icons are provided or are modified versions of original
icons provided by Mark James (Birmingham, UK).<br>
Please visit his web site: http://www.famfamfam.com/<br>

"""
    #__fv = QFont(QFontDatabase().families()[0]) # Spyder-like but needs a QApplication
    __fv = QFont('Courier new')
    __fc = QFont('Courier new')

    _Label_Font = QFont(__fv)
    _Button_Font = QFont(__fv)
    _Table_Font = QFont(__fc)
    _Edit_Font = QFont(__fc)
    _RName_Font = QFont(__fc)
    _NName_Font = QFont(__fc)
    _NName_Font.setBold(True)

    _Default_Fonts = {
        'Label_Family': _Label_Font.family(),
        'Label_Size': _Label_Font.pointSize(),
        'Label_Bold': False,
        'Label_Italic': False,
        'Table_Family': _Table_Font.family(),
        'Table_Size': _Table_Font.pointSize(),
        'Table_Bold': False,
        'Table_Italic': False,
        'Edit_Family': _Edit_Font.family(),
        'Edit_Size': _Edit_Font.pointSize(),
        'Edit_Bold': False,
        'Edit_Italic': False,
        'Button_Family': _Button_Font.family(),
        'Button_Size': _Button_Font.pointSize(),
        'Button_Bold': False,
        'Button_Italic': False,
        'RName_Family': _RName_Font.family(),
        'RName_Size': _RName_Font.pointSize(),
        'RName_Bold': False,
        'RName_Italic': False,
        'NName_Family': _NName_Font.family(),
        'NName_Size': _NName_Font.pointSize(),
        'NName_Bold': False,
        'NName_Italic': True,
    }

    UserColors = [
        'gray',
        'red',
        'green',
        'blue',
        'orange',
        None,
        None,
        None,
        None,
        None,
    ]

    _ColorList = {
        'cold_grey': (0.5000, 0.5400, 0.5300),
        'dim_grey': (0.4118, 0.4118, 0.4118),
        'grey': (0.7529, 0.7529, 0.7529),
        'light_grey': (0.8275, 0.8275, 0.8275),
        'slate_grey': (0.4392, 0.5020, 0.5647),
        'slate_grey_dark': (0.1843, 0.3098, 0.3098),
        'slate_grey_light': (0.4667, 0.5333, 0.6000),
        'warm_grey': (0.5000, 0.5000, 0.4100),
        'black': (0.0000, 0.0000, 0.0000),
        'ivory_black': (0.1600, 0.1400, 0.1300),
        'lamp_black': (0.1800, 0.2800, 0.2300),
        'alizarin_crimson': (0.8900, 0.1500, 0.2100),
        'brick': (0.6100, 0.4000, 0.1200),
        'coral': (1.0000, 0.4980, 0.3137),
        'coral_light': (0.9412, 0.5020, 0.5020),
        'deep_pink': (1.0000, 0.0784, 0.5765),
        'firebrick': (0.6980, 0.1333, 0.1333),
        'geranium_lake': (0.8900, 0.0700, 0.1900),
        'hot_pink': (1.0000, 0.4118, 0.7059),
        'light_salmon': (1.0000, 0.6275, 0.4784),
        'madder_lake_deep': (0.8900, 0.1800, 0.1900),
        'maroon': (0.6902, 0.1882, 0.3765),
        'pink': (1.0000, 0.7529, 0.7961),
        'pink_light': (1.0000, 0.7137, 0.7569),
        'raspberry': (0.5300, 0.1500, 0.3400),
        'rose_madder': (0.8900, 0.2100, 0.2200),
        'salmon': (0.9804, 0.5020, 0.4471),
        'tomato': (1.0000, 0.3882, 0.2784),
        'beige': (0.6400, 0.5800, 0.5000),
        'brown': (0.5000, 0.1647, 0.1647),
        'brown_madder': (0.8600, 0.1600, 0.1600),
        'brown_ochre': (0.5300, 0.2600, 0.1200),
        'burlywood': (0.8706, 0.7216, 0.5294),
        'burnt_sienna': (0.5400, 0.2100, 0.0600),
        'burnt_umber': (0.5400, 0.2000, 0.1400),
        'chocolate': (0.8235, 0.4118, 0.1176),
        'deep_ochre': (0.4500, 0.2400, 0.1000),
        'flesh': (1.0000, 0.4900, 0.2500),
        'flesh_ochre': (1.0000, 0.3400, 0.1300),
        'gold_ochre': (0.7800, 0.4700, 0.1500),
        'greenish_umber': (1.0000, 0.2400, 0.0500),
        'khaki': (0.9412, 0.9020, 0.5490),
        'khaki_dark': (0.7412, 0.7176, 0.4196),
        'light_beige': (0.9608, 0.9608, 0.8627),
        'peru': (0.8039, 0.5216, 0.2471),
        'rosy_brown': (0.7373, 0.5608, 0.5608),
        'raw_sienna': (0.7800, 0.3800, 0.0800),
        'raw_umber': (0.4500, 0.2900, 0.0700),
        'sepia': (0.3700, 0.1500, 0.0700),
        'sienna': (0.6275, 0.3216, 0.1765),
        'saddle_brown': (0.5451, 0.2706, 0.0745),
        'sandy_brown': (0.9569, 0.6431, 0.3765),
        'tan': (0.8235, 0.7059, 0.5490),
        'van_dyke_brown': (0.3700, 0.1500, 0.0200),
        'cadmium_orange': (1.0000, 0.3800, 0.0100),
        'carrot': (0.9300, 0.5700, 0.1300),
        'dark_orange': (1.0000, 0.5490, 0.0000),
        'mars_orange': (0.5900, 0.2700, 0.0800),
        'mars_yellow': (0.8900, 0.4400, 0.1000),
        'orange': (1.0000, 0.5000, 0.0000),
        'orange_red': (1.0000, 0.2706, 0.0000),
        'yellow_ochre': (0.8900, 0.5100, 0.0900),
        'aureoline_yellow': (1.0000, 0.6600, 0.1400),
        'banana': (0.8900, 0.8100, 0.3400),
        'cadmium_lemon': (1.0000, 0.8900, 0.0100),
        'cadmium_yellow': (1.0000, 0.6000, 0.0700),
        'cadmium_yellow_light': (1.0000, 0.6900, 0.0600),
        'gold': (1.0000, 0.8431, 0.0000),
        'goldenrod': (0.8549, 0.6471, 0.1255),
        'goldenrod_dark': (0.7216, 0.5255, 0.0431),
        'goldenrod_light': (0.9804, 0.9804, 0.8235),
        'goldenrod_pale': (0.9333, 0.9098, 0.6667),
        'light_goldenrod': (0.9333, 0.8667, 0.5098),
        'melon': (0.8900, 0.6600, 0.4100),
        'naples_yellow_deep': (1.0000, 0.6600, 0.0700),
        'yellow': (1.0000, 1.0000, 0.0000),
        'yellow_light': (1.0000, 1.0000, 0.8784),
        'chartreuse': (0.4980, 1.0000, 0.0000),
        'chrome_oxide_green': (0.4000, 0.5000, 0.0800),
        'cinnabar_green': (0.3800, 0.7000, 0.1600),
        'cobalt_green': (0.2400, 0.5700, 0.2500),
        'emerald_green': (0.0000, 0.7900, 0.3400),
        'forest_green': (0.1333, 0.5451, 0.1333),
        'green': (0.0000, 1.0000, 0.0000),
        'green_dark': (0.0000, 0.3922, 0.0000),
        'green_pale': (0.5961, 0.9843, 0.5961),
        'green_yellow': (0.6784, 1.0000, 0.1843),
        'lawn_green': (0.4863, 0.9882, 0.0000),
        'lime_green': (0.1961, 0.8039, 0.1961),
        'mint': (0.7400, 0.9900, 0.7900),
        'olive': (0.2300, 0.3700, 0.1700),
        'olive_drab': (0.4196, 0.5569, 0.1373),
        'olive_green_dark': (0.3333, 0.4196, 0.1843),
        'permanent_green': (0.0400, 0.7900, 0.1700),
        'sap_green': (0.1900, 0.5000, 0.0800),
        'sea_green': (0.1804, 0.5451, 0.3412),
        'sea_green_dark': (0.5608, 0.7373, 0.5608),
        'sea_green_medium': (0.2353, 0.7020, 0.4431),
        'sea_green_light': (0.1255, 0.6980, 0.6667),
        'spring_green': (0.0000, 1.0000, 0.4980),
        'spring_green_medium': (0.0000, 0.9804, 0.6039),
        'terre_verte': (0.2200, 0.3700, 0.0600),
        'viridian_light': (0.4300, 1.0000, 0.4400),
        'yellow_green': (0.6039, 0.8039, 0.1961),
        'aquamarine': (0.4980, 1.0000, 0.8314),
        'aquamarine_medium': (0.4000, 0.8039, 0.6667),
        'cyan': (0.0000, 1.0000, 1.0000),
        'cyan_white': (0.8784, 1.0000, 1.0000),
        'turquoise': (0.2510, 0.8784, 0.8157),
        'turquoise_dark': (0.0000, 0.8078, 0.8196),
        'turquoise_medium': (0.2824, 0.8196, 0.8000),
        'turquoise_pale': (0.6863, 0.9333, 0.9333),
        'alice_blue': (0.9412, 0.9725, 1.0000),
        'blue': (0.0000, 0.0000, 1.0000),
        'blue_light': (0.6784, 0.8471, 0.9020),
        'blue_medium': (0.0000, 0.0000, 0.8039),
        'cadet': (0.3725, 0.6196, 0.6275),
        'cobalt': (0.2400, 0.3500, 0.6700),
        'cornflower': (0.3922, 0.5843, 0.9294),
        'cerulean': (0.0200, 0.7200, 0.8000),
        'dodger_blue': (0.1176, 0.5647, 1.0000),
        'indigo': (0.0300, 0.1800, 0.3300),
        'manganese_blue': (0.0100, 0.6600, 0.6200),
        'midnight_blue': (0.0980, 0.0980, 0.4392),
        'navy': (0.0000, 0.0000, 0.5020),
        'peacock': (0.2000, 0.6300, 0.7900),
        'powder_blue': (0.6902, 0.8784, 0.9020),
        'royal_blue': (0.2549, 0.4118, 0.8824),
        'slate_blue': (0.4157, 0.3529, 0.8039),
        'slate_blue_dark': (0.2824, 0.2392, 0.5451),
        'slate_blue_light': (0.5176, 0.4392, 1.0000),
        'slate_blue_medium': (0.4824, 0.4078, 0.9333),
        'sky_blue': (0.5294, 0.8078, 0.9216),
        'sky_blue_deep': (0.0000, 0.7490, 1.0000),
        'sky_blue_light': (0.5294, 0.8078, 0.9804),
        'steel_blue': (0.2745, 0.5098, 0.7059),
        'steel_blue_light': (0.6902, 0.7686, 0.8706),
        'turquoise_blue': (0.0000, 0.7800, 0.5500),
        'ultramarine': (0.0700, 0.0400, 0.5600),
        'blue_violet': (0.5412, 0.1686, 0.8863),
        'cobalt_violet_deep': (0.5700, 0.1300, 0.6200),
        'magenta': (1.0000, 0.0000, 1.0000),
        'orchid': (0.8549, 0.4392, 0.8392),
        'orchid_dark': (0.6000, 0.1961, 0.8000),
        'orchid_medium': (0.7294, 0.3333, 0.8275),
        'permanent_red_violet': (0.8600, 0.1500, 0.2700),
        'plum': (0.8667, 0.6275, 0.8667),
        'purple': (0.6275, 0.1255, 0.9412),
        'purple_medium': (0.5765, 0.4392, 0.8588),
        'ultramarine_violet': (0.3600, 0.1400, 0.4300),
        'violet': (0.5600, 0.3700, 0.6000),
        'violet_dark': (0.5804, 0.0000, 0.8275),
        'violet_red': (0.8157, 0.1255, 0.5647),
        'violet_red_medium': (0.7804, 0.0824, 0.5216),
        'violet_red_pale': (0.8588, 0.4392, 0.5765),
    }

    _ReservedNames = CGK.cgnsnames
    _ReservedTypes = CGK.cgnstypes
    _SortedTypeList = CGK.sortedtypelist

    _UsualQueries = [

# ---------------------------------------------------------------------------
# INDENTATION IS SIGNIFICANT
# ---------------------------------------------------------------------------
    
# --- Search -----------------------------------------------------------
# last two booleans: Update tree, has args
('001. Node name',
'Search by',
'RESULT=(NAME==ARGS[0])',
"""
Search by
Node name

Search all nodes with the exact NAME as argument.

The argument name need not to be a tuple or to have quotes,
all the following values are ok and would match the NAME <i>ZoneType</i>:

ZoneType
'ZoneType'
('ZoneType',)
""", False, True),

('002. Wildcard node name',
'Search by',
"""import fnmatch
RESULT=fnmatch.fnmatchcase(NAME,ARGS[0])
""",
"""
Search by
Wildcard node name

Search all nodes with the wildcard NAME as argument.

Warning: the <b>argument name</b> should be quoted:

'BC*' is ok

BC* would fail
""", False, True),

('003. Node type',
'Search by',
'RESULT=(SIDSTYPE==ARGS[0])',
"""search all nodes with argument SIDS type.""", False, True),

('005. Node value',
'Search by',
"""
from numpy import *
target=eval(ARGS[0])
if   (VALUE is None and target is None): RESULT=True
elif (VALUE is None)            : RESULT=False
elif (target.dtype!=VALUE.dtype): RESULT=False
elif (target.size!=VALUE.size):   RESULT=False
elif (target.shape!=VALUE.shape): RESULT=False
elif (target.tolist()==VALUE.tolist()): RESULT=True
else:                             RESULT=False
""",
"""search all nodes with argument value. The compare is performed
using a straightforward '==' and then relies on the Python/Numpy comparison
operator.""", False, True),

('010. Node with truncated data',
'Search by',
'if (PATH in SKIPS): RESULT=PATH',
"""search all nodes with truncated or unread data, for example if you have set
the maximum data argument for the load, or if you release the memory of a
node.""", False, False),

('004. Wildcard node type',
'Search by',
"""
import fnmatch
RESULT=fnmatch.fnmatchcase(SIDSTYPE,ARGS[0])
""",
"""
Search by
Wildcard node type

Search all nodes with wildcard argument SIDS type.
Warning: the <b>argument type</b> should be quoted:

'Turb*' is ok

Turb* would fail
""", False, True),

('011. Non-MT UserDefinedData',
'Search by',
"""
if (    (SIDSTYPE==CGK.UserDefinedData_ts)
    and (CGU.getValueDataType(NODE)!=CGK.MT)):
  RESULT=True
""",
"""
Search by
Valued UserDefinedData

Search all <b>UserDefinedData_t</b> nodes with a non-<b>MT</b> data type.

No argument.
""", False, False),
# -----------------------------------------------------------------------------
('012. FamilyName',
'Search by',
"""
if (SIDSTYPE in [CGK.FamilyName_ts, CGK.AdditionalFamilyName_ts]):
    RESULT=True
""",
"""
Search by
All <b>FamilyName_t</b> and <b>AdditionalFamilyname_t</b> nodes.
""", False, False),
# -----------------------------------------------------------------------------
('013. FamilyName reference',
'Search by',
"""
if ((SIDSTYPE in [CGK.FamilyName_ts, CGK.AdditionalFamilyName_ts]) and
    (VALUE.tostring().decode('ascii')==ARGS[0])):
    RESULT=True
""",
"""
Search by<br>
Reference to a FamilyName<br>
 
Search all <b>FamilyName</b> nodes with the arg string (plain).<br>
The string arg should be a valid Python string such as:<br>
 
'BLADE(1)'<br>
'Surface ext 1A'<br>
'Left/Wing/Flap'<br>
 
""", False, True),
# -----------------------------------------------------------------------------
('014. Zones',
'Search by',
"""
if (SIDSTYPE in [CGK.Zone_ts]):
    RESULT=True
""",
"""
Search by
All <b>Zone_t</b> nodes.
""", False, False),
# -----------------------------------------------------------------------------
('015. Zones Structured',
'Search by',
"""
if (SIDSTYPE in [CGK.Zone_ts]):
    t=CGU.hasChildName(NODE,CGK.ZoneType_s)
    if (t is None or CGU.stringValueMatches(t,CGK.Structured_s)):
      RESULT=True
""",
"""
Search by
All <b>Zone_t</b> with Structured <b>ZoneType</b> nodes.
""", False, False),
# -----------------------------------------------------------------------------
('016. Zones Unstructured',
'Search by',
"""
if (SIDSTYPE in [CGK.Zone_ts]):
    t=CGU.hasChildName(NODE,CGK.ZoneType_s)
    if (t is not None and CGU.stringValueMatches(t,CGK.Unstructured_s)):
      RESULT=True
""",
"""
Search by
All <b>Zone_t</b> with Unstructured <b>ZoneType</b> nodes.
""", False, False),
# -----------------------------------------------------------------------------
('017. BCs',
'Search by',
"""
if (SIDSTYPE in [CGK.BC_ts]):
    RESULT=True
""",
"""
Search by
All <b>BC_t</b> nodes.
""", False, False),

# --- Replace
# -----------------------------------------------------------------------------
('050. Valued UserDefinedData',
'Replace',
"""
if (     (SIDSTYPE==CGK.UserDefinedData_ts)
     and (CGU.getValueDataType(NODE)!=CGK.MT)):
  NODE[3]=CGK.DataArray_ts
  RESULT=True
""",
"""
Replace
Valued UserDefinedData
 
Search all <b>UserDefinedData_t</b> nodes with a non-<b>MT</b> data type
and replace them as <b>DataArray_t</b>.""", False, False),

('051. Substitute Zone name',
'Replace',
"""
l1=len(ARGS[0])
if ((SIDSTYPE==CGK.Zone_ts) and (NAME[:l1]==ARGS[0])):
  NODE[0]=ARGS[1]+NODE[0][l1:]
  RESULT=True

if (CGU.getValueDataType(NODE)==CGK.C1):
  v=VALUE.tostring().decode('ascii')
  if (v[:l1]==ARGS[0]):
    v=ARGS[1]+v[l1:]
    NODE[1]=CGU.setStringAsArray(v)
    RESULT=True
""",
"""
<h1>Replace</h1>
<h2>Substitute Zone name</h2>
<p>
Search all <b>Zone_t</b> nodes with a name pattern, then rename the
zone with the substitution pattern. Any other reference in the tree,
as a connectivity value for example, is subsitued as well.
<p>
Argument is a tuple with the first pattern to find and
the second as the subsitution pattern. For example:
<pre>
('domain.','zone#')
</pre>
""", True, True),

# -----------------------------------------------------------------------------
('052. FamilySpecified BC type rewrite',
'Replace',
"""
if ((SIDSTYPE in [CGK.FamilyName_ts, CGK.AdditionalFamilyName_ts]) and
    (VALUE.tostring().decode('ascii')==ARGS[0]) and (PARENT[3]==CGK.BC_ts)):
    PARENT[1]=CGU.setStringAsArray(CGK.FamilySpecified_s)
    RESULT=True
""",
"""
<h1>Replace</h1>
<h2>FamilySpecified BC type rewrite</h2>
<p>
Search all <b>FamilyName BC</b> nodes with the arg string (plain).<br>
The string arg should be a valid Python string such as:<br>

'BLADE(1)'<br>
'Surface ext 1A'<br>
'Left/Wing/Flap'<br>

<p>
Once found, the parent <b>BC_t</b> value is forced to <b>FamilySpecified</b>

""", True, True),

# --- Find Elements_t
('020. Elements',
'Find Elements_t',
"""if (SIDSTYPE==CGK.Elements_ts):
  RESULT=True
""",
"""Find all <b>Elements_t</b> nodes """, False, False),

('021. Elements QUAD',
'Find Elements_t',
"""if (SIDSTYPE==CGK.Elements_ts):
  RESULT=VALUE[0] in (CGK.QUAD_4, CGK.QUAD_8, CGK.QUAD_9)
""",
"""Find all <b>Elements_t</b> nodes of type <b>QUAD</b>""", False, False),

('022. Elements TRI',
'Find Elements_t',
"""if (SIDSTYPE==CGK.Elements_ts):
  RESULT=VALUE[0] in (CGK.TRI_3, CGK.TRI_6)
""",
"""Find all <b>Elements_t</b> nodes of type <b>TRI</b>""", False, False),

('023. Elements NGON',
'Find Elements_t',
"""if (SIDSTYPE==CGK.Elements_ts):
  RESULT=VALUE[0] in (CGK.NGON_n,)
""",
"""Find all <b>Elements_t</b> nodes of type <b>NGON_n</b>""", False, False),

('024. Elements HEXA',
'Find Elements_t',
"""if (SIDSTYPE==CGK.Elements_ts):
  RESULT=VALUE[0] in (CGK.HEXA_8, CGK.HEXA_20, CGK.HEXA_27)
""",
"""Find all <b>Elements_t</b> nodes of type <b>HEXA</b>""", False, False),

('025. Elements TETRA',
'Find Elements_t',
"""if (SIDSTYPE==CGK.Elements_ts):
  RESULT=VALUE[0] in (CGK.TETRA_4, CGK.TETRA_10)
""",
"""Find all <b>Elements_t</b> nodes of type <b>TETRA</b>""", False, False),

# --- External Tools
('030. Create Cartesian Zone',
'External Tools',
"""
if (SIDSTYPE==CGK.CGNSTree_ts):
    import Generator.PyTree as G
    z=G.cart((0.,0.,0.), (0.1,0.1,0.2), (10,11,12))
    b=None
    base='BASE'
    if (len(ARGS)>0):
      base=ARGS[0]
      b=CGU.hasChildName(NODE,base)
    if (b is None):
      base=CGU.checkUniqueChildName(NODE,base)
      b=CGL.newCGNSBase(NODE,base,3,3)
    CGU.addChild(b,z)
""",
"""Example of Cartesian zone creation using Cassiopee.
The first argument is the base name, if ommitted a name is generated.""",
True, True),
('031. Bounding boxes',
'External Tools',
"""
if (SIDSTYPE==CGK.Zone_ts):
    import Generator as G
    RESULT=G.bbox(NODE)
""",
"""Example of Bounding box computation using Cassiopee"""),
('100. .Solver#Compute children',
'Edit filters',
"""
if (PARENT[0]=='.Solver#Compute'):
    RESULT=PATH
""",
"""Selects all children nodes of the .Solver#Compute elsA userdefined node""",
False, False),
('101. ReferenceState children',
'Edit filters',
"""
if (PARENT[0]=='ReferenceState'):
    RESULT=PATH
""",
"""Selects all children nodes of the ReferenceState node""",
False, False),
('102. .Solver#Param children',
'Edit filters',
"""
if (PARENT[0]=='.Solver#Param'):
   RESULT=PATH
""",
"""Selects all children nodes of the .Solver#Param elsA userdefined node""",
False, False),
    
    ]

    # -----------------------------------------------------------------
    @classmethod
    def _setOption(cls, name, value):
        setattr(cls, name, value)

    @classmethod
    def _writeFile(cls, tag, name, udata, filename, prefix=""):
        gdate = strftime("%Y-%m-%d %H:%M:%S", gmtime())
        s = u"""# %s - %s - Generated %s\n# coding: utf-8\n%s\nimport PyQt5\n%s=""" % \
            (cls._ToolName, tag, gdate, prefix, name)
        if isinstance(udata, dict):
            s += u"""{\n"""
            for k in udata:
                #          print 'K',k,'V',udata[k],'T',type(udata[k])
                if k[0] != '_':
                    val = '%s' % str(udata[k])
                    if isinstance(udata[k], str):
                        val = u'u"""%s"""' % repr(udata[k]).lstrip("u'").lstrip("'").rstrip("'") # Error
                    elif isinstance(udata[k], bytes):
                        val = u'u"""%s"""' % repr(udata[k].decode('utf-8')).lstrip("u'").lstrip("'").rstrip("'")
                    if not isinstance(k, str):
                        uk = u"u'%s'" % repr(k.decode('utf-8')).lstrip("u'").lstrip("'").rstrip("'")
                    else:
                        uk = u"u'%s'" % repr(k).lstrip("u'").lstrip("'").rstrip("'")
                    s += """%s:%s,\n""" % (uk, val)
            s += u"""}\n\n# --- last line\n"""
        elif isinstance(udata, list):
            s += u"""[\n"""
            for k in udata:
                s += u"""%s,\n""" % (k)
            s += u"""]\n\n# --- last line\n"""
        cls._crpath(filename)
        with open(filename, 'w+') as f:
            f.write(s)


    @classmethod
    def _readFile(cls, name, filename):
        dpath = tempfile.mkdtemp()
        if not op.exists(filename):
            return None
        try:
            copyOneFile(filename, '%s/%s.py' % (dpath, name))
        except IOError:
            removeSubDirAndFiles(dpath)
            return None
        sprev = sys.path
        sys.path = [dpath] + sys.path
        try:
            fp, pathname, description = imp.find_module(name)
        except IndexError:  # ImportError:
            return None
        try:
            mod = imp.load_module(name, fp, pathname, description)
        finally:
            if fp:
                fp.close()
        removeSubDirAndFiles(dpath)
        sys.path = sprev
        return mod

    @classmethod
    def _crpath(cls, path):
        p = op.dirname(path)
        if op.exists(p):
            return True
        os.makedirs(p)

    @classmethod
    def _trpath(cls, path):
        return op.normpath(op.expanduser(op.expandvars(path)))

    @classmethod
    def _writeHistory(cls, control):
        filename = cls._trpath(cls._HistoryFileName)
        cls._writeFile('History', 'history', control._history, filename)

    @classmethod
    def _readHistory(cls, control):
        filename = cls._trpath(cls._HistoryFileName)
        m = cls._readFile('history', filename)
        if m is None:
            return None
        try:
            return m.history
        except:
            return None

    @classmethod
    def _writeOptions(cls, control):
        filename = cls._trpath(cls._OptionsFileName)
        cls._writeFile('User options', 'options', control._options, filename)

    @classmethod
    def _readOptions(cls, control):
        filename = cls._trpath(cls._OptionsFileName)
        m = cls._readFile('options', filename)
        if m is None:
            return None
        try:
            return m.options
        except:
            return None

    @classmethod
    def _writeQueries(cls, control, q):
        filename = cls._trpath(op.join(cls.QueriesDirectory, cls._QueriesDefaultFile))
        cls._writeFile('User queries', 'queries', q, filename, cls.Q_FILE_PRE)

    @classmethod
    def _readQueries(cls, control):
        filename = cls._trpath(op.join(cls.QueriesDirectory, cls._QueriesDefaultFile))
        m = cls._readFile('queries', filename)
        if m is None:
            return None
        try:
            return m.queries
        except:
            return None

    @classmethod
    def _writeFunctions(cls, control, f):
        filename = cls._trpath(op.join(cls.FunctionsDirectory, cls._FunctionsDefaultFile))
        cls._writeFile('User functions', 'functions', f, filename, cls.Q_FILE_PRE)

    @classmethod
    def _readFunctions(cls, control):
        filename = cls._trpath(op.join(cls.FunctionsDirectory, cls._FunctionsDefaultFile))
        m = cls._readFile('functions', filename)
        if m is None:
            return None
        try:
            return m.Q7UserFunction
        except:
            return None

    def __init__(self):
        pass

    def __getitem__(self, name):
        if name[0] != '_':
            return Q7OptionContext.__dict__[name]
        return None

    def __setitem__(self, name, value):
        if name[0] != '_':
            setattr(Q7OptionContext, name, value)
        return None

    def __iter__(self):
        for o in dir(self):
            if o[0] != '_':
                yield o

    def _nextName(self):
        for o in dir(self):
            if o[0] != '_':
                yield o

# -----------------------------------------------------------------
