"""! @package proxypluginpbject
Python module for ProxyPluginObject definings.
A binding to the python embedded module proxyplugin provided by the associated library.
Here is defined the main plugin class from wich to derive the specialization.
In addition threr are auxiliary classes to facilitate the implementation of
object useful for data management.
"""
import proxyplugin
import time
import threading
import sys
import os
import pydoc
import interpreter

mgr = interpreter.PyInterfaceManager()
debug = False

"""! the action types (dict) """
ActionTypes={
    'CHECKABLE': proxyplugin.ACTION_TYPE_CHECKABLE,
    'EX_GROUP': proxyplugin.ACTION_TYPE_EX_GROUP,
    'MENU': proxyplugin.ACTION_TYPE_MENU,
    'NORMAL': proxyplugin.ACTION_TYPE_NORMAL
}

class PyICDTranscoder(object): 
  def __init__(self):
      self.name = ""     

  def encode(self,val):
      pass

  def decode(self,raw):
      pass

class ProxyHandler(object):
    """ ProxyHandler is the root class to derive the icd handler object
    It binds the object to the embedded class ProxyPluginPyHandlerInterface provided by proxyplugin module
    """
    def __init__(self):
        """! @brief The constructor.
        Callback connections and basic constant definition
        """
        
        ## the icd identifier string 
        self.identifier = proxyplugin.__proxy_plugin_icd_identifier__
        ## the icd name string
        self.name = proxyplugin.__proxy_plugin_icd_interface__
        ## the icd filename string
        self.icdfile = proxyplugin.__proxy_plugin_icd_filename__
        ## the icd clock time expressed in usec 
        self.usclock = proxyplugin.__proxy_plugin_icd_us_busclock__
        
        proxyplugin.setConsumeICDEventCallback(proxyplugin.__proxy_plugin_identifier__,
                                               self.identifier,
                                               self.consumeICDEvent)



        index = int(mgr.indexOf(self.name))

        ## the interface handler object coming from the interpreter module
        self.interface = mgr.getInterface(index) if index > -1 else None
        print( self.name,self.icdfile,self.usclock, self.interface )

        if self.interface is None:
            print("ERROR: no interface found {}".format(self.name))
        else:
            ### merge the methods of interface into self object
            interface_meths = set(vars(interpreter.PyInterfaceItem).keys())
            self_meths = set(vars(ProxyHandler).keys())
            methods = interface_meths.difference(self_meths)
            #print(interface_meths,"\n",self_meths)
            for m in methods:
                if m[0] != '_':
                    setattr(self, m, getattr(self.interface, m))

    def consumeICDEvent(self,event_id):
        """!
        @brief callback method that must be reimplementted in order to manage icd events
        @param self     : The object pointer
        @param event_id : event identifier ( see @ref icdevents.h )
        """
        #print(event_id,time.asctime())
        pass

    def sendICDEvent(self, id):
        """!
        @brief it sends an event identified by param id
        @param self  : The object pointer
        @param id    : identifier ( see \ref icdevents.h )
        @return      : None
        """
        return proxyplugin.sendICDEvent(proxyplugin.__proxy_plugin_identifier__,
                                        self.identifier,
                                        id)

    def setMessageFieldReserved(self, msg, field, flag):
        """!
        @brief catch/release the reservation of a field.
        When the reservation is turned on, no any other object or user can modify its value
        @param self The object pointer
        @param msg   : (String) the name of the message
        @param field : (String) the name of the field
        @param flag  : (Boolean) True/False turn On/Off the reservation
        @return (Boolean) true if successully set, false otherwise
        """
        return proxyplugin.setMessageFieldReserved(proxyplugin.__proxy_plugin_identifier__,
                                                   self.identifier,
                                                   msg,
                                                   field,
                                                   flag)

    def commitSingleMessageField(self,msg,field):
        """!
        @brief commit the single message field ( field shall be reserved )
        no other changes are processed in commitment operation leaving pending operations
        unresolved
        no any events are sent
        @param self The object pointer
        @param msg   : (String) the name of the message
        @param field : (String) the name of the field
        """
        return proxyplugin.commitSingleMessageField(proxyplugin.__proxy_plugin_identifier__,
                                                   self.identifier,
                                                   msg,
                                                   field)

    def commitSingleMessage(self,msg):
       """!
       @brief commit the single message ( reserverd fields are not considered )
       no other changes are processed in commitment operation leaving pending operations
       unresolved
       no any events are sent
       @param self The object pointer
       @param msg   : (String) the name of the message
       """
       return proxyplugin.commitSingleMessage(proxyplugin.__proxy_plugin_identifier__,
                                                  self.identifier,
                                                  msg)

    def raiseError(self, msg, severity):
        """!
        @brief it raise an error identified by message and severity
        @param self     : The object pointer
        @param msg      : (String) the error message to be forwarded
        @param severity : (Int) The severity type [0-None 1-low ... 3-high]
        @return         : None
        """
        return proxyplugin.raiseError(proxyplugin.__proxy_plugin_identifier__,
                                      self.identifier,
                                      msg,
                                      severity)

    def setEncodingFrom(self,msg,field,encoder):
        """!
        @brief it set the encoder to the field
        @param self     : The object pointer
        @param msg      : (String) the error message to be forwarded
        @param field    : (String) the name of the field
        @param encoder  : (Object) The encoder object (derived from PyICDTranscoder)
        @return         : True if object encoder is compliants (shall have callable methods encode and decode), False otherwise
        """
        return proxyplugin.setEncodingFrom(proxyplugin.__proxy_plugin_identifier__,
                                      self.identifier,
                                      msg,
                                      field,     
                                      encoder)

    def getEncoderName(self,msg,field):
      """!
      @brief get the string name of encoder ( if any )
      @param self     : The object pointer
      @param msg      : (String) the error message to be forwarded
      @param field    : (String) the name of the field
      @return         : the name of encoder
      """
      return proxyplugin.getEncoderName(proxyplugin.__proxy_plugin_identifier__,
                                    self.identifier,
                                    msg,
                                    field)

    def getMessageFieldValueAsUInt(self,msg,field):
        """!
        @brief get corresponfding integer value of field ( useful for enum and integer field type )
        @param self     : The object pointer
        @param msg      : (String) the error message to be forwarded
        @param field    : (String) the name of the field
        @return         : integer  or None
        """
        return proxyplugin.getAsUInt(proxyplugin.__proxy_plugin_identifier__,
                                      self.identifier,
                                      msg,
                                      field)

class ProxyPluginObject(object):    
    """ ProxyPluginObject is the root class to derive the plugin
    It binds the object to the embedded class ProxyPluginPyInterface provided by proxyplugin module
    """
    def __init__(self,name='Abstract Plugin Object', proxyHandlerRealization=ProxyHandler ):
        """! @brief The constructor.
        Callback connections and basic constant definition
        @param self : the object pointer
        @param name : the plugin name
        @param proxyHandlerRealization : the proxy Handler object used to bind the icd handlers
        """

        self.stopRequest= True

        ## the plugin identifier string
        self.identifier  = proxyplugin.__proxy_plugin_identifier__
        
        ## the plugin name string
        self.name = name
        
        proxyplugin.setName(self.identifier,self.name)
        proxyplugin.setStartCallback(self.identifier,self.start)
        proxyplugin.setStopCallback(self.identifier,self.stop)
        proxyplugin.setOnPluginActionCallback(self.identifier,self.onPluginAction)
       

        #add handlers to the proxyplugin module global dictionary
        interface_name = proxyplugin.__proxy_plugin_icd_interface__
        interface_handler = proxyHandlerRealization()
        proxyplugin.proxy_plugin_handlers_dict[interface_name]= interface_handler

        ## the dictionary containing references for icd handler and proxy implementation ( indexed by icd handler name )
        self.handlers_dict = proxyplugin.proxy_plugin_handlers_dict


    __del__ = lambda self: None

    def start(self):
        """!
        @brief callback method that must be reimplementted in order to manage start events
        @param self  : The object pointer
        """
        pass


    def stop(self):
        """!
        @brief callback method that must be reimplementted in order to manage stop events
        @param self          : The object pointer
        """
        pass

    def onPluginAction(self,action_id):
        """! callback method that must be reimplementted in order to manage plugin events
        @brief
        @param self          : The object pointer
        @param action_id     : (Integer) the identifier with wich the action is recorded.
        """
        pass

    def addAction(self,action_id,action_name,action_type_callable,action_parent=-1):
        """!
        @brief add action to the plugin
        @param self                     : The object pointer
        @param action_id                : (Integer) the identifier with wich the action is recorded.
        @param action_name              : (String) the label of the action ( to be displayed )
        @param action_type_callable     : [(Integer) ( see @ref Action_Types ) or callable function ]
        @param action_parent            : (Integer) the parent id ( if any ) {default (-1) on root level}
        @return (Boolean) True if successfull, False otherwise
        """
        ret = False
        if callable(action_type_callable):
            action_clbk = action_type_callable
            ret = proxyplugin.addCallableAction( self.identifier,
                                      action_id,
                                      action_name,
                                      action_clbk,
                                      action_parent
                                      )
        else:
            action_type = action_type_callable
            ret = proxyplugin.addSimpleAction( self.identifier,
                                      action_id,
                                      action_name,
                                      action_type,
                                      action_parent
                                      )
        return ret;


    def setChecked(self,action_id,val):
        """!
        @brief (for checkable item only) it sets the action checked based on value passed as argument
        @param self      : The object pointer
        @param action_id : (Integer) the action identifier
        @param val       : (Boolean) the value to set the action
        @return (Boolean) true if operation is successfully terminated
        """
        return proxyplugin.setChecked(self.identifier,action_id,val)

    def getChecked(self,action_id):
        """!
        @brief (for checkable item only) it returns the action status
        @param self      : The object pointer
        @param action_id : (Integer) the action identifier
        @return (Boolean) true if checked, false otherwise
        """
        return proxyplugin.getChecked(self.identifier,action_id)

    def openFileDialog(self, caption='Open File', from_dir='.', filters='Any File (*.*)' ):
        """!
        @brief open file dialog
        @param self     : The object pointer
        @param caption  : (String) the caption text ( default 'Open File' )
        @param from_dir : (String) the initial directory  ( default '.' )
        @param filters  : (String) extension file filtering ( optional ) [ Eg "Text File ( *.txt);; Any File (*.*)" ]
        @return         : (String) selected file path
        """
        return proxyplugin.openFileDialog(self.identifier, caption, from_dir, filters)

    def saveFileDialog(self, caption='Save File', from_dir='.', filters='Any File (*.*)' ):
        """!
        @brief save file dialog
        @param self     : The object pointer
        @param caption  : (String) the caption text ( default 'Open File' )
        @param from_dir : (String) the initial directory  ( default '.' )
        @param filters  : (String) extension file filtering ( optional ) [ Eg "Text File ( *.txt);; Any File (*.*)" ]
        @return         : (String) selected file path
        """
        return proxyplugin.saveFileDialog(self.identifier, caption, from_dir, filters)

    def openDirDialog(self, caption='Open Dir', from_dir='.' ):
        """!
        @brief dir dialog
        @param self     : The object pointer
        @param caption  : (String) the caption text ( default 'Open Dir' )
        @param from_dir : (String) the initial directory  ( default '.' )
        @return         : selected dir path
        """
        return proxyplugin.openDirDialog(self.identifier, caption, from_dir)

    def messageBox(self, text, caption='', btn_flag=0, icon_flag=0 ):
        """!
        @brief messagebox dialog
        @param self     : The object pointer
        @param text  : (String) the content text
        @param caption  : (String) the caption text ( '' )
        @param btn_flag : (Integer) {0: None, 1: Info, 2: Warning, 3: Error, 4: Question} ( default 0 )
        @param icon_flag: (Integer) {0: Ok, 1: Ok|Cancel, 2: Abort|Retry|Ignore, 3:Yes|No|Cancel, 4: Yes|No, 5: Retry|Cancel} ( default 0 )
        @return         : (Integer) result
        """
        return proxyplugin.messageBox(self.identifier, text, caption, btn_flag, icon_flag)

    def inputBox(self, text='Text', caption='Input box' ):
        """!
        @brief input dialog box
        @param self     : The object pointer
        @param text     : (String) the content text ( default None )
        @param caption  : (String) the caption text ( default 'Open File' )
        @return         : (String) return text
        """
        return proxyplugin.inputBox(self.identifier,caption, text)

