'Return a list of sorted book ids. If ids_to_sort is None, all book ids
are returned.
fields must be a list of 2-tuples of the form (field_name,
ascending=True or False). The most significant field is the first
2-tuple.'

@read_api
def multisort(self, fields, ids_to_sort=None, virtual_fields=None):

    ids_to_sort = (self._all_book_ids() if (ids_to_sort is None) else ids_to_sort)
    get_metadata = self._get_proxy_metadata
    lang_map = self.fields[u'languages'].book_value_map
    virtual_fields = (virtual_fields or {})
    fm = {u'title': u'sort', u'authors': u'author_sort'}
    def sort_key_func(field):
        u'Handle    series    type    fields,    virtual    fields    and    the    id    field'
        idx = (field + u'_index')
        is_series = (idx in self.fields)
        try:
            func = self.fields[fm.get(field, field)].sort_keys_for_books(get_metadata, lang_map)
        except KeyError:
            if (field == u'id'):
                return IDENTITY
            else:
                return virtual_fields[fm.get(field, field)].sort_keys_for_books(get_metadata, lang_map)
        if is_series:
            idx_func = self.fields[idx].sort_keys_for_books(get_metadata, lang_map)
            def skf(book_id):
                return (func(book_id), idx_func(book_id))
            return skf
        return func
    fields = uniq(fields, operator.itemgetter(0))
    if (len(fields) == 1):
        return sorted(ids_to_sort, key=sort_key_func(fields[0][0]), reverse=(not fields[0][1]))
    sort_key_funcs = tuple((sort_key_func(field) for (field, order) in fields))
    orders = tuple(((1 if order else (-1)) for (_, order) in fields))
    Lazy = object()
    class SortKey(object, ):
        __slots__ = (u'book_id', u'sort_key')
        def __init__(self, book_id):
            self.book_id = book_id
            self.sort_key = [(key(book_id) if (i == 0) else Lazy) for (i, key) in enumerate(sort_key_funcs)]
        def __cmp__(self, other):
            for (i, (order, self_key, other_key)) in enumerate(zip(orders, self.sort_key, other.sort_key)):
                if (self_key is Lazy):
                    self_key = self.sort_key[i] = sort_key_funcs[i](self.book_id)
                if (other_key is Lazy):
                    other_key = other.sort_key[i] = sort_key_funcs[i](other.book_id)
                ans = cmp(self_key, other_key)
                if (ans != 0):
                    return (ans * order)
            return 0
    return sorted(ids_to_sort, key=SortKey)
