public class Events {
    public static void postAddConnection() {
        EventBus.getDefault().post(new AddConnection());
    }

    public static void postConnectionSelected(long connectionID) {
        EventBus.getDefault().post(new ConnectionSelected(connectionID));
    }

    public static void postConnected(long connectionID) {
        EventBus.getDefault().post(new Connected(connectionID));
    }

    public static void postConnectionDeleted() {
        EventBus.getDefault().post(new ConnectionDeleted());
    }

    public static void postCollectionSelected(long connectionId, int index) {
        EventBus.getDefault().post(new CollectionSelected(connectionId, index));
    }

    public static void postAddDocument() {
        EventBus.getDefault().post(new AddDocument());
    }

    public static void postDocumentSelected(int index) {
        EventBus.getDefault().post(new DocumentSelected(index));
    }

    public static void postDocumentClicked(int index) {
        EventBus.getDefault().post(new DocumentClicked(index));
    }

    public static void postCreateCollection(String name) {
        EventBus.getDefault().post(new CreateCollection(name));
    }

    public static void postRenameCollection(String name) {
        EventBus.getDefault().post(new RenameCollection(name));
    }

    public static void postCollectionRenamed(String name) {
        EventBus.getDefault().post(new CollectionRenamed(name));
    }

    public static void postCollectionDropped() {
        EventBus.getDefault().post(new CollectionDropped());
    }

    public static void postConnectionAdded(long connectionId) {
        EventBus.getDefault().post(new ConnectionAdded(connectionId));
    }

    public static void postConnectionUpdated(long connectionId) {
        EventBus.getDefault().post(new ConnectionUpdated(connectionId));
    }

    public static void postEditDocument(int index) {
        EventBus.getDefault().post(new EditDocument(index));
    }

    public static void postDocumentEdited(int index) {
        EventBus.getDefault().post(new DocumentEdited(index));
    }

    public static void postDocumentCreated(String content) {
        EventBus.getDefault().post(new DocumentCreated(content));
    }

    public static void postDocumentDeleted() {
        EventBus.getDefault().post(new DocumentDeleted());
    }

    public static void postChangeDatabase(String name) {
        EventBus.getDefault().post(new ChangeDatabase(name));
    }

    public static void postQueryNamed(String name) {
        EventBus.getDefault().post(new QueryNamed(name));
    }

    public static void postQueryUpdated(String query) {
        EventBus.getDefault().post(new QueryUpdated(query));
    }

    public static void postSettingsChanged() {
        EventBus.getDefault().post(new SettingsChanged());
    }

    public static class AddConnection {
    }

    public static class AddDocument {
    }

    public static class DocumentDeleted {
    }

    public static class ConnectionSelected {
        public long ConnectionId;

        public ConnectionSelected(long connectionId) {
            ConnectionId = connectionId;
        }
    }

    public static class ConnectionDeleted {
    }

    public static class Connected {
        public long ConnectionId;

        public Connected(long connectionId) {
            ConnectionId = connectionId;
        }
    }

    public static class CollectionSelected {
        public long ConnectionId;
        public int Index;

        public CollectionSelected(long connectionId, int index) {
            ConnectionId = connectionId;
            Index = index;
        }
    }

    public static class DocumentSelected {
        public int Index;

        public DocumentSelected(int index) {
            Index = index;
        }
    }

    public static class DocumentClicked {
        public int Index;

        public DocumentClicked(int index) {
            Index = index;
        }
    }

    public static class EditDocument {
        public int Index;

        public EditDocument(int index) {
            Index = index;
        }
    }

    public static class DocumentCreated {
        public String Content;

        public DocumentCreated(String content) {
            Content = content;
        }
    }

    public static class ChangeDatabase {
        public String Name;

        public ChangeDatabase(String name) {
            Name = name;
        }
    }

    public static class QueryNamed {
        public String Name;

        public QueryNamed(String name) {
            Name = name;
        }
    }

    public static class QueryUpdated {
        public String Content;

        public QueryUpdated(String content) {
            Content = content;
        }
    }

    public static class DocumentEdited {
        public int Index;

        public DocumentEdited(int index) {
            Index = index;
        }
    }

    public static class CollectionRenamed {
        public String Name;

        public CollectionRenamed(String name) {
            Name = name;
        }
    }

    public static class RenameCollection {
        public String Name;

        public RenameCollection(String name) {
            Name = name;
        }
    }

    public static class CreateCollection {
        public String Name;

        public CreateCollection(String name) {
            Name = name;
        }
    }

    public static class CollectionDropped {
    }

    public static class ConnectionAdded {
        public long ConnectionId;

        public ConnectionAdded(long connectionId) {
            ConnectionId = connectionId;
        }
    }

    public static class ConnectionUpdated {
        public long ConnectionId;

        public ConnectionUpdated(long connectionId) {
            ConnectionId = connectionId;
        }
    }

    public static class SettingsChanged {
    }
} public class MongoCollectionRef {
	public String Name;
	public long Count;

	public MongoCollectionRef() {
	}

	public MongoCollectionRef(String name) {
		this.Name = name;
		this.Count = -1;
	}
} public class MongoData {
    public static List<MongoCollectionRef> Collections = new ArrayList<>();
    public static List<MongoDocument> Documents = new ArrayList<>();
} public class MongoDocument {
	public String Content;

	public MongoDocument() {
	}

	public MongoDocument(String content) {
		this.Content = content;
	}
} public class MongoHelper {
	private static MongoClient Connection;
	private static MongoDatabase Database;
	private static String DatabaseName;
	private static String Server;
	private static int Port;
	private static String User;
	private static String Password;
	
	public static void connect(String server, int port, String dbname, String user, String pass) throws UnknownHostException {
		disconnect();

		ServerAddress sa = new ServerAddress(server, port);

		if (user != null && user.length() > 0) {
			List<MongoCredential> creds = new ArrayList<>();
			creds.add(MongoCredential.createScramSha1Credential(user, dbname, pass.toCharArray()));
			Connection = new MongoClient(sa, creds);
		} else {
			Connection = new MongoClient(sa);
		}

    	Database = Connection.getDatabase(dbname);
    	Server = server;
    	Port = port;
    	DatabaseName = dbname;
    	
    	User = user;
    	Password = pass;
    	
    	Connection.setWriteConcern(WriteConcern.SAFE);
		Database.listCollectionNames().first();
	}
	
    private static void disconnect() {
    	try {
	    	if (Connection != null) {
	    		Connection.close();
	    		Connection = null;
	    		Database = null;
	    	}
    	} catch (Exception ex) {
    		ex.printStackTrace();
    	}
	}
    
    private static void reconnect() throws UnknownHostException {
    	disconnect();
    	connect(Server, Port, DatabaseName, User, Password);
    }

    public static void changeDatabase(String name) throws UnknownHostException {
    	Log.i("MONGO", "Change to database " + name);
		disconnect();
		connect(Server, Port, name, User, Password);
    }
    
	public static List<MongoCollectionRef> getCollectionNames(boolean includeSystemPrefs) {
		MongoIterable<String> names = Database.listCollectionNames();
    	ArrayList<MongoCollectionRef> list = new ArrayList<>();
    	
    	for (String str : names)
    		if (includeSystemPrefs || !str.startsWith("system."))
    			list.add(new MongoCollectionRef(str));

		return list;
    }

	public static ArrayList<String> getDatabaseNames() {
    	ArrayList<String> list = new ArrayList<String>();

    	for (String str : Connection.getDatabaseNames())
			list.add(str);

    	return list;
    }
	
	public static long getCollectionCount(String name) {
		return Database.getCollection(name).count();
	}
	
	public static void createCollection(String name) throws Exception {
		Database.createCollection(name);
	}
	
	public static void renameCollection(String oldName, String newName) throws UnknownHostException {
		reconnect();
		MongoNamespace ns = new MongoNamespace(Database.getName() + "." + newName);
		Database.getCollection(oldName).renameCollection(ns);
	}

	public static List<MongoDocument> getPageOfDocuments(String collection, String queryText, int start, int take) {
		MongoCollection coll = Database.getCollection(collection);
		FindIterable main = (queryText == null) ? coll.find() : coll.find(Document.parse(queryText));
		FindIterable items = main.skip(start).limit(take);
		final ArrayList<MongoDocument> results = new ArrayList<>();

		items.forEach(new Block<Document>() {
			@Override
			public void apply(final Document document) {
				results.add(new MongoDocument(document.toJson()));
			}
		});

		return results;
	}

	public static void dropCollection(String name) {
		Database.getCollection(name).drop();
	}

	public static String saveDocument(String collectionName, String content) {
		Document doc = Document.parse(content);

		if (doc.containsKey("_id")) {
			Document filter = new Document("_id", doc.get("_id"));
			Database.getCollection(collectionName).findOneAndReplace(filter, doc);
		} else {
			Database.getCollection(collectionName).insertOne(doc);
		}

		return doc.toJson();
	}

	public static void deleteDocument(String collectionName, String content) {
		Document doc = Document.parse(content);

		if (doc.containsKey("_id")) {
			Document filter = new Document("_id", doc.get("_id"));
			Database.getCollection(collectionName).findOneAndDelete(filter);
		}
	}
} public class Constants {
	public static final String LOG_TAG = "mongoexp";

	public static final String ARG_CONNECTION_ID = "connid";
	public static final String ARG_COLLECTION_INDEX = "collname";
	public static final String ARG_ACTIVATE_ON_CLICK = "actonclick";
	public static final String ARG_DOCUMENT_TITLE = "doctitle";
	public static final String ARG_DOCUMENT_INDEX = "doccontent";
	public static final String ARG_CONTENT = "thecontent";

	public static final long SLIDE_ANIM_DURATION = 600;
	
	public static final String NEW_DOCUMENT_CONTENT = "{\n    \n}\n";
	public static final String NEW_DOCUMENT_CONTENT_PADDED = "{\n    \n}\n\n\n\n\n";
} public class MongoBrowserProvider extends ContentProvider {

	private static final String LOG_TAG = "MongoBrowserProvider";
	private static final String DATABASE_NAME = "mongobrowser.db";
	public static final String TABLE_NAME_CONNECTIONS = "connections";
	public static final String TABLE_NAME_QUERIES = "queries";
	private static final int DATABASE_VERSION = 20;

	public static final int INDEX_CONNECTION_ID = 0;
	public static final int INDEX_CONNECTION_NAME = 1;
	public static final int INDEX_CONNECTION_SERVER = 2;
    public static final int INDEX_CONNECTION_PORT = 3; 
    public static final int INDEX_CONNECTION_DB = 4; 
	public static final int INDEX_CONNECTION_USER = 5;
	public static final int INDEX_CONNECTION_PASSWORD = 6;
	public static final int INDEX_CONNECTION_FLAGS = 7;
	public static final int INDEX_CONNECTION_LAST_CONNECT = 8;
	
	public static final String NAME_CONNECTION_NAME = "name";
	public static final String NAME_CONNECTION_SERVER = "server";
    public static final String NAME_CONNECTION_PORT = "port"; 
    public static final String NAME_CONNECTION_DB = "dbname"; 
	public static final String NAME_CONNECTION_USER = "usernm";
	public static final String NAME_CONNECTION_PASSWORD = "pass";
	public static final String NAME_CONNECTION_FLAGS = "cflags";
	public static final String NAME_CONNECTION_LAST_CONNECT = "lastconn";

	public static final int INDEX_QUERY_ID = 0;
	public static final int INDEX_QUERY_NAME = 1;
	public static final int INDEX_QUERY_CONN_ID = 2;
	public static final int INDEX_QUERY_COLL_NAME = 3;
	public static final int INDEX_QUERY_TEXT = 4;
	
	public static final String NAME_QUERY_NAME = "qname";
	public static final String NAME_QUERY_CONN_ID = "connid";
	public static final String NAME_QUERY_COLL_NAME = "coll";
	public static final String NAME_QUERY_TEXT = "qtext";

	//setup authority for provider
	private static final String AUTHORITY = "com.innodroid.provider.mongobrowser";

	//URI's to consume this provider
	public static final Uri CONNECTION_URI = Uri.parse("content://" + AUTHORITY + "/connections");
	public static final String CONNECTION_ITEM_TYPE = "vnd.android.cursor.item/vnd.innodroid.connection";
    public static final String CONNECTION_LIST_TYPE = "vnd.android.cursor.dir/vnd.innodroid.connection";

	public static final Uri QUERY_URI = Uri.parse("content://" + AUTHORITY + "/queries");
	public static final String QUERY_ITEM_TYPE = "vnd.android.cursor.item/vnd.innodroid.query";
    public static final String QUERY_LIST_TYPE = "vnd.android.cursor.dir/vnd.innodroid.query";

    //Create the statics used to differentiate between the different URI requests
    private static final int CONNECTION_ONE = 1; 
    private static final int CONNECTION_ALL = 2;
    private static final int QUERY_ONE = 3; 
    private static final int QUERY_ALL = 4;

	//database members
	private SQLiteOpenHelper mOpenHelper;
    private SQLiteDatabase mDatabase;

	private static final UriMatcher URI_MATCHER;
	
    static 
	{
        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

        URI_MATCHER.addURI(AUTHORITY, "connections/#", CONNECTION_ONE);
        URI_MATCHER.addURI(AUTHORITY, "connections", CONNECTION_ALL);
        URI_MATCHER.addURI(AUTHORITY, "queries/#", QUERY_ONE);
        URI_MATCHER.addURI(AUTHORITY, "queries", QUERY_ALL);
    }

	@Override
	public boolean onCreate() {
		 mOpenHelper = new DatabaseHelper(getContext());
		 mDatabase = mOpenHelper.getWritableDatabase();
		 return true;
	}

	@Override
	public String getType(Uri uri) {
		switch (URI_MATCHER.match(uri)) {
			case CONNECTION_ALL:
				return CONNECTION_LIST_TYPE;
			case CONNECTION_ONE:
				return CONNECTION_ITEM_TYPE;
			case QUERY_ALL:
				return QUERY_LIST_TYPE;
			case QUERY_ONE:
				return QUERY_ITEM_TYPE;
			default: 
				throw new IllegalArgumentException("Unsupported URI:" + uri);
		}
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		Cursor cursor;
		
		switch (URI_MATCHER.match(uri)) {
			case CONNECTION_ALL:
				cursor = mDatabase.query(TABLE_NAME_CONNECTIONS, projection, selection, selectionArgs, null, null, sortOrder);
				break;
			case CONNECTION_ONE:
				String xid = uri.getPathSegments().get(1);
				cursor = mDatabase.query(TABLE_NAME_CONNECTIONS, projection, BaseColumns._ID + " = ?", new String[] { xid }, null, null, sortOrder);
				break;
			case QUERY_ALL:
				cursor = mDatabase.query(TABLE_NAME_QUERIES, projection, selection, selectionArgs, null, null, sortOrder);
				break;
			case QUERY_ONE:
				String yid = uri.getPathSegments().get(1);
				cursor = mDatabase.query(TABLE_NAME_QUERIES, projection, BaseColumns._ID + " = ?", new String[] { yid }, null, null, sortOrder);
				break;
			default:
				throw new IllegalArgumentException("Unsupported URI:" + uri);				
		}
		
		cursor.setNotificationUri(getContext().getContentResolver(), uri);					
		return cursor;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		String table;
		Uri newUri;
		
		switch (URI_MATCHER.match(uri)) {
			case CONNECTION_ALL:
				table = TABLE_NAME_CONNECTIONS;
				newUri = CONNECTION_URI;
				break;
			case QUERY_ALL:
				table = TABLE_NAME_QUERIES;
				newUri = QUERY_URI;
				break;
			default:
				throw new IllegalArgumentException("Unknown URI " + uri);			
		}

		long id = mDatabase.insert(table, null, values);
		newUri = ContentUris.withAppendedId(newUri, id);
		getContext().getContentResolver().notifyChange(newUri, null);
		Log.d(LOG_TAG, "Insert " + id);

		return newUri;
	}
	
	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		int count = 0;
		
		switch (URI_MATCHER.match(uri))
		{
			case CONNECTION_ALL:
				count = mDatabase.update(TABLE_NAME_CONNECTIONS, values, selection, selectionArgs);
				break;
			case CONNECTION_ONE:
				String xid = uri.getPathSegments().get(1);
				count = mDatabase.update(TABLE_NAME_CONNECTIONS, values, BaseColumns._ID + " = ?", new String[] { xid });
				break;
			case QUERY_ALL:
				count = mDatabase.update(TABLE_NAME_QUERIES, values, selection, selectionArgs);
				break;
			case QUERY_ONE:
				String yid = uri.getPathSegments().get(1);
				count = mDatabase.update(TABLE_NAME_QUERIES, values, BaseColumns._ID + " = ?", new String[] { yid });
				break;
			default:
				throw new IllegalArgumentException("Unsupported URI:" + uri);				
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public int delete(Uri uri, String where, String[] whereArgs) {
		int count=0;

		switch (URI_MATCHER.match(uri))
		{
			case CONNECTION_ALL:
				count = mDatabase.delete(TABLE_NAME_CONNECTIONS, where, whereArgs);
				break;
			case CONNECTION_ONE:
				String xid = uri.getPathSegments().get(1);
				count = mDatabase.delete(TABLE_NAME_CONNECTIONS, BaseColumns._ID + " = ?", new String[] { xid });
				break;
			case QUERY_ALL:
				count = mDatabase.delete(TABLE_NAME_QUERIES, where, whereArgs);
				break;
			case QUERY_ONE:
				String yid = uri.getPathSegments().get(1);
				count = mDatabase.delete(TABLE_NAME_QUERIES, BaseColumns._ID + " = ?", new String[] { yid });
				break;
			default:
				throw new IllegalArgumentException("Unsupported URI:" + uri);				
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	private static class DatabaseHelper extends SQLiteOpenHelper {
		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db)  {
		   createDatabase(db);
		}

		private void createDatabase(SQLiteDatabase db) {
			createConnectionsTable(db);
			createQueriesTable(db);

			/*
			insertConnection(db, "Lumenbox DEV", "dbh61.mongolab.com", 27617, "lumenbox_dev", "lumenuser", "hellolumen");
			insertConnection(db, "Lumenbox PROD", "ds031277.mongolab.com", 31277, "lumenbox", "user", "user");
			insertConnection(db, "imMeta DEV", "ds031637.mongolab.com", 31637, "immeta_dev", "imm3ta", "passw0rd");
			insertConnection(db, "imMeta PROD", "ds029817.mongolab.com", 29817, "immeta_prod", "pr0dm3ta", "passw0rd");
			insertConnection(db, "atWork DEV", "ds033487.mongolab.com", 33487, "atwork_dev", "atwork", "!hello1!");
			insertConnection(db, "guag", "alex.mongohq.com", 10053, "getupandgreen", "admin", "hello123");	
			*/	
			
			/* This used for screenshots */
			/*
			insertConnection(db, "Demo App QA", "demo.mongolab.com", 57323, "demo_qa", "app_login", "passw0rd");
			insertConnection(db, "Demo App PROD", "demo.mongolab.com", 33487, "atwork_dev", "atwork", "!hello1!");
			insertConnection(db, "Support Database", "alex.mongohq.com", 10007, "support", "app_login", "hello123");		
			 */			
		}

		private void createConnectionsTable(SQLiteDatabase db) {
			Log.w(LOG_TAG, "Creating a new table - " + TABLE_NAME_CONNECTIONS);
			db.execSQL(
				"CREATE TABLE "  + TABLE_NAME_CONNECTIONS + "(" + BaseColumns._ID + " INTEGER PRIMARY KEY, " 
				 + NAME_CONNECTION_NAME + " TEXT, "
				 + NAME_CONNECTION_SERVER + " TEXT, "
				 + NAME_CONNECTION_PORT + " INTEGER, "
				 + NAME_CONNECTION_DB + " TEXT, "
				 + NAME_CONNECTION_USER + " TEXT, "
				 + NAME_CONNECTION_PASSWORD + " TEXT, "
				 + NAME_CONNECTION_FLAGS + " INTEGER, "
				 + NAME_CONNECTION_LAST_CONNECT + " INTEGER"
				 + " );"
			);			
		}

		private void createQueriesTable(SQLiteDatabase db) {
			Log.w(LOG_TAG, "Creating a new table - " + TABLE_NAME_QUERIES);
			db.execSQL(
				"CREATE TABLE "  + TABLE_NAME_QUERIES + "(" + BaseColumns._ID + " INTEGER PRIMARY KEY, " 
				 + NAME_QUERY_NAME + " TEXT, "
				 + NAME_QUERY_CONN_ID + " INTEGER, "
				 + NAME_QUERY_COLL_NAME + " TEXT, "
				 + NAME_QUERY_TEXT + " TEXT"
				 + " );"
			);			
		}
		
/*
		private long insertConnection(SQLiteDatabase dbx, String name, String server, int port, String db, String user, String pass) {
			ContentValues cv = MongoBrowserProviderHelper.getContentValuesForConnection(name, server, port, db, user, pass);
			return dbx.insert(TABLE_NAME_CONNECTIONS, null, cv);
		}
*/
		
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)  {
			Log.w(LOG_TAG, "Upgrade database");

			if (oldVersion < 20) {
				createQueriesTable(db);
			}
		}
	}
} public class MongoBrowserProviderHelper {
	private static final String LOG_TAG = "MongoBrowserProviderHelper";
	private ContentResolver mResolver;

	public MongoBrowserProviderHelper(ContentResolver resolver) {
		mResolver = resolver;
	}

	public long addConnection(String name, String server, int port, String db, String user, String pass) {
		Log.i(LOG_TAG, "Adding Connection");

		ContentValues values = getContentValuesForConnection(name, server, port, db, user, pass);
		Uri uri = mResolver.insert(MongoBrowserProvider.CONNECTION_URI, values);
		return ContentUris.parseId(uri);
	}
	
	public void updateConnection(long id, String name, String server, int port, String db, String user, String pass) {
		Log.i(LOG_TAG, "Updating Connection");

		ContentValues values = getContentValuesForConnection(name, server, port, db, user, pass);
		mResolver.update(MongoBrowserProvider.CONNECTION_URI, values, BaseColumns._ID + " = ?", new String[] { Long.toString(id) });
	}

	public void updateConnectionLastConnect(long id) {
		Log.i(LOG_TAG, "Updating Connection");
		long lastConnect = System.currentTimeMillis();

		ContentValues cv = new ContentValues();
		cv.put(MongoBrowserProvider.NAME_CONNECTION_LAST_CONNECT, lastConnect);
		mResolver.update(MongoBrowserProvider.CONNECTION_URI, cv, BaseColumns._ID + " = ?", new String[] { Long.toString(id) });
	}

	public long saveQuery(long id, String name, long connectionId, String collectionName, String text) {
		Log.i(LOG_TAG, "Saving query");

		ContentValues cv = new ContentValues();
		cv.put(MongoBrowserProvider.NAME_QUERY_TEXT, text);
		cv.put(MongoBrowserProvider.NAME_QUERY_NAME, name);
		cv.put(MongoBrowserProvider.NAME_QUERY_CONN_ID, connectionId);
		cv.put(MongoBrowserProvider.NAME_QUERY_COLL_NAME, collectionName);

		if (id > 0) {
			Uri uri = ContentUris.withAppendedId(MongoBrowserProvider.QUERY_URI, id);
			mResolver.update(uri, cv, null, null);
			return id;
		} else {
			Uri result = mResolver.insert(MongoBrowserProvider.QUERY_URI, cv);			
			return Long.parseLong(result.getLastPathSegment());
		}
	}

	public void deleteConnection(long id) {
		Log.i(LOG_TAG, "Deleting Connection");

		mResolver.delete(MongoBrowserProvider.CONNECTION_URI, BaseColumns._ID + " = ?", new String[] { Long.toString(id) });
	}

	public int deleteAllConnections() {
		Log.i(LOG_TAG, "Deleting all Connections");
		return mResolver.delete(MongoBrowserProvider.CONNECTION_URI, null, null);
	}
	
	public Cursor findQuery(String name, long connectionId, String collectionName) {
		return mResolver.query(MongoBrowserProvider.QUERY_URI, null, MongoBrowserProvider.NAME_QUERY_NAME + " = ? and " + MongoBrowserProvider.NAME_QUERY_CONN_ID + " = ? and " + MongoBrowserProvider.NAME_QUERY_COLL_NAME + " = ?", new String[] { name, Long.toString(connectionId), collectionName }, null);
	}
	
	public Cursor getNamedQueries(long connectionId, String collectionName) {
		return mResolver.query(MongoBrowserProvider.QUERY_URI, null, MongoBrowserProvider.NAME_QUERY_CONN_ID + " = ? and " + MongoBrowserProvider.NAME_QUERY_COLL_NAME + " = ?", new String[] { Long.toString(connectionId), collectionName }, null);
	}

	public static ContentValues getContentValuesForConnection(String name, String server, int port, String db, String user, String pass) {
		ContentValues cv = new ContentValues();
		cv.put(MongoBrowserProvider.NAME_CONNECTION_NAME, name);
		cv.put(MongoBrowserProvider.NAME_CONNECTION_SERVER, server);
		cv.put(MongoBrowserProvider.NAME_CONNECTION_PORT, port);
		cv.put(MongoBrowserProvider.NAME_CONNECTION_DB, db);
		cv.put(MongoBrowserProvider.NAME_CONNECTION_USER, user);
		cv.put(MongoBrowserProvider.NAME_CONNECTION_PASSWORD, pass);
		return cv;
	}

	public int getConnectionCount() {
		Cursor cursor = mResolver.query(MongoBrowserProvider.CONNECTION_URI, null, null, null, null);
		int count = cursor.getCount();
		cursor.close();
		return count;
	}
} public class MongoDocumentAdapter extends BaseAdapter {
	private Context mContext;
	private boolean mShowLoadMore;
	private List<MongoDocument> mItems = new ArrayList<>();
	
	public MongoDocumentAdapter(Context context) {
		mContext = context;
		mShowLoadMore = true;
	}

	public void setItems(List<MongoDocument> documents) {
		mItems = documents;
	}

	@Override
	public int getItemViewType(int position) {
		if (!mShowLoadMore)
			return 1;
		
		return (position == getCount()-1) ? 0 : 1;
	}
	
	@Override
	public int getCount() {
		int count = mItems.size();
		
		if (!mShowLoadMore)
			return count;
		
		return (count == 0) ? 0 : count+1;
	}

	public int getActualCount() {
		return mItems.size();
	}
	
	@Override
	public int getViewTypeCount() {
		return 2;
	}
	
	@Override
	public View getView(int position, View view, ViewGroup parent) {
		if (mShowLoadMore && position == getCount()-1)
			return getLoadMoreView(position, view, parent);
		else
			return getDocumentItemView(position, view, parent);
	}
	
	private View getLoadMoreView(int position, View view, ViewGroup parent) {
		if (view == null) {
			LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
			view = inflater.inflate(R.layout.list_item_load_more, null);		
		}
		
		return view;
	}
	
	private View getDocumentItemView(int position, View view, ViewGroup parent) {
		if (view == null) {
			LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
			view = inflater.inflate(R.layout.list_item_document, null);
			
			ViewHolder holder = new ViewHolder();
			holder.ContentView = (TextView)view.findViewById(R.id.list_item_document_text);
			view.setTag(holder);
		}
		
		ViewHolder holder = (ViewHolder)view.getTag();
		MongoDocument item = mItems.get(position);
		holder.ContentView.setText(item.Content);

		return view;
	}
	
	public void insert(int position, MongoDocument doc) {
		mItems.add(position, doc);
		notifyDataSetChanged();
	}

	public void update(int position, MongoDocument doc) {
		mItems.set(position, doc);
		notifyDataSetChanged();
	}

	public void delete(int position) {
		mItems.remove(position);
		
		notifyDataSetChanged();
	}
	
	public void showLoadMore(boolean value) {
		mShowLoadMore = value;
		notifyDataSetChanged();
	}
	
	public boolean isShowingLoadMore() {
		return mShowLoadMore;
	}
	
	public void removeAll() {
		mItems.clear();
		mShowLoadMore = true;
		notifyDataSetChanged();
	}

	private class ViewHolder {
		public TextView ContentView;
	}

	@Override
	public MongoDocument getItem(int position) {
		return mItems.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}
} public class MongoQueryAdapter extends android.support.v4.widget.CursorAdapter {
	public MongoQueryAdapter(Context context, Cursor c, boolean autoRequery) {
		super(context, c, autoRequery);
	}
	
	@Override
	public void bindView(View view, Context context, Cursor cursor) {		
		((TextView)view.findViewById(android.R.id.text1)).setText(cursor.getString(MongoBrowserProvider.INDEX_QUERY_NAME));
	}

	@Override
	public View newView(Context context, Cursor cursor, final ViewGroup parent) {
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        return inflater.inflate(android.R.layout.simple_list_item_1, null);
	}
} public class Preferences {
    private SharedPreferences mPrefs;
    private Context mContext;
    private int mDefaultDocumentPageSize;

    private static final String KEY_SHOW_SYSTEM_COLLECTIONS = "show_system_collections";
    private static final String KEY_DOCUMENT_PAGE_SIZE = "document_page_size";
    private static final String KEY_UPDATE_NOTICE_APPVER = "update_notice_ver";

    public Preferences(Context context) {
        mContext = context;
        mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
        mDefaultDocumentPageSize = context.getResources().getInteger(R.integer.default_document_page_size);
    }

    public boolean getShowSystemCollections() {
        return mPrefs.getBoolean(KEY_SHOW_SYSTEM_COLLECTIONS, false);
    }

    public void setShowSystemCollections(boolean value) {
        mPrefs.edit().putBoolean(KEY_SHOW_SYSTEM_COLLECTIONS, value).apply();
    }

    public int getDocumentPageSize() {
        return mPrefs.getInt(KEY_DOCUMENT_PAGE_SIZE, mDefaultDocumentPageSize);
    }

    public void setDocumentPageSize(int value) {
        mPrefs.edit().putInt(KEY_DOCUMENT_PAGE_SIZE, value).apply();
    }

    public boolean showUpdateNotice() {
        String lastShownVersion = mPrefs.getString(KEY_UPDATE_NOTICE_APPVER, "");
        String actualVersion = UiUtils.getAppVersionString(mContext);

        if (actualVersion.equals(lastShownVersion)) {
            return false;
        }

        mPrefs.edit().putString(KEY_UPDATE_NOTICE_APPVER, actualVersion).apply();
        return true;
    }
} public abstract class SafeAsyncTask<T, U, V> extends AsyncTask<T, U, V>{
	private Exception mException;
	private FragmentActivity mFragmentActivity;
	private ProgressDialog mDialog;
	
	protected abstract V safeDoInBackground(T... params) throws Exception;
	protected abstract void safeOnPostExecute(V result);
	protected abstract String getErrorTitle();
	
	public SafeAsyncTask(FragmentActivity activity) {		
		mFragmentActivity = activity;
	}
	
	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		
		String caption = getProgressMessage();
		
		if (caption != null)
			mDialog = ProgressDialog.show(mFragmentActivity, null, caption, true, false);		
	}
	
	@Override
	protected V doInBackground(T... params) {
		mException = null;

		try {
			return safeDoInBackground(params);
		} catch (Exception ex) {
			ex.printStackTrace();
			mException = ex;
			return null;
		}
	}

	@Override
	protected void onPostExecute(V result) {
		super.onPostExecute(result);

		if (mDialog != null)
			mDialog.dismiss();

		if (mException == null)
			safeOnPostExecute(result);
		else
			ExceptionDetailDialogFragment.newInstance(getErrorTitle(), mException).show(mFragmentActivity.getSupportFragmentManager(), null);
	}

	protected String getProgressMessage() {
		return null;
	}
} public class UiUtils {
	public interface AlertDialogCallbacks {
		boolean onOK();
		boolean onNeutralButton();
	}
	
	public interface ConfirmCallbacks {
		boolean onConfirm();
	}

	public static AlertDialogCallbacks EmptyAlertCallbacks = new AlertDialogCallbacks() {
		@Override
		public boolean onOK() {
			return true;
		}		

		@Override
		public boolean onNeutralButton() {
			return true;
		}		
	};
	
	public static Dialog buildAlertDialog(View view, int icon, int title, boolean hasCancel, int middleButtonText, final AlertDialogCallbacks callbacks) {
		return buildAlertDialog(view, icon, view.getResources().getString(title), hasCancel, middleButtonText, callbacks);
	}
	
	public static Dialog buildAlertDialog(View view, int icon, String title, boolean hasCancel, int middleButtonText, final AlertDialogCallbacks callbacks) {
        AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext())
	        .setIcon(icon)
	        .setView(view)
	        .setTitle(title)
	        .setPositiveButton(android.R.string.ok,
	            new DialogInterface.OnClickListener() {
	                public void onClick(DialogInterface dialog, int whichButton) {
	                }
	            }
	        );
        
        if (hasCancel) {
	        builder.setCancelable(true).setNegativeButton(android.R.string.cancel,
		            new DialogInterface.OnClickListener() {
		                public void onClick(DialogInterface dialog, int whichButton) {
		                }
		            }
		        );   	
        }

        if (middleButtonText != 0) {
	        builder.setNeutralButton(middleButtonText,
		            new DialogInterface.OnClickListener() {
		                public void onClick(DialogInterface dialog, int whichButton) {
		                }
		            }
		        );   	
        }

        final AlertDialog dialog = builder.create();

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface di) {
                Button b = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
                b.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                    	if (callbacks.onOK())
                    		dialog.dismiss();
                    }
                });

                b = dialog.getButton(AlertDialog.BUTTON_NEUTRAL);
                b.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                    	if (callbacks.onNeutralButton())
                    		dialog.dismiss();
                    }
                });
            }
        });     
        
        return dialog;
	}
	
	public static Dialog buildAlertDialog(Context context, ListAdapter adapter, OnClickListener listener, int icon, String title) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context)
	        .setIcon(icon)
	        .setAdapter(adapter, listener)
	        .setTitle(title);
        
        builder.setCancelable(true);

        final AlertDialog dialog = builder.create();

        return dialog;
	}

	public static void message(Context context, int title, int message) {
        DialogInterface.OnClickListener onClick = new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
			}
		};

		message(context, title, message, onClick);
	}

	public static void message(Context context, int title, int message, DialogInterface.OnClickListener onClick) {
		new AlertDialog.Builder(context)
				.setIcon(R.drawable.ic_info_black)
				.setMessage(message)
				.setTitle(title)
				.setCancelable(true)
				.setPositiveButton(android.R.string.ok, onClick)
				.create().show();
	}

	public static void confirm(Context context, int message, final ConfirmCallbacks callbacks) {
        new AlertDialog.Builder(context)
	        .setIcon(R.drawable.ic_warning_black)
	        .setMessage(message)
	        .setTitle(R.string.title_confirm)
	        .setCancelable(true)
	        .setPositiveButton(android.R.string.ok,
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int whichButton) {
							callbacks.onConfirm();
						}
					}
			)
	        .setNegativeButton(android.R.string.cancel,
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int whichButton) {
						}
					}
			)
	        .create().show();
	}

	public static String getAppVersionString(Context context) {
		try {
			PackageInfo info = context.getApplicationContext().getPackageManager().getPackageInfo(context.getPackageName(), 0);
			return "v" + info.versionName + " (Build " + info.versionCode + ")";
		} catch (PackageManager.NameNotFoundException e) {
			e.printStackTrace();
			return "";
		}
	}
} public interface ConfirmCallbacks {
	boolean onConfirm();
}
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Toast;
import com.innodroid.mongobrowser.Events;
import com.innodroid.mongobrowser.data.MongoCollectionRef;
import com.innodroid.mongobrowser.data.MongoData;
import com.innodroid.mongobrowser.data.MongoDocument;
import com.innodroid.mongobrowser.util.MongoHelper;
import com.innodroid.mongobrowser.Constants;
import com.innodroid.mongobrowser.R;
import com.innodroid.mongobrowser.data.MongoBrowserProvider;
import com.innodroid.mongobrowser.data.MongoBrowserProviderHelper;
import com.innodroid.mongobrowser.adapters.MongoDocumentAdapter;
import com.innodroid.mongobrowser.adapters.MongoQueryAdapter;
import com.innodroid.mongobrowser.util.Preferences;
import com.innodroid.mongobrowser.util.SafeAsyncTask;
import com.innodroid.mongobrowser.util.UiUtils;
import com.innodroid.mongobrowser.util.UiUtils.ConfirmCallbacks;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import butterknife.OnClick;
import butterknife.OnItemClick;
package com.innodroid.mongobrowser.ui;






public class DocumentListFragment extends BaseListFragment {
    private static final String STATE_ACTIVATED_POSITION = "activated_position";
    private static final String STATE_QUERY_ID = "query_id";
    private static final String STATE_QUERY_NAME = "query_name";
    private static final String STATE_QUERY_TEXT = "query_text";

    private long mConnectionId;
    private int mCollectionIndex;
    private long mQueryID;
    private String mQueryName;
    private String mQueryText;
    private MongoDocumentAdapter mAdapter;