import math
from werkzeug.datastructures import MultiDict

from aleph import authz
from aleph.index import TYPE_DOCUMENT
from aleph.core import get_es, get_es_index
from aleph.model import Collection
from aleph.search.documents import text_query
from aleph.search.fragments import filter_query
from aleph.search.util import parse_filters, add_filter


def round(x, factor):
    rnd = int(math.floor(x / float(factor))) * factor
    return 'More than %s' % format(rnd, '0,.0f')


def format_total(obj):
    total = obj.pop('total', 0)
    if total == 0:
        total = 'No'
    elif total < 15:
        total = 'Some'
    elif total < 100:
        total = round(total, 10)
    elif total < 1000:
        total = round(total, 100)
    else:
        total = round(total, 1000)
    obj['total'] = total
    return obj


def peek_query(args):
    """Peek into hidden collections.

    This allows users to retrieve an approximate result count of a given query
    against those collections which they are not authorised to view. It is a
    rudimentary collaboration mechanism.
    """
    if not isinstance(args, MultiDict):
        args = MultiDict(args)
    text = args.get('q', '').strip()
    q = text_query(text)

    filters = parse_filters(args)
    for entity in args.getlist('entity'):
        filters.append(('entities.id', entity))

    q = filter_query(q, filters, [])
    q = add_filter(q, {
        'not': {
            'terms': {
                'collection_id': authz.collections(authz.READ)
            }
        }
    })
    q = {
        'query': q,
        'size': 0,
        'aggregations': {
            'collections': {
                'terms': {'field': 'collection_id', 'size': 30}
            }
        },
        '_source': False
    }
    # import json
    # print json.dumps(q, indent=2)
    result = get_es().search(index=get_es_index(), body=q,
                             doc_type=TYPE_DOCUMENT)

    aggs = result.get('aggregations', {}).get('collections', {})
    buckets = aggs.get('buckets', [])
    q = Collection.all_by_ids([b['key'] for b in buckets])
    q = q.filter(Collection.creator_id != None)  # noqa
    objs = {o.id: o for o in q.all()}
    roles = {}
    for bucket in buckets:
        collection = objs.get(bucket.get('key'))
        if collection is None or collection.private:
            continue
        if collection.creator_id in roles:
            roles[collection.creator_id]['total'] += bucket.get('doc_count')
        else:
            roles[collection.creator_id] = {
                'name': collection.creator.name,
                'email': collection.creator.email,
                'total': bucket.get('doc_count')
            }

    roles = sorted(roles.values(), key=lambda r: r['total'], reverse=True)
    roles = [format_total(r) for r in roles]
    total = result.get('hits', {}).get('total')
    return format_total({
        'roles': roles,
        'active': total > 0,
        'total': total
    })

@@ -50,16 +50,44 @@
 ultiDict
+%0Afrom sqlalchemy import not_
 %0A%0Afrom a
@@ -1103,16 +1103,302 @@
     %22%22%22%0A
+    cq = Collection.all()%0A    readable = authz.collections(authz.READ)%0A    cq = cq.filter(not_(Collection.id.in_(readable)))%0A    cq = cq.filter(Collection.creator_id != None)  # noqa%0A    cq = cq.filter(Collection.private == False)  # noqa%0A    collections = %7Bc.id: c for c in cq.all()%7D%0A%0A
     if n
@@ -1713,29 +1713,8 @@
 , %7B%0A
-        'not': %7B%0A    
     
@@ -1724,28 +1724,24 @@
  'terms': %7B%0A
-    
             
@@ -1757,22 +1757,16 @@
 on_id': 
-authz.
 collecti
@@ -1772,34 +1772,15 @@
 ions
-(authz.READ)%0A            %7D
+.keys()
 %0A   
@@ -2184,16 +2184,31 @@
 UMENT)%0A%0A
+    roles = %7B%7D%0A
     aggs
@@ -2272,17 +2272,21 @@
     
+for 
 bucket
-s =
+ in
  agg
@@ -2309,211 +2309,30 @@
  %5B%5D)
+:
 %0A    
-q = Collection.all_by_ids(%5Bb%5B'key'%5D for b in buckets%5D)%0A    q = q.filter(Collection.creator_id != None)  # noqa%0A    objs = %7Bo.id: o for o in q.all()%7D%0A    roles = %7B%7D%0A    for bucket in buckets:%0A       
+    collection =
  col
@@ -2338,22 +2338,16 @@
 llection
- = obj
 s.get(bu
@@ -2367,82 +2367,8 @@
 '))%0A
-        if collection is None or collection.private:%0A            continue%0A
     

Fix up edge case in collections peeking.