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

import traceback

import web
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.orm.query import Query
from sqlalchemy.exc import ProgrammingError
from sqlalchemy import create_engine

from nailgun.logger import logger
from nailgun.settings import settings

if settings.DATABASE['engine'] == 'sqlite':
    db_str = "{engine}://{path}".format(
        engine='sqlite',
        path="/" + settings.DATABASE['name']
    )
else:
    db_str = "{engine}://{user}:{passwd}@{host}:{port}/{name}".format(
        **settings.DATABASE
    )

engine = create_engine(db_str, client_encoding='utf8')


class NoCacheQuery(Query):
    """
    Override for common Query class.
    Needed for automatic refreshing objects
    from database during every query for evading
    problems with multiple sessions
    """
    def __init__(self, *args, **kwargs):
        self._populate_existing = True
        super(NoCacheQuery, self).__init__(*args, **kwargs)


def orm():
    if hasattr(web.ctx, "orm"):
        return web.ctx.orm
    else:
        web.ctx.orm = scoped_session(
            sessionmaker(bind=engine, query_cls=NoCacheQuery)
        )
        return web.ctx.orm


def load_db_driver(handler):
    web.ctx.orm = scoped_session(
        sessionmaker(bind=engine, query_cls=NoCacheQuery)
    )
    try:
        return handler()
    except web.HTTPError:
        web.ctx.orm.commit()
        raise
    except:
        web.ctx.orm.rollback()
        raise
    finally:
        web.ctx.orm.commit()
        web.ctx.orm.expire_all()


def syncdb():
    from nailgun.api.models import Base
    Base.metadata.create_all(engine)


def dropdb():
    tables = [name for (name,) in engine.execute(
        "SELECT tablename FROM pg_tables WHERE schemaname = 'public'")]
    for table in tables:
        engine.execute("DROP TABLE IF EXISTS %s CASCADE" % table)


def flush():
    from nailgun.api.models import Base
    session = scoped_session(sessionmaker(bind=engine))
    for table in reversed(Base.metadata.sorted_tables):
        session.execute(table.delete())
    session.commit()

@@ -1878,24 +1878,680 @@
 %22 %25 table)%0A%0A
+    # sql query to list all types, equivalent to psql's %5CdT+%0A    types = %5Bname for (name,) in engine.execute(%22%22%22%0A        SELECT t.typname as type FROM pg_type t%0A        LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace%0A        WHERE (t.typrelid = 0 OR (%0A            SELECT c.relkind = 'c' FROM pg_catalog.pg_class c%0A            WHERE c.oid = t.typrelid%0A        ))%0A        AND NOT EXISTS(%0A            SELECT 1 FROM pg_catalog.pg_type el%0A            WHERE el.oid = t.typelem AND el.typarray = t.oid%0A        )%0A        AND n.nspname = 'public'%0A        %22%22%22)%5D%0A    for type_ in types:%0A        engine.execute(%22DROP TYPE IF EXISTS %25s CASCADE%22 %25 type_)%0A%0A
 %0Adef flush()

Drop all types on 'dropdb' command