#####################################################################
# Copyright Trimble 2019
######################################################################
# Get info from config.xml
from abc import ABC, abstractmethod
try:
  import xml.etree.cElementTree as ET
except ImportError:
  import xml.etree.ElementTree as ET
import json

def find_opt_text(elem,tag_name):
  tag = elem.find(tag_name)
  if(tag != None):
    tag = tag.text
  return tag

def find_opt_obj(elem,tag_name):
  tag = elem.find(tag_name)
  return tag

# Using __slots__ lets pylint check for typos
class DeviceAg(object):
  '''Info from single Ag NAV 900 receiver/device in config.xml'''
  __slots__ = ('skip_setup',
               'io_TSIP',
               'io_RTK_input',
               'io_NMEA_ZDA_output',
               'skip_install',
               'job_key',
               'build_name',
               'tnfs_ip')

  def __init__(self):
    pass
  def __repr__(self):
    mystr = '\n    '
    mystr += '\n    '.join("%s: %s" % (item,getattr(self,item,None)) for item in self.__slots__)
    return mystr


# Using __slots__ lets pylint check for typos
class DeviceSeptentrio(object):
  '''Info from single spetentrio receiver/device in config.xml'''
  __slots__ = ('ftp_hostname',
               'ftp_path',
               'afterIM')

  def __dict__(self):
    return {s: getattr(self, s) for s in self.__slots__ if hasattr(self, s)}
  def __init__(self):
    pass
  def __repr__(self):
    mystr = '\n    '
    mystr += '\n    '.join("%s: %s" % (item,getattr(self,item,None)) for item in self.__slots__)
    return mystr

# Using __slots__ lets pylint check for typos
class DeviceNovatel(object):
  '''Info from single novatel receiver/device in config.xml'''
  __slots__ = ('backup_ip',
               'backup_port')

  def __dict__(self):
    return {s: getattr(self, s) for s in self.__slots__ if hasattr(self, s)}
  def __init__(self):
    pass
  def __repr__(self):
    mystr = '\n    '
    mystr += '\n    '.join("%s: %s" % (item,getattr(self,item,None)) for item in self.__slots__)
    return mystr


# Using __slots__ lets pylint check for typos
class Device(object):
  '''Info from single receiver/device in config.xml'''
  __slots__ = ('n',
               'ip',
               'desc',
               'long_desc',
               'build',
               'user',
               'pw',
               'settingsClone',
               'patchFile',
               'StingerAPI',
               'tag',
               'frozen',
               'do_RTK',
               'do_IMU',
               'port',
               'timg',
               'ag',
               'septentrio',
               'novatel')
  @property
  def __dict__(self):
    return {s: getattr(self, s) for s in self.__slots__ if hasattr(self, s)}
  def __init__(self):
    pass
  def __repr__(self):
    mystr = 'Device:\n  '
    mystr += '\n  '.join("%s: %s" % (item,getattr(self,item,None)) for item in self.__slots__)
    mystr += '\n'
    return mystr

# Using __slots__ lets pylint check for typos
class JammingDevice(object):
  '''Info from single device in config.xml'''
  __slots__ = ('id',
               'n',
               'type',
               'desc',
               'long_desc',
               'enable',
               'api',
               'gpib_address',
               'connected_device',
               'com_port')
  @property
  def __dict__(self):
    return {s: getattr(self, s) for s in self.__slots__ if hasattr(self, s)}
  def __init__(self):
    pass
  def __repr__(self):
    mystr = 'Jamming Device:\n  '
    mystr += '\n  '.join("%s: %s" % (item,getattr(self,item,None)) for item in self.__slots__)
    mystr += '\n'
    return mystr

# Using __slots__ lets pylint check for typos
class ConfigXml(object):
  '''All info from config.xml (+ a little global config info)'''
  __slots__ = ('current_config_device', # what are we trying to config now?
               'ScriptRoot',
               'ResultsQueue',
               'clean_builds',
               'allow_builds',
               'allow_firmware_install',               
               'email_recipients',
               'email_host',
               'spirent_simulator_host_ip',
               'spirent_simulator_host_port',
               'jamming_host_ip',
               'jamming_host_port',
               'hackrf_host_ip',
               'hackrf_host_port',
               'devices',
               'jamming_devices',
               'GlobalRunNum')
  @property
  def __dict__(self):
    return {s: getattr(self, s) for s in self.__slots__ if hasattr(self, s)}
    # return {s: getattr(self, s) if isinstance(getattr(self, s), str) else str(getattr(self, s)) for s in self.__slots__ if hasattr(self, s)}
  def __init__(self):
    self.clean_builds = True # delete Build directory before each test?  Otherwise just cvs update
    self.allow_builds = True # only set False for debugging!
    self.allow_firmware_install = True # upgrade FW?  Only set False for testing!
    self.current_config_device = None
  def __repr__(self):
    mystr = 'ConfigXml:\n  '
    mystr += '\n  '.join("%s: %s" % (item,getattr(self,item,None)) for item in self.__slots__)
    mystr += '\n'
    return mystr

def get_config_xml(cfg_file='config.xml'):
  """
  Return info from global config - mainly config.xml
  """
  cfg = ConfigXml()
  tree = ET.ElementTree(file=cfg_file)
  root = tree.getroot()
  cfg.ResultsQueue = root.find('ResultsQueue').text
  cfg.ScriptRoot = root.find('ScriptRoot').text

  cfg.email_host = find_opt_text( root, 'NotifyOnError/emailHost' )
  cfg.email_recipients = []
  for elem in tree.iter(tag='emailErr'):
    cfg.email_recipients.append( elem.text )

  cfg.spirent_simulator_host_ip = root.find('SpirentSimultor/HostIP').text
  cfg.spirent_simulator_host_port = root.find('SpirentSimultor/Port').text

  cfg.jamming_host_ip = root.find('JammingSource/HostIP').text
  cfg.jamming_host_port = root.find('JammingSource/Port').text

  cfg.hackrf_host_ip = root.find('JammingSource/HackRFServerHostIP').text
  cfg.hackrf_host_port = root.find('JammingSource/HackRFServerPort').text

  cfg.devices = []
  cfg.jamming_devices = []

  # Now get details about the devices we are going to test
  for elem in tree.iter(tag='rx'):
    dev = Device()
    dev.n = int(elem.find('n').text)
    dev.ip = elem.find('ip').text
    dev.desc = elem.find('desc').text
    dev.long_desc = elem.find('long_desc').text
    dev.build = elem.find('build').text
    dev.user = elem.find('user').text
    dev.pw = elem.find('pw').text
    dev.settingsClone = find_opt_text(elem,'settingsClone')
    dev.patchFile = find_opt_text(elem,'patchFile')
    dev.StingerAPI = find_opt_text(elem,'StingerAPI')
    dev.tag = find_opt_text(elem,'tag') # CVS tag
    dev.frozen = find_opt_text(elem,'frozen') # frozen date?
    dev.do_RTK = find_opt_text(elem,'do_RTK')
    dev.do_IMU = find_opt_text(elem,'do_IMU')
    dev.timg = find_opt_text(elem,'timg')
    dev.port = find_opt_text(elem,'port')
    
    dev.septentrio = find_opt_obj(elem,'septentrio')
    for elem in elem.iter(tag='septentrio'):
      devSept = DeviceSeptentrio() 
      devSept.ftp_hostname = find_opt_text(elem,'ftp_hostname')
      devSept.ftp_path = find_opt_text(elem,'ftp_path')
      devSept.afterIM = find_opt_text(elem,'afterIM')
      dev.septentrio = devSept

    dev.novatel = find_opt_obj(elem,'novatel')
    for elem in elem.iter(tag='novatel'):
      devNov = DeviceNovatel() 
      devNov.backup_ip = find_opt_text(elem,'backup_ip')
      devNov.backup_port = find_opt_text(elem,'backup_port')
      dev.novatel = devNov

    dev.ag = find_opt_obj(elem,'ag')
    for elem in elem.iter(tag='ag'):
      devAg = DeviceAg()
      devAg.skip_setup = find_opt_text(elem,'skip_setup')
      devAg.io_TSIP = find_opt_text(elem,'io_TSIP')
      devAg.io_RTK_input = find_opt_text(elem,'io_RTK_input')
      devAg.io_NMEA_ZDA_output = find_opt_text(elem,'io_NMEA_ZDA_output')
      devAg.skip_install = find_opt_text(elem,'skip_install')
      devAg.job_key = find_opt_text(elem,'job_key')
      devAg.build_name = find_opt_text(elem,'build_name')
      devAg.tnfs_ip = find_opt_text(elem,'tnfs_ip')
      dev.ag = devAg

    cfg.devices.append(dev)

  # Now get details about the devices we are going to test
  for elem in tree.iter(tag='jamdev'):
    dev = JammingDevice()
    dev.id = elem.find('id').text
    dev.n = int(elem.find('n').text)
    dev.type = elem.find('deviceType').text
    dev.desc = elem.find('desc').text
    dev.long_desc = elem.find('long_desc').text
    dev.enable = int(elem.find('enable').text)
    dev.api = elem.find('api').text
    dev.gpib_address = find_opt_text(elem,'GPIBAddress')
    dev.connected_device = find_opt_text(elem,'connectedDevice')
    dev.com_port = find_opt_text(elem,'comPort')
    
    cfg.jamming_devices.append(dev)


  # Now load the current run number
  try:
    fid = open('RunNum.txt','r')
    cfg.GlobalRunNum = int(fid.readline())
    fid.close()
  except:
    cfg.GlobalRunNum = None

  return cfg

if __name__ == "__main__":
  cfg = get_config_xml(None, False)
  
