"""
Segregation of pymongo functions from the data modeling mechanisms for split modulestore.
"""
import pymongo

class MongoConnection(object):
    """
    Segregation of pymongo functions from the data modeling mechanisms for split modulestore.
    """
    def __init__(
        self, db, collection, host, port=27017, tz_aware=True, user=None, password=None, **kwargs
    ):
        """
        Create & open the connection, authenticate, and provide pointers to the collections
        """
        self.database = pymongo.database.Database(
            pymongo.MongoClient(
                host=host,
                port=port,
                tz_aware=tz_aware,
                **kwargs
            ),
            db
        )

        if user is not None and password is not None:
            self.database.authenticate(user, password)

        self.course_index = self.database[collection + '.active_versions']
        self.structures = self.database[collection + '.structures']
        self.definitions = self.database[collection + '.definitions']

        # every app has write access to the db (v having a flag to indicate r/o v write)
        # Force mongo to report errors, at the expense of performance
        # pymongo docs suck but explanation:
        # http://api.mongodb.org/java/2.10.1/com/mongodb/WriteConcern.html
        self.course_index.write_concern = {'w': 1}
        self.structures.write_concern = {'w': 1}
        self.definitions.write_concern = {'w': 1}

    def get_structure(self, key):
        """
        Get the structure from the persistence mechanism whose id is the given key
        """
        return self.structures.find_one({'_id': key})

    def find_matching_structures(self, query):
        """
        Find the structure matching the query. Right now the query must be a legal mongo query
        :param query: a mongo-style query of {key: [value|{$in ..}|..], ..}
        """
        return self.structures.find(query)

    def insert_structure(self, structure):
        """
        Create the structure in the db
        """
        self.structures.insert(structure)

    def update_structure(self, structure):
        """
        Update the db record for structure
        """
        self.structures.update({'_id': structure['_id']}, structure)

    def get_course_index(self, key):
        """
        Get the course_index from the persistence mechanism whose id is the given key
        """
        return self.course_index.find_one({'_id': key})

    def find_matching_course_indexes(self, query):
        """
        Find the course_index matching the query. Right now the query must be a legal mongo query
        :param query: a mongo-style query of {key: [value|{$in ..}|..], ..}
        """
        return self.course_index.find(query)

    def insert_course_index(self, course_index):
        """
        Create the course_index in the db
        """
        self.course_index.insert(course_index)

    def update_course_index(self, course_index):
        """
        Update the db record for course_index
        """
        self.course_index.update({'_id': course_index['_id']}, course_index)

    def delete_course_index(self, key):
        """
        Delete the course_index from the persistence mechanism whose id is the given key
        """
        return self.course_index.remove({'_id': key})

    def get_definition(self, key):
        """
        Get the definition from the persistence mechanism whose id is the given key
        """
        return self.definitions.find_one({'_id': key})

    def find_matching_definitions(self, query):
        """
        Find the definitions matching the query. Right now the query must be a legal mongo query
        :param query: a mongo-style query of {key: [value|{$in ..}|..], ..}
        """
        return self.definitions.find(query)

    def insert_definition(self, definition):
        """
        Create the definition in the db
        """
        self.definitions.insert(definition)


