public class EventWorkBenchManager extends Object {
	private static EventWorkBenchManager thisInst;
	
	public static synchronized EventWorkBenchManager getInst(){
		if ( thisInst == null )
			thisInst = new EventWorkBenchManager();

		return thisInst;
	}

	private Set<EventWorkBenchListener>	listeners;
	
	private EventWorkBenchManager(){
		listeners	= new HashSet<EventWorkBenchListener>();
	}
	
	public void registerListener(EventWorkBenchListener listener){
		listeners.add(listener);
	}
	
	public void deregisterListener(EventWorkBenchListener listener){
		listeners.remove(listener);
	}

	public void onEvent( final Event event, final Object data ){
		
		new Thread("EventWorkBenchEventFire"){ 
			public void run(){
				Iterator<EventWorkBenchListener>	it	= listeners.iterator();
				while ( it.hasNext() ){
					try{
						it.next().onEventWorkBench(event, data);
					}catch(Exception e){
						System.out.println(e);
					}
				}
			}
		}.start();

	}
	
} public class EventWrapper {

	public static String	ACTIVE_NAME = "sname";
	public static String	ACTIVE_DB 	= "sdb";
	public static String	ACTIVE_COLL = "scoll";
	public static String	DOC_DATA 		= "data";
	
	public static String	COMMAND			= "command";
	public static String	DBOBJECT		= "dbobject";
	
	public static	Map createMap( Object... args ){
		HashMap	map	= new HashMap();
		
		for ( int x=0; x < args.length; x += 2 ){
			map.put( args[x], args[x+1] );
		}
		
		return map;
	}
} public interface MongoCommandListener {

	public void onMongoCommandStart( MongoCommand mcmd );
	public void onMongoCommandFinished( MongoCommand mcmd );
	
} public class MongoFactory extends Thread {

	private static MongoFactory	thisInst = null;
	
	public static synchronized MongoFactory getInst(){
		if ( thisInst == null )
			thisInst = new MongoFactory();

		return thisInst;
	}
	
	private Map<String,MongoClient>	mongoMap;
	
	private Set<MongoCommandListener>	mongoListeners;
	private Set<MDocumentView>	documentViewListeners;
	
	private List<MongoCommand>	commandQueue;
	private Map<String, Class>	commandMap;
	private boolean bRun = true;

	
	private String activeServer = null, activeDB = null, activeCollection = null;
	
	public MongoFactory(){
		mongoMap							= new HashMap<String,MongoClient>();
		commandQueue					=	new ArrayList<MongoCommand>(); 
		mongoListeners				= new HashSet<MongoCommandListener>();
		documentViewListeners	= new HashSet<MDocumentView>();
		commandMap						= new HashMap<String,Class>();

		// Register the Commands
		commandMap.put("^db\\.[^\\(]+\\.find\\(.*", FindMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.findOne\\(.*", FindOneMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.save\\(.*", SaveMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.update\\(.*", UpdateMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.remove\\(.*", RemoveMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.group\\(.*", GroupMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.aggregate\\(.*", AggregateMongoCommand.class);
		commandMap.put("^db\\.[^\\(]+\\.mapReduce\\(.*", MapReduceMongoCommand.class);
		commandMap.put("^use\\s+.*", UseMongoCommand.class);
		commandMap.put("^show dbs", ShowDbsMongoCommand.class);
		commandMap.put("^show collections", ShowCollectionsMongoCommand.class);
		commandMap.put("^db\\.serverStatus\\(.*", DBserverStatsMongoCommand.class);
		commandMap.put("^db\\.getStats\\(.*", DBStatsMongoCommand.class);

		setName( "MongoFactory" );
		start();
	}
	
	public void registerListener(MongoCommandListener listener){
		if ( listener instanceof MDocumentView )
			documentViewListeners.add( (MDocumentView)listener );
		else
			mongoListeners.add(listener);
	}
	
	public void deregisterListener(MongoCommandListener listener){
		if ( listener instanceof MDocumentView )
			documentViewListeners.remove( (MDocumentView)listener );
		else
			mongoListeners.remove(listener);
	}
		
	public void removeMongo(String sName){
		MongoClient	mclient	= mongoMap.remove(sName);
		if ( mclient != null )
			mclient.close();
	}
	
	
	public MongoClient getMongo(String sName) {
		activeServer = sName;
		
		if ( mongoMap.containsKey(sName) )
			return mongoMap.get(sName);
		else{
			try {
				MongoClient mc	= Activator.getDefault().getMongoClient(sName);
				mongoMap.put( sName, mc );
				return mc;
			} catch (UnknownHostException e) {
				EventWorkBenchManager.getInst().onEvent( org.aw20.mongoworkbench.Event.EXCEPTION, e);
				return null;
			}
		}
	}
	
	public void destroy(){
		bRun = false;
	}
	
	public String getActiveServer(){
		return activeServer;
	}
	
	public String getActiveDB(){
		return activeDB;
	}
	
	public void setActiveDB(String db){
		this.activeDB = db;
	}
	
	public MongoCommand	createCommand( String cmd ) throws Exception {
		
		// remove line breaks
		cmd = cmd.replaceAll("(\\r|\\n)", "");
		cmd = cmd.replaceAll("\\t+", " ");
		cmd	= cmd.trim();

		Iterator p = commandMap.keySet().iterator();
		while (p.hasNext()) {
			String patternStr = (String) p.next();
			if (cmd.matches(patternStr)) {
				Class clazz = (Class) commandMap.get(patternStr);
				try {
					MongoCommand mcmd = (MongoCommand)clazz.newInstance();
					mcmd.setConnection(activeServer, activeDB);
					mcmd.setCommandStr( cmd );
					mcmd.parseCommandStr();
					return mcmd;
				} catch (Exception e) {
					EventWorkBenchManager.getInst().onEvent( Event.EXCEPTION, e);
					return null;
				}
			}
		}
		
		// Determine if this is a command
		if ( cmd.startsWith("db.") || cmd.startsWith("sh.") || cmd.startsWith("rs.") ){
			MongoCommand mcmd = new PassThruMongoCommand();
			mcmd.setConnection(activeServer, activeDB);
			mcmd.setCommandStr(cmd);
			return mcmd;
		}
			
		
		return null;
	}
	
	public void submitExecution( MongoCommand mcmd ){
		synchronized(commandQueue){
			commandQueue.add(mcmd);
			commandQueue.notify();
		}
	}

	public MongoClient getMongoActive() {
		return mongoMap.get(activeServer);
	}

	public DB getMongoActiveDB() {
		return mongoMap.get(activeServer).getDB(activeDB);
	}
	
	public void run(){
		MongoCommand	cmd;
		
		while (bRun){
			
			while ( commandQueue.size() == 0 ){
				synchronized (commandQueue) {
					try {
						commandQueue.wait();
					} catch (InterruptedException e) {
						bRun = false;
						return;
					}
				}
			}
			
			synchronized(commandQueue){
				cmd	= commandQueue.remove(0);
				if ( cmd == null )
					continue;
			}


			// Now let the listeners know we are about to start
			alertDocumentViewsOnMongoCommandStart(cmd);
			alertListenersOnMongoCommandStart(cmd);
			
			// Execute the command
			long startTime	= System.currentTimeMillis();
			try{
				cmd.execute();
			}catch(Throwable t){
				t.printStackTrace();
			}finally{
				cmd.setExecTime( System.currentTimeMillis() - startTime );
				cmd.hasRun();
			}

			if ( cmd.getCollection() != null )
				activeCollection = cmd.getCollection();
			

			// Now let the listeners know we have finished
			alertDocumentViewsOnMongoCommandFinished(cmd);
			alertListenersOnMongoCommandFinished(cmd);
		}
	}

	public void setActiveServerDB(String name, String db) {
		activeServer = name;
		activeDB = db;
	}

	public String getActiveCollection() {
		return activeCollection;
	}
	
	
	private void alertListenersOnMongoCommandStart( MongoCommand cmd ){
		Iterator<MongoCommandListener>	it	= mongoListeners.iterator();
		while ( it.hasNext() ){
			try{
				it.next().onMongoCommandStart(cmd);
			}catch(Exception e){
				EventWorkBenchManager.getInst().onEvent( Event.EXCEPTION, e);
			}
		}
	}
	
	private void alertListenersOnMongoCommandFinished( MongoCommand cmd ){
		Iterator<MongoCommandListener>	it	= mongoListeners.iterator();
		while ( it.hasNext() ){
			try{
				it.next().onMongoCommandFinished(cmd);
			}catch(Exception e){
				EventWorkBenchManager.getInst().onEvent( Event.EXCEPTION, e);
			}
		}
	}
	
	
	private void alertDocumentViewsOnMongoCommandStart( MongoCommand cmd ){}
	
	private void alertDocumentViewsOnMongoCommandFinished( MongoCommand cmd ){
		if ( !cmd.hasQueryData() )
			return;
		
		findDocumentView(cmd);
	}
	
	private void findDocumentView(final MongoCommand cmd){
		Iterator<MDocumentView>	it	= documentViewListeners.iterator();
		
		final String id	= ( cmd.getDB() != null ? cmd.getDB() : "DB" ) + "-" + ( cmd.getCollection() != null ? cmd.getCollection() : "Output" );
		
		while ( it.hasNext() ){
			MDocumentView view = it.next();
			
			if ( view.getViewTitle().equals(id) ){
				final MDocumentView finalView = view;
				Activator.getDefault().getShell().getDisplay().asyncExec(new Runnable() {
					public void run() {
						Activator.getDefault().showView("org.aw20.mongoworkbench.eclipse.view.MDocumentView", id );
						((MDocumentView)finalView).onMongoCommandFinished(cmd);
					}
				});
				return;
			}
		}
		
		
		/* Need to create a new one */
		Activator.getDefault().getShell().getDisplay().asyncExec(new Runnable() {
			public void run() {
				Object view = Activator.getDefault().showView("org.aw20.mongoworkbench.eclipse.view.MDocumentView", id );
				if ( view != null && view instanceof MDocumentView )
					((MDocumentView)view).onMongoCommandFinished(cmd);
			}
		});
		
	}
} public class CollectionCountMongoCommand extends MongoCommand {

	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);

		DB db	= mdb.getDB(sDb);
		
		DBCollection	collection	= db.getCollection(sColl);
		
		setMessage( "count=" + collection.count() );
	}

	public String getCommandString(){
		return "db." + sColl + ".count()";
	}
} public class CollectionRemoveAllMongoCommand extends MongoCommand {

	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);

		DB db	= mdb.getDB(sDb);
		
		DBCollection	collection	= db.getCollection(sColl);
		collection.remove( new BasicDBObject() );
		
		setMessage( "count=" + collection.count() );
	}

	public String getCommandString(){
		return "db." + sColl + ".remove({})";
	}
} public class CollectionStatsMongoCommand extends DBStatsMongoCommand {
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);

		DB db	= mdb.getDB(sDb);

		Set<String>	collNames = db.getCollectionNames();
		Iterator<String>	it	= collNames.iterator();
		while ( it.hasNext() ){
			String col	= it.next();
			
			statsListMap.add( transform( db.getCollection(col).getStats().toMap() ) );
		}
		
		setMessage("#" + statsListMap.size() + " collections ");
	}

	public String getCommandString(){
		return "aw20.stats()";
	}
	
} public class CreateCollectionMongoCommand extends ShowCollectionsMongoCommand {
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");

		if ( sDb == null )
			throw new Exception("no database selected");
		
		DB db	= mdb.getDB( sDb );
		db.createCollection( sColl, new BasicDBObject() );
		
		super.execute();
	}

	@Override
	public String getCommandString() {
		return "db.create('" + sColl + "', {})";
	}
} public class CreateDbsMongoCommand extends ShowDbsMongoCommand {
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");

		DB db	= mdb.getDB( sDb );

		String colTemp = "tmp" + System.currentTimeMillis();
		DBCollection coll = db.createCollection( colTemp, new BasicDBObject() );
		coll.drop();
		
		setDBNames(mdb);
	}

	@Override
	public String getCommandString() {
		return "create database";
	}
} public class DBStatsMongoCommand extends ShowDbsMongoCommand {

	protected List<Map>	statsListMap = new ArrayList<Map>();
	private DecimalFormat df2places = new DecimalFormat("#0.00");
	private DecimalFormat nf = (DecimalFormat) DecimalFormat.getInstance();
	
	public DBStatsMongoCommand(){
		df2places.setGroupingUsed(true);
		
		DecimalFormatSymbols custom=new DecimalFormatSymbols();
		custom.setDecimalSeparator(',');
		nf.setDecimalFormatSymbols(custom);
	}
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");

		setDBNames(mdb);
		Iterator<String> it = dbNames.iterator();
		while ( it.hasNext() ){
			String db = it.next();
			
			CommandResult cmdr = mdb.getDB(db).getStats();
			statsListMap.add( transform(cmdr.toMap()) );
		}
		
		setMessage("Retrived Database Stats; db=" + statsListMap.size() );
	}

	protected Map transform(Map map) {
		
		if ( map.containsKey("avgObjSize") )
			map.put("avgObjSize", df2places.format(map.get("avgObjSize")) );
		
		if ( map.containsKey("paddingFactor") )
			map.put("paddingFactor", df2places.format(map.get("paddingFactor")) );
		
		if ( map.containsKey("fileSize") )
			map.put("fileSize", nf.format(map.get("fileSize")) );
		
		if ( map.containsKey("indexSize") )
			map.put("indexSize", nf.format(map.get("indexSize")) );
		
		if ( map.containsKey("size") )
			map.put("size", nf.format(map.get("size")) );
		
		if ( map.containsKey("lastExtentSize") )
			map.put("lastExtentSize", nf.format(map.get("lastExtentSize")) );
		
		if ( map.containsKey("totalIndexSize") )
			map.put("totalIndexSize", nf.format(map.get("totalIndexSize")) );
		
		if ( map.containsKey("objects") )
			map.put("objects", nf.format(map.get("objects")) );
		
		if ( map.containsKey("count") )
			map.put("count", nf.format(map.get("count")) );
		
		if ( map.containsKey("storageSize") )
			map.put("storageSize", nf.format(map.get("storageSize")) );
		
		if ( map.containsKey("dataSize") )
			map.put("dataSize", nf.format(map.get("dataSize")) );

		return map;
	}

	@Override
	public String getCommandString() {
		return "db.getStats()";
	}
	
	public List<Map> getStatsListMap(){
		return statsListMap;
	}
	
} public class DBserverStatsMongoCommand extends MongoCommand {
	
	private Map<String,Object>	map;
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");

		String db;
		List<String> listDBs = mdb.getDatabaseNames();
		if ( listDBs.size() > 0 )
			db	= listDBs.get(0);
		else
			db	= "admin";
		
		DB dbM	= mdb.getDB( db );

		Object obj = dbM.eval( "db.serverStatus()", (Object[])null );
		if ( obj instanceof Map ){
			map	= (Map)obj;
			setMessage("Server Status - version=" + map.get("version") + "; localTime=" + map.get("localTime"));	
		}else{
			map = null;
			setMessage("invalid result returned");	
		}
	}

	public Map<String,Object>	getStatus(){
		return map;
	}
	
	@Override
	public String getCommandString() {
		return "db.serverStatus()";
	}
} public class DropCollectionMongoCommand extends ShowCollectionsMongoCommand {

	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);

		DB db	= mdb.getDB(sDb);
		
		DBCollection	collection	= db.getCollection(sColl);
		collection.drop();
		
		super.execute();
	}

	public String getCommandString(){
		return "db." + sColl + ".drop()";
	}
} public class DropDbsMongoCommand extends ShowDbsMongoCommand {
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");

		DB db	= mdb.getDB( sDb );
		db.dropDatabase();
		
		setDBNames(mdb);
		
		MongoFactory.getInst().setActiveDB( null );
	}

	@Override
	public String getCommandString() {
		return "drop database";
	}
} public class GridFSCreateBucketCommand extends MongoCommand {
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);
		DB db	= mdb.getDB(sDb);
		
		GridFS	gfs	= new GridFS( db, sColl );
		gfs.getBucketName();

		setMessage("bucketCreated=" + sColl);
	}

	public String getCommandString() {
		return "aw20.gridfs." + sColl + ".create()";
	}
	
} public class GridFSRemoveBucketCommand extends MongoCommand {
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);
		DB db	= mdb.getDB(sDb);
		
		db.getCollection(sColl + ".files").drop();
		db.getCollection(sColl + ".chunks").drop();
		
		setMessage("bucketDrop=" + sColl);
	}

	public String getCommandString() {
		return "aw20.gridfs." + sColl + ".drop()";
	}
	
} public abstract class MongoCommand extends Object {

	public static String KEY_NAME = "_name";

	public static String KEY_COUNT = "_count";

	protected String sName = null, sDb = null, sColl = null, rteMessage = "", cmd = null;

	protected Exception lastException = null;

	protected boolean hasRun = false;

	private long execTime = -1;

	/**
	 * Sets the connection details to which this command pertains to
	 * 
	 * @param mongoName
	 * @param database
	 * @param collection
	 */
	public MongoCommand setConnection(String mongoName, String database, String collection) {
		this.sName = mongoName;
		this.sDb = database;
		this.sColl = collection;
		return this;
	}

	public MongoCommand setConnection(String mongoName, String database) {
		this.sName = mongoName;
		this.sDb = database;
		return this;
	}

	public MongoCommand setConnection(String mongoName) {
		this.sName = mongoName;
		return this;
	}

	public MongoCommand setConnection(MongoCommand mcmd) {
		this.sName = mcmd.sName;
		this.sDb = mcmd.sDb;
		this.sColl = mcmd.sColl;
		return this;
	}

	public boolean isSuccess() {
		return lastException == null;
	}
	
	public boolean hasQueryData(){
		return false;
	}

	public boolean hasRun() {
		return hasRun;
	}

	public void markAsRun() {
		hasRun = true;
	}

	public Exception getException() {
		return lastException;
	}

	public void setException(Exception e) {
		lastException = e;
	}

	public String getExceptionMessage() {
		if (lastException == null)
			return "";

		if (lastException instanceof MongoException) {
			String e = lastException.getMessage();
			if (e.startsWith("command failed [$eval]: {") && e.endsWith("}")) {
				try {
					Map m = (Map) JSON.parse(e.substring(e.indexOf("{")));
					return (String) m.get("errmsg");
				} catch (Exception ee) {
					return lastException.getMessage();
				}
			}
		}

		return lastException.getMessage();
	}

	public long getExecTime() {
		return execTime;
	}

	protected void setMessage(String string) {
		rteMessage = string;
	}

	public String getMessage() {
		return rteMessage;
	}

	public String getName() {
		return sName;
	}

	public String getDB() {
		return sDb;
	}

	public String getCollection() {
		return sColl;
	}

	/**
	 * Override this function to provide the body of the command
	 */
	public abstract void execute() throws Exception;

	public String getCommandString() {
		return this.cmd;
	}

	public void setExecTime(long l) {
		execTime = l;
	}

	public void setCommandStr(String cmd) {
		this.cmd = cmd;
	}

	public void parseCommandStr() throws Exception {}

	public String getMatchIgnoreCase(String patternStr, String target) {
		Pattern pattern = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
		Matcher matcher = pattern.matcher(target);
		if (matcher.find()) {
			if (matcher.groupCount() > 0) {
				return matcher.group(1);
			} else {
				return target.substring(matcher.start(), matcher.end());
			}
		} else {
			return "";
		}
	}
	
	
	public BasicDBObject parse() throws Exception{
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);
		
		DB db	= mdb.getDB(sDb);
		return parseMongoCommandString(db, cmd);
	}
	
	
	protected BasicDBObject parseMongoCommandString(DB db, String cmd) throws Exception {
		
		String newCmd = cmd.replaceFirst("db." + sColl, "a");
		String jsStr = StreamUtil.readToString( this.getClass().getResourceAsStream("parseCommand.txt") ); 
		jsStr = StringUtil.tokenReplace(jsStr, new String[]{"//_QUERY_"}, new String[]{newCmd} );

		BasicDBObject cmdMap = (BasicDBObject)db.eval(jsStr, (Object[])null);
		
		/*
		 * Using JavaScript Engine
		Context cx = Context.enter();
		cx.setLanguageVersion(Context.VERSION_1_7);
		Scriptable scope = cx.initStandardObjects();
		Object returnObj = cx.evaluateString(scope, jsStr, "CustomJS", 1, null);
		
		Map cmdMap = (Map) jsConvert2cfData( (IdScriptableObject)returnObj );
		*/
		
		// Remove the helper methods
		cmdMap.remove("find");
		cmdMap.remove("findOne");
		cmdMap.remove("group");
		cmdMap.remove("aggregate");
		cmdMap.remove("save");
		cmdMap.remove("mapReduce");
		cmdMap.remove("update");
		cmdMap.remove("remove");
		cmdMap.remove("limit");
		cmdMap.remove("skip");
		cmdMap.remove("sort");
		
		return new BasicDBObject( cmdMap );
	}

	
	public static Object jsConvert2cfData(IdScriptableObject obj) throws Exception {

		if (obj instanceof NativeObject) {
			Map struct = new HashMap();

			NativeObject nobj = (NativeObject) obj;
			Object[] elements = nobj.getAllIds();

			Object cfdata;
			
			for (int x = 0; x < elements.length; x++) {
				Object jsObj = nobj.get(elements[x]);

				if (jsObj == null)
					cfdata = null;
				else if (jsObj instanceof NativeObject || jsObj instanceof NativeArray)
					cfdata = jsConvert2cfData((IdScriptableObject) jsObj);
				else
					cfdata = jsObj;

				struct.put((String) elements[x], cfdata);
			}

			return struct;
		} else if (obj instanceof NativeArray) {
			List array = new ArrayList();

			NativeArray nobj = (NativeArray) obj;
			Object cfdata;
			int len = (int) nobj.getLength();

			for (int x = 0; x < len; x++) {
				Object jsObj = nobj.get(x);

				if (jsObj == null)
					cfdata = null;
				else if (jsObj instanceof NativeObject || jsObj instanceof NativeArray)
					cfdata = jsConvert2cfData((IdScriptableObject) jsObj);
				else
					cfdata = jsObj;
				
				array.add(cfdata);
			}

			return array;
		} else {
			return null;
		}
	}

	
	protected BasicDBObject	fixNumbers( BasicDBObject dbo ){
		Iterator<String> it	= dbo.keySet().iterator();
		while (it.hasNext()){
			String field	= it.next();
			Object o	= dbo.get(field);
			if ( o instanceof Double ){
				dbo.put(field, NumberUtil.fixDouble( (Double)o) );
			}else if ( o instanceof BasicDBObject ){
				dbo.put(field, fixNumbers((BasicDBObject)o) );
			}else if ( o instanceof BasicDBList ){
				dbo.put(field, fixNumbers((BasicDBList)o) );
			}
		}
		
		return dbo;
	}
	
	
	protected BasicDBList	fixNumbers( BasicDBList dbo ){
		for ( int x=0; x < dbo.size(); x++ ){
			Object o =	dbo.get(x);
			
			if ( o instanceof Double ){
				dbo.set(x, NumberUtil.fixDouble( (Double)o) );
			}else if ( o instanceof BasicDBObject ){
				dbo.set(x, fixNumbers((BasicDBObject)o) );
			}else if ( o instanceof BasicDBList ){
				dbo.set(x, fixNumbers((BasicDBList)o) );
			}
		}

		return dbo;
	}
} public class ShowCollectionsMongoCommand extends MongoCommand {

	private List<String>	colNames = null, jsNames = null, gridfsNames = null;
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );

		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");

		MongoFactory.getInst().setActiveDB(sDb);
		DB db	= mdb.getDB(sDb);
		Set<String>	colSet	= db.getCollectionNames();
		
		colNames		= new ArrayList<String>(colSet.size());
		jsNames			= new ArrayList<String>(1);
		gridfsNames	= new ArrayList<String>(1);
		
		
		Iterator<String> it = colSet.iterator();
		while ( it.hasNext() ){
			String colName = it.next();
			
			if ( colName.equals("system.js") ){

				DBCollection col = db.getCollection("system.js");
				DBCursor	cursor	= col.find();
				while ( cursor.hasNext() ){
					jsNames.add( cursor.next().get("_id").toString() );						
				}
				
			}else if ( colName.endsWith(".chunks") )
				gridfsNames.add( colName.substring(0, colName.lastIndexOf(".") ) );
			else if ( colName.endsWith(".files") || colName.endsWith("system.indexes") )
				;
			else
				colNames.add( colName );
		}
		
		Collections.sort(colNames);
		
		setMessage("# Collections=" + colNames.size() + "; GridFS=" + gridfsNames.size() + "; Javascript=" + jsNames.size() );
	}

	@Override
	public String getCommandString() {
		return "show collections";
	}
	
	public List<String>	getCollectionNames(){
		return colNames;
	}
	
	public List<String>	getGridFSNames(){
		return gridfsNames;
	}
	
	public List<String>	getJSNames(){
		return jsNames;
	}

} public class ShowDbsMongoCommand extends MongoCommand {

	protected List<String>	dbNames = null;
	
	@Override
	public void execute() throws Exception {
		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");

		setDBNames(mdb);
		
		setMessage("# Databases=" + dbNames.size() );
	}
	
	protected void setDBNames(MongoClient mdb){
		try{
			dbNames = new ArrayList<String>( mdb.getDatabaseNames() );
			Collections.sort(dbNames);
		}catch(com.mongodb.MongoException e){
			if ( e.getMessage().indexOf("unauthorized") > 0 ){
				// Check to see if they have given us a mongo database
				Map m = Activator.getDefault().getServerMap(sName);
				if ( m != null ){
					String db = (String)m.get("database");
					if ( db != null && db.length() > 0 ){
						dbNames = new ArrayList<String>(1);
						dbNames.add(db);
						return;
					}
				}
			}
			throw e;
		}
	}

	@Override
	public String getCommandString() {
		return "show dbs";
	}
	
	public List<String>	getDBNames(){
		return dbNames;
	}

} public class SystemJavaScriptReadCommand extends MongoCommand {

	private String jsName = null, jsCode = null;
	
	public SystemJavaScriptReadCommand(String jsName) {
		this.jsName = jsName;
	}

	@Override
	public void execute() throws Exception {

		MongoClient mdb = MongoFactory.getInst().getMongo( sName );
		
		if ( mdb == null )
			throw new Exception("no server selected");
		
		if ( sDb == null )
			throw new Exception("no database selected");
		
		MongoFactory.getInst().setActiveDB(sDb);
		DB db	= mdb.getDB(sDb);

		DBCollection coll	= db.getCollection("system.js");
		DBObject dbo = coll.findOne( new BasicDBObject("_id", jsName) );
		
		if ( dbo.containsField("value") ){
			jsCode	= ((Code)dbo.get("value")).getCode();
		}
		
		setMessage("System JavaScript loaded=" + jsName);
	}

	public String getCode(){
		return jsCode;
	}
	
	public String getJSName(){
		return jsName;
	}
	
	public String getCommandString() {
		return "aw20.systemjs.read(\"" + jsName + "\")";
	}
} public class UseMongoCommand extends MongoCommand {

	private String dbName = null;
	
	@Override
	public void execute() throws Exception {
		if ( sName == null )
			throw new Exception("no server selected");
		
		dbName = getMatchIgnoreCase("^use\\s+(.*)$", cmd);
		if ( dbName == null )
			throw new Exception( "failed to retrieve database name" );

		// Not unusual for commands to end with a ; so chop it off
		dbName	= dbName.trim();
		if ( dbName.endsWith(";") )
			dbName	= dbName.substring(0, dbName.length()-1);

		// Check for bad characters
		for ( int x=0; x < dbName.length(); x++ ){
			if ( !Character.isLetterOrDigit( dbName.charAt(x) ) && dbName.charAt(x) != '_' )
				throw new Exception("database name contains invalid characters");
		}
		
		sDb = dbName;
		MongoFactory.getInst().setActiveDB(dbName);
	}

	@Override
	public String getCommandString() {
		return isSuccess() ? ("use " + dbName) : "invalid";
	}
} public class Activator extends AbstractUIPlugin implements MConstants {
	public static final String PLUGIN_ID = "org.aw20.MongoWorkBench"; //$NON-NLS-1$

	private static Activator plugin;
	private File configFile, commandFile, serverListFile;
	private volatile Shell shell;

	public synchronized void setShell(Shell s) {
		if (shell == null) {
			shell = s;
			MMenuManager.getInstance().initMenus();
		}
	}

	public void showView( String viewname ){
		showView(viewname, null);
	}
	
	public Object showView( String viewname, String id ){
		try {
			IWorkbench wb = PlatformUI.getWorkbench();
			
			IWorkbenchWindow wbw = null;
			if ( wb.getActiveWorkbenchWindow() == null ){
				wbw	= wb.getWorkbenchWindows()[0];
			}else{
				wbw	= wb.getActiveWorkbenchWindow();
			}
			
			Object v = (MAbstractView)wbw
					.getActivePage()
					.showView( viewname, id, IWorkbenchPage.VIEW_VISIBLE );
			
			if ( id != null && v instanceof MDocumentView )
				((MDocumentView)v).setViewTitle( id );

			return v;
			
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public Shell getShell() {
		return shell;
	}

	
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;

		loadConfig();
		MPrefManager.getInstance().init();
	}

	public void loadConfig() throws IOException {
		Location location = Platform.getConfigurationLocation();
		if (location != null) {
			URL configURL = location.getURL();
			if (configURL != null && configURL.getProtocol().startsWith("file")) {
				File platformDir = new File(configURL.getFile(), Activator.PLUGIN_ID);
				createDir(platformDir.getAbsolutePath());
				String configFileName = platformDir.getAbsolutePath() + "/" + DEFAULT_CONFIG_FILE_NAME;
				
				commandFile	= new File( platformDir.getAbsolutePath(), "command.txt" );
				serverListFile	= new File( platformDir.getAbsolutePath(), "serverlist.bin" );
				
				loadConfig(configFileName);
			}
		} else {
			loadConfig("_dummy_not_exist_");
		}
	}

	private void loadConfig(String configFileName) throws IOException {
		configFile = new File(configFileName);
		InputStream in = null;
		
		try{
			
			if (configFile.exists() && configFile.isFile()) {
				in = new FileInputStream(configFile);
			} else {
				in = StreamUtil.getResourceStream("org/aw20/mongoworkbench/eclipse/resources/" + DEFAULT_CONFIG_FILE_NAME);
			}
		
		}finally{
			if ( in != null )
				in.close();
		}
		
	}

	public void saveConfig() throws IOException {
		OutputStream out = new FileOutputStream(configFile);
		try {

		} finally {
			out.close();
		}
	}

	public void stop(BundleContext context) throws Exception {
		plugin = null;
		saveConfig();
		super.stop(context);
	}

	public static Activator getDefault() {
		return plugin;
	}

	public File	getScratchPadsFile(){
		return new File( commandFile.getParent(), "scratchpads.bin" );
	}

	public List<Map> getServerList() {
		List<Map> serverList	= (List<Map>)FileUtil.loadClass(serverListFile);
		if ( serverList == null )
			return new ArrayList<Map>();
		else
			return serverList;
	}

	public void saveServerList(List<Map> serverList){
		FileUtil.saveClass(serverListFile, serverList);
	}

	public Map<String, Object> getServerMap(String sName) {
		Iterator<Map>	it	= getServerList().iterator();
		while ( it.hasNext() ){
			Map	m = it.next();
			if ( m.get("name").equals(sName) )
				return m;
		}
		return null;
	}
	
	public List<Map> removeServerMap(String sName) {
		List<Map> list = getServerList();
		Iterator<Map>	it	= list.iterator();
		while ( it.hasNext() ){
			Map	m = it.next();
			if ( m.get("name").equals(sName) ){
				it.remove();
				break;
			}
		}
		return list;
	}

	public MongoClient getMongoClient(String sName) throws UnknownHostException{
		Map<String, Object>	props	= getServerMap( sName );
		if ( props == null )
			return null;
		
		
		if ( props.containsKey("username") && props.get("username").toString().length() > 0 
				&& props.containsKey("password") && props.get("password").toString().length() > 0){
			StringBuilder sb = new StringBuilder(32);
			sb.append("mongodb://")
				.append(props.get("username") )
				.append(":")
				.append(props.get("password"))
				.append("@")
				.append(props.get("host"))
				.append(":")
				.append( StringUtil.toInteger(props.get("port"), 27017) );
			
			if ( props.containsKey("database") && props.get("database").toString().length() > 0 )
				sb.append("/").append(props.get("database"));
		
			return new MongoClient( new MongoClientURI(sb.toString()) );
		}else
			return new MongoClient( (String)props.get("host"), StringUtil.toInteger(props.get("port"), 27017) );
	}
	
	
	private String createDir(String dirName) throws IOException {
		File dir = new File(dirName);
		if (dir.exists()) {
			if (!dir.isDirectory()) {
				throw new IOException("Couldn't make directory: " + dir.getCanonicalPath());
			}
		} else {
			if (!dir.mkdirs()) {
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {}
				if (!dir.isDirectory()) {
					throw new IOException("Couldn't make directory: " + dir.getCanonicalPath());
				}
			}
		}
		return dir.getCanonicalPath();
	}
} public class ServerDialog extends Dialog {

	protected Object result;

	protected Shell shlConnectionProperties;
	private Text textHost;
	private Text textPort;
	private Text textDatabase;
	private Text textName;
	private Text textSSH;
	private Text textPrivateKeyFile;
	private Text textUsername;
	private Text textPassword;
	private Button btnDirectConnection;
	private Button btnSshConnection;
	private Label lblStatus;
	
	private FileDialog 		loadDialog;
	private Map	attributes;
	
	/**
	 * Create the dialog.
	 * @param parent
	 * @param style
	 */
	public ServerDialog(Shell parent) {
		this( parent, SWT.DIALOG_TRIM );
	}
	
	public ServerDialog(Shell parent, int style) {
		super(parent, style);
		setText("SWT Dialog");
	}

	/**
	 * Open the dialog.
	 * @return the result
	 */
	public Object open(Map attributes) {
		this.attributes	= attributes;
		
		createContents();
		setAttributes();
		
		shlConnectionProperties.open();
		shlConnectionProperties.layout();
		Display display = getParent().getDisplay();
		while (!shlConnectionProperties.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		return result;
	}

	
	private boolean validateAttributes(){
		lblStatus.setText("");
		
		if ( textName.getText().trim().length() == 0 ){
			lblStatus.setText("no name given");
			return false;
		}
		
		if ( textHost.getText().trim().length() == 0 ){
			lblStatus.setText("no host given");
			return false;
		}
		
		if ( textPort.getText().trim().length() == 0 ){
			lblStatus.setText("no port given");
			return false;
		}
		
		if ( StringUtil.toInteger(textPort.getText().trim(), -1) == -1 ){
			lblStatus.setText("invalid port");
			return false;
		}

		return true;
	}
	
	public void retriveAttributes(){
		attributes.put("name", textName.getText().trim() );
		attributes.put("host", textHost.getText().trim() );
		attributes.put("port", textPort.getText().trim() );

		attributes.put("username", textUsername.getText().trim() );
		attributes.put("password", textPassword.getText().trim() );
		attributes.put("database", textDatabase.getText().trim() );

		attributes.put("sshprivatekey", textPrivateKeyFile.getText().trim() );
		attributes.put("textSSH", textUsername.getText().trim() );
		
		if ( btnDirectConnection.getSelection() ){
			attributes.put("direct", true);
		}else{
			attributes.remove("direct");
		}
	}
	
	public Map getAttributes(){
		return attributes;
	}
	
	
	private void setAttributes(){
		if ( attributes.containsKey("name") )
			textName.setText( (String)attributes.get("name") );

		if ( attributes.containsKey("host") )
			textHost.setText( (String)attributes.get("host") );
		else
			textHost.setText( "127.0.0.1" );

		if ( attributes.containsKey("port") )
			textPort.setText( (String)attributes.get("port") );
		else
			textPort.setText( "27017" );
			
		if ( attributes.containsKey("database") )
			textDatabase.setText( (String)attributes.get("database") );
		
		if ( attributes.containsKey("username") )
			textUsername.setText( (String)attributes.get("username") );
		
		if ( attributes.containsKey("password") )
			textPassword.setText( (String)attributes.get("password") );
		
		if ( attributes.containsKey("sshprivatekey") )
			textPrivateKeyFile.setText( (String)attributes.get("sshprivatekey") );
		
		if ( attributes.containsKey("sshhost") )
			textSSH.setText( (String)attributes.get("sshhost") );
		
		if ( !attributes.containsKey("sshhost") ){
			btnDirectConnection.setSelection(true);
			btnSshConnection.setSelection(false);
			textSSH.setEnabled(false);
			textPrivateKeyFile.setEnabled(false);
		}else{
			btnDirectConnection.setSelection(false);
			btnSshConnection.setSelection(true);
			textSSH.setEnabled(true);
			textPrivateKeyFile.setEnabled(true);
		}
	}
	
	/**
	 * Create contents of the dialog.
	 */
	private void createContents() {
		shlConnectionProperties = new Shell(getParent(), SWT.DIALOG_TRIM | SWT.PRIMARY_MODAL);
		shlConnectionProperties.setSize(450, 394);
		shlConnectionProperties.setText("Connection Properties");
		shlConnectionProperties.setLayout(new BorderLayout(10, 10));
		
		Composite composite = new Composite(shlConnectionProperties, SWT.NONE);
		composite.setLayoutData(BorderLayout.SOUTH);
		composite.setLayout(new GridLayout(4, false));
		
		lblStatus = new Label(composite, SWT.NONE);
		GridData gd_lblStatus = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
		gd_lblStatus.widthHint = 236;
		lblStatus.setLayoutData(gd_lblStatus);
		new Label(composite, SWT.NONE);
		
		Button btnNewButton = new Button(composite, SWT.NONE);
		btnNewButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
		btnNewButton.setText("Ok");
		btnNewButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if ( validateAttributes() ){
					result	= true;
					retriveAttributes();
					shlConnectionProperties.close();				
				}
			}
		});
		
		Button btnCancelButton = new Button(composite, SWT.NONE);
		btnCancelButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				result	= false;
				shlConnectionProperties.close();
			}
		});
		btnCancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		btnCancelButton.setText("Cancel");
		
		Composite composite_1 = new Composite(shlConnectionProperties, SWT.NONE);
		composite_1.setLayoutData(BorderLayout.CENTER);
		composite_1.setLayout(new FormLayout());
		
		Group grpServer = new Group(composite_1, SWT.NONE);
		FormData fd_grpServer = new FormData();
		fd_grpServer.top = new FormAttachment(0, 10);
		fd_grpServer.left = new FormAttachment(0, 10);
		fd_grpServer.bottom = new FormAttachment(0, 143);
		fd_grpServer.right = new FormAttachment(0, 434);
		grpServer.setLayoutData(fd_grpServer);
		grpServer.setText("Server");
		grpServer.setLayout(new GridLayout(3, false));
		
		Label lblName = new Label(grpServer, SWT.NONE);
		lblName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblName.setText("Name:");
		
		textName = new Text(grpServer, SWT.BORDER);
		textName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		new Label(grpServer, SWT.NONE);
		
		Label lblHost = new Label(grpServer, SWT.NONE);
		lblHost.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblHost.setText("Host:");
		
		textHost = new Text(grpServer, SWT.BORDER);
		textHost.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		new Label(grpServer, SWT.NONE);
		
		Label lblPort = new Label(grpServer, SWT.NONE);
		lblPort.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblPort.setText("Port:");
		
		textPort = new Text(grpServer, SWT.BORDER);
		textPort.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
		new Label(grpServer, SWT.NONE);
		
		Label lblDatabase = new Label(grpServer, SWT.NONE);
		lblDatabase.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblDatabase.setText("Database:");
		
		textDatabase = new Text(grpServer, SWT.BORDER);
		GridData gd_textDatabase = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
		gd_textDatabase.widthHint = 151;
		textDatabase.setLayoutData(gd_textDatabase);
		
		Label lblCanBeBlank = new Label(grpServer, SWT.NONE);
		lblCanBeBlank.setText("may be blank");
		
		Group grpConnection = new Group(composite_1, SWT.NONE);
		grpConnection.setLayout(new GridLayout(5, false));
		FormData fd_grpConnection = new FormData();
		fd_grpConnection.top = new FormAttachment(grpServer, 6);
		fd_grpConnection.left = new FormAttachment(0, 10);
		fd_grpConnection.right = new FormAttachment(0, 434);
		grpConnection.setLayoutData(fd_grpConnection);
		grpConnection.setText("Connection");
		
		Group grpAuthentication = new Group(composite_1, SWT.NONE);
		fd_grpConnection.bottom = new FormAttachment(grpAuthentication, -6);
		
		btnDirectConnection = new Button(grpConnection, SWT.RADIO);
		btnDirectConnection.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				btnDirectConnection.setSelection(true);
				btnSshConnection.setSelection(false);
				textSSH.setEnabled(false);
				textPrivateKeyFile.setEnabled(false);
			}
		});
		btnDirectConnection.setSelection(true);
		btnDirectConnection.setText("Direct Connection");
		new Label(grpConnection, SWT.NONE);
		
		Label lblSsh = new Label(grpConnection, SWT.NONE);
		lblSsh.setToolTipText("user@host(:port)");
		lblSsh.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblSsh.setText("SSH:");
		
		textSSH = new Text(grpConnection, SWT.BORDER);
		textSSH.setToolTipText("user@host(:port)");
		textSSH.setEnabled(false);
		textSSH.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		new Label(grpConnection, SWT.NONE);
		
		btnSshConnection = new Button(grpConnection, SWT.RADIO);
		btnSshConnection.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				btnDirectConnection.setSelection(false);
				btnSshConnection.setSelection(true);
				textSSH.setEnabled(true);
				textPrivateKeyFile.setEnabled(true);
			}
		});
		btnSshConnection.setText("SSH Connection");
		btnSshConnection.setEnabled(false);
		new Label(grpConnection, SWT.NONE);
		
		Label lblPrivateKeyFile = new Label(grpConnection, SWT.NONE);
		lblPrivateKeyFile.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblPrivateKeyFile.setText("Private Key File:");
		
		textPrivateKeyFile = new Text(grpConnection, SWT.BORDER);
		textPrivateKeyFile.setToolTipText("Full pathname to the private key file");
		textPrivateKeyFile.setEnabled(false);
		textPrivateKeyFile.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		
		Button btnPrivateKeyFileBrowse = new Button(grpConnection, SWT.NONE);
		btnPrivateKeyFileBrowse.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				String keyFileName = loadDialog.open();
				if (keyFileName != null) {
					textPrivateKeyFile.setText(keyFileName);
				}
			}
		});
		
		btnPrivateKeyFileBrowse.setEnabled(false);
		btnPrivateKeyFileBrowse.setText("Browse");
		grpAuthentication.setLayout(new GridLayout(2, false));
		FormData fd_grpAuthentication = new FormData();
		fd_grpAuthentication.top = new FormAttachment(0, 240);
		fd_grpAuthentication.bottom = new FormAttachment(100);
		fd_grpAuthentication.left = new FormAttachment(0, 10);
		fd_grpAuthentication.right = new FormAttachment(0, 434);
		grpAuthentication.setLayoutData(fd_grpAuthentication);
		grpAuthentication.setText("Authentication");
		
		Label lblUsername = new Label(grpAuthentication, SWT.NONE);
		lblUsername.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblUsername.setText("Username:");
		
		textUsername = new Text(grpAuthentication, SWT.BORDER);
		textUsername.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		
		Label lblPassword = new Label(grpAuthentication, SWT.NONE);
		lblPassword.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblPassword.setText("Password:");
		
		textPassword = new Text(grpAuthentication, SWT.BORDER);
		textPassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

		loadDialog = new FileDialog(getParent(), SWT.OPEN);
	}
} public class TextInputPopup extends Dialog {

	protected String result = null;

	protected Shell shell;
	private Text text;

	/**
	 * Create the dialog.
	 * @param parent
	 * @param style
	 */
	public TextInputPopup(Shell parent, String title ) {
		super(parent, SWT.DIALOG_TRIM );
		setText( title );
	}

	/**
	 * Open the dialog.
	 * @return the result
	 */
	public String open(String label) {
		createContents(label);
		shell.open();
		shell.layout();
		Display display = getParent().getDisplay();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		return result;
	}

	/**
	 * Create contents of the dialog.
	 */
	private void createContents(String label) {
		shell = new Shell(getParent(), SWT.DIALOG_TRIM);
		shell.setSize(285, 111);
		shell.setText(getText());
		shell.setLayout(new BorderLayout(0, 0));
		
		Composite composite = new Composite(shell, SWT.NONE);
		composite.setLayoutData(BorderLayout.CENTER);
		GridLayout gl_composite = new GridLayout(2, false);
		gl_composite.marginBottom = 10;
		gl_composite.marginRight = 10;
		gl_composite.marginTop = 10;
		gl_composite.marginLeft = 10;
		composite.setLayout(gl_composite);
		
		Label lblLabel = new Label(composite, SWT.NONE);
		lblLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblLabel.setText(label);
		
		text = new Text(composite, SWT.BORDER);
		text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		
		Composite composite_1 = new Composite(shell, SWT.NONE);
		composite_1.setLayoutData(BorderLayout.SOUTH);
		composite_1.setLayout(new GridLayout(2, true));
		
		Button btnOk = new Button(composite_1, SWT.NONE);
		btnOk.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				result	= text.getText().trim();
				if ( result.length() == 0 )
					result = null;

				shell.close();
			}
		});
		btnOk.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
		btnOk.setText("Ok");
		
		Button btnCancel = new Button(composite_1, SWT.NONE);
		btnCancel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
		btnCancel.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				shell.close();
			}
		});
		btnCancel.setText("Cancel");
	}
} public class MSwtUtil extends Object {

	public static Text createText( Composite comp ){
		Text txt = new Text(comp, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
		txt.setFont(SWTResourceManager.getFont("Courier New", 9, SWT.NORMAL));
		txt.setTabs(2);
		return txt;
	}
	
	public static void addListenerToMenuItems(Menu menu, Listener listener) {
		MenuItem[] itemArray = menu.getItems();
		for (int i = 0; i < itemArray.length; ++i) {
			itemArray[i].addListener(SWT.Selection, listener);
		}
	}

	public static void copyToClipboard(String s) {
		Display display = Display.findDisplay(Thread.currentThread());
		Clipboard clipboard = new Clipboard(display);
		TextTransfer textTransfer = TextTransfer.getInstance();
		clipboard.setContents(new Object[] { s }, new Transfer[] { textTransfer });
		clipboard.dispose();
	}

	public static Image getImage(Device device, String imageFileName) {
		InputStream in = null;
		try {
			in = StreamUtil.getResourceStream("org/aw20/mongoworkbench/eclipse/resources/" + imageFileName);
			ImageData imageData = new ImageData(in);
			return new Image(device, imageData);
		} catch (Exception e) {
			return null;
		} finally {
			StreamUtil.closeStream(in);
		}
	}
	
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.aw20.mongoworkbench.EventWorkBenchManager;
import org.aw20.mongoworkbench.EventWrapper;
import org.aw20.mongoworkbench.MongoCommandListener;
import org.aw20.mongoworkbench.MongoFactory;
import org.aw20.mongoworkbench.command.CollectionCountMongoCommand;
import org.aw20.mongoworkbench.command.CollectionRemoveAllMongoCommand;
import org.aw20.mongoworkbench.command.CollectionStatsMongoCommand;
import org.aw20.mongoworkbench.command.CreateCollectionMongoCommand;
import org.aw20.mongoworkbench.command.CreateDbsMongoCommand;
import org.aw20.mongoworkbench.command.DBStatsMongoCommand;
import org.aw20.mongoworkbench.command.DBserverStatsMongoCommand;
import org.aw20.mongoworkbench.command.DropCollectionMongoCommand;
import org.aw20.mongoworkbench.command.DropDbsMongoCommand;
import org.aw20.mongoworkbench.command.GridFSCreateBucketCommand;
import org.aw20.mongoworkbench.command.GridFSRemoveBucketCommand;
import org.aw20.mongoworkbench.command.MongoCommand;
import org.aw20.mongoworkbench.command.ShowCollectionsMongoCommand;
import org.aw20.mongoworkbench.command.ShowDbsMongoCommand;
import org.aw20.mongoworkbench.command.SystemJavaScriptReadCommand;
import org.aw20.mongoworkbench.command.UseMongoCommand;
import org.aw20.mongoworkbench.eclipse.Activator;
import org.aw20.mongoworkbench.eclipse.dialog.ServerDialog;
import org.aw20.mongoworkbench.eclipse.dialog.TextInputPopup;
import org.aw20.util.MSwtUtil;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
			actionList[ACTION_COLLECTIONMETADATA_NAME].setText( selectedItem.getParentItem().getText() );
			menuManager.add( actionList[ACTION_COLLECTIONMETADATA_NAME] );
			menuManager.add( new Separator() );
			menuManager.add( actionList[ACTION_GRIDFS_CREATE] );

		} else if ( nodeType == NodeType.METADATA && selectedItem.getText().equals("Stored Javascript") ) {
			
			actionList[ACTION_COLLECTIONMETADATA_NAME].setText( selectedItem.getParentItem().getText() );
			menuManager.add( actionList[ACTION_COLLECTIONMETADATA_NAME] );
			menuManager.add( new Separator() );
			menuManager.add( actionList[ACTION_SYSTEMJAVASCRIPT_ADD] );
			menuManager.add( actionList[ACTION_SYSTEMJAVASCRIPT_RELOAD] );

		} else if ( nodeType == NodeType.COLLECTION ) {
			
			actionList[ACTION_COLLECTION_NAME].setText( selectedItem.getText() );
			menuManager.add( actionList[ACTION_COLLECTION_NAME] );
			menuManager.add( new Separator() );
			menuManager.add( actionList[ACTION_COLLECTION_SHOWINDEXES] );
			menuManager.add( actionList[ACTION_COLLECTION_COUNT] );
			menuManager.add( actionList[ACTION_COLLECTION_EMPTY] );
			menuManager.add( actionList[ACTION_COLLECTION_DROP] );
			
		} else if ( nodeType == NodeType.GRIDFS ) {
			
			actionList[ACTION_COLLECTION_NAME].setText( selectedItem.getText() );
			menuManager.add( actionList[ACTION_COLLECTION_NAME] );
			menuManager.add( new Separator() );
			menuManager.add( actionList[ACTION_GRIDFS_DELETE] );
			
		} else if ( nodeType == NodeType.JAVASCRIPT ) {
				
			actionList[ACTION_COLLECTION_NAME].setText( selectedItem.getText() );
			menuManager.add( actionList[ACTION_COLLECTION_NAME] );
			menuManager.add( new Separator() );
			menuManager.add( actionList[ACTION_SYSTEMJAVASCRIPT_DELETE] );
				
		}
		
	}

	
	
	/**
	 * Context Menu was clicked
	 * 
	 * @param type
	 */
	protected	void actionRun( int type ){
		if ( type == ACTION_SERVER_REFRESH || type == ACTION_DATABASE_REFRESH || type == ACTION_COLLECTIONMETADATA_REFRESH ){
			onReload();
		}else if ( type == ACTION_SERVER_DISCONNECT ){
			
			MessageBox messageBox = new MessageBox(parent.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
      messageBox.setMessage("Do you really want to disconnect from this server?\r\n\r\n     " + tree.getSelection()[0].getText() );
      messageBox.setText("Server Disconnect");
      int response = messageBox.open();
      if (response == SWT.YES){
      	String sName	= tree.getSelection()[0].getText();
      	MongoFactory.getInst().removeMongo(sName);
      	tree.getSelection()[0].removeAll();
      }
			
		}else if ( type == ACTION_SERVER_DELETE ){

			MessageBox messageBox = new MessageBox(parent.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
      messageBox.setMessage("Do you really want delete this server connection?\r\n\r\n     " + tree.getSelection()[0].getText() );
      messageBox.setText("Server Delete Confirmation");
      int response = messageBox.open();
      if (response == SWT.YES){
      	TreeItem	selectedItem	= tree.getSelection()[0];
      	String sName	= selectedItem.getText();
      	
      	MongoFactory.getInst().removeMongo(sName);
      	serverList	= Activator.getDefault().removeServerMap(sName);
      	Activator.getDefault().saveServerList(serverList);
      	selectedItem.removeAll();

      	tree.removeAll();
      	drawServerNodes();
      }
			
		}else if ( type == ACTION_SERVER_EDIT ){
			
			TreeItem	selectedItem	= tree.getSelection()[0];
    	String sName	= selectedItem.getText();
    	onConnectSelect( Activator.getDefault().getServerMap(sName) );
			
		}else if ( type == ACTION_SERVER_CREATEDATABASE ){
			
			TextInputPopup	popup	= new TextInputPopup(parent.getShell(), "Create Database");
			String newDbName	= popup.open("Database:");
			if ( newDbName != null ){
      	TreeItem	selectedItem	= tree.getSelection()[0];
      	
  			String sName	= selectedItem.getText();
  			MongoFactory.getInst().setActiveServerDB( sName, newDbName );
  			MongoFactory.getInst().submitExecution( new CreateDbsMongoCommand().setConnection(sName, newDbName) );
			}
			
		}else if ( type == ACTION_SERVER_STATS ){
			
			Activator.getDefault().showView("org.aw20.mongoworkbench.eclipse.view.MDBShowStatistics");
			TreeItem	selectedItem	= tree.getSelection()[0];
			String sName	= selectedItem.getText();
			MongoFactory.getInst().submitExecution( new DBStatsMongoCommand().setConnection(sName) );
			MongoFactory.getInst().submitExecution( new DBserverStatsMongoCommand().setConnection(sName) );

		}else if ( type == ACTION_DATABASE_DROP ){
			
			MessageBox messageBox = new MessageBox(parent.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
      messageBox.setMessage("Do you really want drop this database?\r\n\r\n     " + tree.getSelection()[0].getText() );
      messageBox.setText("Drop Database Confirmation");
      int response = messageBox.open();
      if (response == SWT.YES){
      	
      	TreeItem	selectedItem	= tree.getSelection()[0];
  			String sName	= selectedItem.getParentItem().getText();
  			String sDB		= selectedItem.getText();
  			MongoFactory.getInst().setActiveServerDB( sName, sDB );
  			MongoFactory.getInst().submitExecution( new DropDbsMongoCommand().setConnection(sName, sDB) );