#!/usr/bin/env python

# -*- coding: utf-8 -*-
"""

 _____ _    ______ _____ _____   _   _ _ _
/  __ \ |   | ___ \_   _/  ___| | | | | | |
| /  \/ |__ | |_/ / | | \ `--.  | | | | | |_ _ __ ___  _ __
| |   | '_ \|    /  | |  `--. \ | | | | | __| '__/ _ \| '_ \
| \__/\ | | | |\ \ _| |_/\__/ / | |_| | | |_| | | (_) | | | |
 \____/_| |_\_| \_|\___/\____/   \___/|_|\__|_|  \___/|_| |_|



font generated by:
http://patorjk.com/software/taag/#p=display&f=Doom&t=ChRIS%20Ultron

plugin

The plugin class encapsulates access to sub programs that provide
various functionalities to the system.

"""

from __future__ import print_function

import  crun
import  sys
import  os
import  argparse
import  json
import  sys
import  C_snode
import  branch

import  message

class Plugin(object):
    """The base Plugin class
    """


    def decode(self, x):
        dic = {
            '\\' : b'\xe2\x95\x9a',
            '-'  : b'\xe2\x95\x90',
            '/'  : b'\xe2\x95\x9d',
            '|'  : b'\xe2\x95\x91',
            '+'  : b'\xe2\x95\x94',
            '%'  : b'\xe2\x95\x97',
        }
        return (''.join(dic.get(i, i.encode('utf-8')).decode('utf-8') for i in x))

    def box_print(self):
        print(self.decode('+------------------------------------%'))
        print(self.decode('|           Plugin control           |'))
        print(self.decode('\\------------------------------------/'))

    def log(self, *args):
        '''
        get/set the internal pipeline log message object.

        Caller can further manipulate the log object with object-specific
        calls.
        '''
        if len(args):
            self._log = args[0]
        else:
            return self._log

    def name(self, *args):
        '''
        get/set the descriptive name text of this object.
        '''
        if len(args):
            self.__name = args[0]
        else:
            return self.__name

    def blank_string(self, length):
        str_t   = u''
        for i in range(0, length):
            str_t += ' '
        return str_t

    def debug_obj(self, astr_methodName):
        """Print some debugging info..."""
        self.debug('%s -------+\n'  % astr_methodName);
        self.debug('%s        |\n'  % self.blank_string(len(astr_methodName)))
        self.debug('%s        V\n'  % self.blank_string(len(astr_methodName)))
        self.debug('this:               %s\n' % str(self))
        self.debug('plugin:             %s\n' % str(self.plugin))
        self.debug('%s        |\n'  % self.blank_string(len(astr_methodName)))
        self.debug('%s        |\n'  % self.blank_string(len(astr_methodName)))
        self.debug('%s        +-----------------> %s ---> \n' % (self.blank_string(len(astr_methodName)),astr_methodName));

    def getList(self, *args, **kwargs):
        self.debug_obj('plugin.getList()');
        return {'pluginList' : self._l_plugin}

    def set(self, astr_pluginName):
        self.pluginName = astr_pluginName
        self.plugin     = eval('%s()' % self.pluginName)
        self.debug_obj('plugin.set()');
        return {'success': True, 'pluginName': astr_pluginName, 'plugin': str(self.plugin), 'container': str(self)}

    def __init__(self, **kwargs):

        self._pluginTree        = C_snode.C_stree()
        self.BR                 = branch.BranchTree(within = self)

        self._l_plugin          = []
        self.pluginName         = ""
        self.plugin             = None
        self.debug              = message.Message(logTo = "./debug.log")
        self.debug._b_syslog    = True
        self._log               = message.Message()
        self._log._b_syslog     = True
        self.__name             = "Plugin"
        self.within             = None                      # The feed or plugin this branch is within

        for key, val in kwargs.iteritems():
            if key == 'within': self.within     = val


    def run(self, *args, **kwargs):
        d_info = {'container': str(self), 'plugin': str(self.plugin)}
        self.debug_obj('plugin.run()');
        return {'info': d_info, 'run': self.plugin()}

    def status(self, *args, **kwargs):
        return self.plugin.status()

class Plugin_FS(Plugin):
    '''
    Plugin Feed Synthesis

    These plugins create new feeds, and are typically housed at the "root" logical level and not
    part of an existing data tree.

    '''
    _dict_plugin = {
      'plugins': {
        'pacs_pull' : {
            'name':         {
                'body': 'pacs_pull'
            },
            'args': {
                'query':    {
                    'MRN':          '<someMRN>',
                    'PatientName':  '<someName>',
                    'state':        'expanded'
                },
                'host': {
                    'PACShostIP':   '<someIP>',
                    'PACShostPort': '<somePort>',
                    'PACS_FQN':     ('0.0.0.0', '104'),
                    'state':        'collapsed'
                }
            },
            'icons': {
                'thumbnail':        'thn.png',
                'full':             'full.png'
            },
            'executable': {
                'body':             'pacs_pull.bash'
            },
            'note': {
                'body':             'This plugin queries a PACS for image data.'
            },
            'summary' :{
                'runview':     '../../data/pacs_pull/pacs_pull-runview.html',
                'dataview':    '../../data/pacs_pull/pacs_pull-dataview.html',
                'label':       'Pacs pull',
                'color':       'blue',
                'icon':        'icons:cloud-download'
            }
        },
        'file_upload' : {
            'name':         'file_upload',
            'args':         {
                'directory':    '<someDirectory>',
                'ls_args':      '<argsForls>',
            },
            'executable': {
                'body':             '<Some AJAX>'
            },
            'icons': {
                'thumbnail':    'thn.png',
                'full':         'full.png'
            },
            'note': {
                'body':             'This plugin uploads from client to server.',
            },
            'summary' :{
                'runview':     '../../data/file_upload/file_upload-runview.html',
                'dataview':    '../../data/file_upload/file_upload-dataview.html',
                'label':       'File upload',
                'color':       'amber',
                'icon':        'icons:cloud-upload'
            }
        },
        'file_browser' : {
            'name':         'file_browser',
            'args':         {
                'directory':    '<someDirectory>',
                'ls_args':      ['-a', '-l', '-1d'],
                'arg3':         'val3'
            },
            'executable': {
                'body':             'ls'
            },
            'icons': {
                'thumbnail':    'thn.png',
                'full':         'full.png'
            },
            'note': {
                'body':             'Generate a Feed anchored on a passed server directory.',
            },
            'summary' :{
                'runview':     '../../data/file_browser/file_browser-runview.html',
                'dataview':    '../../data/file_browser/file_browser-dataview.html',
                'label':       'File browser',
                'color':       'green',
                'icon':        'icons:folder-open'
            }
        },
        'search' : {
            'name':         'search',
            'args':         {
                'directory':    '<someDirectory>',
                'ls_args':      ['-a', '-l', '-1d'],
                'arg3':         'val3'
            },
            'executable': {
                'body':             'ls'
            },
            'icons': {
                'thumbnail':    'thn.png',
                'full':         'full.png'
            },
            'note': {
                'body':             'Generate a Feed anchored on a passed server directory.',
            },
            'summary' :{
                'runview':     '../../data/search/search-runview.html',
                'dataview':    '../../data/search/search-dataview.html',
                'label':       'Search',
                'color':       'red',
                'icon':        'icons:search'
            }
        }
      }
    }

    def __init__(self, **kwargs):
        """Constructor.

        This essentially calls up the chain to the base constructor

        Args:
            astr_FeedRepo (string): A location on the file system that houses
                all the feeds.

        """
        b_internalsCreate   = True
        Plugin.__init__(self, **kwargs)
        for key, val in kwargs.iteritems():
            if key == 'internalsCreate':    b_internalsCreate   = val

        if b_internalsCreate: self.create(**kwargs)

    def create(self, **kwargs):
        """Create a new plugin container.

        A plugin "create" call.

        Creating a Plugin entails building the directories and one-to-one
        objects:
            - name
            - args
            - executable
            - note (aka help, freeform text, etc)


        Args:
          **kwargs (user=): The user creating the plugin.
          **kwargs (str_ObjectID=): The string object reference used to access
            the Feed

        Returns:
          True if successful, False otherwise.

        """

        s = self._pluginTree
        s.cd('/')
        s.initFromDict(Plugin_FS._dict_plugin)

        # Specify all the REST PUSH data files
        if s.cd('/plugins/pacs_pull/note')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_pull/executable')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_pull/name')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_pull/args/query')['status']:
            s.touch('REST',
                    {'PUSH': {
                            'MRN':              'file',
                            'PatientName':      'file',
                            'state':            'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_pull/args/host')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'PACShostIP':       'file',
                            'PACShostPort':     'file',
                            'PACS_FQN':         'file',
                            'state':            'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/file_upload/executable')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/file_upload/note')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                            }
                    }
                    )

        if s.cd('/plugins/file_upload/args')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'directory':        'file',
                            'ls_args':          'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/file_browser/executable')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )
        if s.cd('/plugins/file_browser/note')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/file_browser/args')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'directory':        'file',
                            'ls_args':          'file',
                            'arg3':             'file',
                            'timestamp':        'file'
                        }
                    }
                    )


        s.tree_metaData_print(False)
        self.BR._branchTree = self._pluginTree

class Plugin_DS(Plugin):
    '''
    Plugin Data Synthesis

    These plugins create new data, and are embedded within a feed -- specifically within the dataView
    component of a Feed. They create new dataViews down the tree as output.

    '''
    _dict_plugin = {
        'plugins': {
            'pacs_push' : {
                'name':         {'body': 'pacs_push'},
                'args': {
                    'host': {
                    'PACShostIP':       '<someIP>',
                    'PACShostPort':     '<somePort>',
                    'PACS_FQN':         ('0.0.0.0', '104'),
                    'state':            'collapsed'
                    }
                },
                'icons': {
                    'thumbnail':        'thn.png',
                    'full':             'full.png'
                },
                'executable': {
                    'body':             'pacs_push.bash'
                },
                'note': {
                    'body':             'This plugin pushes DICOM data to a remote PACS.'
                }
            },
            'mri_convert' : {
                'name':         {'body': 'mri_convert'},
                'args':         {
                    'directory':        '<someDirectory>',
                    'file':             '<someFile>',
                    'outputFormat':     'nii'
                },
                'executable': {
                    'body':             'mri_convert'
                },
                'icons': {
                    'thumbnail':        'thn.png',
                    'full':             'full.png'
                },
                'note': {
                    'body':             'Convert data from one format to another.',
                }
            },
            'recon_all' : {
                'name':         {'body': 'recon_all'},
                'args':         {
                    'directory':        '<someDirectory>',
                    'file':             '<someFile>',
                    'otherCLIA':        '<other command line args>',
                },
                'executable': {
                    'body':             'recon_all'
                },
                'icons': {
                    'thumbnail':        'thn.png',
                    'full':             'full.png'
                },
                'note': {
                    'body':             "Run FreeSurfer's recon-all on data",
                }
            },
        }
    }

    def __init__(self, **kwargs):
        """Constructor.

        This essentially calls up the chain to the base constructor

        Args:
            astr_FeedRepo (string): A location on the file system that houses
                all the feeds.

        """
        b_internalsCreate   = True
        Plugin.__init__(self, **kwargs)
        for key, val in kwargs.iteritems():
            if key == 'internalsCreate':    b_internalsCreate   = val

        if b_internalsCreate: self.create(**kwargs)

    def create(self, **kwargs):
        """Create a new plugin container.

        A plugin "create" call.

        Creating a Plugin entails building the directories and one-to-one
        objects:
            - name
            - args
            - executable
            - note (aka help, freeform text, etc)


        Args:
          **kwargs (user=): The user creating the plugin.
          **kwargs (str_ObjectID=): The string object reference used to access
            the Feed

        Returns:
          True if successful, False otherwise.

        """

        s = self._pluginTree
        s.cd('/')
        s.initFromDict(Plugin_DS._dict_plugin)

        # Specify all the REST PUSH data files
        if s.cd('/plugins/pacs_push/note')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_push/executable')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_push/name')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':         'file',
                            'timestamp':    'file'
                        }
                    }
                    )

        if s.cd('/plugins/pacs_push/args/host')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'PACShostIP':       'file',
                            'PACShostPort':     'file',
                            'PACS_FQN':         'file',
                            'state':            'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/mri_convert/note')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':             'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/mri_convert/args')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'directory':        'file',
                            'file':             'file',
                            'outputFormat':     'file'
                        }
                    }
                    )

        if s.cd('/plugins/mri_convert/executable')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':             'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/recon_all/note')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':             'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/recon_all/executable')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'body':             'file',
                            'timestamp':        'file'
                        }
                    }
                    )

        if s.cd('/plugins/recon_all/args')['status']:
            s.touch('REST',
                    {
                        'PUSH': {
                            'directory':        'file',
                            'file':             'file',
                            'otherCLIA':        'file',
                            'timestamp':        'file'
                        }
                    }
                    )


        s.tree_metaData_print(False)
        self.BR._branchTree = self._pluginTree



class Plugin_homePage(Plugin):
    """Plugins specific to the homePage view
    """

    def __init__(self):
        Plugin.__init__(self)
        self._l_plugin  = ['file_browser', 'pacs_pull']

class Plugin_dataView(Plugin):

    def __init__(self):
        Plugin.__init__(self)
        self._l_plugin  = ['mri_convert', 'recon_all', 'tractography']


class file_browser(object):

    def __init__(self):
        self._str_name              = 'file_browser'
        self.str_serverDirectory    = '/home/chris/data/3432545'

    def __call__(self, *args, **kwargs):
        return {'directory': self.str_serverDirectory}

    def status(self, *args, **kwargs):
        return {'status': "running"}

class pacs_pull(object):
    def __init__(self):
        self._str_name              = 'pacs_pull'
        self.str_MRN                = '3432545'
        self.str_localDir           = '/home/chris/data/%s' % self.str_MRN

    def __call__(self, *args, **kwargs):
        return {'directory': self.str_localDir}

    def status(self, *args, **kwargs):
        return {'status': "running"}


if __name__ == "__main__":

    pt  = Plugin_FS()

    print(pt._pluginTree)

    d_ret = {
        'VERB':             'GET',
        'ROOT':             'Plugin',
        'payloadFile':      'action.json',
        'searchType':       'NAME',
        'searchTarget':     '*',
        'returnAsDict':     True,
        'pathInBranch':     '/',
        'schema':           'void'
    }

    print(pt.BR.branch_branchList_fromTreeGet(d_ret = d_ret))

    p   = Plugin_homePage()
    p.debug._b_syslog   = False
    print(p.getList())
    p.set('file_browser')
    print(p.run())
    p.set('pacs_pull')
    print(p.run())
