
from com.xebialabs.xltest.repository import TestRunsRepository

def text2symbol(text):
    if text == '':
        return 'arrow-down'
    if '+' == text[0]:
        return 'arrow-up'
    if '0' == text[0]:
        return 'equals'
    return 'arrow-down'

def text2symbolnegative(text):
    if text == '':
        return 'arrow-up'
    if '+' == text[0]:
        return 'arrow-down'
    if '0' == text[0]:
        return 'equals'
    return 'arrow-up'

def make_trend_text(now, prev):
    if now > prev:
        return '+' + str(long(now) - long(prev))
    if prev > now:
        return '-' + str(long(prev) - long(now))
    return '0'

def make_trend_text_in_min_sec(now, prev):
    if now > prev:
        return '+' + make_readable_time(now.subtract(prev))
    if prev > now:
        return '-' + make_readable_time(prev.subtract(now))
    return '0'

def make_readable_time(full_run_time_in_millis):
    full_run_time_in_sec = full_run_time_in_millis.longValue() / 1000l
    full_run_time_in_min = 0
    if full_run_time_in_sec > 60:
        full_run_time_in_min = full_run_time_in_sec / 60
        full_run_time_in_sec = full_run_time_in_sec - (full_run_time_in_min * 60)
    return str(full_run_time_in_min) + "m" + str(full_run_time_in_sec) + "s"


events = testRun.getEvents()
passed_set=set()
failed_set=set()
start_timestamp = 0
finish_timestamp = 0

if events:
    total_duration = 0
    n_tests = 0
    for ev in events:
        if ev.type == 'executionStarted':
            start_timestamp = ev.get('timestamp')
        elif ev.type == 'executionFinished':
            finish_timestamp = ev.get('timestamp')
        if ev.type == 'importStarted' and not start_timestamp:
            start_timestamp = ev.get('timestamp')
        elif ev.type == 'importFinished' and not finish_timestamp:
            finish_timestamp = ev.get('timestamp')
        elif ev.type == 'functionalResult':
            result = ev.get('result')
            if result is None:
                continue
            n_tests = n_tests + 1
            total_duration = long(total_duration) + ev.get('duration')
            if result == 'PASSED':
                passed_set.add(ev.get('name'))
            else:
                failed_set.add(ev.get('name'))
if n_tests > 0:
    average_duration = long(total_duration) / n_tests
else:
    average_duration = 0
full_run_time_in_millis = finish_timestamp.longValue() - start_timestamp.longValue()
overall_run_time = make_readable_time(full_run_time_in_millis)

trend_available = False
previousRuns = testRuns.getPreviousRuns(testRun, 1)
if previousRuns and len(previousRuns) == 1:
    trend_available = True
    previousRun = previousRuns[0]
    events = previousRun.getEvents()
    prev_passed_set=set()
    prev_failed_set=set()
    prev_start_timestamp = 0
    prev_finish_timestamp = 0
    prev_total_duration = 0
    prev_n_tests = 0
    if events:
        for ev in events:
            if ev.type == 'executionStarted':
                prev_start_timestamp = ev.get('timestamp')
            elif ev.type == 'executionFinished':
                prev_finish_timestamp = ev.get('timestamp')
            elif ev.type == 'importStarted' and not prev_start_timestamp:
                prev_start_timestamp = ev.get('timestamp')
            elif ev.type == 'importFinished' and not prev_finish_timestamp:
                prev_finish_timestamp = ev.get('timestamp')
            elif ev.type == 'functionalResult':
                result = ev.get('result')
                if result is None:
                    continue
                prev_n_tests = prev_n_tests + 1
                prev_total_duration = prev_total_duration + ev.get('duration')
                if result == 'PASSED':
                    prev_passed_set.add(ev.get('name'))
                else:
                    prev_failed_set.add(ev.get('name'))
    if prev_n_tests > 0:
        prev_average_duration = prev_total_duration / prev_n_tests
    else:
        prev_average_duration = 0
    prev_full_run_time_in_millis = prev_finish_timestamp.longValue() - prev_start_timestamp.longValue()

if trend_available:
    successful_tests_trend_text = make_trend_text(len(passed_set), len(prev_passed_set))
    failed_tests_trend_text = make_trend_text(len(failed_set), len(prev_failed_set))
    average_duration_trend_text = make_trend_text(average_duration, prev_average_duration)
    overall_run_time_trend_text = make_trend_text_in_min_sec(full_run_time_in_millis, prev_full_run_time_in_millis)
else:
    successful_tests_trend_text = ''
    failed_tests_trend_text = ''
    average_duration_trend_text = ''
    overall_run_time_trend_text = ''
    print 'WARNING: no previous run found'


flakiness_trend_available = False
previousRuns = testRuns.getPreviousRuns(testRun, 2)
if previousRuns and len(previousRuns) == 2:
    flakiness_trend_available = True
    previousRun = previousRuns[1]
    events = previousRun.getEvents()
    prev_prev_passed_set=set()
    prev_prev_failed_set=set()
    if events:
        for ev in events:
            if ev.type == 'functionalResult':
                result = ev.get('result')
                if result is None:
                    continue
                if result == 'PASSED':
                    prev_prev_passed_set.add(ev.get('name'))
                else:
                    prev_prev_failed_set.add(ev.get('name'))


flakiness_score = 0
if trend_available:
    unchanged = 0
    changed = 0
    for name in passed_set:
        if name in prev_passed_set:
            unchanged = unchanged + 1
        if name in prev_failed_set:
            changed = changed + 1
    for name in failed_set:
        if name in prev_passed_set:
            changed = changed + 1
        if name in prev_failed_set:
            unchanged = unchanged + 1
    flakiness_score = 0
    if changed + unchanged > 0:
        flakiness_score = (float(changed) / (float(changed) + float(unchanged))) * float(100)

prev_flakiness_score = 0
if flakiness_trend_available:
    unchanged = 0
    changed = 0
    for name in prev_passed_set:
        if name in prev_prev_passed_set:
            unchanged = unchanged + 1
        if name in prev_prev_failed_set:
            changed = changed + 1
    for name in prev_failed_set:
        if name in prev_prev_passed_set:
            changed = changed + 1
        if name in prev_prev_failed_set:
            unchanged = unchanged + 1
    if changed and unchanged:
        prev_flakiness_score = (float(changed) / (float(changed) + float(unchanged))) * float(100)
    else:
        prev_flakiness_score = 0

flakiness_score_trend_text = '0'
if flakiness_trend_available:
    diff = flakiness_score - prev_flakiness_score
    if diff > 0:
        flakiness_score_trend_text = '+' + '%.2f' % diff
    else:
        flakiness_score_trend_text = '%.2f' % diff



resultHolder.setResult(
{
    'trend_available':trend_available,
    'successful_tests':len(passed_set),
    'successful_tests_trend_text':successful_tests_trend_text,
    'successful_tests_trend_symbol':text2symbol(successful_tests_trend_text),
    'failed_tests':len(failed_set),
    'failed_tests_trend_text':failed_tests_trend_text,
    'failed_tests_trend_symbol':text2symbolnegative(failed_tests_trend_text),
    'flakiness_score':'%.2f' % flakiness_score,
    'flakiness_score_trend_text':flakiness_score_trend_text,
    'flakiness_score_trend_symbol':text2symbolnegative(flakiness_score_trend_text),
    'average_duration':average_duration,
    'average_duration_trend_text':average_duration_trend_text,
    'average_duration_trend_symbol':text2symbolnegative(average_duration_trend_text),
    'overall_run_time':overall_run_time,
    'overall_run_time_trend_text':overall_run_time_trend_text,
    'overall_run_time_trend_symbol':text2symbolnegative(overall_run_time_trend_text)
})