# lxml supports CDATA and xml.etree.ElementTree does not
# See https://lxml.de/tutorial.html
from lxml.etree import CDATA, Element, SubElement, tostring
import pandas as pd

def addAxisPoint (curvePoints, identifierNumber, ordinal, xScreen, yScreen, xGraph, yGraph, IsXOnly = 'False'):
    point = SubElement (curvePoints, 'Point')
    point.set ('Identifier', 'Axes\tpoint\t{}' . format (identifierNumber))
    point.set ('Ordinal', '{}' . format (ordinal))
    point.set ('IsAxisPoint', 'True')
    point.set ('IsXOnly', IsXOnly)
    point.set ('Index', '329')
    positionScreen = SubElement (point, 'PositionScreen')
    positionScreen.set ('X', '{}' . format (xScreen))
    positionScreen.set ('Y', '{}' . format (yScreen))
    positionGraph = SubElement (point, 'PositionGraph')
    positionGraph.set ('X', '{}' . format (xGraph))
    positionGraph.set ('Y', '{}' . format (yGraph))
    
def addGraphPoint (curvePoints, identifierIndex, ordinal, xScreen, yScreen):
    point = SubElement (curvePoints, 'Point')
    point.set ('Identifier', 'Curve1\tpoint\t{}' . format (identifierIndex))
    point.set ('Ordinal', '0')
    point.set ('IsAxisPoint', 'False')
    point.set ('IsXOnly', 'False')
    point.set ('Index', '329')
    positionScreen = SubElement (point, 'PositionScreen')
    positionScreen.set ('X', '{}' . format (xScreen))
    positionScreen.set ('Y', '{}' . format (yScreen))

def createTestCase(xAxes, yAxes, xData, yData, xScale, yScale, title):
    """xAxes looks like [xScreen, xGraph], where xScreen is an array of
    x pixel values for the axes, and xGraph is the corresponding graph 
    coordinates. yAxes is similar.
    If passing four axis points, the first two rows should be for the x axis
    and the next two values for the y axis. 
    xData and yData are both 1D arrays of the pixel values of the
    data points.
    xScale and yScale are the various scale types (e.g. Linear, Log).
    title is the desired title of the output."""
    
    document = Element ('Document')
    document.set ('VersionNumber', '11.0')
    document.set ('AxesPointsRequired', '0')
    
    image = SubElement (document, 'Image')
    image.set ('Width', '605')
    image.set ('Height', '340')
    image.text = CDATA ('[encoded data, 11700 characters]')

    coordSystem = SubElement (document, 'CoordSystem')
    general = SubElement (coordSystem, 'General')
    general.set ('CursorSize', '3')
    general.set ('ExtraPrecision', '1')
    coords = SubElement (coordSystem, 'Coords')
    coords.set ('Type', '0')
    coords.set ('TypeString', 'Cartesian')
    coords.set ('Coords', '0')
	
    if (xScale == 'Linear'):
        coords.set ('ScaleXTheta', '0')
    elif (xScale == 'Log'):
        coords.set ('ScaleXTheta', '1')
    coords.set ('ScaleXThetaString', xScale)
	
    if (yScale == 'Linear'):
        coords.set ('ScaleYRadius', '0')
    elif (yScale == 'Log'):
        coords.set ('ScaleYRadius', '1')
    coords.set ('ScaleYRadiusString', yScale)
	
    coords.set ('UnitsX', '0')
    coords.set ('UnitsXString', 'Number')
    coords.set ('UnitsY', '0')
    coords.set ('UnitsYString', 'Number')
    coords.set ('UnitsTheta', '0')
    coords.set ('UnitsThetaString', 'Degrees (DDD.DDDDD)')
    coords.set ('UnitsRadius', '0')
    coords.set ('UnitsRadiusString', 'Number')
    coords.set ('UnitsDate', '3')
    coords.set ('UnitsDateString', 'YYYY/MM/DD')
    coords.set ('UnitsTime', '2')
    coords.set ('UnitsTimeString', 'HH:MM:SS')
    digitizeCurve = SubElement (coordSystem, 'DigitizeCurve')
    digitizeCurve.set ('CursorInnerRadius', '5')
    digitizeCurve.set ('CursorLineWidth', '2')
    digitizeCurve.set ('CursorSize', '1')
    digitizeCurve.set ('CursorStandardCross', 'True')
    export = SubElement (coordSystem, 'Export')
    export.set ('PointsSelectionFunctions', '1')
    export.set ('PointsSelectionFunctionsString', 'InterpolateFirstCurve')
    export.set ('PointsIntervalFunctions', '10')
    export.set ('PointsIntervalUnitsFunctions', '1')
    export.set ('PointsSelectionRelations', '0')
    export.set ('PointsSelectionRelationsString', 'Interpolate')
    export.set ('PointsIntervalUnitsRelations', '1')
    export.set ('PointsIntervalRelations', '10')
    export.set ('LayoutFunctions', '0')
    export.set ('LayoutFunctionsString', 'AllPerLine')
    export.set ('Delimiter', '0')
    export.set ('OverrideCsvTsv', 'False')
    export.set ('DelimiterString', 'Commas')
    export.set ('ExtrapolateOutsideEndpoints', 'True')
    export.set ('Header', '1')
    export.set ('HeaderString', 'Simple')
    export.set ('XLabel', 'x')
    curveNamesNotExported = SubElement (export, 'CurveNamesNotExported')
    axesChecker = SubElement (coordSystem, 'AxesChecker')
    axesChecker.set ('Mode', '1')
    axesChecker.set ('Seconds', '3')
    axesChecker.set ('LineColor', '6')
    gridDisplay = SubElement (coordSystem, 'GridDisplay')
    gridDisplay.set ('Stable', 'True')
    gridDisplay.set ('DisableX', '0')
    gridDisplay.set ('CountX', '4')
    gridDisplay.set ('StartX', '0')
    gridDisplay.set ('StepX', '5')
    gridDisplay.set ('StopX', '15')
    gridDisplay.set ('DisableY', '0')
    gridDisplay.set ('CountY', '5')
    gridDisplay.set ('StartY', '-2')
    gridDisplay.set ('StepY', '1')
    gridDisplay.set ('StopY', '2')
    gridDisplay.set ('Color', '0')
    gridDisplay.set ('ColorString', 'Black')
    gridRemoval = SubElement (coordSystem, 'GridRemoval')
    gridRemoval.set ('Stable', 'False')
    gridRemoval.set ('DefinedGridLines', 'False') 
    gridRemoval.set ('CloseDistance', '10') 
    gridRemoval.set ('CoordDisableX', '0') 
    gridRemoval.set ('CoordDisableXString', 'Count') 
    gridRemoval.set ('CountX', '2') 
    gridRemoval.set ('StartX', '-0.256806') 
    gridRemoval.set ('StepX', '3.07889') 
    gridRemoval.set ('StopX', '2.82208') 
    gridRemoval.set ('CoordDisableY', '0') 
    gridRemoval.set ('CoordDisableYString', 'Count') 
    gridRemoval.set ('CountY', '24') 
    gridRemoval.set ('StartY', '-0.986309') 
    gridRemoval.set ('StepY', '0.0866021') 
    gridRemoval.set ('StopY', '1.00554')
    pointMatch = SubElement (coordSystem, 'PointMatch')
    pointMatch.set ('PointSize', '48')
    pointMatch.set ('ColorAccepted', '4')
    pointMatch.set ('ColorAcceptedString', 'Green')
    pointMatch.set ('ColorCandidate', '7')
    pointMatch.set ('ColorCandidateString', 'Yellow')
    pointMatch.set ('ColorRejected', '6')
    pointMatch.set ('ColorRejectedString', 'Red')
    segments = SubElement (coordSystem, 'Segments')
    segments.set ('PointSeparation', '25')
    segments.set ('MinLength', '2')
    segments.set ('FillCorners', 'False')
    segments.set ('LineWidth', '4')
    segments.set ('LineColor', '4')
    segments.set ('LineColorString', 'Green')
    curve = SubElement (coordSystem, 'Curve')
    curve.set ('CurveName', 'Axes')
    colorFilter = SubElement (curve, 'ColorFilter')
    colorFilter.set ('CurveName', 'Axes')
    colorFilter.set ('Mode', '1')
    colorFilter.set ('ModeString', 'Intensity')
    colorFilter.set ('IntensityLow', '0')
    colorFilter.set ('IntensityHigh', '50')
    colorFilter.set ('ForegroundLow', '0')
    colorFilter.set ('ForegroundHigh', '10')
    colorFilter.set ('HueLow', '180')
    colorFilter.set ('HueHigh', '360')
    colorFilter.set ('SaturationLow', '50')
    colorFilter.set ('SaturationHigh', '100')
    colorFilter.set ('ValueLow', '0')
    colorFilter.set ('ValueHigh', '50')
    curveStyle = SubElement (curve, 'CurveStyle')
    curveStyle.set ('CurveName', 'Axes')
    lineStyle = SubElement (curveStyle, 'LineStyle')
    lineStyle.set ('Width', '0')
    lineStyle.set ('Color', '8')
    lineStyle.set ('ColorString', 'Transparent')
    lineStyle.set ('ConnectAs', '4')
    lineStyle.set ('ConnectAsString', 'ConnectSkipForAxisCurve')
    pointStyle = SubElement (curveStyle, 'PointStyle')
    pointStyle.set ('Radius', '10')
    pointStyle.set ('LineWidth', '1')
    pointStyle.set ('Color', '6')
    pointStyle.set ('ColorString', 'Red')
    pointStyle.set ('Shape', '1')
    pointStyle.set ('ShapeString', 'Cross')
    curvePoints = SubElement (curve, 'CurvePoints')
    xScreen = xAxes[0]
    xGraph = xAxes[1]
    yScreen = yAxes[0]
    yGraph = yAxes[1]
    # When adding the axis points, make sure to account for four axis points.
    if (len(xScreen) == 3):
        addAxisPoint (curvePoints, 209, 1, xScreen[0], 
                      yScreen[0], xGraph[0], yGraph[0])
        addAxisPoint (curvePoints, 211, 2, xScreen[1], 
                      yScreen[1], xGraph[1], yGraph[1])
        addAxisPoint (curvePoints, 213, 3, xScreen[2], 
                      yScreen[2], xGraph[2], yGraph[2])
    else:
        addAxisPoint (curvePoints, 209, 1, xScreen[0], 
                      yScreen[0], xGraph[0], 0, IsXOnly = 'True')
        addAxisPoint (curvePoints, 211, 2, xScreen[1], 
                      yScreen[1], xGraph[1], 0, IsXOnly = 'True')
        addAxisPoint (curvePoints, 213, 3, xScreen[2], 
                      yScreen[2], 0, yGraph[2])
        addAxisPoint (curvePoints, 215, 4, xScreen[3], 
                      yScreen[3], 0, yGraph[3])
    
    curvesGraphs = SubElement (coordSystem, 'CurvesGraphs')
    curve = SubElement (curvesGraphs, 'Curve')
    curve.set ('CurveName', 'Curve1')
    
    colorFilter = SubElement (curve, 'ColorFilter')
    colorFilter.set ('CurveName', 'Curve1')
    colorFilter.set ('Mode', '1')
    colorFilter.set ('ModeString', 'Hue')
    colorFilter.set ('IntensityLow', '0')
    colorFilter.set ('IntensityHigh', '50')
    colorFilter.set ('ForegroundLow', '0')
    colorFilter.set ('ForegroundHigh', '10')
    colorFilter.set ('HueLow', '204')
    colorFilter.set ('HueHigh', '211')
    colorFilter.set ('SaturationLow', '50')
    colorFilter.set ('SaturationHigh', '100')
    colorFilter.set ('ValueLow', '0')
    colorFilter.set ('ValueHigh', '50')
    curveStyle = SubElement (curve, 'CurveStyle')
    curveStyle.set ('CurveName', 'Curve1')
    lineStyle = SubElement (curveStyle, 'LineStyle')
    lineStyle.set ('Width', '1')
    lineStyle.set ('Color', '1')
    lineStyle.set ('ColorString', 'Blue')
    lineStyle.set ('ConnectAs', '0')
    lineStyle.set ('ConnectAsString', 'FunctionSmooth')
    pointStyle = SubElement (curveStyle, 'PointStyle')
    pointStyle.set ('Radius', '10')
    pointStyle.set ('LineWidth', '1')
    pointStyle.set ('Color', '1')
    pointStyle.set ('ColorString', 'Blue')
    pointStyle.set ('Shape', '1')
    pointStyle.set ('ShapeString', 'Cross')
    curvePoints = SubElement (curve, 'CurvePoints')
    
    addGraphPoint (curvePoints, 290, 0, xData, yData)
    testFile = (tostring (document,
                     pretty_print = True,
                     xml_declaration = True,
                     encoding = 'UTF-8',
                     doctype = '<!DOCTYPE engauge>').decode ('utf-8'))

    try: 
        f = open(title, 'w')
    except Exception as e:
        f = open(title, 'w+')
    f.write(testFile)
    f.close()