#/***********************************************************************
# * Licensed Materials - Property of IBM 
# *
# * IBM SPSS Products: Statistics Common
# *
# * (C) Copyright IBM Corp. 1989, 2020
# *
# * US Government Users Restricted Rights - Use, duplication or disclosure
# * restricted by GSA ADP Schedule Contract with IBM Corp. 
# ************************************************************************/

# version: 1.1.1
# author: JKP, IBM SPSS

# history
# 15-jul-2014 syntax control of name separator character

import random, codecs, textwrap
import spss
from spssaux import  _isseq, getSpssMajorVersion
from extension import Template, Syntax, processcmd

def SetMacroFromVariableSets(setnames=None, macroname=None, fail=False, outfile=None, sep=" "):
    """Define a macro consisting of all the variables in the specified variable sets.  Return set of variables.
    
    setnames is a string or sequence of variable set names to include.  These are not case sensitive.
    The union of the names will be returned in an arbitrary order.  If not specified, all sets are included
    macroname is the name to assign to the macro.  If not specified no macro is created.
    fail specifies whether or not to raise an exception if any set in the list is not found.
    By default, sets not found are ignored.
    sep is the separator string to use between variables
    if outfile is specified, the variable names are written to that file.  If a macroname is given,
    the names are written with the syntax that defines the macro.
    For version 16 or later, the file is utf-8.  For earlier versions it is written as plain text.
    
    The (Python) set of variables defined in the sets is returned."""
    
    if setnames is not None and not _isseq(setnames):
        setnames = setnames.split()
    randomtag = "_SS_" + str(random.randint(0,999999999))
    spss.CreateXPathDictionary(randomtag)
    variables = set()
    try:
        if setnames is None:
            setvars = spss.EvaluateXPath(randomtag, "/", """//variableSetVariable/@name""")
            if setvars == [] and fail:
                raise ValueError("No set variables found")
            else:
                variables = set(setvars)
        else:
            setnames = [n.lower() for n in setnames]   # requested names in lower case
            dssetnames = spss.EvaluateXPath(randomtag, "/", """//variableSet/@name""")   #available names, actual case
            dssetnamesdict = dict ([(n.lower(), n) for n in dssetnames])  # key is lowercase, value is actual case
            for name in setnames:
                # retrieve requested names by actual case
                setvars = spss.EvaluateXPath(randomtag, "/", 
                    """/dictionary/variableSet[@name="%s"]/variableSetVariable/@name""" % dssetnamesdict.get(name, ""))
                if setvars == [] and fail:
                    raise ValueError("Variable set name not found: %s" % name)
                variables.update(set(setvars))
    finally:
        spss.DeleteXPathHandle(randomtag)
        
    # separator must contain whitespace or textwrap will not work properly
    if not (" " in sep or "\t" in sep):
        sep = " " + sep + " "
    if not macroname is None:
        tw = textwrap.wrap(sep.join(variables), 80, break_long_words=False)
        spss.SetMacroValue(macroname, "\n".join(tw))
    if not outfile is None:
        if getSpssMajorVersion() >=16:   # write a utf-8 file
            f = codecs.open(outfile, "wb", encoding="utf_8_sig")
        else:
            f = open(outfile, "w")
        if not macroname is None:
            f.write("DEFINE %s ()\n" % macroname)
        tw = textwrap.wrap(sep.join(variables), 80, break_long_words=False)
        f.writelines([t + "\n" for t in tw])
        if not macroname is None:
            f.write("!ENDDEFINE.\n")
        f.close()

    return variables

helptext = r"""SETSMACRO [SETS=list of variable set names]
[MACRONAME=name] [FAIL={NO*|YES}] [SEPARATOR="string"]
[/SAVE OUTFILE=filespecification]
[/HELP].

Create macro variable for one or more variable sets.

SETS specifies a list of set names to retrieve.  The list is not case sensitive.
If it is omitted, all sets are retrieved.

MACRONAME optionally gives a name for a macro whose value will be all the variable names
in the sets retrieved.  Duplicate variables names are ignored.

SEPARATOR specifies the character(s) to be used between names
and defaults to a blank.

FAIL specifies whether to raise an error if any requested set is not found.  By default, no error
is raised.

OUTFILE can specify a filename to receive the list of variables found in the sets retrieved.
If MACRONAME is specified, it will contain the syntax for defining the macro.  Otherwise it
holds just the names.

/HELP prints this help and does nothing else.

"""

def Run(args):
        """Execute the SETSMACRO command"""

        args = args[list(args.keys())[0]]
        ###print args   #debug
        oobj = Syntax([
                Template("SETS", subc="",  ktype="literal", var="setnames", islist=True),
                Template("MACRONAME", subc="",  ktype="varname", var="macroname", islist=False),
                Template("SEPARATOR", subc="", ktype="literal", var="sep"),
                Template("FAIL", subc="",  ktype="bool", var="fail", islist=False),
                Template("OUTFILE", subc="SAVE",  ktype="literal", var="outfile", islist=False),
                Template("HELP", subc="", ktype="bool")])

        # A HELP subcommand overrides all else
        if "HELP" in args:
            #print helptext
            helper()
        else:
                processcmd(oobj, args, SetMacroFromVariableSets)

def helper():
    """open html help in default browser window
    
    The location is computed from the current module name"""
    
    import webbrowser, os.path
    
    path = os.path.splitext(__file__)[0]
    helpspec = "file://" + path + os.path.sep + \
         "markdown.html"
    
    # webbrowser.open seems not to work well
    browser = webbrowser.get()
    if not browser.open_new(helpspec):
        print(("Help file not found:" + helpspec))
try:    #override
    from extension import helper
except:
    pass