package com.futureplatforms.kirin.android.db;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.futureplatforms.kirin.dependencies.StaticDependencies;
import com.futureplatforms.kirin.dependencies.db.Database;
import com.futureplatforms.kirin.dependencies.db.DatabaseDelegate;
import com.futureplatforms.kirin.dependencies.db.Transaction.RowSet;
import com.futureplatforms.kirin.dependencies.db.Transaction.Statement;
import com.futureplatforms.kirin.dependencies.db.Transaction.StatementWithRowsReturn;
import com.futureplatforms.kirin.dependencies.db.Transaction.StatementWithTokenReturn;
import com.futureplatforms.kirin.dependencies.db.Transaction.TxElementType;
import com.futureplatforms.kirin.dependencies.db.Transaction.TxRowsCB;
import com.futureplatforms.kirin.dependencies.db.Transaction.TxTokenCB;
import com.futureplatforms.kirin.dependencies.internal.TransactionBackend;
import com.futureplatforms.kirin.dependencies.internal.TransactionBundle;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class AndroidDatabase implements DatabaseDelegate {

	private class Helper extends SQLiteOpenHelper {
		public Helper(String name) {
			super(_Context, name, null, 1);
		}

		@Override
		public void onCreate(SQLiteDatabase db) { }

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
	}
	
	private final Map<String, SQLiteDatabase> _DbMap = Maps.newHashMap();
	private final Context _Context;
	
	public AndroidDatabase(Context context) {
		this._Context = context;
	}
	
	private static class AndroidDatabaseImpl extends Database {

		private final StaticDependencies deps = StaticDependencies.getInstance();
		private SQLiteDatabase db;
		
		public AndroidDatabaseImpl(SQLiteDatabase db) {
			this.db = db;
		}
		
		@Override
		protected void performTransaction(TransactionCallback cb) {
			cb.onSuccess(new TransactionBackend() {
				
				@Override
				public void pullTrigger(TransactionBundle bundle) {
					db.beginTransaction();
					
					List<TxElementType> types = bundle._Types;
					int statementCount=0, batchCount=0;
					for (TxElementType type : types) {
						if (type == TxElementType.Statement) {
							Statement st = bundle._Statements.get(statementCount);
							statementCount++;
							
							// Execute the statement
							Cursor cursor = db.rawQuery(st._SQL, st._Params);
							if (st instanceof StatementWithRowsReturn) {
								// rows return
								// construct RowSet from cursor
								ImmutableList<String> columnNames = ImmutableList.copyOf(cursor.getColumnNames());
								RowSet rowset = new RowSet(columnNames);
								int colCount = cursor.getColumnCount();
								while (cursor.moveToNext()) {
									for (int i=0; i<colCount; i++) {
										List<String> values = Lists.newArrayList();
										// Everything has to be a string...
										int entryType = cursor.getType(i);
										switch (entryType) {
											case Cursor.FIELD_TYPE_BLOB: {
												values.add(new String(cursor.getBlob(i)));
											} break;
											
											case Cursor.FIELD_TYPE_FLOAT: {
												values.add(String.valueOf(cursor.getDouble(i)));
											} break;
											
											case Cursor.FIELD_TYPE_INTEGER: {
												values.add(String.valueOf(cursor.getInt(i)));
											} break;
											
											case Cursor.FIELD_TYPE_NULL: {
												values.add(null);
											} break;
											
											case Cursor.FIELD_TYPE_STRING: {
												values.add(cursor.getString(i));
											} break;
										}
										rowset.addRow(values);
									}
								}
								TxRowsCB c = ((StatementWithRowsReturn) st)._Callback;
								if (c != null) { c.onSuccess(rowset); }
							} else {
								// token return -- stick it on the dropbox!!
								String token = AndroidDbDropbox.getInstance().putCursor(cursor);
								TxTokenCB c = ((StatementWithTokenReturn) st)._Callback;
								if (c != null) { c.onSuccess(token); }
							}
						} else {
							String[] batch = bundle._Batches.get(batchCount);
							for (String sql : batch) {
								db.execSQL(sql);
							}
							batchCount++;
							deps.getLogDelegate().log("SQL FILES not implemented");
						}
					}
					bundle._ClosedCallback.onComplete();
				}
			});
		}
	}
	
	@Override
	public void open(String filename, DatabaseOpenedCallback cb) {
		SQLiteDatabase _db = _DbMap.get(_DbMap);
        if (_db == null || !_db.isOpen()) {
            SQLiteOpenHelper helper = new Helper(filename);
            _db = helper.getWritableDatabase();
            _DbMap.put(filename, _db);
        }
        
        cb.onOpened(new AndroidDatabaseImpl(_db));
	}

	@Override
	public void close(Database db) {
		
	}

}

@@ -4508,16 +4508,99 @@
 %09%7D%0A%09%7D%0A%09%0A
+%09private static final Map%3CString, SQLiteOpenHelper%3E helpers = Maps.newHashMap();%0A%09%0A
 %09@Overri
@@ -4594,32 +4594,32 @@
 );%0A%09%0A%09@Override%0A
-
 %09public void ope
@@ -4753,16 +4753,129 @@
 en()) %7B%0A
+        %09if (!helpers.containsKey(filename)) %7B%0A        %09%09helpers.put(filename, new Helper(filename));%0A        %09%7D%0A
         
@@ -4904,26 +4904,27 @@
 elper = 
-new Helper
+helpers.get
 (filenam
@@ -5133,17 +5133,15 @@
 e db) %7B%0A
-%09%09
 %0A%09%7D%0A%0A%7D%0A

Put SQLiteOpenHelpers into a static map -- see http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection