# -*- coding: utf-8 -*-

from pyramid.settings import asbool
from pyramid.settings import aslist

from sqlalchemy.schema import MetaData
from sqlalchemy.orm import sessionmaker

# from .meta import metadata

import zope.sqlalchemy

from amnesia.utils.db import engine_from_config


def get_engine(settings, prefix='sqlalchemy.'):
    return engine_from_config(settings, prefix)


def get_metadata(settings):
    return MetaData()


def get_session_factory(engine):
    # The sessionmaker factory generates new Session objects when called.
    factory = sessionmaker()

    # An Engine with which newly created Session objects will be associated.
    factory.configure(bind=engine)

    return factory


def get_tm_session(session_factory, transaction_manager):
    """
    Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.

    This function will hook the session to the transaction manager which
    will take care of committing any changes.

    - When using pyramid_tm it will automatically be committed or aborted
      depending on whether an exception is raised.

    - When using scripts you should wrap the session in a manager yourself.
      For example::

          import transaction

          engine = get_engine(settings)
          session_factory = get_session_factory(engine)
          with transaction.manager:
              dbsession = get_tm_session(session_factory, transaction.manager)

    """
    dbsession = session_factory()
    zope.sqlalchemy.register(dbsession,
                             transaction_manager=transaction_manager)
    return dbsession


def includeme(config):
    """
    Initialize the model for a Pyramid app.

    Activate this setup using ``config.include('amnesia.db')``.

    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'

    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')

    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    engine = get_engine(settings)
    meta = get_metadata(settings)

    if asbool(settings.get('amnesia.reflect_db', False)):
        meta.reflect(bind=engine)

        for schema in aslist(settings.get('amnesia.reflect_schemas', [])):
            meta.reflect(bind=engine, schema=schema)

    session_factory = get_session_factory(engine)
    config.registry['dbsession_factory'] = session_factory
    config.registry['metadata'] = meta
    config.registry['engine'] = engine

    # make request.dbsession available for use in Pyramid
    config.add_request_method(
        # r.tm is the transaction manager used by pyramid_tm
        lambda r: get_tm_session(session_factory, r.tm),
        'dbsession',
        reify=True
    )

@@ -751,16 +751,30 @@
 _manager
+, request=None
 ):%0A    %22
@@ -1473,16 +1473,41 @@
 factory(
+info=%7B%22request%22: request%7D
 )%0A    zo
@@ -1529,16 +1529,25 @@
 egister(
+%0A        
 dbsessio
@@ -1552,37 +1552,8 @@
 ion,
-%0A                            
  tra
@@ -1588,16 +1588,21 @@
 _manager
+%0A    
 )%0A    re
@@ -2088,169 +2088,121 @@
 y')%0A
+%0A
     
-engine = get_engine(set
+# hook to share the dbengine fixture in tes
 ting
-s)
 %0A    
-meta = get_metadata(settings)%0A%0A    if asbool(settings.get('amnesia.reflect_db', False)):%0A        meta.reflect(bind=
+dbengine = settings.get('dbengine')%0A    if not db
 engine
-)%0A
+:
 %0A   
@@ -2210,128 +2210,74 @@
     
-for schema in aslist(settings.get('amnesia.reflect_schemas', %5B%5D)):%0A     
+dbengine = get_engine(settings)%0A%0A
     
-   
 meta
-.reflect(bind=engine, schema=schema)%0A
+ = get_metadata(settings)
 %0A   
@@ -2307,32 +2307,34 @@
 session_factory(
+db
 engine)%0A    conf
@@ -2384,16 +2384,17 @@
 factory%0A
+%0A
     conf
@@ -2445,16 +2445,18 @@
 gistry%5B'
+db
 engine'%5D
@@ -2458,16 +2458,18 @@
 ine'%5D = 
+db
 engine%0A%0A
@@ -2476,104 +2476,507 @@
     
-# make request.dbsession available for use in Pyramid%0A    config.add_request_method(%0A        # r
+if asbool(settings.get('amnesia.reflect_db', False)):%0A        meta.reflect(bind=dbengine)%0A%0A        schemas = aslist(settings.get('amnesia.reflect_schemas', %5B%5D))%0A        for schema in schemas:%0A            meta.reflect(bind=dbengine, schema=schema)%0A%0A    # make request.dbsession available for use in Pyramid%0A    def dbsession(request):%0A        # hook to share the dbsession fixture in testing%0A        dbsession = request.environ.get('app.dbsession')%0A        if dbsession is None:%0A            # request
 .tm 
@@ -3033,17 +3033,23 @@
     
-lambda r:
+    dbsession =
  get
@@ -3052,32 +3052,49 @@
  get_tm_session(
+%0A                
 session_factory,
@@ -3099,23 +3099,64 @@
 y, r
-.tm),%0A        '
+equest.tm, request=request%0A            )%0A        return 
 dbse
@@ -3164,18 +3164,50 @@
 sion
-',
+%0A
 %0A    
-   
+config.add_request_method(dbsession,
  rei
@@ -3213,15 +3213,10 @@
 ify=True
-%0A    
 )%0A

update cookiecutter