import os
import sys
import struct
import logging

from ming.orm import state, session, mapper, MappedClass
from ming.orm.base import instrument, DocumentTracker

from pylons import c
from bson import BSON
from allura import model as M
from allura.command import ReindexCommand

log = logging.getLogger(__name__)

def main():
    if len(sys.argv) != 4:
        log.error('Usage: %s <dirname> <new_shortname> <new_unix_group_name>', sys.argv[0])
        return 2
    dirname = sys.argv[1]
    new_pname = sys.argv[2]
    new_ug_name = sys.argv[3]
    return restore_project(dirname, new_pname, new_ug_name)

def restore_project(dirname, new_shortname, new_unix_group_name):
    log.info('Reloading %s into %s', dirname, new_shortname)
    with open(os.path.join(dirname, 'project.bson')) as fp:
        project_doc = _read_bson(fp)
    project = M.Project.query.get(_id=project_doc['_id'])
    st = state(project)
    st.document = instrument(project_doc, DocumentTracker(st))
    if project is None:
        log.fatal('Project not found')
        return 2
    project.shortname = new_shortname
    project.set_tool_data('sfx', unix_group_name=new_unix_group_name)
    project.deleted = False
    c.project = project
    for name, cls in MappedClass._registry.iteritems():
        if session(cls) is None: continue
        m = mapper(cls)
        sess = session(cls).impl
        fname = os.path.join(dirname, '%s.bson' % (cls.__mongometa__.name))
        if not os.path.exists(fname): continue
        if ('project_id' not in m.property_index
            and 'app_config_id' not in m.property_index): continue
        with open(fname, 'rb') as fp:
            num_objects = 0
            while True:
                doc = _read_bson(fp)
                if doc is None: break
                num_objects += 1
                sess.insert(m.doc_cls(doc))
        log.info('%s: loaded %s objects from %s',
                 name, num_objects, fname)
    session(project).flush()
    reindex= ReindexCommand('reindex')
    reindex.run(['--project', new_shortname])
    return 0

def _read_bson(fp):
    slen = fp.read(4)
    if not slen: return None
    bson = BSON(fp.read(struct.unpack('!l', slen)[0]))
    return bson.to_dict()

if __name__ == '__main__':
    sys.exit(main())
