import os
import traceback

from .util import AbortError


def resolve_resultspecs(archive, suites, resultspecs):
    for resultspec in resultspecs:
        results = resolve_resultspec(archive, suites, resultspec)
        for result in results:
            yield result


def resolve_resultspec(archive, suites, resultspec):
    if os.path.isfile(resultspec):
        try:
            return [archive.read_result(resultspec)]
        except Exception:
            traceback.print_exc()
            msg = 'Unable to read resultspec "{}"'
            raise AbortError(msg.format(resultspec))

    if resultspec == '':
        resultspec_parts = []
    else:
        resultspec_parts = resultspec.split('/')

    # Pull most recent result from all cases available: resultspec == ''
    pick_recents_all_suites = len(resultspec_parts) == 0
    # Pull most recent result from all cases in a suite: resultspec == <suite_id>
    pick_recents_one_suite = len(resultspec_parts) == 1
    # Pull most recent result from a case: resultspec == <suite_id>/<case_id>
    pick_recent = len(resultspec_parts) == 2
    # Pull (n+1)th most recent reuslt from a case: resultspec == <suite_id>/<case_id>/~<n>
    pick_by_index = len(resultspec_parts) == 3 and resultspec_parts[2].startswith('~')
    # Pull specific result: resultspec == <suite_id>/<case_id>/<result_id>
    pick_by_result_id = len(resultspec_parts) == 3 and not pick_by_index

    if pick_recent or pick_by_index:
        if resultspec_parts[1] not in suites[resultspec_parts[0]].collect().keys():
            msg = 'Unable to locate "{}"; the case "{}" does not exist within suite "{}"'
            raise AbortError(msg.format(resultspec, resultspec_parts[1], resultspec_parts[0]))
        if pick_recent:
            i = -1
        else:
            try:
                i = -1 - int(resultspec_parts[2][1:])
            except ValueError:
                msg = 'Invalid resultspec "{}"; the third part must be a valid result_id' + \
                    'or a tilde followed by an integer, but not "{}"'
                raise AbortError(msg.format(resultspec, resultspec_parts[2][1]))
        try:
            result = archive.select_recent(suites, i, *resultspec_parts[:2])
            return [result]
        except IndexError:
            msg = 'Unable to locate any results matching "{}", there are more than {} results present.'
            raise AbortError(msg.format(resultspec, i))
    elif pick_by_result_id:
        result = archive.select(*resultspec_parts)
        if result is None:
            msg = 'Unable to locate result "{}" in the archive at "{}"'
            raise AbortError(msg.format(resultspec, archive.root))
        else:
            return [result]
    elif pick_recents_all_suites:
        return archive.select_recents_all(suites)
    elif pick_recents_one_suite:
        return archive.select_recents_suite(suites, resultspec_parts[0])
    else:
        msg = 'Invalid result spec "{}". ' + \
              'Resultspecs must point to a result file, ' + \
              'have the fully qualified form "SUITEID/CASEID/RESULTID", ' + \
              'or if it is partially qualified, such as "SUITEID/CASEID", ' + \
              'it will select the most recent result that matches.'
        raise AbortError(msg.format(resultspec))


def print_resultspec(result):
    try:
        suite_id = result['suite_id']
        case_id = result['case_id']
        result_id = result['result_id']
        return '{}/{}/{}'.format(suite_id, case_id, result_id)
    except KeyError:
        return 'Invalid result "{}"'.format(repr(result))

import os
import traceback

from .util import AbortError


def resolve_resultspecs(archive, suites, resultspecs):
    for resultspec in resultspecs:
        results = resolve_resultspec(archive, suites, resultspec)
        for result in results:
            yield result


def resolve_resultspec(archive, suites, resultspec):
    if os.path.isfile(resultspec):
        try:
            return [archive.read_result(resultspec)]
        except Exception:
            traceback.print_exc()
            msg = 'Unable to read resultspec "{}"'
            raise AbortError(msg.format(resultspec))

    if resultspec == '':
        resultspec_parts = []
    else:
        resultspec_parts = resultspec.split('/')

    # Pull most recent result from all cases available: resultspec == ''
    pick_recents_all_suites = len(resultspec_parts) == 0
    # Pull most recent result from all cases in a suite: resultspec == <suite_id>
    pick_recents_one_suite = len(resultspec_parts) == 1
    # Pull most recent result from a case: resultspec == <suite_id>/<case_id>
    pick_recent = len(resultspec_parts) == 2
    # Pull (n+1)th most recent reuslt from a case: resultspec == <suite_id>/<case_id>/~<n>
    pick_by_index = len(resultspec_parts) == 3 and resultspec_parts[2].startswith('~')
    # Pull specific result: resultspec == <suite_id>/<case_id>/<result_id>
    pick_by_result_id = len(resultspec_parts) == 3 and not pick_by_index

    if pick_recent or pick_by_index:
        if resultspec_parts[1] not in suites[resultspec_parts[0]].collect().keys():
            msg = 'Unable to locate "{}"; the case "{}" does not exist within suite "{}"'
            raise AbortError(msg.format(resultspec, resultspec_parts[1], resultspec_parts[0]))
        if pick_recent:
            i = -1
        else:
            try:
                i = -1 - int(resultspec_parts[2][1:])
            except ValueError:
                msg = 'Invalid resultspec "{}"; the third part must be a valid result_id' + \
                    'or a tilde followed by an integer, but not "{}"'
                raise AbortError(msg.format(resultspec, resultspec_parts[2][1]))
        try:
            result = archive.select_recent(suites, i, *resultspec_parts[:2])
            return [result]
        except IndexError:
            msg = 'Unable to locate any results matching "{}", there are more than {} results present.'
            raise AbortError(msg.format(resultspec, i))
    elif pick_by_result_id:
        result = archive.select(*resultspec_parts)
        if result is None:
            msg = 'Unable to locate result "{}" in the archive at "{}"'
            raise AbortError(msg.format(resultspec, archive.root))
        else:
            return [result]
    elif pick_recents_all_suites:
        return archive.select_recents_all(suites)
    elif pick_recents_one_suite:
        return archive.select_recents_suite(suites, resultspec_parts[0])
    else:
        msg = 'Invalid result spec "{}". ' + \
              'Resultspecs must point to a result file, ' + \
              'have the fully qualified form "SUITEID/CASEID/RESULTID", ' + \
              'or if it is partially qualified, such as "SUITEID/CASEID", ' + \
              'it will select the most recent result that matches.'
        raise AbortError(msg.format(resultspec))


def print_resultspec(result):
    try:
        suite_id = result['suite_id']
        case_id = result['case_id']
        result_id = result['result_id']
        return '{}/{}/{}'.format(suite_id, case_id, result_id)
    except KeyError:
        return 'Invalid result "{}"'.format(repr(result))

# Pull most recent result from all cases available: resultspec == '' # Pull most recent result from all cases in a suite: resultspec == <suite_id> # Pull most recent result from a case: resultspec == <suite_id>/<case_id> # Pull (n+1)th most recent reuslt from a case: resultspec == <suite_id>/<case_id>/~<n> # Pull specific result: resultspec == <suite_id>/<case_id>/<result_id>