#
# ------------------------------------------------------------
# Copyright (c) All rights reserved
# SiLab, Institute of Physics, University of Bonn
# ------------------------------------------------------------
#

import os
from yaml import load, BaseLoader, scanner

from basil.HL.RegisterHardwareLayer import HardwareLayer


class scpi(HardwareLayer):
    '''Implement Standard Commands for Programmable Instruments (SCPI).
    '''

    def __init__(self, intf, conf):
        super(scpi, self).__init__(intf, conf)

    def init(self):
        device_desciption = os.path.dirname(__file__) + '/' + self._init['device'].lower().replace(" ", "_") + '.yaml'
        try:
            with open(device_desciption, 'r') as in_file:
                self._scpi_commands = load(in_file, Loader=BaseLoader)
        except scanner.ScannerError:
            raise RuntimeError('Parsing error for ' + self._init['device'] + ' device description in ' + device_desciption)
        except IOError:
            raise RuntimeError('Cannot find a device description for ' + self._init['device'] + ' Consider adding it!')
        name = self.get_name()
        if self._scpi_commands['identifier'] not in self.get_name():
            raise RuntimeError('Wrong device description (' + self._init['device'] + ') loaded for ' + name)

    def clear(self):  # SCPI command mandatory by IEEE 488.2
        self._intf.write('*CLS')

    def reset(self):  # SCPI command mandatory by IEEE 488.2
        self._intf.write('*RST')

    def trigger(self):  # SCPI command mandatory by IEEE 488.2
        self._intf.write('*TRG')

    def get_name(self):  # SCPI command mandatory by IEEE 488.2
        return self._intf.query('*IDN?')

    def __getattr__(self, name):
        '''called only on last resort if there are no attributes in the instance that match the name
        '''
        if name not in self._scpi_commands:
            raise ValueError('SCPI command %s is not defined for %s' % (name, self.__class__))

        def method(*args, **kwargs):
            channel = kwargs.pop('channel', None)
            command = self._scpi_commands['channel'][str(channel)][name] if channel is not None else self._scpi_commands[name]
            name_split = name.split('_', 1)
            if len(name_split) == 1:
                self._intf.write(command)
            elif len(name_split) == 2 and name_split[0] == 'set' and len(args) == 1 and not kwargs:
                self._intf.write(command + ' ' + str(args[0]))
            elif len(name_split) == 2 and name_split[0] == 'get' and not args and not kwargs:
                return self._intf.query(command)

        return method

@@ -1854,148 +1854,8 @@
 '''%0A
-        if name not in self._scpi_commands:%0A            raise ValueError('SCPI command %25s is not defined for %25s' %25 (name, self.__class__))%0A%0A
     
@@ -1937,16 +1937,37 @@
 , None)%0A
+            try:%0A    
         
@@ -2012,23 +2012,22 @@
 nnel
-'%5D%5Bstr(
+ %25s' %25 
 channel
-)
 %5D%5Bna
@@ -2084,16 +2084,135 @@
 s%5Bname%5D%0A
+            except:%0A                raise ValueError('SCPI command %25s is not defined for %25s' %25 (name, self.__class__))%0A
         

throw exception correctly if channel is specified