
import sqlalchemy
from sqlalchemy import orm, Column, types, ForeignKey

from alchy import model, query, manager, events

from .base import TestQueryBase


Model = model.make_declarative_base()


class TestEventsBase(TestQueryBase):
    @classmethod
    def setUpClass(cls):
        cls.db = manager.Manager(Model=Model, config=cls.config)

    def setUp(self):
        self.db.create_all()

    def tearDown(self):
        self.db.drop_all()


class TestEvents(TestEventsBase):
    """Test Model events"""

    class Huey(Model):
        event_tracker = {}

        __tablename__ = 'huey'
        __events__ = {
            'before_insert': 'before_insert',
            'after_insert': [
                'after_insert1',
                'after_insert2',
                ('after_insert3', {'raw': True})
            ],
            'on_set': [('on_set_name', {'attribute': 'name'})]
        }

        _id = Column(types.Integer(), primary_key=True)
        name = Column(types.String())
        dewey_id = Column(types.Integer(), ForeignKey('dewey._id'))

        def before_insert(mapper, connection, target):
            target.event_tracker['before_insert'] = target.query.all()
            target.name = 'Huey'

        def after_insert1(mapper, connection, target):
            target.event_tracker['after_insert1'] = target.query.all()
            target.event_tracker['after_insert2'] = 1

        def after_insert2(mapper, connection, target):
            target.event_tracker['after_insert2'] += 1

        def after_insert3(mapper, connection, target):
            from sqlalchemy.orm.state import InstanceState
            assert isinstance(target, InstanceState)

        def on_set_name(target, value, oldvalue, initator):
            target.event_tracker['set_name'] = 1

    class Dewey(Model):
        __tablename__ = 'dewey'
        __events__ = None

        _id = Column(types.Integer(), primary_key=True)
        name = Column(types.String())
        number = Column(types.Integer())
        min_hueys = Column(types.Boolean())
        hueys = orm.relationship('Huey')

        @events.before_insert()
        def before_insert(mapper, connection, target):
            target.name = 'Dewey'

        @events.on_set('name', retval=True)
        def on_set_name(target, value, oldvalue, initator):
            if oldvalue is None or (
                    hasattr(oldvalue, '__class__') and
                    oldvalue.__class__.__name__ == 'symbol'):
                # oldvalue is a symbol for either NO_VALUE or NOT_SET so allow
                # update
                return value
            else:
                # value previously set, so prevent edit
                return oldvalue

        @events.on_append('hueys')
        def on_append_hueys(target, value, intiator):
            if len(target.hueys) >= 1:
                target.min_hueys = True

        @events.on_remove('hueys')
        def on_remove_hueys(target, value, initator):
            if not len(target.hueys) >= 1:
                target.min_hueys = False

        @events.before_insert_update()
        def before_edit(mapper, connection, target):
            target.number = (target.number or 0) + 1

    def tearDown(self):
        super(TestEvents, self).tearDown()

        # clear event tracker
        self.Huey.event_tracker.clear()

    def test_events_using_class_attribute(self):