public interface EventWorkBenchListener {

	public void onEventWorkBench( Event event, Object data );
	
} 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 FindOneMongoCommand extends MongoCommand {
	private	DBObject dbo;
	
	@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);
		DBObject cmdMap = parseMongoCommandString(db, cmd);
		
		DBCollection	collection	= db.getCollection(sColl);
		
		// Construct the query
		int argSize	= ((List)cmdMap.get("findOneArg")).size();
		
		if ( argSize == 1 ){
			DBObject ref = (DBObject)((List)cmdMap.get("findOneArg")).get(0);
			dbo = collection.findOne(ref);
		}else if (argSize >= 2) {
			List findArg = (List)cmdMap.get("findOneArg");
			DBObject ref = (DBObject) findArg.get(0);
			DBObject key = (DBObject) findArg.get(1);
			dbo = collection.findOne(ref, key);
		}else
			throw new Exception("no query specified");

		setMessage( "loaded: " + (dbo != null) );
	}

	@Override
	public void parseCommandStr() throws Exception {
		sColl = getCollNameFromAction(cmd, "findOne");
		
		if ( sColl == null || sColl.length() == 0 )
			throw new Exception("failed to determine collection from command");
	}

	public DBObject getDbObject(){
		return dbo;
	}
	
	public boolean hasQueryData(){
		return true;
	}
	
	protected String getCollNameFromAction(String actionStr, String actionName) {
		return getMatchIgnoreCase("^db\\.([^\\(]+)\\." + actionName + "\\(", actionStr);
	}
} public class GridFSRemoveFileCommand extends MongoCommand {

	private String id;
	
	public GridFSRemoveFileCommand(String id) {
		this.id = id;
	}

	@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.substring(0,sColl.lastIndexOf(".")) );
		gfs.remove( new ObjectId(id) );

		setMessage("fileRemoved="+id);
	}

	public String getCommandString() {
		return "aw20.gridfs." + sColl.substring(0,sColl.lastIndexOf(".")) + ".remove(" + id + ")";
	}
	
} 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 SaveMongoCommand extends FindMongoCommand {

	private Object	id = 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);
		BasicDBObject cmdMap	= parseMongoCommandString(db, cmd);
		
		if ( !cmdMap.containsField("saveArg") )
			throw new Exception("no save document");
		
		DBObject	document				= fixNumbers( (BasicDBObject)cmdMap.get("saveArg") );
		DBCollection	collection	= db.getCollection(sColl);
		
		// Run the command
		db.requestStart();
		WriteResult writeresult;
		try{
			writeresult = collection.save(document, WriteConcern.JOURNAL_SAFE);
			id	= document.get("_id");
		}finally{
			db.requestDone();
		}

		// Get the result
		Map mwriteresult	= (Map)JSON.parse( writeresult.toString() );
		mwriteresult.put("exeDate", new Date() );
		
		EventWorkBenchManager.getInst().onEvent( Event.WRITERESULT, mwriteresult );
		
		setMessage( "Saved: updatedExisting=" + mwriteresult.get("updatedExisting") + "; documentsUpdated=" + mwriteresult.get("n") );
	}
	
	public Object	getObjectId(){
		return id;
	}
	
	@Override
	public void parseCommandStr() throws Exception {
		sColl = getCollNameFromAction(cmd, "save");
		
		if ( sColl == null || sColl.length() == 0 )
			throw new Exception("failed to determine collection from command");
	}
} public class TreeRender {
	
	private static Image oidImage;
	private static Image intImage;
	private static Image doubleImage;
	private static Image stringImage;
	private static Image dateImage;
	private static Image longImage;
	private static Image boolImage;
	private static Image listImage;
	private static Image mapImage;
	private static Image nullImage;
	private static Image jsImage;

	private Tree	tree;
	
	
	public TreeRender(Device device, Tree tree ){
		this( device, tree, true );
	}
	
	public TreeRender(Device device, Tree tree, boolean showType ){
		this.tree = tree;
		
		if ( oidImage == null ){
			oidImage 			= MSwtUtil.getImage(device, "bullet_star.png");
			intImage 			= MSwtUtil.getImage(device, "bullet_blue.png");
			longImage 		= MSwtUtil.getImage(device, "bullet_red.png");
			doubleImage 	= MSwtUtil.getImage(device, "bullet_orange.png");
			stringImage 	= MSwtUtil.getImage(device, "bullet_green.png");
			dateImage 		= MSwtUtil.getImage(device, "bullet_white.png");
			boolImage 		= MSwtUtil.getImage(device, "bullet_yellow.png");
			listImage 		=	MSwtUtil.getImage(device, "stop_blue.png");
			mapImage 			= MSwtUtil.getImage(device, "stop_green.png");
			nullImage 		= MSwtUtil.getImage(device, "bullet_black.png");
			jsImage 			= MSwtUtil.getImage(device, "bullet_right.png");
		}
		
		tree.setHeaderVisible(true);
		tree.setLinesVisible(true);
		
		TreeColumn trclmnNewColumn = new TreeColumn(tree, SWT.NONE);
		trclmnNewColumn.setWidth(120);
		trclmnNewColumn.setText("Key");

		TreeColumn trclmnNewColumn2 = new TreeColumn(tree, SWT.NONE);
		trclmnNewColumn2.setWidth(150);
		trclmnNewColumn2.setText("Value");
		
		if ( showType ){
			TreeColumn trclmnNewColumn3 = new TreeColumn(tree, SWT.NONE);	
			trclmnNewColumn3.setWidth(55);
			trclmnNewColumn3.setText("Type");
		}
		
		tree.pack();
	}
	
	
	public void	render( Object data ){
		tree.removeAll();
		
		if ( data == null )
			return;
		
		if ( data instanceof Map ){
			
			Map	map	= (Map)data;
			if ( map.size() == 0 )
				return;
			drawItem("", null, map, (map.size() < 35) );
			
		}else if (data instanceof List){
			
			List list	= (List)data;
			if ( list.size() == 0 )
				return;
			
			drawItem("", null, list, (list.size() < 35) );

		}
	}
	
	
	private void drawItem(String parentFieldName, TreeItem parentItem, Map data, boolean expand) {
		
		String[] keyArr = (String[])data.keySet().toArray(new String[0]);
		Arrays.sort(keyArr);
		
		for ( String key : keyArr ){
			if (!data.containsKey(key))
				continue;

			Object value = data.get(key);

			TreeItem newItem; 
			if ( parentItem == null )
				newItem = new TreeItem(tree, SWT.SINGLE);
			else
				newItem = new TreeItem(parentItem, SWT.SINGLE);

			String fieldName = parentFieldName + "." + key;
			if ( fieldName.startsWith(".") )
				fieldName = fieldName.substring(1);

			newItem.setData("fieldName", fieldName);
			newItem.setData("value", value);

			if (value == null) {
				newItem.setText(key);
				newItem.setImage(nullImage);
				setItemInfo(newItem, key, value);
			} else if (value instanceof Map) {
				newItem.setText(key);
				newItem.setImage(mapImage);
				newItem.setData("class", Map.class );
				drawItem(fieldName, newItem, (Map) value, expand);
			} else if (value instanceof List) {
				newItem.setText(key);
				newItem.setImage(listImage);
				newItem.setData("class", List.class );
				drawItem(fieldName, newItem, (List) value, expand);
			} else {
				setItemInfo(newItem, key, value);
			}

			if (expand) {
				if ( parentItem != null )
					parentItem.setExpanded(expand);
				
				newItem.setExpanded(expand);
			}
		}
	}
	
	private void drawItem(String parentFieldName, TreeItem parentItem, List data, boolean expand) {
		for (int i = 0; i < data.size(); ++i) {
			TreeItem newItem = new TreeItem(parentItem, SWT.SINGLE);
			Object value = data.get(i);

			String fieldName = parentFieldName + "." + i;
			if (fieldName.startsWith("."))
				fieldName = fieldName.substring(1);
			
			newItem.setData("fieldName", fieldName);
			newItem.setData("value", value);

			if (value == null) {
				newItem.setText("[" + i + "]");
				newItem.setImage(nullImage);
				setItemInfo(newItem, "[" + i + "]", value);
			} else if (value instanceof Map) {
				newItem.setText("[" + i + "]");
				newItem.setImage(mapImage);
				newItem.setData("class", Map.class );
				drawItem(fieldName, newItem, (Map) value, expand);
			} else if (value instanceof List) {
				newItem.setText("[" + i + "]");
				newItem.setImage(listImage);
				newItem.setData("class", List.class );
				drawItem(fieldName, newItem, (List) value, expand);
			} else {
				setItemInfo(newItem, "[" + i + "]", value);
			}

			if (expand) {
				if ( parentItem != null )
					parentItem.setExpanded(expand);

				newItem.setExpanded(expand);
			}
		}
	}

	
	public static void setItemInfo(TreeItem treeItem, String key, Object value) {
		treeItem.setText(0, key);
		treeItem.setText(1, String.valueOf(value) );
		
		if (value instanceof Integer) {
			treeItem.setImage(intImage);
			treeItem.setText(2, "int32" );	
			treeItem.setData("class", Integer.class );
		} else if (value instanceof Long) {
			treeItem.setImage(longImage);
			treeItem.setText(2, "int64" );
			treeItem.setData("class", Long.class );
		} else if (value instanceof Double) {
			treeItem.setImage(doubleImage);
			treeItem.setText(2, "double" );	
			treeItem.setData("class", Double.class );
		} else if (value instanceof Date) {
			treeItem.setImage(dateImage);
			treeItem.setText(2, "date" );
			treeItem.setText(1, DateUtil.getSQLDate( (Date)value ) );
			treeItem.setData("class", Date.class );
		} else if (value instanceof String) {
			treeItem.setImage(stringImage);
			treeItem.setText(2, "string" );
			treeItem.setData("class", String.class );
		} else if (value instanceof ObjectId) {
			treeItem.setImage(oidImage);
			treeItem.setText(2, "objectId" );
			treeItem.setData("class", ObjectId.class );
		} else if (value instanceof Boolean) {
			treeItem.setImage(boolImage);
			treeItem.setText(2, "boolean" );
			treeItem.setData("class", Boolean.class );
		} else if (value instanceof Code) {
			treeItem.setImage(jsImage);
			treeItem.setText(2, "code" );
			treeItem.setData("class", Code.class );
		} else if (value instanceof Pattern) {
			treeItem.setImage(jsImage);
			treeItem.setText(2, "regex" );
			treeItem.setData("class", Pattern.class );
		} else if ( value instanceof byte[] ){
			treeItem.setImage(jsImage);
			treeItem.setText(2, "binary" );
			treeItem.setText(1, "[bin " + ((byte[])value).length + " bytes]" );
			treeItem.setData("class", Byte.class );
		}
	}
} public class TreeWalker {

	/**
	 * Walks the Tree creating the object model 
	 * 
	 * @param tree
	 * @return
	 */
	public static Map<String, Object> toObject( Tree tree ){
		return fromMap( tree.getItems() );
	}
	
	
	private static Object toObject(TreeItem item){
		Class nodeClass = (Class)item.getData("class");
		
		if ( nodeClass == String.class ){
			return item.getText(1);
		} else if ( nodeClass == Boolean.class ){
			return StringUtil.toBoolean( item.getText(1), false );
		} else if ( nodeClass == Integer.class ){
			return StringUtil.toInteger( item.getText(1), Integer.MIN_VALUE);
		} else if ( nodeClass == Long.class ){
			return StringUtil.toLong(item.getText(1), Long.MIN_VALUE);
		} else if ( nodeClass == Double.class ){
			return StringUtil.toDouble(item.getText(1), Double.MIN_VALUE);
		} else if ( nodeClass == Date.class ){
			return DateUtil.parseDate(item.getText(1), "yyyy-MM-dd HH:mm:ss");
		} else if ( nodeClass == Code.class ){
			return new Code( item.getText(1) );
		} else if ( nodeClass == ObjectId.class ){
			return new ObjectId( item.getText(1) );
		} else if ( nodeClass == Pattern.class ){
			return Pattern.compile(item.getText(1));
		} else if ( nodeClass == Byte.class ){
		//TODO
			return null;
		} else
			return item.getText(1);
	}
	
	
	private static Map<String, Object> fromMap(TreeItem items[]){
		Map<String, Object>	map	= new HashMap<String, Object>();
		
		for ( int x=0; x<items.length; x++ ){
			TreeItem item	= items[x];
			
			Class nodeClass = (Class)item.getData("class");
			
			if ( nodeClass == null ){
				map.put( item.getText(0), null);
			} else if ( nodeClass == Map.class ){
				map.put( item.getText(0), fromMap(item.getItems()) );
			} else if ( nodeClass == List.class ){
				map.put( item.getText(0), fromList(item.getItems()) );
			} else {
				map.put( item.getText(0), toObject(item) );
			}

		}
		
		return map;
	}
	
	
	private static List<Object> fromList(TreeItem items[]){
		List<Object>	list = new ArrayList<Object>();
		
		for ( int x=0; x<items.length; x++ ){
			TreeItem item	= items[x];
			
			Class nodeClass = (Class)item.getData("class");
			
			if ( nodeClass == null ){
				list.add(null);
			} else if ( nodeClass == Map.class ){
				list.add( fromMap(item.getItems()) );
			} else if ( nodeClass == List.class ){
				list.add( fromList(item.getItems()) );
			} else {
				list.add( toObject(item) );
			}

		}

		return list;
	}
		
} public class JSONFormatter extends Object {

	private StringBuilder sb;
	private String tab;
	private String nl = System.getProperty("line.separator");

	public static String format( Object object ){
		return new JSONFormatter().parseObject(object);
	}
	
	public JSONFormatter() {
		this("  ");
	}
	
	public JSONFormatter(String _tab) {
		this.tab = _tab;
	}
	
	/**
	 * Treats a List, Map, String, Integer, Long, Float, Double, or Boolean as a JSON Object and formats it in JSON format.
	 * 
	 * Unrecognized Object Types will be marked "binary-object"
	 * 
	 * @param _o A valid object to be parsed may be a Boolean, Integer, Float, String, or Map or List containing any of the other object
	 * @return Formatted Json
	 */
	public String parseObject(Object _o) {
		sb = new StringBuilder(256);
		parseValue(_o);
		return sb.toString();
	}
	
	private void parseValue(Object _o) {
		parseValue(_o, 0);
	}
	
	private void parseValue(Object _o, int _depth) {
		
		if ( _o instanceof String || _o instanceof Character ){
			sb.append("\"" + _o.toString() + "\"");
		} else if (_o instanceof Map) {
			sb.append("{");
			parseObject((Map<String, Object>)_o, _depth + 1);
			sb.append("}");
		} else if (_o instanceof List) {
			sb.append("[");
			parseArray((List)_o, _depth + 1);
			sb.append("]");
		} else if (_o instanceof Float || _o instanceof Double) {
			String d = String.valueOf(_o);
			if ( d.endsWith(".0") )
				sb.append(d.substring(0,d.length()-2));
			else
				sb.append(d);
		} else if (_o instanceof Integer || _o instanceof Long || _o instanceof Boolean) {
			sb.append(_o.toString());
		} else if (_o == null) {
			sb.append("null");
		} else if ( _o instanceof Date ){
			sb.append( "ISODate(\"" );
			sb.append( DateUtil.getDateString( (Date)_o, "yyyy-MM-dd'T'HH:mm:ss.SSS") );
			sb.append( "Z\")");
		} else if ( _o instanceof ObjectId ){
			sb.append( "ObjectId(\"" );
			sb.append( (ObjectId)_o );
			sb.append( "\")");
		} else if ( _o instanceof Pattern ){
			sb.append( "/" );
			sb.append( (Pattern)_o );
			sb.append( "/");
		} else if ( _o instanceof byte[] ){	
			sb.append( "BinData(0,\"" );
			sb.append( Base64.encodeBytes((byte[])_o) );
			sb.append( "\")");
		} else {
			sb.append( _o.getClass().getName() );
		}
	}
	
	private void parseObject(Map<String, Object> _map, int _depth) {
		String margin = getMargin(_depth);
		
		String[] keyArr = (String[])_map.keySet().toArray(new String[0]);
		Arrays.sort(keyArr);
		for ( String key : keyArr ){
			Object value = _map.get(key);
			
			// Write out this key/value pair
			sb.append(nl)
				.append(margin)
				.append("\"")
				.append( key )
				.append("\" : ");
			parseValue(value, _depth);
			sb.append(",");
		}
		
		// Remove final comma
		if ( sb.charAt(sb.length()-1) == ','){
			sb.delete(sb.length() - 1, sb.length());
			sb.append(nl).append(getMargin(_depth - 1));
		} else {
			sb.append(" ");
		}
	}
	
	private void parseArray(List _list, int _depth) {
		
		// Parse through an array
		boolean empty = true;
		for( Object o : _list) {
			empty = false;
			parseValue(o, _depth);
			sb.append(", ");
		}

		// Remove final comma
		if (!empty)
			sb.delete(sb.length() - 2, sb.length());
		else
			sb.append(" ");
	}
	
	// Gets the margin for the specified _depth level
	private String getMargin(int _depth) {
		StringBuilder margin = new StringBuilder(32);
		for (int i = 0; i < _depth; i++)
			margin.append(this.tab);
		
		return margin.toString();
	}
} public class StringUtil extends Object {

	/**
	 * Takes a string filled with tokens and replaces them with their corresponding value
	 * 
	 * @param _template
	 * @param _keys
	 * @param _values
	 * @return
	 */
	public static String tokenReplace(String _template, String[] _tokens, String[] _values) {
		if ((_values != null && _tokens.length != _values.length) || _template == null)
			return _template;

		int c1 = -1, jump = 0;
		for (int x = 0; x < _tokens.length; x++) {

			c1 = _template.indexOf(_tokens[x]);
			while (c1 != -1) {
				if (_values != null && _values[x] != null) {
					_template = _template.substring(0, c1) + _values[x] + _template.substring(c1 + _tokens[x].length());
					jump = _values[x].length();
				} else {
					_template = _template.substring(0, c1) + _template.substring(c1 + _tokens[x].length());
					jump = 0;
				}

				c1 = _template.indexOf(_tokens[x], c1 + jump);
			}
		}

		return _template;
	}
	
	public static double toDouble(Object _value, double _default) {
		if (_value == null)
			return _default;
		else if (_value instanceof Integer)
			return ((Integer) _value).doubleValue();
		else if (_value instanceof Long)
			return ((Long) _value).doubleValue();
		else if (_value instanceof Double)
			return (Double) _value;
		else if (_value instanceof Float)
			return ((Float) _value).doubleValue();
		else
			return toDouble(_value.toString(), _default);
	}

	public static double toDouble(String _value, double _default) {
		if (_value == null || _value.length() == 0)
			return _default;
		else {
			try {
				return Double.parseDouble(_value);
			} catch (Exception e) {
				return _default;
			}
		}
	}


	/**
	 * Converts a string to an integer, and if unable to do so, returns the default value
	 * 
	 * @param _value
	 * @param _default
	 * @return
	 */
	public static int toInteger(Object _value, int _default) {
		if (_value == null)
			return _default;
		else if (_value instanceof Integer)
			return (Integer) _value;
		else if (_value instanceof Long)
			return ((Long) _value).intValue();
		else if (_value instanceof Double)
			return ((Double) _value).intValue();
		else if (_value instanceof Float)
			return ((Float) _value).intValue();
		else
			return toInteger(_value.toString(), _default, 10);
	}

	public static int toInteger(String _value, int _default) {
		return toInteger(_value, _default, 10);
	}

	public static int toInteger(String _value, int _default, int _radix) {
		if (_value == null || _value.length() == 0)
			return _default;
		else {
			try {
				return Integer.parseInt(_value, _radix);
			} catch (Exception e) {
				return _default;
			}
		}
	}

	public static boolean toBoolean(Object _value, boolean _default) {
		if ( _value == null )
			return _default;
		else if ( _value instanceof Boolean )
			return (Boolean)_value;
		else
			return toBoolean( _value.toString(), _default );
	}
	
	public static boolean toBoolean(String _value, boolean _default) {
		if (_value == null || _value.length() == 0)
			return _default;

		if (_value.equalsIgnoreCase("true"))
			return true;
		else if (_value.equalsIgnoreCase("false"))
			return false;
		else if (_value.equalsIgnoreCase("yes"))
			return true;
		else if (_value.equalsIgnoreCase("no"))
			return false;
		else if (StringUtil.toInteger(_value, 0) >= 1)
			return true;
		else if (StringUtil.toInteger(_value, 0) == 0)
			return false;

		return _default;
	}

	/**
	 * Converts a string to an integer, and if unable to do so, returns the default value
	 * 
	 * @param _value
	 * @param _default
	 * @return
	 */
	public static long toLong(Object _value, long _default) {
		if (_value == null)
			return _default;
		else if (_value instanceof Integer)
			return ((Integer) _value).longValue();
		else if (_value instanceof Long)
			return ((Long) _value);
		else if (_value instanceof Double)
			return ((Double) _value).longValue();
		else if (_value instanceof Float)
			return ((Float) _value).longValue();
		else
			return toLong(_value.toString(), _default, 10);
	}

	public static long toLong(String _value, long _default) {
		return toLong(_value, _default, 10);
	}

	public static long toLong(String _value, long _default, int _radix) {
		if (_value == null || _value.length() == 0)
			return _default;
		else {
			try {
				return Long.parseLong(_value, _radix);
			} catch (Exception e) {
				return _default;
			}
		}
	}

	/**
	 * Tries to cast Object to String. If object is null, it will return null.
	 * 
	 * @param _o
	 * @return String value of _o
	 */
	public static String toString(Object _o) {
		return toString(_o, null);
	}

	/**
	 * Tries to cast Object to String. If object is null, it will return the default value supplied..
	 * 
	 * @param _o
	 * @param _default
	 * @return String value of _o
	 */
	public static String toString(Object _o, String _default) {
		if (_o == null) {
			return _default;
		} else {
			try {
				return (String) _o;
			} catch (ClassCastException e) {
				return _default;
			}
		}
	}

	/**
	 * Removes the tags from a string
	 */
	public static String removeTags(String _str) {
		return _str.replaceAll("</?\\s*(\\w+)(\\s+[\\w-]+=([\\w\\.]+|\"[^\"]*\"|'[^']*'))*\\s*/?>", "");
	}

	/**
	 * Replaces all occurrences of specified characters in a String with the given String replacements
	 * 
	 * @param _src
	 *          The String in which the chars should be replaced
	 * @param _old
	 *          A list of characters to be replaced
	 * @param _new
	 *          A list of Strings to use as replacements. The first String will be used when an occurence of the first char is found, and so on.
	 * @throws IllegalArgumentException
	 *           if the size of the _old and _new arrays don't match
	 * @return String with replacements inserted
	 */
	public static String replaceChars(String _src, char[] _old, String[] _new) {
		if (_old.length != _new.length) {
			throw new IllegalArgumentException("Method misuse: _old.length != _new.length");
		}
		int strLen = _src.length();
		int charsLen = _old.length;
		StringBuffer buffer = new StringBuffer(_src);
		StringWriter writer = new StringWriter(strLen);
		char nextChar;
		boolean foundCh;

		for (int i = 0; i < strLen; i++) {
			nextChar = buffer.charAt(i);
			foundCh = false;

			for (int j = 0; j < charsLen; j++) {
				if (nextChar == _old[j]) {
					writer.write(_new[j]);
					foundCh = true;
				}
			}
			if (!foundCh) {
				writer.write(nextChar);
			}
		}

		return writer.toString();
	}

	/*
	 * Makes an HTML friendly version of the string, escaping the necessary tags > < " '
	 * 
	 * @param str The string of HTML @return String with HTML
	 */
	public static String escapeForHtml(String str) {
		return replaceChars(str, new char[] { '&', '<', '>', '\"' }, new String[] { "&amp;", "&lt;", "&gt;", "&quot;" });
	}

	/**
	 * Decodes back from HTML
	 * 
	 * @param str
	 * @return
	 */
	public static String escapeFromHtml(String str) {
		try {
			return tokenReplace(str, new String[] { "&amp;", "&lt;", "&gt;", "&quot;" }, new String[] { "&", "<", ">", "\"" });
		} catch (Exception e) {
			return str;
		}
	}

	/*
	 * Fully encodes a string for html, replacing characters outwith the a-zA-Z0-9 ranges with the html escaped version
	 * 
	 * from http://www.owasp.org/index.php/How_to_perform_HTML_entity_encoding_in_Java
	 * 
	 * @_html the html string to escape
	 */
	public static StringBuilder escapeHtmlFull(String _html) {
		StringBuilder b = new StringBuilder(_html.length());
		for (int i = 0; i < _html.length(); i++) {
			char ch = _html.charAt(i);
			if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9') {
				// safe
				b.append(ch);
			} else if (Character.isWhitespace(ch)) {
				// paranoid version: whitespaces are unsafe - escape
				// conversion of (int)ch is naive
				b.append("&#").append((int) ch).append(";");
			} else if (Character.isISOControl(ch)) {
				// paranoid version:isISOControl which are not isWhitespace removed !
				// do nothing do not include in output !
			} else {
				// paranoid version
				// the rest is unsafe, including <127 control chars
				b.append("&#" + (int) ch + ";");
			}
		}
		return b;
	}

	/*
	 * Takes a string of items and returns them back as a List object
	 * 
	 * @param str The string list @param delimitor the delimitor of the string list
	 */
	public static List<String> listToList(String str, String delimitor) {
		if (str == null || str.length() == 0)
			return new ArrayList<String>();

		String[] array = listToArray(str, delimitor);
		ArrayList<String> list = new ArrayList<String>();
		for (int x = 0; x < array.length; x++)
			list.add(array[x]);

		return list;
	}

	public static List<String> listToList(String str) {
		return listToList(str, ",");
	}

	/*
	 * Takes a string of items and returns them back as an Array of Strings
	 * 
	 * @param str The string list @param delimitor the delimitor of the string list
	 */
	public static String[] listToArray(String str, String delimitor) {
		if (str == null || str.length() == 0)
			return new String[0];

		return str.split(delimitor);
	}

	public static String[] listToArray(String str) {
		return listToArray(str, ",");
	}

	public static String readToString(Reader _reader) throws IOException {
		StringBuffer sb = new StringBuffer();
		char[] buff = new char[1024];
		int read;
		while ((read = _reader.read(buff)) != -1)
			sb.append(buff, 0, read);
		return sb.toString();

	}

	/**
	 * Takes a string representation of an IP address, a.b.c.d, and converts into a long
	 * 
	 * "192.168.1.1" --> 3232235777
	 * 
	 * @param ipAddress
	 * @return
	 */
	public static long ipStringToLong(String ipAddress) {
		String[] addressParts = ipAddress.split("\\.");
		if (addressParts.length != 4)
			return -1;

		String hexVal = "";
		for (int i = 0; i < 4; i++) {
			int intVal = StringUtil.toInteger(addressParts[i], 0);
			String hexTemp = Integer.toHexString(intVal);
			if (hexTemp.length() < 2) {
				hexTemp = "0" + hexTemp;
			}
			// Builds a String of the hex values for each byte
			hexVal = hexVal + hexTemp;
		}
		return Long.parseLong(hexVal, 16);
	}
}
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.aw20.mongoworkbench.EventWorkBenchListener;
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.FindOneMongoCommand;
import org.aw20.mongoworkbench.command.GridFSRemoveFileCommand;
import org.aw20.mongoworkbench.command.MongoCommand;
import org.aw20.mongoworkbench.command.SaveMongoCommand;
import org.aw20.mongoworkbench.eclipse.view.table.TreeRender;
import org.aw20.mongoworkbench.eclipse.view.table.TreeWalker;
import org.aw20.util.DateUtil;
import org.aw20.util.JSONFormatter;
import org.aw20.util.StringUtil;
import org.bson.types.Code;
import org.bson.types.ObjectId;
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.custom.TreeEditor;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.wb.swt.SWTResourceManager;
			} else if ( newtype.equals("regex") ){

				item.setData( "class", Pattern.class );
				item.setText( 2,"regex");

			} else if ( nodeClass == Byte.class ){
				
			}

		}
	}
	
	
	private boolean isKeyLegal( String t ){
		if ( t.length() == 0 )
			return false;
		
		for ( int x=0; x < t.length(); x++ ){
			char c = t.charAt(x);
			
			if ( !Character.isLetterOrDigit(c) && c != '_' )
				return false;
		}
		
		return true;
	}
	
	
	private boolean isValidType( String t ){
		for ( int x=0; x < allTypes.length; x++ ){
			if ( t.equals(allTypes[x] ) )
				return true;
		}
		return false;
	}
	
	
	@Override
	public void onEventWorkBench(org.aw20.mongoworkbench.Event event, final Object data) {

		switch (event) {
			case DOCUMENT_VIEW: {
				shell.getDisplay().asyncExec(new Runnable() {
					public void run() {
						redraw((Map) data);
					}
				});
				break;
			}
			case ELEMENT_VIEW: {
				break;
			}
			case WRITERESULT: {
				shell.getDisplay().asyncExec(new Runnable() {
					public void run() {
						writeResult((Map) data);
					}
				});
				break;
			}
			default:
				break;
		}

	}

	protected void writeResult(Map data) {
		wrTreeRender.render(data);
	}

	private void onDelete() {
		if (activeDocumentMap == null)
			return;

		Map m = (Map)activeDocumentMap.get(EventWrapper.DOC_DATA);
		String id = m.get("_id").toString();
		
		MessageBox messageBox = new MessageBox(parent.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
    messageBox.setMessage("Do you delete this document?\r\n\r\n     " + id );
    messageBox.setText("Document Delete");
    int response = messageBox.open();
    if (response == SWT.YES){
	
    	if ( activeDocumentMap.get(EventWrapper.ACTIVE_COLL).toString().endsWith(".files") ){

    		try {
					MongoCommand mcmd = new GridFSRemoveFileCommand(id);
					mcmd.setConnection((String) activeDocumentMap.get(EventWrapper.ACTIVE_NAME),  (String)activeDocumentMap.get(EventWrapper.ACTIVE_DB),  (String)activeDocumentMap.get(EventWrapper.ACTIVE_COLL));
					MongoFactory.getInst().submitExecution(mcmd);
				} catch (Exception e) {
					EventWorkBenchManager.getInst().onEvent(org.aw20.mongoworkbench.Event.EXCEPTION, e);
				}
    		
    	}else{
    	
				try {
					MongoCommand mcmd = MongoFactory.getInst().createCommand("db." + activeDocumentMap.get(EventWrapper.ACTIVE_COLL) + ".remove({_id:ObjectId(\"" + id + "\")})");
					mcmd.setConnection((String) activeDocumentMap.get(EventWrapper.ACTIVE_NAME));
					MongoFactory.getInst().submitExecution(mcmd);
				} catch (Exception e) {
					EventWorkBenchManager.getInst().onEvent(org.aw20.mongoworkbench.Event.EXCEPTION, e);
				}
			
    	}
    }
	}

	
	private void redraw(Map data) {
		btnSave.setEnabled(false);
		btnDelete.setEnabled(false);

		// Update the JSON
		textJSON.setText("");

		activeDocumentMap = data;

		if (activeDocumentMap.get(EventWrapper.DOC_DATA) instanceof Map || activeDocumentMap.get(EventWrapper.DOC_DATA) instanceof List) {
			//DB db = MongoFactory.getInst().getMongoActiveDB();
			//textJSON.setText((String) db.eval("tojson(arguments[0])", new Object[] { activeDocumentMap.get(EventWrapper.DOC_DATA) }));
			textJSON.setText( JSONFormatter.format(activeDocumentMap.get(EventWrapper.DOC_DATA)) );