from __future__ import absolute_import

import six

from sentry.utils.safe import get_path, trim
from sentry.utils.strings import truncatechars

from .base import BaseEvent


def get_crash_location(exception, platform=None):
    default = None
    for frame in reversed(get_path(exception, 'stacktrace', 'frames', filter=True) or ()):
        fn = frame.get('filename') or frame.get('abs_path')
        if fn:
            func = frame.get('function')
            if func is not None:
                from sentry.interfaces.stacktrace import trim_function_name
                func = trim_function_name(func, frame.get('platform') or platform)
            if frame.get('in_app'):
                return fn, func
            if default is None:
                default = fn, func
    return default


class ErrorEvent(BaseEvent):
    key = 'error'

    def has_metadata(self, data):
        exception = get_path(data, 'exception', 'values', -1)
        return exception and any(v is not None for v in six.itervalues(exception))

    def get_metadata(self, data):
        exception = get_path(data, 'exception', 'values', -1)
        if not exception:
            return {}

        loc = get_crash_location(exception, data.get('platform'))
        rv = {
            'value': trim(get_path(exception, 'value', default=''), 1024),
        }

        # If the exception mechanism indicates a synthetic exception we do not
        # want to record the type and value into the metadata.
        if not get_path(exception, 'mechanism', 'synthetic'):
            rv['type'] = trim(get_path(exception, 'type', default='Error'), 128)

        # Attach crash location if available
        if loc is not None:
            fn, func = loc
            if fn:
                rv['filename'] = fn
            if func:
                rv['function'] = func

        return rv

    def get_title(self, metadata):
        ty = metadata.get('type')
        if ty is None:
            return metadata.get('function') or '<unknown>'
        if not metadata.get('value'):
            return ty
        return u'{}: {}'.format(
            ty,
            truncatechars(metadata['value'].splitlines()[0], 100),
        )

    def get_location(self, metadata):
        return metadata.get('filename')

[((31, 20, 31, 61), 'sentry.utils.safe.get_path', 'get_path', ({(31, 29, 31, 33): 'data', (31, 35, 31, 46): '"""exception"""', (31, 48, 31, 56): '"""values"""', (31, 58, 31, 60): '-1'}, {}), "(data, 'exception', 'values', -1)", False, 'from sentry.utils.safe import get_path, trim\n'), ((35, 20, 35, 61), 'sentry.utils.safe.get_path', 'get_path', ({(35, 29, 35, 33): 'data', (35, 35, 35, 46): '"""exception"""', (35, 48, 35, 56): '"""values"""', (35, 58, 35, 60): '-1'}, {}), "(data, 'exception', 'values', -1)", False, 'from sentry.utils.safe import get_path, trim\n'), ((13, 26, 13, 82), 'sentry.utils.safe.get_path', 'get_path', (), '', False, 'from sentry.utils.safe import get_path, trim\n'), ((46, 15, 46, 60), 'sentry.utils.safe.get_path', 'get_path', ({(46, 24, 46, 33): 'exception', (46, 35, 46, 46): '"""mechanism"""', (46, 48, 46, 59): '"""synthetic"""'}, {}), "(exception, 'mechanism', 'synthetic')", False, 'from sentry.utils.safe import get_path, trim\n'), ((41, 26, 41, 66), 'sentry.utils.safe.get_path', 'get_path', (), '', False, 'from sentry.utils.safe import get_path, trim\n'), ((47, 30, 47, 74), 'sentry.utils.safe.get_path', 'get_path', (), '', False, 'from sentry.utils.safe import get_path, trim\n'), ((32, 56, 32, 81), 'six.itervalues', 'six.itervalues', ({(32, 71, 32, 80): 'exception'}, {}), '(exception)', False, 'import six\n')]