Perform a smart search on prefix list.

            * `auth` [BaseAuth]
                AAA options.
            * `query_str` [string]
                Search string
            * `search_options` [options_dict]
                Search options. See :func:`search_prefix`.
            * `extra_query` [dict_to_sql]
                Extra search terms, will be AND:ed together with what is
                extracted from the query string.

            Return a dict with three elements:
                * :attr:`interpretation` - How the query string was interpreted.
                * :attr:`search_options` - Various search_options.
                * :attr:`result` - The search result.

                The :attr:`interpretation` is given as a list of dicts, each
                explaining how a part of the search key was interpreted (ie. what
                prefix attribute the search operation was performed on).

                The :attr:`result` is a list of dicts containing the search result.

            The smart search function tries to convert the query from a text
            string to a `query` dict which is passed to the
            :func:`search_prefix` function.  If multiple search keys are
            detected, they are combined with a logical AND.

            It tries to automatically detect IP addresses and prefixes and put
            these into the `query` dict with "contains_within" operators and so
            forth.

            See the :func:`search_prefix` function for an explanation of the
            `search_options` argument.

            This is the documentation of the internal backend function. It's
            exposed over XML-RPC, please also see the XML-RPC documentation for
            :py:func:`nipap.xmlrpc.NipapXMLRPC.smart_search_prefix` for full
            understanding.

def smart_search_prefix(self, auth, query_str, search_options=None, extra_query=None):
        """ Perform a smart search on prefix list.

            * `auth` [BaseAuth]
                AAA options.
            * `query_str` [string]
                Search string
            * `search_options` [options_dict]
                Search options. See :func:`search_prefix`.
            * `extra_query` [dict_to_sql]
                Extra search terms, will be AND:ed together with what is
                extracted from the query string.

            Return a dict with three elements:
                * :attr:`interpretation` - How the query string was interpreted.
                * :attr:`search_options` - Various search_options.
                * :attr:`result` - The search result.

                The :attr:`interpretation` is given as a list of dicts, each
                explaining how a part of the search key was interpreted (ie. what
                prefix attribute the search operation was performed on).

                The :attr:`result` is a list of dicts containing the search result.

            The smart search function tries to convert the query from a text
            string to a `query` dict which is passed to the
            :func:`search_prefix` function.  If multiple search keys are
            detected, they are combined with a logical AND.

            It tries to automatically detect IP addresses and prefixes and put
            these into the `query` dict with "contains_within" operators and so
            forth.

            See the :func:`search_prefix` function for an explanation of the
            `search_options` argument.

            This is the documentation of the internal backend function. It's
            exposed over XML-RPC, please also see the XML-RPC documentation for
            :py:func:`nipap.xmlrpc.NipapXMLRPC.smart_search_prefix` for full
            understanding.
        """

        if search_options is None:
            search_options = {}

        self._logger.debug("smart_search_prefix query string: %s" % query_str)

        success, query = self._parse_prefix_query(query_str)
        if not success:
            return {
                'interpretation': query,
                'search_options': search_options,
                'result': [],
                'error': True,
                'error_message': 'query interpretation failed'
            }

        if extra_query is not None:
            query = {
                'operator': 'and',
                'val1': query,
                'val2': extra_query
            }

        self._logger.debug("smart_search_prefix: query expanded to: %s" % unicode(query))

        search_result = self.search_prefix(auth, query, search_options)
        search_result['interpretation'] = query
        search_result['error'] = False

        return search_result