<commit_before>package rhomobile;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.io.HttpConnection;

import net.rim.blackberry.api.browser.Browser;
import net.rim.device.api.browser.field.BrowserContent;
import net.rim.device.api.browser.field.BrowserContentChangedEvent;
import net.rim.device.api.browser.field.Event;
import net.rim.device.api.browser.field.RedirectEvent;
import net.rim.device.api.browser.field.RenderingApplication;
import net.rim.device.api.browser.field.RenderingException;
import net.rim.device.api.browser.field.RenderingOptions;
import net.rim.device.api.browser.field.RenderingSession;
import net.rim.device.api.browser.field.RequestedResource;
import net.rim.device.api.browser.field.UrlRequestedEvent;
import net.rim.device.api.io.http.HttpHeaders;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.ApplicationManager;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.KeyListener;
import net.rim.device.api.system.SystemListener;
import net.rim.device.api.system.TrackwheelListener;
import net.rim.device.api.ui.ContextMenu;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.Status;
import net.rim.device.api.ui.container.MainScreen;

import com.rho.RhoClassFactory;
import com.rho.RhoConf;
import com.rho.RhoEmptyLogger;
import com.rho.RhoLogger;
import com.rho.RhoRuby;
import com.rho.location.GeoLocation;
import com.rho.net.RhoConnection;
import com.rho.sync.SyncThread;


/**
 *
 */
final public class RhodesApplication extends UiApplication implements RenderingApplication, SystemListener
{
	// Menu Labels
	public static final String LABEL_HOME = "Home";
	public static final String LABEL_REFRESH = "Refresh";
	public static final String LABEL_SYNC = "Sync";
	public static final String LABEL_OPTIONS = "Options";
	public static final String LABEL_LOG = "Log";
	public static final String LABEL_SEPARATOR = "separator";
	public static final String LABEL_CLOSE = "Close";
	
	private static final RhoLogger LOG = RhoLogger.RHO_STRIP_LOG ? new RhoEmptyLogger() : 
		new RhoLogger("RhodesApplication");

	class CKeyListener  implements KeyListener{

		public boolean keyChar(char key, int status, int time) {
	        if( key == Characters.ENTER ) {
	        
	        	openLink();
	        	return true;
	        }
			return false;
		}

		public boolean keyDown(int keycode, int time) {
			int nKey = Keypad.key(keycode);
			if ( nKey == Keypad.KEY_ESCAPE )
			{
				back();
				return true;
			}

			return false;
		}

		public boolean keyRepeat(int keycode, int time) {return false;}
		public boolean keyStatus(int keycode, int time) {return false;}
		public boolean keyUp(int keycode, int time) {return false;}
    };

    class CTrackwheelListener implements TrackwheelListener{

		public boolean trackwheelClick(int status, int time) {
			openLink();
			return true;
		}

		public boolean trackwheelRoll(int amount, int status, int time) {return false;}
		public boolean trackwheelUnclick(int status, int time) {return false;}
    }

    /*class SyncNotificationsImpl extends SyncNotifications{
    	public void performNotification(String url, String body){

    		HttpHeaders headers = new HttpHeaders();
    		headers.addProperty("Content-Type", "application/x-www-form-urlencoded");
    		postUrl(url, body, headers);
*/
/*    		String curUrl = (String)_history.lastElement();
    		curUrl.replace('\\', '/');
    		if ( curUrl.equalsIgnoreCase(url) )
    			navigateUrl(curUrl);*/

  //  	}

    //}

    String canonicalizeURL( String url ){
		if ( url == null || url.length() == 0 )
			return "";

		url.replace('\\', '/');
		if ( !url.startsWith(_httpRoot) ){
    		if ( url.charAt(0) == '/' )
    			url = _httpRoot.substring(0, _httpRoot.length()-1) + url;
    		else
    			url = _httpRoot + url;
		}

		return url;
    }

    void navigateUrl(String url){
    	PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(
        		canonicalizeURL(url), null, null, null, this);
        thread.start();                       
    }
    
	public String getPathForMenuItem(String url) {
		url = _httpRoot +
			url.substring(url.charAt(0) == '\\' || url.charAt(0) == '/' ? 1 : 0 );
		return url;
	}
    
    void addMenuItem(String label, String value){
    	LOG.TRACE("Adding menu item: label: " + label + ", value: " + value);
    	_mainScreen.addCustomMenuItem(label, value);
    }
    
    void resetMenuItems() {
    	_mainScreen.setMenuItems(new Vector());
    }

    public void postUrl(String url, String body, HttpHeaders headers){
        PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(
        		canonicalizeURL(url), headers, body.getBytes(), null, this);
        thread.start();                       
    }

    void saveCurrentLocation(String url) {
    	if (RhoConf.getInstance().getBool("KeepTrackOfLastVisitedPage")) {
			RhoConf.getInstance().setString("LastVisitedPage",url);
			RhoConf.getInstance().saveToFile();
			LOG.TRACE("Saved LastVisitedPage: " + url);
		}   	
    }

    boolean restoreLocation() {
    	LOG.TRACE("Restore Location to LastVisitedPage");
    	if (RhoConf.getInstance().getBool("KeepTrackOfLastVisitedPage")) {
			String url = RhoConf.getInstance().getString("LastVisitedPage");
			if (url.length()>0) {
				LOG.TRACE("Navigating to LastVisitedPage: " + url);
				this.navigateUrl(url);
				return true;
			}
		} 
		return false;
    }
   
    void back(){
    	if ( _history.size() <= 1 )
    		return;

    	int nPos = _history.size()-2;
    	String url = (String)_history.elementAt(nPos);
    	_history.removeElementAt(nPos+1);

    	saveCurrentLocation(url);
    	
    	navigateUrl(url);
    }

    void addToHistory(String strUrl, String refferer ){
    	int nPos = -1;
    	for( int i = _history.size()-1; i >= 0; i-- ){
    		if ( strUrl.equalsIgnoreCase((String)_history.elementAt(i)) ){
    			nPos = i;
    			break;
    		}
    		/*String strUrl1 = strUrl + "/index";
    		if ( strUrl1.equalsIgnoreCase((String)_history.elementAt(i)) ){
    			nPos = i;
    			break;
    		}*/
    		if ( refferer != null && refferer.equalsIgnoreCase((String)_history.elementAt(i)) ){
    			nPos = i;
    			break;
    		}

    	}
    	if ( nPos == -1 ){
    		boolean bReplace = RhoConnection.findIndex(strUrl) != -1;

    		if ( bReplace )
    			_history.setElementAt(strUrl, _history.size()-1 );
    		else
    			_history.addElement(strUrl);
    	}
    	else{
    		_history.setSize(nPos+1);
    		_history.setElementAt(strUrl, _history.size()-1 );
    	}
    	saveCurrentLocation(strUrl);
    }

    void openLink(){
    	Menu menu = _mainScreen.getMenu(0);
        int size = menu.getSize();
        for(int i=0; i<size; i++)
        {
            MenuItem item = menu.getItem(i);
            String label = item.toString();
            if(label.equalsIgnoreCase("Get Link")) //TODO: catch by ID?
            {
              item.run();
            }
        }
    }

	private static final String REFERER = "referer";

    private RenderingSession _renderingSession;

    private CMainScreen _mainScreen = null;

    private HttpConnection  _currentConnection;

    private Vector _history;

    private final String _httpRoot = "http://localhost:8080/";

    private boolean _isFullBrowser = false;
    
    private static PushListeningThread _pushListeningThread = null;
    
    private static RhodesApplication _instance;

    public static RhodesApplication getInstance(){ return _instance; }
    /***************************************************************************
     * Main.
     **************************************************************************/
    public static void main(String[] args)
    {
    	//RhoLogger.InitRhoLog();
    	//LOG.TRACE("Rhodes MAIN started ***--------------------------***");
    	
    	//_pushListeningThread = new PushListeningThread();
    	//_pushListeningThread.start();
    	
		_instance = new RhodesApplication();
		_instance.enterEventDispatcher();
		_pushListeningThread.stop();
		
        RhoLogger.close();
		//LOG.TRACE("Rhodes MAIN exit ***--------------------------***");
    }

    void doClose(){   	
    	LOG.TRACE("Rhodes DO CLOSE ***--------------------------***");
/*    	
		SyncEngine.stop(null);
		GeoLocation.stop();
        RhoRuby.RhoRubyStop();
        
    	try{
    		RhoClassFactory.getNetworkAccess().close();
    	}catch(IOException exc){
    		LOG.ERROR(exc);
    	}
*/
    }

	public void activate() {
    	LOG.TRACE("Rhodes activate ***--------------------------***");
//		SyncEngine.start(null);
    	try{
    		GeoLocation.start();
    	}catch(Exception exc){
    		LOG.ERROR("GeoLocation failed to start", exc);
    	}

		super.activate();
	}

	public void deactivate() {
    	LOG.TRACE("Rhodes deactivate ***--------------------------***");		
//		SyncEngine.stop(null);
		GeoLocation.stop();

		super.deactivate();
	}

    class CMainScreen extends MainScreen{
    	
    	private Vector menuItems = new Vector();

		private MenuItem homeItem = new MenuItem(RhodesApplication.LABEL_HOME, 200000, 10) {
			public void run() {
					navigateHome();
				}
			};
		private MenuItem refreshItem = new MenuItem(RhodesApplication.LABEL_REFRESH, 200000, 10) {
			public void run() {
				refreshCurrentPage();
				}
			};
		private MenuItem syncItem = new MenuItem(RhodesApplication.LABEL_SYNC, 200000, 10) {
			public void run() {
					SyncThread.doSyncAllSources();
				}
			};
		private MenuItem optionsItem = new MenuItem(RhodesApplication.LABEL_OPTIONS, 200000, 10) {
			public void run() {
					String curUrl = RhoRuby.getOptionsPage();
					curUrl = getPathForMenuItem(curUrl);

					addToHistory(curUrl, null );
			    	
					navigateUrl(curUrl);
				}
			};
		private MenuItem logItem = new MenuItem(RhodesApplication.LABEL_LOG, 200000, 10) {
			public void run() {
					LogScreen screen = new LogScreen();
			        //Push this screen to display it to the user.
			        UiApplication.getUiApplication().pushScreen(screen);
				}
			};

		private MenuItem separatorItem = MenuItem.separator(200000);
		
		private MenuItem closeItem = new MenuItem(RhodesApplication.LABEL_CLOSE, 200000, 10) {
			public void run() {
					close();
				}
			};

		protected void makeMenu(Menu menu, int instance) {
	        // TODO: This is really a hack, we should replicate the "Get Link" functionality
			// Also, for some reason the menu size becomes 0 when there is 1 item left (page view)
	    	for(int i=0; i < menu.getSize(); i++) {
	    		System.out.println("Getting menu item: " + i);
	    	    MenuItem item = menu.getItem(i);
	    	    String label = item.toString();
	    	    if(!label.equalsIgnoreCase("Get Link")) {
	    	    	menu.deleteItem(i);
	                if ( i > 0 ) 
	                	i = i - 1;
	    	    }
	    	}
			// Remove default items
			//menu.deleteAll();
			// Delete Page View
	    	// TODO: menu.getSize() above incorrectly reports size 0 when
	    	// there is 1 item left!
	    	MenuItem pgview = menu.getItem(0);
	    	if (pgview != null && pgview.getId() == 853)
	    		menu.deleteItem(0);
	    	
			ContextMenu contextMenu = ContextMenu.getInstance();
	        contextMenu.clear();
	        
			// Draw default menu
			if (menuItems == null || menuItems.size() == 0) {
				setDefaultItemToMenu(RhodesApplication.LABEL_HOME, homeItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_REFRESH, refreshItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_SYNC, syncItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_OPTIONS, optionsItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_LOG, logItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_SEPARATOR, separatorItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_CLOSE, closeItem, contextMenu);
			}

			// Draw menu from rhodes framework
			Enumeration elements = menuItems.elements();
			while (elements.hasMoreElements()) {
				MenuItem item = (MenuItem)elements.nextElement();
				contextMenu.addItem(item);
			}
		
			this.makeContextMenu(contextMenu);
			menu.add(contextMenu);
		}
		
		public void addCustomMenuItem(String label, final String value) {
			// Is this a default item? If so, use the existing menu item we have.
    	    if (value.equalsIgnoreCase(RhodesApplication.LABEL_HOME)) {
    	    	setDefaultItemToMenuItems(label, homeItem);
    	    } else if (value.equalsIgnoreCase(RhodesApplication.LABEL_REFRESH)) {
    	    	setDefaultItemToMenuItems(label, refreshItem);
    	    } else if (value.equalsIgnoreCase(RhodesApplication.LABEL_SYNC)) {<commit_msg>support :back menu item [#792]<commit_after>package rhomobile;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.io.HttpConnection;

import net.rim.blackberry.api.browser.Browser;
import net.rim.device.api.browser.field.BrowserContent;
import net.rim.device.api.browser.field.BrowserContentChangedEvent;
import net.rim.device.api.browser.field.Event;
import net.rim.device.api.browser.field.RedirectEvent;
import net.rim.device.api.browser.field.RenderingApplication;
import net.rim.device.api.browser.field.RenderingException;
import net.rim.device.api.browser.field.RenderingOptions;
import net.rim.device.api.browser.field.RenderingSession;
import net.rim.device.api.browser.field.RequestedResource;
import net.rim.device.api.browser.field.UrlRequestedEvent;
import net.rim.device.api.io.http.HttpHeaders;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.ApplicationManager;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.KeyListener;
import net.rim.device.api.system.SystemListener;
import net.rim.device.api.system.TrackwheelListener;
import net.rim.device.api.ui.ContextMenu;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.Status;
import net.rim.device.api.ui.container.MainScreen;

import com.rho.RhoClassFactory;
import com.rho.RhoConf;
import com.rho.RhoEmptyLogger;
import com.rho.RhoLogger;
import com.rho.RhoRuby;
import com.rho.location.GeoLocation;
import com.rho.net.RhoConnection;
import com.rho.sync.SyncThread;


/**
 *
 */
final public class RhodesApplication extends UiApplication implements RenderingApplication, SystemListener
{
	// Menu Labels
	public static final String LABEL_HOME = "Home";
	public static final String LABEL_REFRESH = "Refresh";
	public static final String LABEL_BACK = "Back";
	public static final String LABEL_SYNC = "Sync";
	public static final String LABEL_OPTIONS = "Options";
	public static final String LABEL_LOG = "Log";
	public static final String LABEL_SEPARATOR = "separator";
	public static final String LABEL_CLOSE = "Close";
	
	private static final RhoLogger LOG = RhoLogger.RHO_STRIP_LOG ? new RhoEmptyLogger() : 
		new RhoLogger("RhodesApplication");

	class CKeyListener  implements KeyListener{

		public boolean keyChar(char key, int status, int time) {
	        if( key == Characters.ENTER ) {
	        
	        	openLink();
	        	return true;
	        }
			return false;
		}

		public boolean keyDown(int keycode, int time) {
			int nKey = Keypad.key(keycode);
			if ( nKey == Keypad.KEY_ESCAPE )
			{
				back();
				return true;
			}

			return false;
		}

		public boolean keyRepeat(int keycode, int time) {return false;}
		public boolean keyStatus(int keycode, int time) {return false;}
		public boolean keyUp(int keycode, int time) {return false;}
    };

    class CTrackwheelListener implements TrackwheelListener{

		public boolean trackwheelClick(int status, int time) {
			openLink();
			return true;
		}

		public boolean trackwheelRoll(int amount, int status, int time) {return false;}
		public boolean trackwheelUnclick(int status, int time) {return false;}
    }

    /*class SyncNotificationsImpl extends SyncNotifications{
    	public void performNotification(String url, String body){

    		HttpHeaders headers = new HttpHeaders();
    		headers.addProperty("Content-Type", "application/x-www-form-urlencoded");
    		postUrl(url, body, headers);
*/
/*    		String curUrl = (String)_history.lastElement();
    		curUrl.replace('\\', '/');
    		if ( curUrl.equalsIgnoreCase(url) )
    			navigateUrl(curUrl);*/

  //  	}

    //}

    String canonicalizeURL( String url ){
		if ( url == null || url.length() == 0 )
			return "";

		url.replace('\\', '/');
		if ( !url.startsWith(_httpRoot) ){
    		if ( url.charAt(0) == '/' )
    			url = _httpRoot.substring(0, _httpRoot.length()-1) + url;
    		else
    			url = _httpRoot + url;
		}

		return url;
    }

    void navigateUrl(String url){
    	PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(
        		canonicalizeURL(url), null, null, null, this);
        thread.start();                       
    }
    
	public String getPathForMenuItem(String url) {
		url = _httpRoot +
			url.substring(url.charAt(0) == '\\' || url.charAt(0) == '/' ? 1 : 0 );
		return url;
	}
    
    void addMenuItem(String label, String value){
    	LOG.TRACE("Adding menu item: label: " + label + ", value: " + value);
    	_mainScreen.addCustomMenuItem(label, value);
    }
    
    void resetMenuItems() {
    	_mainScreen.setMenuItems(new Vector());
    }

    public void postUrl(String url, String body, HttpHeaders headers){
        PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(
        		canonicalizeURL(url), headers, body.getBytes(), null, this);
        thread.start();                       
    }

    void saveCurrentLocation(String url) {
    	if (RhoConf.getInstance().getBool("KeepTrackOfLastVisitedPage")) {
			RhoConf.getInstance().setString("LastVisitedPage",url);
			RhoConf.getInstance().saveToFile();
			LOG.TRACE("Saved LastVisitedPage: " + url);
		}   	
    }

    boolean restoreLocation() {
    	LOG.TRACE("Restore Location to LastVisitedPage");
    	if (RhoConf.getInstance().getBool("KeepTrackOfLastVisitedPage")) {
			String url = RhoConf.getInstance().getString("LastVisitedPage");
			if (url.length()>0) {
				LOG.TRACE("Navigating to LastVisitedPage: " + url);
				this.navigateUrl(url);
				return true;
			}
		} 
		return false;
    }
   
    void back(){
    	if ( _history.size() <= 1 )
    		return;

    	int nPos = _history.size()-2;
    	String url = (String)_history.elementAt(nPos);
    	_history.removeElementAt(nPos+1);

    	saveCurrentLocation(url);
    	
    	navigateUrl(url);
    }

    void addToHistory(String strUrl, String refferer ){
    	int nPos = -1;
    	for( int i = _history.size()-1; i >= 0; i-- ){
    		if ( strUrl.equalsIgnoreCase((String)_history.elementAt(i)) ){
    			nPos = i;
    			break;
    		}
    		/*String strUrl1 = strUrl + "/index";
    		if ( strUrl1.equalsIgnoreCase((String)_history.elementAt(i)) ){
    			nPos = i;
    			break;
    		}*/
    		if ( refferer != null && refferer.equalsIgnoreCase((String)_history.elementAt(i)) ){
    			nPos = i;
    			break;
    		}

    	}
    	if ( nPos == -1 ){
    		boolean bReplace = RhoConnection.findIndex(strUrl) != -1;

    		if ( bReplace )
    			_history.setElementAt(strUrl, _history.size()-1 );
    		else
    			_history.addElement(strUrl);
    	}
    	else{
    		_history.setSize(nPos+1);
    		_history.setElementAt(strUrl, _history.size()-1 );
    	}
    	saveCurrentLocation(strUrl);
    }

    void openLink(){
    	Menu menu = _mainScreen.getMenu(0);
        int size = menu.getSize();
        for(int i=0; i<size; i++)
        {
            MenuItem item = menu.getItem(i);
            String label = item.toString();
            if(label.equalsIgnoreCase("Get Link")) //TODO: catch by ID?
            {
              item.run();
            }
        }
    }

	private static final String REFERER = "referer";

    private RenderingSession _renderingSession;

    private CMainScreen _mainScreen = null;

    private HttpConnection  _currentConnection;

    private Vector _history;

    private final String _httpRoot = "http://localhost:8080/";

    private boolean _isFullBrowser = false;
    
    private static PushListeningThread _pushListeningThread = null;
    
    private static RhodesApplication _instance;

    public static RhodesApplication getInstance(){ return _instance; }
    /***************************************************************************
     * Main.
     **************************************************************************/
    public static void main(String[] args)
    {
    	//RhoLogger.InitRhoLog();
    	//LOG.TRACE("Rhodes MAIN started ***--------------------------***");
    	
    	//_pushListeningThread = new PushListeningThread();
    	//_pushListeningThread.start();
    	
		_instance = new RhodesApplication();
		_instance.enterEventDispatcher();
		_pushListeningThread.stop();
		
        RhoLogger.close();
		//LOG.TRACE("Rhodes MAIN exit ***--------------------------***");
    }

    void doClose(){   	
    	LOG.TRACE("Rhodes DO CLOSE ***--------------------------***");
/*    	
		SyncEngine.stop(null);
		GeoLocation.stop();
        RhoRuby.RhoRubyStop();
        
    	try{
    		RhoClassFactory.getNetworkAccess().close();
    	}catch(IOException exc){
    		LOG.ERROR(exc);
    	}
*/
    }

	public void activate() {
    	LOG.TRACE("Rhodes activate ***--------------------------***");
//		SyncEngine.start(null);
    	try{
    		GeoLocation.start();
    	}catch(Exception exc){
    		LOG.ERROR("GeoLocation failed to start", exc);
    	}

		super.activate();
	}

	public void deactivate() {
    	LOG.TRACE("Rhodes deactivate ***--------------------------***");		
//		SyncEngine.stop(null);
		GeoLocation.stop();

		super.deactivate();
	}

    class CMainScreen extends MainScreen{
    	
    	private Vector menuItems = new Vector();

		private MenuItem homeItem = new MenuItem(RhodesApplication.LABEL_HOME, 200000, 10) {
			public void run() {
					navigateHome();
				}
			};
		private MenuItem refreshItem = new MenuItem(RhodesApplication.LABEL_REFRESH, 200000, 10) {
			public void run() {
					refreshCurrentPage();
				}
			};
		private MenuItem backItem = new MenuItem(RhodesApplication.LABEL_BACK, 200000, 10) {
			public void run() {
					back();
				}
			};
		private MenuItem syncItem = new MenuItem(RhodesApplication.LABEL_SYNC, 200000, 10) {
			public void run() {
					SyncThread.doSyncAllSources();
				}
			};
		private MenuItem optionsItem = new MenuItem(RhodesApplication.LABEL_OPTIONS, 200000, 10) {
			public void run() {
					String curUrl = RhoRuby.getOptionsPage();
					curUrl = getPathForMenuItem(curUrl);

					addToHistory(curUrl, null );
			    	
					navigateUrl(curUrl);
				}
			};
		private MenuItem logItem = new MenuItem(RhodesApplication.LABEL_LOG, 200000, 10) {
			public void run() {
					LogScreen screen = new LogScreen();
			        //Push this screen to display it to the user.
			        UiApplication.getUiApplication().pushScreen(screen);
				}
			};

		private MenuItem separatorItem = MenuItem.separator(200000);
		
		private MenuItem closeItem = new MenuItem(RhodesApplication.LABEL_CLOSE, 200000, 10) {
			public void run() {
					close();
				}
			};

		protected void makeMenu(Menu menu, int instance) {
	        // TODO: This is really a hack, we should replicate the "Get Link" functionality
			// Also, for some reason the menu size becomes 0 when there is 1 item left (page view)
	    	for(int i=0; i < menu.getSize(); i++) {
	    		System.out.println("Getting menu item: " + i);
	    	    MenuItem item = menu.getItem(i);
	    	    String label = item.toString();
	    	    if(!label.equalsIgnoreCase("Get Link")) {
	    	    	menu.deleteItem(i);
	                if ( i > 0 ) 
	                	i = i - 1;
	    	    } 
	    	}
			// Remove default items
			//menu.deleteAll();
			// Delete Page View
	    	// TODO: menu.getSize() above incorrectly reports size 0 when
	    	// there is 1 item left!
	    	MenuItem pgview = menu.getItem(0);
	    	if (pgview != null && pgview.getId() == 853)
	    		menu.deleteItem(0);
	    	
			ContextMenu contextMenu = ContextMenu.getInstance();
	        contextMenu.clear();
	        
			// Draw default menu
			if (menuItems == null || menuItems.size() == 0) {
				setDefaultItemToMenu(RhodesApplication.LABEL_HOME, homeItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_REFRESH, refreshItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_SYNC, syncItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_OPTIONS, optionsItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_LOG, logItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_SEPARATOR, separatorItem, contextMenu);
				setDefaultItemToMenu(RhodesApplication.LABEL_CLOSE, closeItem, contextMenu);
			}

			// Draw menu from rhodes framework
			Enumeration elements = menuItems.elements();
			while (elements.hasMoreElements()) {
				MenuItem item = (MenuItem)elements.nextElement();
				contextMenu.addItem(item);
			}
		
			this.makeContextMenu(contextMenu);
			menu.add(contextMenu);
		}
		
		public void addCustomMenuItem(String label, final String value) {
			// Is this a default item? If so, use the existing menu item we have.
    	    if (value.equalsIgnoreCase(RhodesApplication.LABEL_HOME)) {
    	    	setDefaultItemToMenuItems(label, homeItem);
    	    } else if (value.equalsIgnoreCase(RhodesApplication.LABEL_REFRESH)) {
    	    	setDefaultItemToMenuItems(label, refreshItem);
    	    } else if (value.equalsIgnoreCase(RhodesApplication.LABEL_BACK)) {
    	    	setDefaultItemToMenuItems(label, backItem);
    	    }  else if (value.equalsIgnoreCase(RhodesApplication.LABEL_SYNC)) {
{'fraction_non_alphanumeric': 0.137910085054678, 'fraction_numerical': 0.007632138517618469, 'mean_word_length': 3.0062366899908732, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6436197', 'n_tokens_mistral': 8992, 'n_tokens_neox': 8080, 'n_words': 1726}