text: # -*- coding: utf-8 -*-
  from __future__ import absolute_import
  from . import vimba_structure as structs
  from .vimba_dll import VimbaDLL
  from .vimba_exception import VimbaException
  from .vimba_system import VimbaSystem
  from .vimba_camera import VimbaCamera
  from .vimba_interface import VimbaInterface
  from ctypes import *
  
  
  class Vimba(object):
  
      """
      An Allied Vision Technology Vimba API.
      This API provides access to AVT cameras.
      """
  
      # todo - assign camera info and feature info as own object proeprties
  
      def __init__(self):
  
          # create own system singleton object
          self._system = VimbaSystem()
  
          # lists of VimbaCameraInfo and VimbaInterfaceInfo objects
          # can't be called before startup() so populate later
          self._interfaceInfos = None
  
          # dict of {camera ID : VimbaCamera object} as we don't want to forget
          # them
          self._cameras = {}
  
          # dict of {interface ID : VimbaInterface object} as we don't want to
          # forget them
          self._interfaces = {}
  
      def __enter__(self):
          """
          Define vimba context for safe execution.
  
          The vimba object should be used like this:
              # start Vimba
              with Vimba() as vimba:
                  system = vimba.getSystem()
                  # ...
          """
          self.startup()
          return self
  
      def __exit__(self, type, value, traceback):
          """
          Shutdown Vimba when the with context is left. This allows cleanup
          when an error occurs in the main program. The system will not hang
          on a kernel call after an exception.
          """
          self.shutdown()
  
      def _getInterfaceInfos(self):
          """
          Gets interface info of all available interfaces.
  
          :returns: list -- interface info for available interfaces.
          """
          if self._interfaceInfos is None:
              # args
              numFound = c_uint32(-1)
  
              # call once just to get the number of interfaces
              # Vimba DLL will return an error code
              errorCode = VimbaDLL.interfacesList(None,
                                                  0,
                                                  byref(numFound),
                                                  sizeof(structs.VimbaInterfaceInfo))
              if errorCode != 0:
                  raise VimbaException(errorCode)
  
              numInterfaces = numFound.value
  
              # args
              interfaceInfoArray = (structs.VimbaInterfaceInfo * numInterfaces)()
  
              # call again to get the features
              # Vimba DLL will return an error code
              errorCode = VimbaDLL.interfacesList(interfaceInfoArray,
                                                  numInterfaces,
                                                  byref(numFound),
                                                  sizeof(structs.VimbaInterfaceInfo))
              if errorCode != 0:
                  raise VimbaException(errorCode)
              self._interfaceInfos = list(
                  interfaceInfo for interfaceInfo in interfaceInfoArray)
          return self._interfaceInfos
  
      def _getCameraInfos(self):
          """
          Gets camera info of all attached cameras.
  
          :returns: list -- camera info for available cameras.
          """
          # args
          dummyCameraInfo = structs.VimbaCameraInfo()
          numFound = c_uint32(-1)
  
          # call once just to get the number of cameras
          # Vimba DLL will return an error code
          errorCode = VimbaDLL.camerasList(byref(dummyCameraInfo),
                                           0,
                                           byref(numFound),
                                           sizeof(dummyCameraInfo))
          if errorCode != 0 and errorCode != -9:
              raise VimbaException(errorCode)
  
          numCameras = numFound.value
  
          # args
          cameraInfoArray = (structs.VimbaCameraInfo * numCameras)()
  
          # call again to get the features
          # Vimba DLL will return an error code
          errorCode = VimbaDLL.camerasList(cameraInfoArray,
                                           numCameras,
                                           byref(numFound),
                                           sizeof(dummyCameraInfo))
          if errorCode != 0:
              raise VimbaException(errorCode)
          return list(camInfo for camInfo in cameraInfoArray)
  
      def getSystem(self):
          """
          Gets system singleton object.
  
          :returns: VimbaSystem object -- the system singleton object.
          """
          return self._system
  
      def getInterfaceIds(self):
          """
          Gets IDs of all available interfaces.
  
          :returns: list -- interface IDs for available interfaces.
          """
          return list(interfaceInfo.interfaceIdString for interfaceInfo in self._getInterfaceInfos())
  
      def getCameraIds(self):
          """
          Gets IDs of all available cameras.
  
          :returns: list -- camera IDs for available cameras.
          """
          return list(camInfo.cameraIdString.decode() for camInfo in self._getCameraInfos())
  
      def getInterfaceInfo(self, interfaceId):
          """
          Gets interface info object of specified interface.
  
          :param interfaceId: the ID of the interface object to get.
  
          :returns: VimbaInterfaceInfo object -- the interface info object specified.
          """
          # don't do this live as we already have this info
          # return info object if it exists
          for interfaceInfo in self._getInterfaceInfos():
              if interfaceInfo.interfaceIdString == interfaceId:
                  return interfaceInfo
          # otherwise raise error
          raise VimbaException(-54)
  
      def getCameraInfo(self, cameraId):
          """
          Gets camera info object of specified camera.
  
          :param cameraId: the ID of the camera object to get.
                           This might not only be a cameraId as returned by getCameraIds() 
                           but also e.g. a serial number. Check the Vimba documentation for 
                           other possible values.
  
          :returns: VimbaCameraInfo object -- the camera info object specified.
          """
          cameraInfo = structs.VimbaCameraInfo()
          errorCode = VimbaDLL.cameraInfoQuery(cameraId.encode(),
                                               cameraInfo,
                                               sizeof(cameraInfo))
          if errorCode == 0:
              return cameraInfo
  
          # otherwise raise error
          raise VimbaException(-50)
  
      def getInterface(self, interfaceId):
          """
          Gets interface object based on interface ID string. Will not recreate
          interface object if it already exists.
  
          :param interfaceId: the ID of the interface.
  
          :returns: VimbaInterface object -- the interface object specified.
          """
          # check ID is valid
          if interfaceId in self.getInterfaceIds():
              # create it if it doesn't exist
              if interfaceId not in self._interfaces:
                  self._interfaces[interfaceId] = VimbaInterface(interfaceId)
              return self._interfaces[interfaceId]
          raise VimbaException(-54)
  
      def getCamera(self, cameraId):
          """
          Gets camera object based on camera ID string. Will not recreate
          camera object if it already exists.
  
          :param cameraId: the ID of the camera object to get. 
                           This might not only be a cameraId as returned by getCameraIds() 
                           but also e.g. a serial number. Check the Vimba documentation for 
                           other possible values.
  
          :returns: VimbaCamera object -- the camera object specified.
          """
          # check ID is valid
          if cameraId in self.getCameraIds():
              # create it if it doesn't exist
              if cameraId not in self._cameras:
                  self._cameras[cameraId] = VimbaCamera(cameraId)
              return self._cameras[cameraId]
          else:
              # the given string might not be a camera ID -> check for other IDs
              cameraInfo = structs.VimbaCameraInfo()
              errorCode = VimbaDLL.cameraInfoQuery(cameraId.encode(),
                                                   cameraInfo,
                                                   sizeof(cameraInfo))
              if errorCode != 0:
                  raise VimbaException(-50)   # camera not found
              
              cameraIdString = cameraInfo.cameraIdString.decode()
              if cameraIdString not in self._cameras:
                  self._cameras[cameraIdString] = VimbaCamera(cameraIdString)
              return self._cameras[cameraIdString]
              
  
      def getVersion(self):
          """
          Retrieve the version number of VimbaC.
  
          :returns: string - Vimba API version info.
          """
          # args
          versionInfo = structs.VimbaVersion()
  
          # Vimba DLL will return an error code
          errorCode = VimbaDLL.versionQuery(
              versionInfo,
              sizeof(versionInfo)
          )
          if errorCode:
              raise VimbaException(errorCode)
  
          versionStr = '.'.join([str(versionInfo.major),
                                 str(versionInfo.minor),
                                 str(versionInfo.patch)])
          return versionStr
  
      def startup(self):
          """
          Initialize the VimbaC API.
          """
          # Vimba DLL will return an error code
          errorCode = VimbaDLL.startup()
          if errorCode != 0:
              raise VimbaException(errorCode)
  
      def shutdown(self):
          """
          Perform a shutdown on the API.
          """
          VimbaDLL.shutdown()
  