import logging
import optparse
from collections import defaultdict

from pylons import c
from ming.orm import ThreadLocalORMSession

from allura import model as M

log = logging.getLogger(__name__)

PAGESIZE=1024

def main():
    parser = optparse.OptionParser(usage="""%prog -- [options] [/p/ someproject/optional-subproj mount-point]\n\n
        Specify a neighborhood url-prefix, project shortname, and mountpoint to run for just one repo.  Omit that
        to run for all repos.
    """)
    parser.add_option(
        '--clean', action='store_true', dest='clean', default=False,
        help='remove all RepoObjects before refresh')
    parser.add_option(
        '--all', action='store_true', dest='all', default=False,
        help='refresh all commits (not just the ones that are new')
    parser.add_option(
        '--notify', action='store_true', dest='notify', default=False,
        help='send email notifications of new commits')
    options, args = parser.parse_args()
    if args:
        nbhd = M.Neighborhood.query.get(url_prefix=args[0])
        shortname = args[1]
        mount_point = args[2]
        q_project = {'shortname': shortname, 'neighborhood_id': nbhd._id}
        projects = {shortname:[mount_point]}
    else:
        projects = {}
        q_project = {}
    log.info('Refreshing repositories')
    if options.clean:
        log.info('Removing all repository objects')
        M.repository.RepoObject.query.remove()
        M.repo.CommitDoc.m.remove({})
        M.repo.TreeDoc.m.remove({})
        M.repo.TreesDoc.m.remove({})
        M.repo.DiffInfoDoc.m.remove({})
        M.repo.LastCommitDoc.m.remove({})
        M.repo.CommitRunDoc.m.remove({})
    for chunk in chunked_project_iterator(q_project):
        for p in chunk:
            c.project = p
            if projects:
                mount_points = projects[p.shortname]
            else:
                mount_points = [ ac.options.mount_point
                                 for ac in M.AppConfig.query.find(dict(project_id=p._id)) ]
            for app in (p.app_instance(mp) for mp in mount_points):
                c.app = app
                if not hasattr(app, 'repo'): continue
                if options.clean:
                    M.LastCommitFor.query.remove(dict(repo_id=c.app.repo._id))
                try:
                    c.app.repo._impl._setup_hooks()
                except:
                    log.exception('Error setting up hooks for %r', c.app.repo)
                try:
                    if options.all:
                        log.info('Refreshing ALL commits in %r', c.app.repo)
                    else:
                        log.info('Refreshing NEW commits in %r', c.app.repo)
                    c.app.repo.refresh(options.all, notify=options.notify)
                except:
                    log.exception('Error refreshing %r', c.app.repo)
        ThreadLocalORMSession.flush_all()
        ThreadLocalORMSession.close_all()

def chunked_project_iterator(q_project):
    page = 0
    while True:
        results = (M.Project.query
                   .find(q_project)
                   .skip(PAGESIZE*page)
                   .limit(PAGESIZE)
                   .all())
        if not results: break
        yield results
        page += 1


if __name__ == '__main__':
    main()
