Perform a smart search.

            The smart search function tries extract a query from
            a text string. This query is then passed to the search_prefix
            function, which performs the search.

def smart_search_prefix(self):
        """ Perform a smart search.

            The smart search function tries extract a query from
            a text string. This query is then passed to the search_prefix
            function, which performs the search.
        """

        search_options = {}
        extra_query = None
        vrf_filter = None

        if 'query_id' in request.json:
            search_options['query_id'] = request.json['query_id']

        if 'include_all_parents' in request.json:
            if request.json['include_all_parents'] == 'true':
                search_options['include_all_parents'] = True
            else:
                search_options['include_all_parents'] = False

        if 'include_all_children' in request.json:
            if request.json['include_all_children'] == 'true':
                search_options['include_all_children'] = True
            else:
                search_options['include_all_children'] = False

        if 'parents_depth' in request.json:
            search_options['parents_depth'] = request.json['parents_depth']
        if 'children_depth' in request.json:
            search_options['children_depth'] = request.json['children_depth']
        if 'include_neighbors' in request.json:
            if request.json['include_neighbors'] == 'true':
                search_options['include_neighbors'] = True
            else:
                search_options['include_neighbors'] = False
        if 'max_result' in request.json:
            if request.json['max_result'] == 'false':
                search_options['max_result'] = False
            else:
                search_options['max_result'] = request.json['max_result']
        if 'offset' in request.json:
            search_options['offset'] = request.json['offset']
        if 'parent_prefix' in request.json:
            search_options['parent_prefix'] = request.json['parent_prefix']
        if 'vrf_filter' in request.json:
            vrf_filter_parts = []

            # Fetch VRF IDs from search query and build extra query dict for
            # smart_search_prefix.
            vrfs = request.json['vrf_filter']

            if len(vrfs) > 0:
                vrf = vrfs[0]
                vrf_filter = {
                    'operator': 'equals',
                    'val1': 'vrf_id',
                    'val2': vrf if vrf != 'null' else None
                }

                for vrf in vrfs[1:]:
                    vrf_filter = {
                        'operator': 'or',
                        'val1': vrf_filter,
                        'val2': {
                            'operator': 'equals',
                            'val1': 'vrf_id',
                            'val2': vrf if vrf != 'null' else None
                        }
                    }

        if vrf_filter:
            extra_query = vrf_filter

        if 'indent' in request.json:
            if extra_query:
                extra_query = {
                        'operator': 'and',
                        'val1': extra_query,
                        'val2': {
                            'operator': 'equals',
                            'val1': 'indent',
                            'val2': request.json['indent']
                        }
                    }
            else:
                extra_query = {
                    'operator': 'equals',
                    'val1': 'indent',
                    'val2': request.json['indent']
                    }

        try:
            result = Prefix.smart_search(request.json['query_string'],
                search_options, extra_query)
            # Remove error key in result from backend as it interferes with the
            # error handling of the web interface.
            # TODO: Reevaluate how to deal with different types of errors; soft
            # errors like query string parser errors and hard errors like lost
            # database.
            del result['error']
        except NipapError, e:
            return json.dumps({'error': 1, 'message': e.args, 'type': type(e).__name__})

        return json.dumps(result, cls=NipapJSONEncoder)