#!/usr/bin/env python3
"""Create pgf boxplots for emper-fs-eval experiment results"""

import sys
import yaml


def parse_data(stream):
    """Convert yamls string to dict"""
    return yaml.safe_load(stream)

TIKZ_TEMPLATE = \
"""\\documentclass[]{standalone}
\\usepackage{pgfplots}
\\pgfplotsset{compat=1.17}
\\usepgfplotslibrary{statistics}
\\begin{document}
\\begin{tikzpicture}
\\begin{axis}[
    ylabel={time [s]},
    xtick=\\empty,
    ymajorgrids=true,
    boxplot/draw direction=y,
    legend columns=2,
    area legend,
    legend style={
        draw=none,
        fill=none,
        at={(0.5,-0.1)},
        anchor=north
    },
]
$PLOTS$
\\end{axis}
\\end{tikzpicture}
\\end{document}
"""

PLOT_TEMPLATE = \
"""\\addplot+[
    boxplot prepared={{
          lower whisker={lower_whisker},
          lower quartile={lower_quartile},
          median={median},
          average={mean},
          upper quartile={upper_quartile},
          upper whisker={upper_whisker},
      }},
] coordinates{{{outlier_cords}}};
\\addlegendentry{{{syscall}}}
"""


def generate_boxplot(data) -> str:
    """Create a boxplot"""
    key = 'duration_time:u'
    plots = ''
    for syscall, stats in data.items():
        outlier_cords = ''
        for outlier in stats[key]['outliers']:
            outlier_cords += f'(0, {outlier}) '
        plots += PLOT_TEMPLATE.format(syscall=syscall.replace('_', '-'),
                                      outlier_cords=outlier_cords,
                                      **stats[key])

    return TIKZ_TEMPLATE.replace('$PLOTS$', plots)


def main():
    """Create a boxplot from read yaml data"""
    if len(sys.argv) == 1:
        _data = parse_data(sys.stdin)
    else:
        with open(sys.argv[1], 'r', encoding='utf-8') as yaml_file:
            _data = parse_data(yaml_file)

    tikz = generate_boxplot(_data)

    if len(sys.argv) > 2:
        with open(sys.argv[2], 'w', encoding='utf-8') as saveto:
            print(tikz, file=saveto)
    else:
        print(tikz)


if __name__ == '__main__':
    main()