package com.oberon.client;
/*
 * Copyright 2008-2014 Mirko Solazzi - OBEROn Platform [www.oberonplatform.com]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

import java.net.URLDecoder;
import java.util.StringTokenizer;
import java.util.Vector;

import com.oberon.client.common.*;
import com.oberon.ooql.connection.ConnectionManager;
import com.oberon.ooql.connection.OBConnection;
import com.oberon.ooql.sdk.Arg;
import com.oberon.ooql.sdk.Dictionary;
import com.oberon.ooql.sdk.FileOperator;
import com.oberon.ooql.sdk.Form;
import com.oberon.ooql.sdk.ObjectObj;
import com.oberon.ooql.sdk.Link;
import com.oberon.ooql.sdk.Stage;
import com.oberon.ooql.sdk.View;
import com.oberon.util.StringUtils;

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;

/**
 * Basic SWT Client
 * 
 * @author Mirko Solazzi
 * @version  5.0
 */
public class OberonClient extends Application {

	public Label statusBar = null;
	public CTabFolder topTabFolder = null;

	/**
	 * Creates the client SWT structure and open the Home page
	 * 
	 * @param mainMenu
	 *          the application main menu; if null the main menu is read from the
	 *          configuration file (is the "application" property in the
	 *          [CONNECTION] section)
	 */
	public OberonClient(String mainMenu) {
		if (display == null || display.isDisposed()) {
			display = new Display();
		}
		application_MainMenu = mainMenu;
		setApp(this);
		appIcon = getIcon("logo_g.png");
		globalfont = loadMonospacedFont(display);
		shell = new Shell(display , Application.ON_TOP | SWT.MIN | SWT.MAX | SWT.RESIZE );
		shell.setText(name);
		shell.setData(this);
		shell.setLocation(70, 70);
		shell.setMenuBar(new org.eclipse.swt.widgets.Menu(shell,SWT.BAR));
		shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
		try {
			shell.setImage(appIcon);
		} catch (Exception e) {
		}
		conf = new Configuration(ConnectionManager.CONFIG_FILE);

		try {
			setWindowWidth(Integer.parseInt(conf.getValue(Application.CONF_VIEW_SECTION, TAGS.CONF_VIEW_width)));
		} catch (Exception e) {
			setWindowWidth(1000);
		}
		try {
			setWindowHeight(Integer.parseInt(conf.getValue(Application.CONF_VIEW_SECTION, TAGS.CONF_VIEW_height)));
		} catch (Exception e) {
			setWindowHeight(600);
		}
		try {
			int iFontSize = Integer.parseInt(conf.getValue(CONF_VIEW_SECTION, TAGS.CONF_VIEW_fontsize));
			FontData[] fD = globalfont.getFontData();
			fD[0].setHeight(iFontSize);
			globalfont = new Font(display, fD);
		} catch (Exception e) {
		}

		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 1;
		gridLayout.marginHeight = gridLayout.marginWidth = 0;
		shell.setLayout(gridLayout);
		shell.setSize(getWindowWidth(), getWindowHeight());

		SashForm sashForm = new SashForm(shell, SWT.NONE);
		sashForm.setOrientation(SWT.HORIZONTAL);
		GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
		sashForm.setLayoutData(gridData);

		// Main Panel
		SashForm mainPanel = new SashForm(sashForm, SWT.NONE);
		mainPanel.setOrientation(SWT.VERTICAL);
		gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
		gridData.verticalSpan = 3;
		mainPanel.setLayoutData(gridData);

		topTabFolder = new CTabFolder(mainPanel, SWT.H_SCROLL);
		topTabFolder.setFont(globalfont);
		topTabFolder.setUnselectedCloseVisible(false);
		topTabFolder.setSimple(false);
		topTabFolder.setBorderVisible(true);
		topTabFolder.setLayoutData(new GridData(GridData.FILL_BOTH));

		// Set up a gradient background for the selected tab
		topTabFolder.setSelectionBackground(
				new Color[] { display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW), display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW),
						display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW) }, new int[] { 50, 100 });
		topTabFolder.setSelectionForeground(display.getSystemColor(SWT.COLOR_WHITE));

		// Status Bar
		SashForm statusPanel = new SashForm(shell, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		statusPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		statusPanel.setLayout(layout);
		statusBar = new Label(statusPanel, SWT.BORDER);
		statusBar.setFont(globalfont);

		shell.open();
		
		// Open Framework
		openConnections();
		if (shell.isDisposed()) {
			return;
		}

		// CSS Styles
		setCSSStyles();

		// Menu Bar
		if (application_MainMenu == null) {
			application_MainMenu = conf.getValue(OBConnection.CONN_SECTION, ConnectionManager.PROP_APPLICATION);
		}
		if (application_MainMenu == null) {
			new SelectApplicationDialog(this);
			if (application_MainMenu != null) {
				selectApplication = true;
			}
		}
		if (application_MainMenu == null) {
			shell.dispose();
			return;
		}

		name = getMenuTranslation(application_MainMenu);
		
		org.eclipse.swt.widgets.Menu menu = null;
		if (framework!=null) {
			menu = createMenu(application_MainMenu);
			shell.setMenuBar(menu);
			shell.setText(name + " [" + framework.getUserName() + "]");
		} else {
			shell.setText(name);
		}			

		handleRequest(new ApplicationRequest(TAGS.PAGE_Home, (ApplicationSession)session));

		shell.addListener(SWT.Close, new Listener() {
			public void handleEvent(Event e) {
				try {
					confirmExit();
				} catch (Exception ex) {
				}
				e.doit = false;
			};
		});
		shell.addDisposeListener(new DisposeListener() {
			public void widgetDisposed(DisposeEvent e) {
				Shell[] shvect = e.display.getShells();
				for (int i = 0; i < shvect.length; i++) {
					if (!e.equals(shvect[i])) {
						try {
							shvect[i].getDisplay().dispose();
						} catch (Exception ex) {
						}
					}
				}
			}
		});

		shell.setFocus();
		log(getCommonTranslation("Ready"));

		if (menu.getItems().length == 0) {
			doChangeUser(new ApplicationRequest("", (ApplicationSession)session));
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Common dialogs
	////////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Open the Framework dialog to login into OBEROn
	 */
	public void setFramework() {
		FrameworkDlg dlg = new FrameworkDlg(this);
		dlg.open(framework,doLogin(null));
	}
	
	private Runnable doLogin(final ApplicationRequest request){
    return new Runnable(){
       public void run(){     	 
     			try {
     				shell.setMenuBar(createMenu(application_MainMenu));
     				name = getMenuTranslation(application_MainMenu);
     				shell.setText(name + " [" + framework.getUserName() + "]");
     				session.removeAttribute(TAGS.sequence);
     			} catch (Exception ex) {
     		 }
     		 if (request!=null) {
     			try {
    				CTabItem[] items = topTabFolder.getItems();
    				for (int i = 0; i < items.length; i++) {
    					items[i].dispose();
    				}
    				Shell[] shvect = shell.getShells();
    				for (int i = 0; i < shvect.length; i++) {
    					if (!shell.equals(shvect[i])) {
    						try {
    							shvect[i].dispose();
    						} catch (Exception ex) {
    						}
    					}
    				}
    				session.removeAttribute(TAGS.sequence);
    				handleRequest(new ApplicationRequest(TAGS.PAGE_Home, request.getSession()));
    			} catch (Exception ex) {}
     		 }	
       }
    };
  }
	

	/**
	 * Open the Password dialog to change the OBEROn password
	 */
	public void setpassword() {
		if (framework != null) {
			PasswordDlg dlg = new PasswordDlg(this);
			dlg.open(framework);
		}
	}

	/**
	 * Ask confirm message when exit from the application
	 */
	public static void confirmExit() throws Exception {
		MessageBox msg = new MessageBox(getApp().shell, SWT.APPLICATION_MODAL | SWT.ICON_WARNING | SWT.OK | SWT.CANCEL);
		msg.setText(getApp().name);
		msg.setMessage(getCommonTranslation("MSG_ConfirmExit"));
		if (msg.open() == SWT.OK)
			try { getApp().shell.dispose(); } catch (Exception ex) {}
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// Application Request Handlers
	// //////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Handle an Application request
	 * 
	 * @return true when the request page is a common page
	 */
	public boolean handleRequest(ApplicationRequest request) {
		String page = request.getRequestPage();
		System.out.println("OPEN " + request);
		if (page.endsWith(TAGS.PAGE_Home)) {
			doHome(request);
		} else if (page.endsWith(TAGS.PAGE_Index) || page.endsWith(TAGS.PAGE_Logout)) {
			doChangeUser(request);
		} else if (page.indexOf(TAGS.FORM_CheckPageOpener+"('") >= 0 || page.indexOf(TAGS.FORM_ActionCloseWindow+"()") >= 0) {
			doClose(request);
		} else if (page.endsWith(TAGS.PAGE_Search)) {
			doSearch(request);
		} else if (page.endsWith(TAGS.PAGE_SearchResults)) {
			doSearchResult(request);
		} else if (page.endsWith(TAGS.PAGE_Select)) {
			doSelect(request);
		} else if (page.indexOf(TAGS.FORM_ActionConnect+"('") >= 0) {
			doConnect(request);
		} else if (page.endsWith(TAGS.PAGE_Edit)) {
			doEdit(request);
		} else if (page.endsWith(TAGS.PAGE_EditLink)) {
			doEditLink(request);
		} else if (page.endsWith(TAGS.PAGE_Lifecycle)) {
			doLifecycle(request);
		} else if (page.endsWith(TAGS.PAGE_Validations)) {
			doValidations(request);
		} else if (page.endsWith(TAGS.PAGE_Navigate)) {
			doNavigate(request);
		} else if (page.endsWith(TAGS.PAGE_SpaceTree)) {
			doSpaceTree(request);
		} else if (page.endsWith(TAGS.PAGE_Files)) {
			doFiles(request);
		} else if (page.endsWith(TAGS.PAGE_Activity)) {
			doActivityList(request);
		} else if (page.endsWith(TAGS.PAGE_ActivityCompletion)) {
			doActivityCompletion(request);
		} else if (page.endsWith(TAGS.PAGE_DoWork)) {
			doWork(request);
		} else if (page.endsWith(TAGS.PAGE_DictionaryReload)) {
			try {
				Dictionary.resetCache(framework);
			} catch (Exception e) {}
		} else {
			return false;
		}
		return true;
	}

	/**
	 * Open the Home page
	 */
	public void doHome(ApplicationRequest request) {
		try {
			String sTitle = getCommonTranslation("Welcome");
			session.removeAttribute(TAGS.Object);
			Composite globalpanel = createPagePanel(sTitle, "", false, request);
			if (globalpanel != null) {
				Composite panel = new Composite(globalpanel, SWT.NONE);
				panel.setLayoutData(new GridData(GridData.FILL_BOTH));

				GridLayout imageLayout = new GridLayout();
				imageLayout.horizontalSpacing = 1;
				panel.setLayout(imageLayout);
				Label bImage = new Label(panel, SWT.CENTER);
				Image homeImg = HTMLUtil.getImage(application_MainMenu + "_home.jpg", 0, 400, session);
				if (homeImg != null && homeImg.getImageData().width > 1) {
					bImage.setImage(homeImg);
				} else {
					try {
						bImage.setImage(getIcon("home.jpg"));
					} catch (Exception ex) {
					}
				}
				bImage.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));

				Text aboutText = new Text(panel, SWT.BORDER | SWT.MULTI | SWT.WRAP);
				aboutText.setFont(globalfont);
				GridData txGD = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
				txGD.minimumHeight = 60;
				aboutText.setLayoutData(txGD);
				String sText = name + "\n";
				sText += "OBEROn Platform [version: " + ConnectionManager.version + " - build " + ConnectionManager.build + "]\n";
				sText += ConnectionManager.copyright;
				aboutText.setEditable(false);
				aboutText.setText(sText);

				addPageToContainer(globalpanel, sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Open the Change User pop-up dialog
	 */
	public void doChangeUser(ApplicationRequest request) {
		FrameworkDlg dlg = new FrameworkDlg(this);
		dlg.open(framework,doLogin(request));
	}

	/**
	 * Close a page or a pop-up dialog
	 */
	public void doClose(ApplicationRequest request) {
		Widget window = getWindow((Control)request.getReferer());
		if ( window instanceof Shell ) {	// POPUP
			Shell popDialog = (Shell) window;
			popDialog.close();
		} else if (window instanceof CTabItem) {
			try {
				// Get TAB Opener
				CTabItem opener = (CTabItem) getData(window,TAGS.OPENER);
				if (opener != null && topTabFolder.getItemCount() > 1) {
					window.dispose();
				} else if (request != null) {
					String page = request.getRequestPage();
					page = StringUtils.getStringPart(page, TAGS.FORM_CheckPageOpener+"('", "')");
					if (page.length() > 0) {
						ApplicationRequest clrequest = new ApplicationRequest(page, request.getSession());
						clrequest.setLocale(request.getLocale());
						handleRequest(clrequest);
					} else {
						window.dispose();
					}
				}
			} catch (Exception ex) {
			}
		}
	}


	/**
	 * Open a search filter page
	 */
	public void doSearch(ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession)request.getSession();
			String sFormName = HTMLUtil.getInputParameter(TAGS.form, request);
			if (sFormName.equals("")) {
				log("NO INPUT FORM");
				return;
			}
			Form form = Form.open(sFormName, framework,null);

			session.removeAttribute(TAGS.view);
			session.removeAttribute(TAGS.sequence);
			String sTitle = getTranslation(sFormName);
			session.removeAttribute(TAGS.Object);

			Composite globalpanel = createPagePanel(sTitle, "", false, request);
			if (globalpanel != null) {
				ScrolledComposite panel = Forms.createSearchForm(globalpanel, TAGS.PAGE_SearchResults, form, request);
				panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				addPageToContainer(globalpanel, sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	
	/**
	 * Open the search result set page
	 */
	public void doSearchResult(final ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession)request.getSession();
			String sFormName = HTMLUtil.getInputParameter(TAGS.form, request);
			if (sFormName.equals("")) {
				log("NO INPUT FORM");
				return;
			}
			session.removeAttribute(TAGS.Object);
			Form form = Form.open(sFormName, framework,null);
			String formHTMLName = Forms.getFormHTMLName(form);

			if (HTMLUtil.getInputParameter(TAGS.frf, request).equals("true")) {
				Forms.clearSearchResults(formHTMLName,session);
				session.removeAttribute(TAGS.view);
				request.setParameter(TAGS.frf, "false");
				handleRequest(request);
				return;
			}

			// Menu Bar
			String sTitle = getTranslation(sFormName + "_results");
			session.removeAttribute(TAGS.Object);
			// Perform Search
			try {
				String sMessage = Forms.searchObjects(form, request);
				if (sMessage.length() > 0) {
					if (sMessage.startsWith(TAGS.FORM_ActionAlert+"(")) {
						sMessage = StringUtils.getStringPart(sMessage, TAGS.FORM_ActionAlert+"(\"", "\");");
					}
					showMessage(shell, sMessage, "", SWT.ICON_WARNING);
				}
				/*
				 * if ( getInputParameter(TAGS.autorefresh,request).length()>0 ) {
				 * setTimeout("reloadData()", getInputParameter(TAGS.autorefresh,request)
				 * ); var clickable = true;
				 */
			} catch (Exception e) {
				log(e.getMessage());
			}
			// List views
			Vector<String> vViews = View.getUserViews(framework);
			Vector<String> vFormViews = StringUtils.StringTokensToVector(HTMLUtil.getInputParameter(TAGS.views, request),"|");
			if (vFormViews.size()>0) {
				for (int i = vViews.size() - 1; i >= 0; i--) {
					if (vFormViews.indexOf((vViews.elementAt(i))) < 0) {
						vViews.removeElementAt(i);
					}
				}
			}
			// int iPageSize = 10;
			// try { iPageSize = Integer.parseInt(
			// HTMLUtil.getInputParameter(TAGS.pagesize,request) ); } catch (Exception e
			// ){}

			boolean bShowViewList = true;
			String sView = HTMLUtil.getInputParameter(TAGS.view, request);
			if (sView.startsWith("(")) {
				sView = sView.substring(1, sView.length() - 1);
				bShowViewList = false;
			}

			Composite globalpanel = createPagePanel(sTitle, "", false, request);
			if (globalpanel != null) {
				ResultSetPanel rst = new ResultSetPanel(globalpanel, request);
				if (bShowViewList && vViews.size() > 0) {
					rst.resetViews(sView, vViews);
				} else {
					rst.applyView(sView);
				}
				session.setAttribute(TAGS.sequence, new Vector<String>());
				rst.process(Forms.getSearchResults(formHTMLName, session), true);

				Table table = rst.getTable();
				setData(table,TAGS.REQUEST, request);
				table.addListener(SWT.MouseUp, new Listener() {
					public void handleEvent(Event e) {
						if (e.button != 3)
							return;
						Table table = ((Table) e.widget);
						TableItem item = table.getItem(new Point(e.x, e.y));
						if (item == null)
							return;
						TableItem[] items = { item };
						table.setSelection(items);
						try {
							org.eclipse.swt.widgets.Menu popup = new org.eclipse.swt.widgets.Menu(table);
							Forms.fillObjectPopUpMenu(popup, table, (String)getData(item,TAGS.ID),null, 
									(ApplicationSession) ((ApplicationRequest) getData(table,TAGS.REQUEST)).getSession());
							if (popup.getItemCount() > 0) {
								Point sh = shell.getLocation();
								Point ch = ((Control) e.widget).getLocation();
					  		popup.setLocation(new Point(Application.computeWidth(20)+sh.x+ch.x+e.x,Application.computeHeight(100)+sh.y+ch.y+e.y));
								popup.setVisible(true);
							}
						} catch (Exception ex) {
						}
					}
				});

				addPageToContainer(globalpanel, sTitle, request);
			}

		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	

	/**
	 * Open a object selection page
	 */
	public void doSelect(final ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = HTMLUtil.getInputParameter(TAGS.id, request);

			String sFormName = HTMLUtil.getInputParameter(TAGS.form, request);
			if (sFormName.equals("")) {
				log("NO INPUT FORM");
				return;
			}
			Form form = Form.open(sFormName, framework,null);
			String formHTMLName = Forms.getFormHTMLName(form);
			session.removeAttribute(TAGS.Object);

			String sTitle = getTranslation(sFormName);

			Composite globalpanel = createPagePanel(sTitle, "", false, request);
			if (globalpanel != null) {
				SashForm sashForm = new SashForm(globalpanel, SWT.NONE);
				sashForm.setOrientation(SWT.VERTICAL);
				GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
				sashForm.setLayoutData(gridData);

				final ScrolledComposite panel = Forms.createSearchForm(sashForm, TAGS.PAGE_Select+"?"+TAGS.id+"="+sID,form,request);
				panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				Forms.clearSearchResults(formHTMLName,session);
				// Perform Search
				try {
					String sMessage = Forms.searchObjects(form, request);
					if (sMessage.length() > 0) {
						if (sMessage.startsWith(TAGS.FORM_ActionAlert+"(")) {
							sMessage = StringUtils.getStringPart(sMessage, TAGS.FORM_ActionAlert+"(\"", "\");");
						}
						showMessage(shell, sMessage, "", SWT.ICON_WARNING);
					}
				} catch (Exception e) {
					log(e.getMessage());
				}
				boolean bMulti = false;
				if (HTMLUtil.getInputParameter(TAGS.multiple, request).equals("true")) {
					bMulti = true;
				}
				ResultSetTable rstTable = new ResultSetTable(getApp(), sashForm, bMulti, new Listener() {
					public void handleEvent(Event e) {
						TableColumn column = (TableColumn) e.widget;
						ResultSetTable.sortColumn(column);
					}
				} ,request.getLocale());

				if (request.getParameter(TAGS.search) != null) {
					final Table table = rstTable.getTable();
					table.setRedraw(false);					
					// List views
					Vector<String> vViews = View.getUserViews(framework);
					// Apply view
					String sView = HTMLUtil.getInputParameter(TAGS.view, request);
					if (sView.startsWith("(")) {
						sView = sView.substring(1, sView.length() - 1);
					}
					if (vViews.indexOf(sView) < 0) {
						sView = "";
					}
					Vector<String> vResult = Forms.getSearchResults(formHTMLName, session);
					rstTable.processResult(vResult, sView);
					if (!sView.equals("")) {
						View view = View.open(sView,framework.getUserName(),framework);
						rstTable.reloadTableData( view, true );
					}
					table.setSortDirection(SWT.DOWN);
					ResultSetTable.sortColumn(table.getColumn(1));
					table.setRedraw(true);

					table.setLayoutData(new GridData(GridData.FILL_BOTH));
					table.addMouseListener(new MouseListener() {
						public void mouseDoubleClick(MouseEvent event) {
							try {
								final TableItem item = table.getSelection()[0];
								String sID = (String)getData(item,TAGS.ID);
								ApplicationRequest fwrequest = new ApplicationRequest(TAGS.PAGE_Edit,request.getSession());
								fwrequest.setParameter(TAGS.id, sID);
								fwrequest.setTarget(TAGS._blank);
								fwrequest.setLocale(request.getLocale());
								fwrequest.setReferer(panel);
								handleRequest(fwrequest);
							} catch (Exception exx) {
							}
						}
						public void mouseDown(MouseEvent event) {	};
						public void mouseUp(MouseEvent event) { }
					});					
				}
				addPageToContainer(globalpanel, sTitle, request);
				setData(getWindow(globalpanel),TAGS.TABLE, rstTable.getTable());
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	
	private void doConnect(ApplicationRequest request) {
		// used with object selection panel
		try {
			Widget window = getWindow((Control)request.getReferer());
			String page = request.getRequestPage();
			page = StringUtils.getStringPart(page, TAGS.FORM_ActionConnect+"('", "')");
			if (page.length() > 0 && page.indexOf("','") > 0) {
				request = (ApplicationRequest) getData(window,TAGS.REQUEST);
				if (request != null) {
					Table table = (Table) getData(window,TAGS.TABLE);
					if (table != null) {
						TableItem[] items = table.getSelection();
						if (items.length == 0) {
							errorMessage(table.getShell(), new Exception(getCommonTranslation("MSG_SelectAtLeastOneObject")), "");
						} else {
							String sID = HTMLUtil.getInputParameter(TAGS.id, request);
							StringTokenizer sT = new StringTokenizer(page, "','");
							String linktype = sT.nextToken();
							String versus = sT.nextToken();
							String objectlist = "";
							for (int i = 0; i < items.length; i++) {
								if (i > 0) {
									objectlist += ",";
								}
								objectlist += getData(items[i],TAGS.ID);
							}
							
							ApplicationRequest fwrequest = new ApplicationRequest(TAGS.PAGE_DoWork,request.getForwardTarget(),request.getSession());
							fwrequest.setParameter(TAGS.id, sID);
							fwrequest.setParameter(TAGS.action, TAGS.FORM_ActionLink);
							fwrequest.setParameter(TAGS.linktype, linktype);
							fwrequest.setParameter(TAGS.versus, versus);
							fwrequest.setParameter(TAGS.list, objectlist);
							fwrequest.setParameter(TAGS.close, "true");	
							fwrequest.setLocale(request.getLocale());
							fwrequest.setReferer(window);
							handleRequest(fwrequest);
						}
					}
				}
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	
	/**
	 * Open a object Create/Edit page
	 */
	public void doEdit(ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession)request.getSession();
			String sID = (request.getParameter(TAGS.id)!=null ? request.getParameter(TAGS.id) : request.getParameter(TAGS._id));
			boolean bCreateNew;
			boolean bClone = false;
			ObjectObj object;

			if (sID == null || sID.length() == 0 || HTMLUtil.getInputParameter(TAGS.create, request).equals("true")) {
				bCreateNew = true;
				session.removeAttribute(TAGS.Object);
				object = new ObjectObj();
			} else {
				sID = sID.trim();
				bCreateNew = false;
				if (HTMLUtil.getInputParameter(TAGS.clone, request).equals("true")) {
					bClone = true;
				}
				object = ObjectObj.open(sID, true,framework);
				session.setAttribute(TAGS.Object, object);
			}

			// Create/Edit Form
			String sFormName = HTMLUtil.getInputParameter(TAGS.form, request);
			Form form = null;
			try {
				if (sFormName.length() == 0) {
					sFormName = object.getClass(framework).getDefaultForm(true);
				}
				form = Form.open(sFormName, framework,null);
			} catch (Exception e) {
				session.setAttribute(TAGS.errormessage, e.getMessage());
			}

			// Save Data
			String sForwardPage = Forms.saveFormData(bCreateNew? TAGS.PAGE_Edit : "", object, form, request);
			if (sForwardPage.length() > 0) {
				ApplicationRequest fwrequest = new ApplicationRequest(sForwardPage,request.getForwardTarget(),session);
				fwrequest.setLocale(request.getLocale());
				fwrequest.setReferer(request.getReferer());
				handleRequest(fwrequest);
				return;
			}
			String sTitle = getTranslation(sFormName + (bClone ? "_clone" : ""));
			String sSubTitle = "";
			if (sID != null && sID.length() > 0) {
				if (bCreateNew) {
					object =  ObjectObj.open(sID, true,framework);
					object.resetID();
				}
				sSubTitle = sTitle;
				sTitle = getClassNameRevision(object, session);
			}

			Composite globalpanel = createPagePanel(sTitle, sSubTitle, !bCreateNew, request);
			if (globalpanel != null) {
				ScrolledComposite panel = Forms.createForm(globalpanel, TAGS.PAGE_Edit, object, form, request);
				panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}

		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Open a link Edit page
	 */
	public void doEditLink(ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = (request.getParameter(TAGS.linkid) != null ? request.getParameter(TAGS.linkid) : 
        (request.getParameter(TAGS.id) != null ? request.getParameter(TAGS.id) :request.getParameter(TAGS._id)));
			if (sID == null || sID.length() == 0) {
				return;
			} else {
				sID = sID.trim();
			}
			Link link = Link.open(sID, true, framework); 
			session.setAttribute(TAGS.Link, link);

			// Edit Form
			String sFormName = HTMLUtil.getInputParameter(TAGS.form, request);
			Form form = null;
			try {
				if (sFormName.length() == 0) {
					sFormName = link.getLinkType(framework).getDefaultForm();
				}
				form = Form.open(sFormName, framework,null);
			} catch (Exception e) {
				session.setAttribute(TAGS.errormessage, e.getMessage());
			}

			// Save Data
			String sForwardPage = Forms.saveFormData("", link, form, request);
			if (sForwardPage.length() > 0) {
				// System.out.println(sForwardPage);
				ApplicationRequest fwrequest = new ApplicationRequest(sForwardPage,request.getForwardTarget(), session);
				fwrequest.setLocale(request.getLocale());
				fwrequest.setReferer(request.getReferer());
				handleRequest(fwrequest);
				return;
			}

			String sTitle = getLinkData(link, session);
			String sSubTitle = getTranslation(sFormName);

			Composite globalpanel = createPagePanel(sTitle, sSubTitle, true, request);
			if (globalpanel != null) {
				ScrolledComposite panel = Forms.createForm(globalpanel, TAGS.PAGE_EditLink, link, form, request);
				panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	
	/**
	 * Open the lifecycle page
	 */
	public void doLifecycle(ApplicationRequest request) {
		try {
			final ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = (request.getParameter(TAGS.id) != null ? request.getParameter(TAGS.id) : request.getParameter(TAGS._id));
			if (sID == null || sID.length() == 0) {
				return;
			} else {
				sID = sID.trim();
			}
			final ObjectObj object =  ObjectObj.open(sID,false,framework);
			session.setAttribute(TAGS.Object, object);
			String sTitle = getClassNameRevision(object, session);
			String sSubTitle = getCommonTranslation("Lifecycle");

			Composite globalpanel = createPagePanel(sTitle, sSubTitle, true, request);
			if (globalpanel != null) {				
				LifecyclePanel lcPanel = new LifecyclePanel(globalpanel, object,request);
				lcPanel.panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Open the validations panel
	 */
	public void doValidations(ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = (request.getParameter(TAGS.id) != null ? request.getParameter(TAGS.id) : request.getParameter(TAGS._id));
			if (sID == null || sID.length() == 0) {
				return;
			} else {
				sID = sID.trim();
			}
			ObjectObj object =  ObjectObj.open(sID,false,framework);
			session.setAttribute(TAGS.Object, object);
			request.setParameter(TAGS.counter, ""+object.getSyncCounter());
			String sTitle = getClassNameRevision(object, session);
			String sSubTitle = getCommonTranslation("Validations");
			sSubTitle += " - " + getCommonTranslation("Stage");
			sSubTitle += ": " + ((Stage) request.getAttribute(TAGS.stage)).getName();
			Composite globalpanel = createPagePanel(sTitle, sSubTitle, true, request);
			if (globalpanel != null) {				
				ValidationPanel val = new ValidationPanel(globalpanel,object,request);
				val.panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Open the object navigation page
	 */
	public void doNavigate(final ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = (request.getParameter(TAGS.id) != null ? request.getParameter(TAGS.id) : request.getParameter(TAGS._id));
			if (sID == null || sID.length() == 0) {
				return;
			} else {
				sID = sID.trim();
			}

			ObjectObj object =  ObjectObj.open(sID,false,framework);
			session.setAttribute(TAGS.Object, object);

			// Menu Bar
			String sTitle = getClassNameRevision(object, session);
			String sSubTitle = getCommonTranslation("Navigate");

			// List views
			Vector<String> vViews = View.getUserViews(framework);
			Vector<String> vFormViews = StringUtils.StringTokensToVector(HTMLUtil.getInputParameter(TAGS.views, request),"|");
			if (vFormViews.size()>0) {
				for (int i = vViews.size() - 1; i >= 0; i--) {
					if (vFormViews.indexOf((vViews.elementAt(i))) < 0) {
						vViews.removeElementAt(i);
					}
				}
			}

			boolean bShowViewList = true;
			String sView = HTMLUtil.getInputParameter(TAGS.view, request);
			if (sView.startsWith("(")) {
				sView = sView.substring(1, sView.length() - 1);
				bShowViewList = false;
			}

			Composite globalpanel = createPagePanel(sTitle, sSubTitle, true, request);
			if (globalpanel != null) {
				NavigatorPanel nav = new NavigatorPanel(globalpanel, request);
				nav.panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				if (bShowViewList && vViews.size() > 0) {
					nav.resetViews(sView, vViews);
				} else {
					nav.applyView(sView);
				}
				nav.process(object);

				Tree tree = nav.getTree();
				setData(tree,TAGS.REQUEST, request);
				tree.addListener(SWT.MouseUp, new Listener() {
					public void handleEvent(Event e) {
						if (e.button != 3)
							return;
						Tree tree = ((Tree) e.widget);
						TreeItem item = tree.getItem(new Point(e.x, e.y));
						if (item == null)
							return;
						TreeItem[] items = { item };
						tree.setSelection(items);
						try {
							org.eclipse.swt.widgets.Menu popup = new org.eclipse.swt.widgets.Menu(tree);
							Forms.fillObjectPopUpMenu(popup, tree, (String)getData(item,TAGS.ID), (String)getData(item,TAGS.LINKID),
							(ApplicationSession)((ApplicationRequest) getData(tree,TAGS.REQUEST)).getSession());
							if (popup.getItemCount() > 0) {
								Point sh = Application.getApp().shell.getLocation();
								Point ch = ((Control) e.widget).getLocation();
					  		popup.setLocation(new Point(Application.computeWidth(20)+sh.x+ch.x+e.x,Application.computeHeight(140)+sh.y+ch.y+e.y));
								popup.setVisible(true);
							}
						} catch (Exception ex) {
						}
					}
				});

				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	
	/**
	 * Open the object spacetree
	 */
	public void doSpaceTree(ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = (request.getParameter(TAGS.id) != null ? request.getParameter(TAGS.id) : request.getParameter(TAGS._id));
			if (sID == null || sID.length() == 0) {
				return;
			} else {
				sID = sID.trim();
			}

			ObjectObj object =  ObjectObj.open(sID,false,framework);
			session.setAttribute(TAGS.Object, object);

			String sLinkType = HTMLUtil.getInputParameter(TAGS.linktype, request);
			if (sLinkType.length() == 0) {
				sLinkType = "*";
			}

			// Menu Bar
			String sTitle = getClassNameRevision(object, session);
			String sSubTitle = getCommonTranslation("SpaceTree");

			Composite globalpanel = createPagePanel(sTitle, sSubTitle, true, request);
			if (globalpanel != null) {
				SpaceTreePanel spacetree = new SpaceTreePanel(globalpanel, request);
				spacetree.panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
				spacetree.process(new String[] { object.getClassName(), object.getName(), object.getRevision(), object.getID() }, sLinkType);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Open the files panel
	 */
	public void doFiles(ApplicationRequest request) {
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sID = (request.getParameter(TAGS.id) != null ? request.getParameter(TAGS.id) : request.getParameter(TAGS._id));
			if (sID == null || sID.length() == 0) {
				return;
			} else {
				sID = sID.trim();
			}
			ObjectObj object =  ObjectObj.open(sID,false,framework);
			session.setAttribute(TAGS.Object, object);
			request.setParameter(TAGS.counter, ""+object.getSyncCounter());
			String sTitle = getClassNameRevision(object, session);
			String sSubTitle = getCommonTranslation("Files");
			Composite globalpanel = createPagePanel(sTitle, sSubTitle, true, request);
			if (globalpanel != null) {			
				FilePanel filePanel = new FilePanel(globalpanel, object,request);
				filePanel.panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}


	/**
	 * Open the activity list page
	 */
	public void doActivityList(ApplicationRequest request) {
		try {
			// Menu Bar
			String sTitle = getCommonTranslation("ActivityList");
			session.removeAttribute(TAGS.Object);
			Composite globalpanel = createPagePanel(sTitle, "", false, request);
			if (globalpanel != null) {
				ActivityListPanel actlist = new ActivityListPanel(globalpanel, request);
				actlist.panel.setLayoutData(new GridData(GridData.FILL_BOTH));
				addPageToContainer(globalpanel, sTitle, request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Open the default activity completion popup
	 */
	public void doActivityCompletion(ApplicationRequest request) {
		framework = getFramework(request.getSession());
		try {
			ApplicationSession session = (ApplicationSession) request.getSession();
			String sProcess = HTMLUtil.getInputParameter(TAGS.process, request);
			String sStep = HTMLUtil.getInputParameter(TAGS.step, request);

			ApplicationRequest fwrequest = new ApplicationRequest(request);
			String sCommand = "process show '" + sProcess + "' get { workflow.step['"+sStep+"'].{ type decision }  } token '';";
			String sType = performOOQLCommands(sCommand).elementAt(0);
			if (sType.startsWith("decision")) {
				int iType = (sType.indexOf("multiple") > 0 ? SWT.CHECK : SWT.RADIO);
				sCommand = "process show '"+sProcess+"' get { step['"+sStep+"'].params["+Arg.TRANSITIONS+"] } token '';";
				String sTransitions = performOOQLCommands(sCommand).elementAt(0);
				Vector<String> vChoices = StringUtils.StringTokensToVector(sTransitions, ";");
				DecisionDlg dlg = new DecisionDlg(getCommonTranslation("DecisionList"), URLDecoder.decode(
						HTMLUtil.getInputParameter(TAGS.label, request), StringUtils.UTF8), getApp(), shell, session);
				String sChoices = dlg.makeDecision(vChoices, iType);
				if (sChoices.length() > 0) {
					setNoVerbose();
					sCommand = "process complete '"+sProcess+"' step '"+sStep+"' choice "+sChoices+";";
					log(sCommand);
					performOOQLCommands(sCommand);
					fwrequest.setTarget("");
					fwrequest.setRequestPage(TAGS.PAGE_Activity);
					fwrequest.setReferer(request.getReferer());
					handleRequest(fwrequest);
				}
			} else if (sType.startsWith("action")) {
				DecisionDlg dlg = new DecisionDlg(getCommonTranslation("CompleteActivity"), URLDecoder.decode(
						HTMLUtil.getInputParameter(TAGS.label, request), StringUtils.UTF8), getApp(), shell, session);
				if (dlg.completeAction()) {
					setNoVerbose();
					sCommand = "process complete '"+sProcess+"' step '"+sStep+"' ;";
					log(sCommand);
					performOOQLCommands(sCommand);
					fwrequest.setTarget("");
					fwrequest.setRequestPage(TAGS.PAGE_Activity);
					fwrequest.setReferer(request.getReferer());
					handleRequest(fwrequest);
				}
			}

		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}

	/**
	 * Perform object operations
	 */
	public void doWork(ApplicationRequest request) {
		framework = getFramework(request.getSession());
		String sId = request.getParameter(TAGS.id);
		String sAction = request.getParameter(TAGS.action);
		if (sId != null && sAction != null) {
			String sCommand = "";
			String sCounter = request.getParameter(TAGS.counter);
			if (sCounter!=null) { sCounter="sync "+sCounter+" "; }
			if (sAction.equals(TAGS.FORM_ActionProgress) || sAction.equals(TAGS.FORM_ActionRegress)) {
				sCommand = "object "+sAction+" "+sId+" "+sCounter+"; ";
				try {
					performOOQLCommands(sCommand);
				} catch (Exception e) {
					session.setAttribute(TAGS.errormessage, e.getMessage());
				}
			} else if (sAction.equals(TAGS.FORM_ActionValidate) || 
					   sAction.equals(TAGS.FORM_ActionRefuse) || 
					   sAction.equals(TAGS.FORM_ActionIgnore)) {
				String sValidation = request.getParameter(TAGS.validation);
				String sNote = request.getParameter(TAGS.note);
				if (sValidation != null) {
					sCommand = "object "+sAction+" "+sId+" "+sCounter+"validation '"+sValidation+"' ";
					if (sNote != null) {
						sCommand += "note '"+StringUtils.replaceString(sNote, "'", "\\\'" + "'")+"'";
					}
				}
				sCommand += ";";
				try {
					performOOQLCommands(sCommand);
				} catch (Exception e) {
					session.setAttribute(TAGS.errormessage, e.getMessage());
				}
			} else if (sAction.equals(TAGS.FORM_ActionLink) || sAction.equals(TAGS.FORM_ActionUnlink) 
					|| sAction.equals(TAGS.FORM_ActionErase) || sAction.equals(TAGS.FORM_ActionActive) 
					|| sAction.equals(TAGS.FORM_ActionInactive) || sAction.startsWith(TAGS.FORM_ActionDuplicate+"[")) {
				String sVersus = request.getParameter(TAGS.versus);
				if (sVersus == null) {
					sVersus = "to";
				}
				String sLinkType = request.getParameter(TAGS.linktype);
				if (sAction.equals(TAGS.FORM_ActionLink)) {
					sCommand = "object addlink "+sId+" "+sVersus+" <ID> linktype '"+sLinkType+ "';";
				} else if (sAction.equals(TAGS.FORM_ActionUnlink)) {
					if (sLinkType == null) {
						sCommand = "link destroy <ID>;";
					} else {
						sCommand = "object removelink "+sId+" "+sVersus+" <ID> linktype '"+sLinkType+ "';";
					}
				} else if (sAction.equals(TAGS.FORM_ActionErase)) {
					sCommand = "object destroy <ID>;";
				} else if (sAction.equals(TAGS.FORM_ActionActive) || sAction.equals(TAGS.FORM_ActionInactive)) {
					if (sLinkType == null) {
						sCommand = "link edit <ID> "+sAction+";";
					} else {
						sCommand = "link edit object "+sId+" "+sVersus+" <ID> linktype '"+sLinkType+"' "+sAction+" ;";
					}
				} else if (sAction.startsWith(TAGS.FORM_ActionDuplicate+"[")) {
					String sSubAction = StringUtils.getStringPart(sAction, TAGS.FORM_ActionDuplicate+"[", "]");
					StringTokenizer sT = new StringTokenizer(sSubAction, "|");
					sSubAction = sT.nextToken();
					if (sSubAction.startsWith("i")) {
						sCommand = "link edit <ID> inactive;";
					} else {
						sCommand = "";
					}
					if (sSubAction.endsWith("i")) {
						sCommand += "link clone <ID> inactive";
					} else {
						sCommand += "link clone <ID> active";
					}
					while (sT.hasMoreTokens()) {
						sCommand += " field["+StringUtils.replaceString(sT.nextToken(),",", "] '")+"'";
					}
					sCommand += ";";
				}
				String sObjects = request.getParameter(TAGS.list);
				StringTokenizer sToken = new StringTokenizer(sObjects.trim(), ",");
				String sMessage = "";
				while (sToken.hasMoreTokens()) {
					String sToId = sToken.nextToken();
					if (!sToId.equals("")) {
						try {
							 //System.out.println(StringUtils.replaceString(sCommand,"<ID>",sToId));
							 performOOQLCommands(StringUtils.replaceString(sCommand, "<ID>", sToId));
						} catch (Exception e) {
							sMessage += e.getMessage() + "\n";
						}
					}
				}
				if (!sMessage.equals("")) {
					session.setAttribute(TAGS.errormessage, sMessage);
				}
			} else if (sAction.equals(TAGS.FORM_ActionFileDelete)) {
				String[][] files = (String[][]) request.getAttribute(TAGS.files);
				if (files.length > 0) {
					for (int i = 0; i < files.length; i++) {
						sCommand += "object filedelete "+sId+" filetype '"+files[i][0]+ "' name '"+files[i][1]+"';";
					}
					try {
						performOOQLCommands(sCommand);
					} catch (Exception e) {
						session.setAttribute(TAGS.errormessage, e.getMessage());
					}
				}
			} else if (sAction.equals(TAGS.FORM_ActionFileGet)) {
				String[][] files = (String[][]) request.getAttribute(TAGS.files);
				if (files.length > 0) {
					try {
						ObjectObj object = ObjectObj.open(sId, framework);
						FileOperator fileOperator = new FileOperator();
						fileOperator.get();
						fileOperator.setToPath(request.getParameter(TAGS.path));
						fileOperator.setLock(request.getParameter(TAGS.unlock).equals("true"));			
						for (int i = 0; i < files.length; i++) {
							try {
								fileOperator.resetFileNames();
								fileOperator.setFromFileType(files[i][0]);
								fileOperator.addFileGetName(files[i][1]);
								object.fileget(fileOperator, framework);
							} catch (Exception e) {
								session.setAttribute(TAGS.errormessage, e.getMessage());
							}
						}
					} catch (Exception e) {
						session.setAttribute(TAGS.errormessage, e.getMessage());
					}
				}
			} else if (sAction.equals(TAGS.FORM_ActionFilePut)) {
				FileOperator fileOperator = new FileOperator();
				try {
					ObjectObj object = ObjectObj.open(sId, framework);
					fileOperator.put();
					fileOperator.setToFileType(request.getParameter(TAGS.filetype));	
					StringTokenizer sT = new StringTokenizer(request.getParameter(TAGS.filepath),",");
					while (sT.hasMoreTokens()) {
						fileOperator.addFilePutName(sT.nextToken());
					}
					fileOperator.setLock(request.getParameter(TAGS.unlock).equals("false"));
					fileOperator.setOverwrite(request.getParameter(TAGS.overwrite).equals("true"));
					fileOperator.setIndexed(request.getParameter(TAGS.indexed).equals("true"));
					object.fileput(fileOperator, framework);
				//	putFiles(sId, , , request.getParameter(TAGS.filename), , , );
				} catch (Exception e) {
					session.setAttribute(TAGS.errormessage, e.getMessage());
				}
			}
		}
		// Forward Page
		String sForwardPage = request.getParameter(TAGS.fwd);
		if (sForwardPage != null) {
			sForwardPage += (sForwardPage.indexOf('?')>0?"&":"?")+TAGS.id+"="+sId;
		} else {
			sForwardPage = "";
		}
		Widget window = getWindow( (Control)request.getReferer() );
		if (window!=null) {
			if (request.getParameter(TAGS.close) != null) {
				Widget opener = (Widget) getData(window,TAGS.OPENER);				
				goForward(opener, sForwardPage);				
				doClose(request);
			} else {
				goForward(window, sForwardPage);
			}
		}
	}
	
	/**
	 * Open a URL in a target window
	 * 
	 * @param targetwin  the target window (a CTabItem or a dialog Shell)
	 * @param url        the URL to open
	 */
	public void goForward(Widget targetwin, String url) {
		if (targetwin != null) {
			if (targetwin instanceof CTabItem) {
				try {
					topTabFolder.setSelection((CTabItem) targetwin);
				} catch (Exception ex) {
				}
			}
			ApplicationRequest request = (ApplicationRequest) getData(targetwin,TAGS.REQUEST);
			if (url.length() > 0) {
				ApplicationRequest fwrequest = new ApplicationRequest(url, request.getForwardTarget(),request.getSession());
				fwrequest.setLocale(request.getLocale());
				fwrequest.setReferer(request.getReferer());
				handleRequest(fwrequest);
			} else { // Refresh
				request.setTarget(request.getForwardTarget());
				handleRequest(request);
			}
		}
	}
	
	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// Page Containers
	// //////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Creates the page container
	 * 
	 * @param title       the page title
	 * @param subTitle    the page subtitle
	 * @param objectMenu  if true show the object contextual menu
	 * @param request     related Application request
	 */
	public Composite createPagePanel(String title, String subTitle, boolean objectMenu, ApplicationRequest request) {
		final ApplicationSession session = (ApplicationSession) request.getSession();
		Composite globalpanel = new Composite(topTabFolder, SWT.NONE);
		GridLayout gd = new GridLayout();
		gd.marginWidth = 1;
		gd.marginTop = 0;
		gd.numColumns = 1;
		gd.verticalSpacing = 0;
		globalpanel.setLayout(gd);
		if (title.length() > 0) {
			Composite titlepanel = new Composite(globalpanel, SWT.NONE);
			titlepanel.setLayout(new GridLayout());
			titlepanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			HTMLUtil.setClass(titlepanel, TAGS.CSS_TitlePanel, true, session);
			Label ltitle = new Label(titlepanel, SWT.NONE);
			ltitle.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			ltitle.setText(title);
			HTMLUtil.setClass(ltitle, TAGS.CSS_Title, session);
			if (subTitle.length() > 0) {
				Label lsubtitle = new Label(titlepanel, SWT.NONE);
				lsubtitle.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
				lsubtitle.setText(subTitle);
				HTMLUtil.setClass(lsubtitle, TAGS.CSS_SubTitle, session);
			}
		}
		if (objectMenu && request.getParameter(TAGS.popup)==null) {			
			Composite menu = Forms.createObjectMenu(globalpanel, session);
			if (menu != null) {
				menu.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			}
		}

		String sMessage = Forms.getErrorMessage(session);
		if (sMessage.length() > 0) {
			errorMessage(globalpanel.getShell(), new Exception(sMessage), "");
		}
		// Set scrollbars
		Boolean scrollbars = true;
		String sTarget = request.getTarget();
		if (sTarget.length() > 0 && !sTarget.equals(TAGS._blank)) { 
			Shell popDialog = getDialog(sTarget);
			if (popDialog != null && getData(popDialog,TAGS.scrollbars)!=null) {
				scrollbars = (Boolean)getData(popDialog,TAGS.scrollbars);
			}
		}
		setData(globalpanel, TAGS.scrollbars,scrollbars );
		return globalpanel;
	}

	/**
	 * Add page to a TabFolder's Item
	 * 
	 * @param panel    the page panel
	 * @param title    the TabItem title
	 * @param request  related Application request
	 */
	public void addPageToContainer(Composite panel, String title, ApplicationRequest request) {
		String sTarget = request.getTarget();
		if (sTarget.length() > 0 && !sTarget.equals(TAGS._blank)) { // POPUP
			Shell popDialog = getDialog(sTarget);
			if (popDialog != null) {
				Control[] controls = popDialog.getChildren();
				for (int i = 0; i < controls.length; i++) {
					controls[i].dispose();
				}
				panel.setParent(popDialog);
				if (getData(popDialog,TAGS.pagetitle)==null || ((Boolean)getData(popDialog,TAGS.pagetitle)==true)){
					popDialog.setText(title);
				}										
				popDialog.layout(true);
				popDialog.open();
			}	else {
				log("Invalid target: " + sTarget);
				return ;
			}
		} else {  // TAB
			CTabItem tabItem;
			boolean bNew = request.getTarget().equals(TAGS._blank);
			int iCurrentTab  = (topTabFolder.getSelectionIndex()>=0?topTabFolder.getSelectionIndex():0);		
			if (topTabFolder.getItemCount() == 0 || bNew) {
				// Create new TAB
				tabItem = new CTabItem(topTabFolder, SWT.CLOSE);
				tabItem.setText(title);
				tabItem.setControl(panel);
				// set the OPENER TAB
				if (bNew) {
					setData(tabItem,TAGS.OPENER, topTabFolder.getItem(iCurrentTab));
				}
			} else {
				// Get the current TAB content
				tabItem = topTabFolder.getItem(iCurrentTab);
				tabItem.setText(title);
				tabItem.setControl(panel);
			}
			request.removeParameter(ApplicationRequest.target);
			setData(tabItem,TAGS.REQUEST, request);
			topTabFolder.setSelection(topTabFolder.indexOf(tabItem));
			setData(panel,TAGS.WINDOW, tabItem );
		}
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// OBEROn Language
	// //////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Convert the language code from the Application format to standard ISO code
	 */
	public String translateOberonLanguageToISO639Language(String language) {
		try {
			return language.toLowerCase().substring(0, 2);
		} catch (Exception e) {
			return "en";
		}
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// LOG
	// //////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Show a message in the application Log panel or in the status bar
	 */
	public void log(String message) {
		statusBar.setText(message.replace('\n', ' '));
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// CSS Styles
	// //////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Defines CSS styles
	 */
	public void setCSSStyles() {

		CSSStyle form = new CSSStyle(TAGS.CSS_Form);
		form.setBackGroundColor(255, 255, 255);
		//form.setBackGroundImage("Application_home.jpg");
		form.setPadding(10, 10, 10, 10);
		HTMLUtil.addCSSStyle(form);
		
		CSSStyle titlepanel = new CSSStyle(TAGS.CSS_TitlePanel);
		titlepanel.setBackGroundColor(150, 150, 150);
		HTMLUtil.addCSSStyle(titlepanel);
		
		CSSStyle title = new CSSStyle(TAGS.CSS_Title);
		title.setFont("Arial", 16, SWT.BOLD);
		title.setColor(255, 255, 255);
		title.setTextAlignment("right");
		HTMLUtil.addCSSStyle(title);

		CSSStyle subtitle = new CSSStyle(TAGS.CSS_SubTitle);
		subtitle.setFont("Arial", 12, SWT.NORMAL);
		subtitle.setColor(200, 200, 255);
		subtitle.setTextAlignment("right");
		HTMLUtil.addCSSStyle(subtitle);
		
		CSSStyle object_menu = new CSSStyle(TAGS.CSS_ObjectMenu);
		object_menu.setColor(255, 255, 255);
		object_menu.setBackGroundColor(0, 0, 0);
		HTMLUtil.addCSSStyle(object_menu);
		
		CSSStyle td = new CSSStyle(TAGS.CSS_Cell);
		td.setBackGroundColor(230, 230, 250);
		HTMLUtil.addCSSStyle(td);
		
		CSSStyle label = new CSSStyle(TAGS.CSS_Label);
		label.setFont("Arial", 9, SWT.NORMAL);
		HTMLUtil.addCSSStyle(label);
		
		CSSStyle tdlabel = new CSSStyle(TAGS.CSS_LabelCell);
		tdlabel.setFont("Arial", 10, SWT.BOLD);
		HTMLUtil.addCSSStyle(tdlabel);
		
		CSSStyle section = new CSSStyle(TAGS.CSS_Section);
		section.setFont("Arial", 12, SWT.BOLD);
		section.setColor(250, 250, 250);
		section.setPadding(1, 1, 1, 1);
		section.setMargin(0,0, 0, 0);
		section.setBackGroundColor(200, 200, 200);
		HTMLUtil.addCSSStyle(section);
		
		CSSStyle anchor = new CSSStyle(TAGS.CSS_Href);
		anchor.setColor(0, 0, 255);
		anchor.setFont("Arial", 10, SWT.ITALIC);
		HTMLUtil.addCSSStyle(anchor);
		
		CSSStyle buttons = new CSSStyle(TAGS.CSS_ButtonBar);
		buttons.setTextAlignment("right");
		buttons.setBackGroundColor(230, 200, 250);
		HTMLUtil.addCSSStyle(buttons);
		
		CSSStyle button = new CSSStyle(TAGS.CSS_Button);
		button.setTextAlignment("center");
		button.setBackGroundColor(200, 200, 200);
		HTMLUtil.addCSSStyle(button);
		
	}
	
	/*  AVAILABLE STYLE OPTIONS
	 * 
                     BgColor  BgImg   Img   Color  Font   Margin  Padding  Spacing    TextAling   VertAling
  CSS_Form               x       x      -      -      -       -       x         -           -           -
  CSS_TitlePanel         x       x      -      -      -       x       x         x           -           - 
  CSS_Title              x       x      -      x      x       x       -         -           x           x
  CSS_SubTitle           x       x      -      x      x       x       -         -           x           x
  CSS_ObjectMenu         x       x      -      -      -       -       x         x           -           - 
  CSS_Cell               x       x      -      -      -       -       x         x           x           x
  CSS_Label              x       x      -      x      x       x       -         -           -           -
  CSS_LabelCell          x       x      -      x      x       x       -         -           x           x
  CSS_Section            x       x      -      x      x       -       x         -           x           x
  CSS_Text               x       x      -      x      x       x       -         -           -           -
  CSS_TextArea           x       x      -      x      x       x       -         -           -           -
  CSS_Select             x       x      -      x      x       x       -         -           -           -
  CSS_List               x       x      -      x      x       x       -         -           -           -
  CSS_Checkbox           x       x      -      -      x       x       x         x           -           -
  CSS_Href               x       x      -      x      x       x       -         -           -           - 
  CSS_Image              x       x      -      -      -       x       -         -           -           - 
  CSS_StaticText         x       x      -      x      x       x       -         -           -           -
  CSS_ButtonBar          x       x      -      -      -       -       x         x           x           -
  CSS_Button             x       -      x      -      x       x       -         -           -           -
  
  */


	// //////////////////////////////////////////////////////////////////////////////////////////////////

	public static void main(String[] args) throws Exception {

		OberonClient app = new OberonClient(null);

		while (!app.shell.isDisposed()) {
			if (!app.display.readAndDispatch())
				app.display.sleep();
		}

	}

}
