import uuid
import logging
import time
import binascii

from utils import table_exists

class Index (object):
    
    """
    Index is an instance of an index of an entity. An index is a matching
    between any entity property and an entity id. It is used for performing
    look ups that do not use an entity id. The following is an example:

        You have an entity that holds user information (the dict you pass
        in are the parameter defaults):
            user = Entity('users',{
                'name':''
            })
            new_user = user.create({
                'name':'Ian'
            })

        But what if you want to find entities by their name and not just
        their 16-byte binary uuid? Well then you need to create an index
        for that property.

            user.add_index(Index(user, property='name'))

        Now you can perform .find or .count operations on your User Entity
        Store like the following:
            
            ian = user.find(name='Ian')
        
    The following is an example of a relationship between two entities.
        
        If you have a user entity, and each user is connected with a team
        then you can create a relationship between the two like so.

            user = Entity('users', {
                'name':'My Name',
                'team_id':''
            })
            team = Entity('teams', {
                'name':'My Team'
            })

        Then you can create a index like the following to represent a
        realtionship between user and team (in this case a many-to-one):
            
            user.add_index(Index(user, property='team_id', relationship=True))

        If you wanted to create a many-to-many relatinoship you can do the
        following:
            
            user.add_index(Index(user, property='team_id', relationship=True))
            team.add_index(Index(team, property='user_id', relationship=True))

        If you want a one-to-one relationship you will need to enforce that
        restraint yourself by performing some sort of .count() method.
        
        Finally, to find all users in a team is simple.

            team_members = user.find(team_id=cur_team['id'])
        
    Only one index per property.
    """

    def __init__ (self, entity, property, **params):
        
        """
        Class Constructor

        entity
            The entity you want to index, it will use the same database.
            If sharding is turned on, then it will use the same db pool.

        property
            The property you want to index
        
        Optional Parameters:

        shard_on
            The value you want to shard users based upon. If you want to
            shard based upon user_id then set shard_on = 'user_id'.

            If no value is given, then no sharding is performed.

        relationship
            Set value to true if the property is a uuid meaning that the
            value is a pointer to another entity in the database.
        
        multi
            Set true, otherwise, assumed false, that the indexed field
            is a list of values. Therefore, it will automatically create
            n rows in the index table for the n values in the list.
        """
        
        #   Setup the index
        self.table = '%s_%s_index' % (entity.table, property)
        self.entity_key_id = entity.key_id
        self.property = property
        self.db = entity.db

        self.shard_on = None
        self.relationship = False
        self.multi_mode = False

        if 'shard_on' in params:
            self.shard_on = params['shard_on']
        if 'relationship' in params:
            self.relationship = params['relationship']
        if 'multi' in params:
            self.multi_mode = params['multi_mode']
    
    def create (self, params):
        
        """
        Takes an Entity dictionary and then creates the associated indexes.
        """
        
        sql = 'INSERT INTO %s (%s, %s, datetime) VALUES ' \
              '(%%s, %%s, %%s)' %  (
            self.table,
            self.entity_key_id,
            self.property
        )

        logging.info('Insert into index table[%s]: %s --> %s %s = %s' % (
            self.table,
            params['id'],
            params[self.property],