## based on code found in Internet and in the mailing list

import re

import sqlalchemy
from sqlalchemy import orm, Table

from sqlkit.db import utils

def get_create_statement(meta, dialect='postgres'):
    """
    return the create statement of a
    obj may be a table or a metadata

    :param meta: the metadata from which we want to get the create statement
    :param dialect: the engine type

    """
    # http://www.sqlalchemy.org/trac/wiki/FAQ#HowcanIgettheCREATETABLEDROPTABLEoutputasastring
    
    from sqlalchemy import create_engine, Table
    from StringIO import StringIO

    def executor(s):
        buf.write(str(s.compile(dialect=engine.dialect)))
        buf.write(";\n")

    dialect = dialect or 'postgres'
    
    buf = StringIO()

    if sqlalchemy.__version__ <= '0.6':
        executor = lambda s, p="": buf.write(s+p)
        
    engine = create_engine("%s://" % dialect, strategy='mock',
                           executor=executor)

    meta.create_all(engine)
    return buf.getvalue()


def debug_inline_params(stmt, bind=None):
    """
    Compiles a query or a statement and inlines bindparams.

    WARNING: Does not do any escaping.
    """
    if isinstance(stmt, orm.Query):
        if bind is None:
            bind = stmt.session.get_bind(stmt._mapper_zero_or_none())
        stmt = stmt.statement
    else:
        if bind is None:
            bind = stmt.bind 

    compiler = bind.dialect.statement_compiler(bind.dialect, stmt)
    compiler.bindtemplate = "%%(%(name)s)s"
    compiler.compile()
    return compiler.string % dict((k,repr(v)) for k,v in compiler.params.items())

def get_table_definition(table, sql=None, meta=None, dialect=None):
    """
    Return the table definition that would be issued by a metadata.create
    statement

    :param table: the table (sqla >= 0.6) or table_name. In case Table is provided no other args are needed
    :param sql: the sql statement as generated by metada.create_all().
                If missing, meta must be provided
    :param meta: the metadata to be used to get the table's creation statement
    :param dialect: the dialect. Used by meta option (default: postgres)
    """
    # SQLAlchemy 0.6 has clause constructs representing DDL operations, so the operation is much simpler:
    # 
    # from sqlalchemy.schema import CreateTable
    # print CreateTable(mytable)

    if sqlalchemy.__version__ >= '0.6' and isinstance(table, Table):
        from sqlalchemy.schema import CreateTable
        return CreateTable(table)

    if isinstance(table, Table):
        meta = meta or table.metadata
        table = table.name

    if not sql:
        assert meta is not None
        sql = get_create_statement(meta, dialect)

    # ?= does not consume the matched string
    PAT = "(?P<table_def>CREATE TABLE (?P<name>\w+).*?(?=CREATE TABLE|$))"
    tables = {}

    def sub(m):
        tables[m.group('name')] = m.group('table_def')

    c=re.compile(PAT, re.DOTALL)
    c.sub(sub, sql)
    return tables[table]

