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

from sqlalchemy import MetaData, Table, Column,  Integer, TIMESTAMP, DATETIME, String, create_engine
from sqlalchemy.orm import Session
from sqlalchemy.ext.automap import automap_base


BASIC_TYPES = {
    String: ['length'],
    Integer: [],
    TIMESTAMP: [],
    DATETIME: [],
}


class DB(object):
    """Facade for the low level DB operations"""
    def __init__(self, dsn, schema=None):
        self.engine = create_engine(dsn)
        meta = MetaData()
        meta.reflect(bind=self.engine, schema=schema)
        base = automap_base(metadata=meta)
        base.prepare()
        self.base = base
        self.meta = meta

    def get_meta_table(self, key):
        return self.meta.tables.get(key)

    def get_meta_names(self):
        return self.meta.classes.keys()

    def get_base_class(self, key):
        return self.base.classes.get(key)

    def get_base_names(self):
        return self.base.classes.keys()

    def get_session(self):
        return Session(self.engine)

    def get_rows(self, session, cls, modified=None):
        return session.query(cls).all()

    def generate_table(self, table, meta=None):
        if meta is None:
            meta = MetaData()
        columns = []
        for col in table.columns.values():
            new_col = col.copy()
            if isinstance(new_col.type, NUMBER):
                new_col.type = Integer
            elif isinstance(new_col.type, DATETIME):
                new_col.type = DATETIME
            columns.append(new_col)
        return Table(table.name, meta, *columns)

    def safe_generate_table(self, table, meta=None):
        """Substitute basic types for generic ones"""
        if meta is None:
            meta = MetaData()
        columns = []
        for col in table.columns.values():
            for col_type in BASIC_TYPES.keys():
                if isinstance(col.type, col_type):
                    kwarg_types = BASIC_TYPES[col_type]
                    kwargs = {}
                    for kwarg_type in kwarg_types:
                        kwargs[kwarg_type] = getattr(col.type, kwarg_type)
                    new_col = Column(
                        col.name,
                        col_type(**kwargs),
                        primary_key=col.primary_key,
                        nullable=col.nullable
                    )
                    columns.append(new_col)
        return Table(table.name, meta, *columns)




class Mirror(object):
    """API for cli mirroring operations"""
    def __init__(self, source, target, source_schema=None, target_schema=None):
        self.source = DB(source, source_schema)
        self.target = DB(target, target_schema)

    def diff(self, tables, modified):
        pass

    def create(self, tables):
        meta = MetaData(bind=self.target.engine)
        for table in self.source.meta.sorted_tables:
            self.source.generate_table(table, meta)
        meta.create_all()

    def recreate(self, tables):
        pass

    def mirror(self, tables):
        pass


@@ -452,16 +452,67 @@
 ne(dsn)%0A
+        self.base = None%0A        self.meta = None%0A%0A
         
@@ -583,24 +583,25 @@
 schema)%0A
+%0A
         
 base = a
@@ -596,90 +596,135 @@
     
-base = automap_base(metadata=
+self.set_meta(
 meta)%0A
- 
+%0A
     
-   base.prepare()%0A        self.base = base
+def get_meta_table(self, key):%0A        return self.meta.tables.get(key)%0A%0A    def set_meta(self, meta):
 %0A   
@@ -749,84 +749,103 @@
 eta%0A
-%0A
     
-def get_meta_table(self, key):%0A        return self.meta.tables.get(key)
+    base = automap_base(metadata=self.meta)%0A        base.prepare()%0A        self.base = base
 %0A%0A  
@@ -1762,19 +1762,25 @@
 stitute 
-bas
+db specif
 ic types
@@ -2564,18 +2564,16 @@
 umns)%0A%0A%0A
-%0A%0A
 class Mi
@@ -3063,24 +3063,59 @@
 create_all()
+%0A        self.target.set_meta(meta)
 %0A%0A    def re
@@ -3172,30 +3172,387 @@
 (self, tables):%0A        
-pass
+src_session = self.source.get_session()%0A        trg_session = self.target.get_session()%0A%0A        for key in self.source.get_base_names():%0A            src_cls = self.source.get_base_name(key)%0A            trg_cls = self.target.get_base_name(key)%0A%0A            rows = self.source.get_rows(session=src_session, cls=src_cls)%0A%0A            import ipdb; ipdb.set_trace()
 %0A%0A

Add initial mirror logic