r"""

An interpreter that provides blot-like syntax and functionality.  To run
the interpreter simply call the start function.

"""

#==============================================================================
#
#  Program:   ParaView
#  Module:    pvblot.py
#
#  Copyright (c) Kitware, Inc.
#  All rights reserved.
#  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
#
#     This software is distributed WITHOUT ANY WARRANTY; without even
#     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#     PURPOSE.  See the above copyright notice for more information.
#
#==============================================================================

#-------------------------------------------------------------------------
# Copyright 2009 Sandia Corporation.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------

import cmd
import inspect
import blotish

class _PVBlotInterp(cmd.Cmd):
    r"""pvblot - A blot-like interpreter using ParaView as a back end.

    The pvblot interpreter reads commands in a manner similar to the SEACAS
    blot command and performs visualization using the ParaView framework.
    The images you get from pvblot will often provide more information than
    those generated by the original blot tool.  Comments begin with "$" and
    continue to the end of the line.  Commands are case insensitive and can
    be abbreviated with any unique prefix.  Keep in mind that there are
    some differences in the blot commands and those offered here.  There
    are also many blot commands that are not replicated here.
    """
    prompt = "BLOT> "
    _blotish_commands = {}
    def __init__(self, completekey='tab', stdin=None, stdout=None):
        cmd.Cmd.__init__(self, completekey, stdin, stdout)
        for funcname in dir(blotish):
            if funcname[0] == '_': continue
            exec "func = blotish.%s" % funcname
            if not inspect.isfunction(func): continue
            if func.__doc__.startswith("Alias"): continue
            self._blotish_commands[funcname] = func
        # Insert dummy commands for help.
        self._blotish_commands['exit'] = _PVBlotInterp.do_exit
    def get_command(self, command_name):
        """Given a command name, returns the function that implements it.
        The command name should be in all lower case.  The command name
        need only cover the first part of the command uniquely."""
        valid_commands = []
        for existing_command in self._blotish_commands.keys():
            if existing_command.startswith(command_name):
                valid_commands.append(existing_command)
        if len(valid_commands) != 1:
            raise blotish.BlotishError, "No such command '" + command_name + "'"
        return self._blotish_commands[valid_commands[0]]
    def precmd(self, command):
        comment_start = command.find('$')
        if (comment_start >= 0):
            command = command[:comment_start]
        return command.lower()
    def do_help(self, command_name):
        if len(command_name) < 1:
            print _PVBlotInterp.__doc__
            print "The following commands are supported:"
            print "  ",
            blotish_commands = self._blotish_commands.keys()
            blotish_commands.sort()
            for c in blotish_commands:
                print c,
            print
            print
            print "For more information on any command, try help <command>."
            return
        try:
            command = self.get_command(command_name)
            print command.__doc__
        except blotish.BlotishError, err:
            print err
    def do_exit(self, rest):
        "Exit the blot interpreter."
        return 1
    def emptyline(self): pass
    def default(self, s):
        try:
            args = s.split()
            command = self.get_command(args[0])
            command(*args[1:])
        except blotish.BlotishError, err:
            print err


def start(filename=None):
    "Start the pvblot interpreter."
    # Turn off progress printing while running.
    import paraview.servermanager
    doProgressToggle = (paraview.servermanager.progressObserverTag != None)
    if doProgressToggle: paraview.servermanager.ToggleProgressPrinting()
    blotish.detour(filename)
    pvblotinterp = _PVBlotInterp()
    pvblotinterp.cmdloop()
    if doProgressToggle: paraview.servermanager.ToggleProgressPrinting()

def initialize(filename=None):
    """Initialize the pvblot interpreter for non-interactive use.

    Normally you just call start and it takes care of reading and executing
    commands.  However, in situation where you are not reading from stdin and
    stdout, you may need some other controlling mechanism to call methods
    one at a time.  In that case, use the initialize, execute, and finalize
    functions.
    """
    # Turn off progress printing while running.
    import paraview.servermanager
    global doProgressToggle
    doProgressToggle = (paraview.servermanager.progressObserverTag != None)
    if doProgressToggle: paraview.servermanager.ToggleProgressPrinting()
    blotish.detour(filename)
    global interpreter
    interpreter = _PVBlotInterp()

def execute(command):
    """Run a command in the interpreter.

    Normally you just call start and it takes care of reading and executing
    commands.  However, in situation where you are not reading from stdin and
    stdout, you may need some other controlling mechanism to call methods
    one at a time.  In that case, use the initialize, execute, and finalize
    functions.

    This function returns a true value if the exit command is given.
    """
    global interpreter
    command = interpreter.precmd(command)
    stop = interpreter.onecmd(command)
    stop = interpreter.postcmd(stop, command)
    return stop

def finalize():
    """Clean up the interpreter.

    Normally you just call start and it takes care of reading and executing
    commands.  However, in situation where you are not reading from stdin and
    stdout, you may need some other controlling mechanism to call methods
    one at a time.  In that case, use the initialize, execute, and finalize
    functions.
    """
    global interpreter
    interpreter = None
    global doProgressToggle
    if doProgressToggle: paraview.servermanager.ToggleProgressPrinting()

#If we are running this source file directly, start it up.
if __name__ == '__main__':
    import sys
    try:
        if len(sys.argv) > 1:
            start(sys.argv[1])
        else:
            start()
    except blotish.BlotishError, err:
        print err

