#!/usr/bin/env python3

from collections import namedtuple
import xml.etree.ElementTree as ET
from xml.dom import minidom
import argparse

DocEntry = namedtuple('DocEntry', ['iform', 'regsize', 'mask', 'tp', 'lat'])

def main():
   parser = argparse.ArgumentParser(description="Add data to XML file from Intel's CSV doc")
   parser.add_argument('-xml')
   parser.add_argument('-csv')
   parser.add_argument('-outputXML')
   parser.add_argument('-arch')
   args = parser.parse_args()

   docDict = dict()

   with open(args.csv, 'r') as f:
      for i, line in enumerate(f):
         if i > 0:
            de = DocEntry(*line.strip().split(','))
            docDict.setdefault(de.iform, []).append(de)

   root = ET.parse(args.xml).getroot()


   for instrNode in root.iter('instruction'):
      iform = instrNode.attrib['iform']

      if iform in docDict:
         matchingDEs = set(docDict[iform])

         if len(matchingDEs) > 1:
            for de in list(matchingDEs):
               if de.regsize != '-':
                  if not instrNode.findall('./operand[@type="reg"][@width="{}"]'.format(de.regsize)):
                     matchingDEs.remove(de)

         for de in list(matchingDEs):
            if 'mask' in instrNode.attrib:
               if (instrNode.attrib['mask'] == '1' and de.mask == 'no') or (instrNode.attrib['mask'] == '0' and de.mask == 'yes'):
                  matchingDEs.remove(de)

         if len(matchingDEs) == 0:
            print('No matching iform: ' + iform)
         elif len(matchingDEs) > 1:
            print('Multiple matching iforms: ' + iform)
         else:
            de = next(iter(matchingDEs))

            archNode = instrNode.find('./architecture[@name="{}"]'.format(args.arch))
            if archNode is None:
               archNode = ET.SubElement(instrNode, "architecture")
               archNode.attrib['name'] = args.arch

            docNode = ET.SubElement(archNode, "doc")
            if de.tp: docNode.attrib['TP'] = de.tp
            if de.lat: docNode.attrib['latency'] = de.lat

   with open(args.outputXML, "w") as f:
      rough_string = ET.tostring(root, 'utf-8')
      reparsed = minidom.parseString(rough_string)
      f.write('\n'.join([line for line in reparsed.toprettyxml(indent=' '*2).split('\n') if line.strip()]))


if __name__ == "__main__":
    main()
