package com.oberon.client;
/*
 * Copyright 2013 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.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

import com.oberon.client.Application;
import com.oberon.client.ApplicationRequest;
import com.oberon.client.Configuration;
import com.oberon.client.common.ActivityListPanel;
import com.oberon.client.common.FilePanel;
import com.oberon.client.common.Forms;
import com.oberon.client.common.LifecyclePanel;
import com.oberon.client.common.NavigatorPanel;
import com.oberon.client.common.ResultSetPanel;
import com.oberon.client.common.ResultSetTable;
import com.oberon.client.common.ScrollingTable;
import com.oberon.client.common.ScrollingTable.TableItem;
import com.oberon.client.common.SwipeDismissTouchListener;
import com.oberon.client.common.ValidationPanel;
import com.oberon.client.common.ScrollingTable.TableColumn;
import com.oberon.ooql.connection.ConnectionManager;
import com.oberon.ooql.sdk.Arg;
import com.oberon.ooql.sdk.Dictionary;
import com.oberon.ooql.sdk.Form;
import com.oberon.ooql.sdk.Link;
import com.oberon.ooql.sdk.MenuItem;
import com.oberon.ooql.sdk.ObjectObj;
import com.oberon.util.StringUtils;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.widget.DrawerLayout;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.TabHost.TabSpec;

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

  private DrawerLayout mDrawerLayout;
  private ListView mDrawerList;
	private TabHost topTabFolder = null;	
	AlertDialog editorDlg;
	private static int TabHeight = 35; 
	ProgressDialog loadingProgress ;
	private Runnable m_handleTask = null;
	public Handler m_handler = new Handler();
	boolean verticalOrientation ;
	private ImageButton m_btnAbout;
	private ImageButton m_btnPrefs;
	private ImageButton m_btnExit;
	private ImageButton m_btnLogs;
	private StringBuffer logText = new StringBuffer();

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		setApp(this);		
		try {
		  super.onCreate(savedInstanceState);
		} catch (Exception ex) {}
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.main);
		
		m_btnAbout = (ImageButton) findViewById(R.id.btnAbout);
		m_btnAbout.setOnClickListener(mBtnListener);
		m_btnPrefs = (ImageButton) findViewById(R.id.btnPrefs);
		m_btnPrefs.setOnClickListener(mBtnListener);
		m_btnLogs = (ImageButton) findViewById(R.id.btnLogs);
		m_btnLogs.setOnClickListener(mBtnListener);
		m_btnExit = (ImageButton) findViewById(R.id.btnExit);
		m_btnExit.setOnClickListener(mBtnListener);		
		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    mDrawerList = (ListView) findViewById(R.id.left_drawer);    
		      
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
		prefs.registerOnSharedPreferenceChangeListener(this);

		DisplayMetrics displaymetrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
		screenWidth = displaymetrics.widthPixels-40;
		screenHeight = displaymetrics.heightPixels-40;
		screenDensity = displaymetrics.scaledDensity;
		TabHeight = Math.round(35*Application.screenDensity);
		verticalOrientation = (screenWidth<screenHeight);
		loadingProgress=new ProgressDialog(this);
		loadingProgress.setMessage("Connecting...");
    
		setCSSStyles();
		
		topTabFolder = (TabHost) findViewById(R.id.tab_host);
		topTabFolder.setup(); 
		topTabFolder.setTag(new ArrayList());		
		topTabFolder.getTabWidget().getLayoutParams().height=TabHeight;
		
		conf = new Configuration(this);		
		loadingProgress.show();
		m_handler.postDelayed(new Runnable() {
			public void run() {
				runOnUiThread(new Runnable() {
					public void run() {
						doServerConnect( getConnectionProperty( ConnectionManager.PROP_SERVERURL ) ,true );
						loadingProgress.hide();
					}
				});
			}
		},500);		
		
		Intent intent = getIntent();
		if (intent != null) {
			onNewIntent(intent);
		}
	}
			
	
	private View.OnClickListener mBtnListener = new View.OnClickListener() {
		public void onClick(View view) {
			if (view.getId() == R.id.btnAbout) {
				final Dialog dialog = new Dialog(getApp());
				dialog.setContentView(R.layout.about_dialog);
				dialog.setTitle("About OBEROn");
				dialog.setCancelable(true);	
				String sText = "OBEROn Platform\n";
				sText += "Object Based Enterprise Resource Organization\n";
				sText += "Version: " + ConnectionManager.version + " - Build " + ConnectionManager.build + "\n";
				sText += ConnectionManager.copyright + "\n";
				sText += ConnectionManager.credits;
				TextView abouttext  = (TextView) dialog.findViewById(R.id.AboutText);
				abouttext.setText(sText);
				abouttext.setTextSize(16);
				TextView linktext = (TextView) dialog.findViewById(R.id.LinkText);
				linktext.setText(Html.fromHtml("<a href=\""+URL_OBERON+"\">"+URL_OBERON+"</a>"));
				linktext.setMovementMethod(LinkMovementMethod.getInstance());
				Button button = (Button) dialog.findViewById(R.id.OKButton);
				button.setOnClickListener(new OnClickListener() {
					public void onClick(View v) {
						dialog.dismiss();
					}
				});  
				dialog.show();
			} else if (view.getId() == R.id.btnPrefs) {
				Intent intent = new Intent(getApp(),PreferencePanel.class);
				startActivityForResult(intent, 0);
			} else if (view.getId() == R.id.btnLogs) {
				final EditText text = new EditText(view.getContext());
				text.setSingleLine(false);
				text.setTextSize(12);
				text.setText(logText.toString());
				text.post(new Runnable() { 
          public void run() { 
          	text.setSelection(logText.length()-1);
          	text.requestFocus();
          } 
        });
				new AlertDialog.Builder(getApp())
				.setIcon(android.R.drawable.ic_dialog_alert)
				.setTitle("OBEROn - version "+ConnectionManager.version)
				.setView(text)
				.setNegativeButton(R.string.close, null)
				.show();				
			} else if (view.getId() == R.id.btnExit) {
				new AlertDialog.Builder(getApp())
				.setIcon(android.R.drawable.ic_dialog_alert)
				.setTitle("OBEROn - version "+ConnectionManager.version)
				.setMessage(R.string.exit_confirm)
				.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						finish();   								
					}
				})
				.setNegativeButton(R.string.no, null)
				.show();
			}
	}};
	
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Connection dialogs
	////////////////////////////////////////////////////////////////////////////////////////////////////

	class PostRunnable implements Runnable {
		public void run() {
		}
	}
	
	private void doServerConnect(final String url,boolean reloadPages) {
		try {
			closeConnections();
			PreferencePanel.setStringPref(this, "CONNECTION.serverURL", url);
			openConnections();			
			startUI(reloadPages);
		} catch (Exception ex) {
			if (!isConnected()) {
				showMessage(getApp(),ex.getMessage(),"OBEROn connect", new PostRunnable() {
						public void run() {
							showServerDialog(url);
						}
				});
			} else {
				showLoginDialog(getConnectionProperty(ConnectionManager.PROP_OBUSR));
			}
		}
	}

	private void doLogin(final String name,String pwd) {
		try {
			openFramework(name, pwd);
			PreferencePanel.setStringPref(this, "CONNECTION.uid", name);
			PreferencePanel.setStringPref(this, "CONNECTION.pwd", pwd);
			startUI(false);
		} catch (Exception ex) {
			showMessage(getApp(),ex.getMessage(),"OBEROn login",new PostRunnable() {
				public void run() {
					showLoginDialog(name);
				}
		});				
		}
	}
		
	private void showServerDialog(String url) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.serverURL);
		final LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		final View content = inflater.inflate(R.layout.server_url, (ViewGroup) findViewById(R.id.serverLayout));
		EditText serverURL = (EditText) content.findViewById(R.id.serverURL);
		serverURL.setText(url);
		builder.setView(content);
		builder.setCancelable(false);
		builder.setPositiveButton(R.string.connect, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				Dialog source = (Dialog) dialog;
				source.setCancelable(false);
				EditText serverURL = (EditText) source.findViewById(R.id.serverURL);
				String url = serverURL.getText().toString();
				doServerConnect(url,false);
			}
		});
		builder.setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				finish();
			}
		});
		editorDlg = builder.create();		
		editorDlg.show();
	}
	
	private void showLoginDialog(String user) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.userLogin);
		final LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		final View content = inflater.inflate(R.layout.login, (ViewGroup) findViewById(R.id.loginLayout));
		EditText userName = (EditText) content.findViewById(R.id.userName);
		userName.setText(user);
		builder.setView(content);
		builder.setPositiveButton(R.string.login, new DialogInterface.OnClickListener() {

			public void onClick(DialogInterface dialog, int which) {
				Dialog source = (Dialog) dialog;
				source.setCancelable(false);
				EditText userName = (EditText) source.findViewById(R.id.userName);
				String name = userName.getText().toString();

				EditText userPwd = (EditText) source.findViewById(R.id.userPwd);
				String pwd = userPwd.getText().toString();
				doLogin(name,pwd);
			}
		});
		editorDlg = builder.create();
		editorDlg.show();
	}
	
	private void startUI(boolean reloadPages) {
		application_MainMenu = getConnectionProperty(ConnectionManager.PROP_APPLICATION); // set fixed Name for special purpose applications;
		name = getMenuTranslation(application_MainMenu);
		ArrayAdapter<MenuItem> menuAdapter = createMenu(this,application_MainMenu,
				 new int[]{R.layout.menu_item,R.id.menu_icon,R.id.menu_text,R.id.menu_expand},
		     new int[]{R.drawable.empty,R.drawable.expand,R.drawable.expanded});
     // Set the adapter for the list view
     mDrawerList.setAdapter(menuAdapter);

      loadingProgress.setMessage(getCommonTranslation("Loading")+"...");
	    final ArrayList requests = (ArrayList) getLastNonConfigurationInstance();
	    if (requests != null && reloadPages) {
	    	topTabFolder.clearAllTabs();
			  ((ArrayList<TabHost.TabSpec>)topTabFolder.getTag()).clear();
			  int selected = -1;
			  for (int i=0;i<requests.size();i++) {
			  	try {
				  	ApplicationRequest request = (ApplicationRequest) requests.get(i);
				  	request.setTarget(TAGS._blank);
				  	request.removeParameter(TAGS.create);
				  	request.removeParameter(TAGS.update);
				  	request.removeParameter(TAGS.clone);
				  	if (request.getAttribute(TAGS.SELECTED)!=null) {
				  		request.removeAttribute(TAGS.SELECTED);
				  		selected = i;
				  	} 
				  	handleRequest(new ApplicationRequest(request, (ApplicationSession) session));	  					  	
				  } catch (Exception ex) {}
			  	if (selected>=0) topTabFolder.setCurrentTab(selected);
			  } 
	    } else {
	    	handleRequest(new ApplicationRequest(TAGS.PAGE_Home,  (ApplicationSession) session));
	    }
	}
	
	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
		conf = new Configuration(this);
		if (PreferencePanel.isOn) {
			if ( key.equals("CONNECTION.serverURL") || key.equals("CONNECTION.connections") || key.equals("CONNECTION.application")) {
				doServerConnect(getConnectionProperty( ConnectionManager.PROP_SERVERURL ),false);
			} 
		}
	}
	
	@Override
	public Object onRetainNonConfigurationInstance() {
	    ArrayList list = new ArrayList();
		  FrameLayout layout = topTabFolder.getTabContentView();
		  for (int i=0;i<layout.getChildCount();i++) {
		  	View child = layout.getChildAt(i);
		  	ApplicationRequest request = (ApplicationRequest)getData(child, TAGS.REQUEST) ;
		  	if (i==topTabFolder.getCurrentTab()) { request.setAttribute(TAGS.SELECTED, ""); }
		  	list.add(request);
		  }
	    return list;
	}
		
	public void onDestroy() {
		super.onDestroy();
		if (getApp() == this)
			setApp(null);		
	}
	
	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// Application Request Handlers
	// //////////////////////////////////////////////////////////////////////////////////////////////////

	public boolean handleRequest(final ApplicationRequest request) {
		try {
			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 
			imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
		} catch (Exception ex){}
		mDrawerLayout.closeDrawers();
		
		loadingProgress.show();
		
		m_handleTask = new Runnable() {
			public void run() {
				runOnUiThread(new Runnable() {
					public void run() {
						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)) {
							showLoginDialog(getConnectionProperty(ConnectionManager.PROP_OBUSR));
				  	} 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_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) {
							}
						} 
						loadingProgress.hide();
					}
				});
			}
		};
		m_handler.postDelayed(m_handleTask,50);
		return true;
	}

	/**
	 * Open the Home page
	 */
	public void doHome(ApplicationRequest request) {
		try {
			String sTitle = getCommonTranslation("Welcome");
			session.removeAttribute(TAGS.Object);
			LinearLayout globalpanel = createPagePanel(this,sTitle, "", false, request);
			if (globalpanel != null) {
				ImageView homeImg = new ImageView(this);
				homeImg.setImageDrawable(getResources().getDrawable(R.drawable.home));
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
				params.weight=1;
				globalpanel.addView(homeImg,params);

				TextView aboutText = new TextView(this);
				params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				params.weight=1;
				params.setMargins(10,20,10,50);
				globalpanel.addView(aboutText,params);
				String sText = name + "\n";
				sText += "OBEROn Platform [version: " + ConnectionManager.version + " - build " + ConnectionManager.build + "]\n";
				sText += ConnectionManager.copyright;
				aboutText.setEnabled(false);
				aboutText.setTextSize(20);
				aboutText.setGravity(Gravity.CENTER | Gravity.CENTER_VERTICAL);				
				aboutText.setText(sText);

				addPageToContainer(globalpanel, "Home" , request);
			}
		} catch (Exception ex) {
			log(ex.getMessage());
		}
	}
	
	
	/**
	 * Close a page or a pop-up dialog
	 */
	public void doClose(ApplicationRequest request) {
		View window = getWindow((View)request.getReferer());
		if ( getData(window,TAGS.WINDOW) instanceof AlertDialog ) {	// POPUP
			AlertDialog popDialog = (AlertDialog) getData((View)window,TAGS.WINDOW);
			popDialog.hide();
		} else if (window instanceof View) {
			try {
				// Get TAB Opener
				View opener = (View) getData((View)window,TAGS.OPENER);
				if (opener != null && topTabFolder.getTabWidget().getChildCount() > 1) {
					removeTab(topTabFolder.getCurrentTab());
				} 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 {
						removeTab(topTabFolder.getCurrentTab());
					}
				}
			} 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);

			LinearLayout globalpanel = createPagePanel(this,sTitle, "", false, request);
			if (globalpanel != null) {
				ScrollView panel = Forms.createSearchForm(globalpanel, TAGS.PAGE_SearchResults, form, request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(panel,params);
				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(getApp(), sMessage, "",null);
				}
				/*
				 * 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 vViews = com.oberon.ooql.sdk.View.getUserViews(framework);
			Vector vFormViews = StringUtils.StringTokensToVector(HTMLUtil.getInputParameter(TAGS.views, request),"|");
			if (vFormViews.size()>0) {
				for (int i = vViews.size() - 1; i >= 0; i--) {
					if (vFormViews.indexOf(((String) 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;
			}
			
			LinearLayout globalpanel = createPagePanel(this,sTitle, "", false, request);
			if (globalpanel != null) {
				ResultSetPanel rst = new ResultSetPanel(globalpanel, request);
				rst.getTable().setOnRowLongClickListener( new OnLongClickListener() {
							public boolean onLongClick(View view) {
								try {
									String sID = (String) getData(view,TAGS.ID);
									Forms.fillObjectPopUpMenu(view,sID,null,(ApplicationSession)request.getSession());
								} catch (Exception exx) {
								}
								return true;
							}
						}
				);
				if (bShowViewList && vViews.size() > 0) {
					rst.resetViews(sView, vViews);
				} else {
					rst.applyView(sView);
				}				
				session.setAttribute(TAGS.sequence, new Vector());				
				rst.process(Forms.getSearchResults(formHTMLName, session), true);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(rst.panel,params);	
				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);

			LinearLayout globalpanel = createPagePanel(this,sTitle, "", false, request);
			if (globalpanel != null) {
				final ScrollView panel = Forms.createSearchForm(globalpanel, TAGS.PAGE_Select+"?"+TAGS.id+"="+sID,form,request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(panel,params);
				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(getApp(), sMessage, "",null);
					}
				} catch (Exception e) {
					log(e.getMessage());
				}
				boolean bMulti = false;
				if (HTMLUtil.getInputParameter(TAGS.multiple, request).equals("true")) {
					bMulti = true;
				}
				ResultSetTable rstTable = new ResultSetTable(getApp(), globalpanel, bMulti,request.getLocale() );
				
				if (request.getParameter(TAGS.search) != null) {
					final ScrollingTable table = rstTable.getTable();	
					table.setOnColumnSortListener(new OnClickListener() {
						public void onClick(View columnView) {
							TableColumn column = (TableColumn)Application.getData(columnView,TAGS.COLUMN);
							ResultSetTable.sortColumn(column, request != null ? (ApplicationSession) request.getSession() : null);
						}
					});
					// List views
					Vector vViews = com.oberon.ooql.sdk.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 vResult = Forms.getSearchResults(formHTMLName, session);
					rstTable.processResult(vResult, sView);
					if (!sView.equals("")) {
						com.oberon.ooql.sdk.View view = com.oberon.ooql.sdk.View.open(sView,framework.getUserName(),framework);
						rstTable.processResult(vResult, sView);
						rstTable.applyView(view,false,true);
					}
					table.setSortDirection(ScrollingTable.SORT_DIRECTION_UP);
					ResultSetTable.sortColumn(table.getColumn(1));
				}
				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 {
			View window = getWindow( (View)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) {
					ScrollingTable table = (ScrollingTable) getData(window,TAGS.TABLE);
					if (table != null) {
						TableItem[] items = table.getSelection();
						if (items.length == 0) {
							errorMessage(getApp(), new Exception(getCommonTranslation("MSG_SelectAtLeastOneObject")), "",null);
						} 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 += items[i].getData(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);
			}
			LinearLayout globalpanel = createPagePanel(this,sTitle, sSubTitle, !bCreateNew, request);
			if (globalpanel != null) {				
				ScrollView panel = Forms.createForm(globalpanel, TAGS.PAGE_Edit, object, form, request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(panel,params);
				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);
			LinearLayout globalpanel = createPagePanel(this,sTitle, sSubTitle, true, request);
			if (globalpanel != null) {				
				ScrollView panel = Forms.createForm(globalpanel, TAGS.PAGE_EditLink, link, form, request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(panel,params);
				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");

			LinearLayout globalpanel = createPagePanel(this,sTitle, sSubTitle, true, request);
			if (globalpanel != null) {
				LifecyclePanel lcPanel = new LifecyclePanel(globalpanel, object,request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(lcPanel.panel,params);
				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 += ": " + request.getParameter(TAGS.stage);
			LinearLayout globalpanel = createPagePanel(this,sTitle, sSubTitle, true, request);
			if (globalpanel != null) {
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				ValidationPanel val = new ValidationPanel(globalpanel, object,request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(val.panel,params);
				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 vViews = com.oberon.ooql.sdk.View.getUserViews(framework);
			Vector vFormViews = StringUtils.StringTokensToVector(HTMLUtil.getInputParameter(TAGS.views, request),"|");
			if (vFormViews.size()>0) {
				for (int i = vViews.size() - 1; i >= 0; i--) {
					if (vFormViews.indexOf(((String) 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;
			}

			LinearLayout globalpanel = createPagePanel(this,sTitle, sSubTitle, true, request);
			if (globalpanel != null) {
				NavigatorPanel nav = new NavigatorPanel(globalpanel, request);
				nav.getTree().setOnNodeLongClickListener( new OnLongClickListener() {
					public boolean onLongClick(View view) {
						try {
							String sID = (String) getData(view,TAGS.ID);
							String sLinkID = (String) getData(view,TAGS.LINKID);
							Forms.fillObjectPopUpMenu(view,sID,sLinkID,(ApplicationSession)request.getSession());
						} catch (Exception exx) {
						}
						return true;
					}
				});
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(nav.panel,params);
				if (bShowViewList && vViews.size() > 0) {
					nav.resetViews(sView, vViews);
				} else {
					nav.applyView(sView);
				}
				nav.process(object);			
				String sPrefix = sSubTitle.length() > 0 ? "(" + sSubTitle.substring(0, 1) + ") " : "";
				addPageToContainer(globalpanel, sPrefix + sTitle, request);
			}
		} 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");
			
			LinearLayout globalpanel = createPagePanel(this,sTitle, sSubTitle, true, request);
			if (globalpanel != null) {				
				FilePanel val = new FilePanel(globalpanel,object, request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(val.panel,params);
				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);
			LinearLayout globalpanel = createPagePanel(this,sTitle, "", false, request);
			if (globalpanel != null) {
				ActivityListPanel actlist = new ActivityListPanel(globalpanel, request);
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
				globalpanel.addView(actlist.panel,params);
				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 {
			final ApplicationSession session = (ApplicationSession) request.getSession();
			final String sProcess = HTMLUtil.getInputParameter(TAGS.process, request);
			final String sStep = HTMLUtil.getInputParameter(TAGS.step, request);

			final ApplicationRequest fwrequest = new ApplicationRequest(request);
			fwrequest.setTarget("");
			fwrequest.setRequestPage(TAGS.PAGE_Activity);
			fwrequest.setReferer(request.getReferer());
			String sCommand = "process show '" + sProcess + "' get { workflow.step['"+sStep+"'].{ type decision }  } token '';";
			String sType = (String) performOOQLCommands(sCommand).elementAt(0);
			if (sType.startsWith("decision")) {
				boolean bMultiple =  ( sType.indexOf("multiple") > 0 );
				LinearLayout listChoices = new LinearLayout(getApp());
				listChoices.setPadding(30, 20, 30, 20);
				listChoices.setOrientation(LinearLayout.VERTICAL);
				ScrollView sc = new ScrollView(getApp());
				sc.setFillViewport(true);
				sc.addView(listChoices);
				TextView message = new TextView(listChoices.getContext());
				message.setText(URLDecoder.decode(HTMLUtil.getInputParameter(TAGS.label, request), StringUtils.UTF8)+"\n");
				listChoices.addView(message);
				sCommand = "process show '"+sProcess+"' get { step['"+sStep+"'].params["+Arg.TRANSITIONS+"] } token '';";
				String sTransitions = (String) performOOQLCommands(sCommand).elementAt(0);
				Vector vChoices = StringUtils.StringTokensToVector(sTransitions, ";");				
				final CompoundButton[] choices = new CompoundButton[vChoices.size()];
				LinearLayout.LayoutParams params;
				if (bMultiple) {
					for (int i=0;i<vChoices.size();i++) {
						choices[i] = new CheckBox(listChoices.getContext());
						choices[i].setText((String)vChoices.elementAt(i));
						params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
						params.bottomMargin=15;
						listChoices.addView(choices[i],params);
					}
				} else {
					RadioGroup group = new RadioGroup(listChoices.getContext());
					listChoices.addView(group);
					for (int i=0;i<vChoices.size();i++) {
						choices[i] = new RadioButton(group.getContext());
						choices[i].setText((String)vChoices.elementAt(i));
						params = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.FILL_PARENT,RadioGroup.LayoutParams.WRAP_CONTENT);
						params.bottomMargin=15;
						group.addView(choices[i],params);
					}
				}
				new AlertDialog.Builder(getApp())
				.setIcon(Application.getIcon("decision"))
				.setTitle(getCommonTranslation("DecisionList"))
				.setView(sc)
				.setPositiveButton(Application.getCommonTranslation("Complete"), new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						String sChoices = "";
						for (int i = 0; i < choices.length; i++) {
							if (choices[i].isChecked()) {
								sChoices += "\"" + choices[i].getText() + "\" ";
							}
						}
						if (sChoices.length() > 0) {
							String sCommand = "process complete '"+sProcess+"' step '"+sStep+"' choice "+sChoices+";";
							try {
								performOOQLCommands(sCommand);
								handleRequest(fwrequest);
							} catch (Exception ex) {
								session.setAttribute(TAGS.errormessage, ex.getMessage());
							}
						}
					}
				})
				.setNegativeButton(Application.getCommonTranslation("Cancel"), null)
				.show();
			} else if (sType.startsWith("action")) {
				new AlertDialog.Builder(getApp())
				.setIcon(Application.getIcon("action"))
				.setTitle(getCommonTranslation("CompleteActivity"))
				.setMessage(URLDecoder.decode(HTMLUtil.getInputParameter(TAGS.label, request), StringUtils.UTF8))
				.setPositiveButton(Application.getCommonTranslation("Complete"), new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						String sCommand = "process complete '"+sProcess+"' step '"+sStep+"' ;";
						try {
							performOOQLCommands(sCommand);
							handleRequest(fwrequest);
						} catch (Exception ex) {
							session.setAttribute(TAGS.errormessage, ex.getMessage());
						}							
					}
				})
				.setNegativeButton(Application.getCommonTranslation("Cancel"), null)
				.show();
			}
		} 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());
					}
				}
			} 
		}
		// Forward Page
		String sForwardPage = request.getParameter(TAGS.fwd);
		if (sForwardPage != null) {
			sForwardPage += (sForwardPage.indexOf('?')>0?"&":"?")+TAGS.id+"="+sId;
		} else {
			sForwardPage = "";
		}
		View window = getWindow( (View)request.getReferer() );
		if (window!=null) {
			if (request.getParameter(TAGS.close) != null) {
				View opener = (View) 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 
	 * @param url          the URL to open
	 */
	public void goForward(View targetwin, String url) {
		if (targetwin != null) {
			if (targetwin instanceof LinearLayout) {
				try {
					FrameLayout mTabContent = topTabFolder.getTabContentView();
					int i=0;
					while (i<mTabContent.getChildCount()) {
						if ( mTabContent.getChildAt(i).equals(targetwin) ) {
							topTabFolder.setCurrentTab(i); break;		
						}
						i++;
					}
				} 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 panel
	 * 
	 * @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 LinearLayout createPagePanel(Context context,String title, String subTitle, boolean objectMenu, ApplicationRequest request) {
		final ApplicationSession session = (ApplicationSession)request.getSession();
		LinearLayout globalpanel = new LinearLayout(this);
		setData(globalpanel, TAGS.WIDTH , screenWidth);
		globalpanel.setOrientation(LinearLayout.VERTICAL);
		if (title.length() > 0) {
			LinearLayout panel = new LinearLayout(this);
			panel.setOrientation(LinearLayout.HORIZONTAL);
			LinearLayout.LayoutParams params=new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
			globalpanel.addView(panel);
			if (objectMenu && request.getParameter(TAGS.popup)==null) {
				ObjectObj object = (ObjectObj) session.getAttribute(TAGS.Object);				
				if (object!=null) {
					final String sID = object.getID();
					ImageButton showMenu = new ImageButton(globalpanel.getContext());
					showMenu.setImageDrawable(getIcon("menu_button"));
					showMenu.setBackgroundColor(Color.BLACK);
					params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT);
					panel.addView(showMenu,params);				
					showMenu.setOnClickListener(new OnClickListener() {
						public void onClick(View view) {
							try {							
								Forms.fillObjectPopUpMenu(view,sID,null,session);
							} catch (Exception ex) {}
						}
					});
				}
			}  		
			LinearLayout titlepanel = new LinearLayout(this);
			titlepanel.setOrientation(verticalOrientation?LinearLayout.VERTICAL:LinearLayout.HORIZONTAL);
			params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
			panel.addView(titlepanel,params);
			HTMLUtil.setClass(titlepanel, TAGS.CSS_TitlePanel, true, session);

			TextView ltitle = new TextView(context);
			if (verticalOrientation) {
				params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
			} else {
				params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
				params.weight=1;
			}
			titlepanel.addView(ltitle,params);
			ltitle.setText(title);
			HTMLUtil.setClass(ltitle, TAGS.CSS_Title, session);		  		 

			if (subTitle.length() > 0) {
				TextView lsubtitle = new TextView(context);
				if (verticalOrientation) {
					params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
				} else {
					params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
					params.weight=1;
				}
				titlepanel.addView(lsubtitle,params);
				lsubtitle.setText(subTitle);
				HTMLUtil.setClass(lsubtitle, TAGS.CSS_SubTitle, session);
			}
		} else if (objectMenu && request.getParameter(TAGS.popup)==null) {
			HorizontalScrollView menu = Forms.createObjectMenu(globalpanel, session);
			if (menu != null) {
				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
				globalpanel.addView(menu,params);
			}			
		}

		String sMessage = Forms.getErrorMessage((ApplicationSession)session);
		if (sMessage.length() > 0) {
			errorMessage(this, new Exception(sMessage),"",null);
		}

		// Set scrollbars
		Boolean scrollbars = true;
		String sTarget = request.getTarget();
		if (sTarget.length() > 0 && !sTarget.equals(TAGS._blank)) { 
			LinearLayout popDialog = (LinearLayout)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 or to PopUp window
	 * 
	 * @param panel    the page panel
	 * @param title    the TabItem title
	 * @param request  related Application request
	 */
	public void addPageToContainer(final LinearLayout panel, String indicator, ApplicationRequest request) {
		
		String sTarget = request.getTarget();
		if (sTarget.length() > 0 && !sTarget.equals(TAGS._blank)) { // POPUP
			LinearLayout popDialog = (LinearLayout)getDialog(sTarget);
			if (popDialog != null) {
				popDialog.removeAllViews();
				popDialog.invalidate();
				popDialog.addView(panel);		
				popDialog.setPadding(0,0,0,0);
				AlertDialog dialogWin = (AlertDialog)getData(popDialog,TAGS.WINDOW);	
				if (getData(popDialog,TAGS.pagetitle)==null || ((Boolean)getData(popDialog,TAGS.pagetitle)==true)){
					dialogWin.setTitle(indicator);
				}								
				
				android.view.WindowManager.LayoutParams lp = dialogWin.getWindow().getAttributes(); 
				lp.width = android.view.WindowManager.LayoutParams.WRAP_CONTENT; 
				lp.height = android.view.WindowManager.LayoutParams.WRAP_CONTENT; 				
				dialogWin.getWindow().setAttributes(lp);
				
				dialogWin.show();
			}	else {
				getApp().log("Invalid target: " + sTarget);
				return ;
			}
		} else {  // TAB
			LinearLayout tabItem;
			boolean bNew = request.getTarget().equals(TAGS._blank);
			int iCurrentTab         = (topTabFolder.getCurrentTab()>=0?topTabFolder.getCurrentTab():0);
			TabWidget mTabWidget    = topTabFolder.getTabWidget();      // Container of tab Indicators 
			FrameLayout mTabContent = topTabFolder.getTabContentView(); // Container of tab Views

			if ( mTabWidget.getChildCount() == 0 || bNew ) {
				tabItem = panel;
				// Create new TAB
				TabSpec tabSpec = topTabFolder.newTabSpec(indicator);
				tabSpec.setIndicator(indicator);
				tabSpec.setContent(new TabHost.TabContentFactory(){
					public View createTabContent(String tag) {            	         	
						return panel;
					}       
				});		
				topTabFolder.addTab(tabSpec);
				((ArrayList<TabHost.TabSpec>)topTabFolder.getTag()).add(tabSpec);	
				// set the OPENER TAB
				if (bNew) {
					setData(tabItem,TAGS.OPENER, mTabContent.getChildAt(iCurrentTab) );
					topTabFolder.setCurrentTab( mTabWidget.getChildCount()-1);
				}
			} else {
				// Get the current TAB content
				tabItem = (LinearLayout)mTabContent.getChildAt(iCurrentTab);
				tabItem.removeAllViews();				
				// Move the childrens from panel to current TAB
				int count = panel.getChildCount();
				View[] views = new View[count];
				for (int i=0;i<count;i++) {
					views[i]=panel.getChildAt(i);
				}
				panel.removeAllViews();
				for (int i=0;i<count;i++) {
					tabItem.addView(views[i]);
				}				
				// Update the indicator
				TextView txtIndicator = (TextView) topTabFolder.getCurrentTabView().findViewById(android.R.id.title);
				txtIndicator.setText(indicator);
				List<TabSpec> mTabSpecs = (ArrayList<TabHost.TabSpec>)topTabFolder.getTag();
				((TabHost.TabSpec) mTabSpecs.get(iCurrentTab)).setIndicator(indicator);
			}			
			request.removeParameter(ApplicationRequest.target);
			setData(tabItem,TAGS.REQUEST, request);
			refreshTabs();
			setData(panel,TAGS.WINDOW, tabItem );
		} 		
	}
	
	private void refreshTabs() {
		// Refresh the Tabs
		TabWidget tab_widget = topTabFolder.getTabWidget();
		final int tabChildrenCount = tab_widget.getChildCount();
		View currentTab;
		for (int i = 0; i < tabChildrenCount; i++) {
			currentTab= tab_widget.getChildAt(i);
			currentTab.getLayoutParams().height = TabHeight;
			currentTab.setOnTouchListener(new SwipeDismissTouchListener(currentTab, Integer.valueOf(i), 
          new SwipeDismissTouchListener.DismissCallbacks() {
							public boolean canDismiss(Object token) {
								return true;
							}
							public void onDismiss(View view, Object token) {
								 removeTab(((Integer)token).intValue());
							}
         }));
		}						
		tab_widget.requestLayout(); 
	}
	
	private void removeTab(int index) {
    List<TabSpec> mTabSpecs = (ArrayList<TabHost.TabSpec>)topTabFolder.getTag();
    if (index>=0) mTabSpecs.remove(index);
    topTabFolder.clearAllTabs();
    for (int i=0;i<mTabSpecs.size();i++) {
   		 topTabFolder.addTab(mTabSpecs.get(i));    	
		}
    refreshTabs();
    if (index>=0) topTabFolder.setCurrentTab(index>0?index-1:index+1);
	}
	
	
	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// 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 text) {
		logText.append(text+"\n");
	}
	
	
	// //////////////////////////////////////////////////////////////////////////////////////////////////
	// CSS Styles
	// //////////////////////////////////////////////////////////////////////////////////////////////////

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

		CSSStyle form = new CSSStyle(TAGS.CSS_Form);
		form.setBackGroundColor(25, 25, 25);
		form.setPadding(20, 20, 20, 20);
		HTMLUtil.addCSSStyle(form);
		
		CSSStyle titlepanel = new CSSStyle(TAGS.CSS_TitlePanel);
		titlepanel.setBackGroundColor("#442d5b");
		HTMLUtil.addCSSStyle(titlepanel);
		
		CSSStyle title = new CSSStyle(TAGS.CSS_Title);
		title.setFont(Typeface.create("Arial", CSSStyle.BOLD), 21);
		title.setColor(HTMLUtil.WHITE);
		title.setTextAlignment("right");
		HTMLUtil.addCSSStyle(title);

		CSSStyle subtitle = new CSSStyle(TAGS.CSS_SubTitle);
		subtitle.setFont(Typeface.create("Arial", CSSStyle.NORMAL), 18);
		subtitle.setColor(100, 230, 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(200, 200, 230);
		HTMLUtil.addCSSStyle(td);
		
		CSSStyle label = new CSSStyle(TAGS.CSS_Label);
		label.setFont(Typeface.create("Arial", CSSStyle.NORMAL), 15);
		label.setColor(250, 0, 0);
		HTMLUtil.addCSSStyle(label);
		
		CSSStyle tdlabel = new CSSStyle(TAGS.CSS_LabelCell);
		tdlabel.setFont(Typeface.create("Arial", CSSStyle.BOLD), 16);
		tdlabel.setVerticalAlignment("top");
		tdlabel.setBackGroundColor(20,20,20);
		tdlabel.setColor(230,230, 230);
		HTMLUtil.addCSSStyle(tdlabel);
		
		CSSStyle section = new CSSStyle(TAGS.CSS_Section);
		section.setFont(Typeface.create("Arial", CSSStyle.BOLD), 18);
		section.setColor(0, 250, 250);
		section.setPadding(1, 1, 1, 1);
		section.setBackGroundColor(180, 200, 220);
		HTMLUtil.addCSSStyle(section);
		
		CSSStyle text = new CSSStyle(TAGS.CSS_Text);
		text.setFont(Typeface.create("Arial", CSSStyle.NORMAL), 16);
		text.setColor(0, 0, 0);		
		HTMLUtil.addCSSStyle(text);
		
		CSSStyle textarea = new CSSStyle(TAGS.CSS_TextArea);
		textarea.setFont(Typeface.create("Arial", CSSStyle.NORMAL), 16);
		textarea.setColor(0, 0, 0);		
		HTMLUtil.addCSSStyle(textarea);
		
		CSSStyle select = new CSSStyle(TAGS.CSS_Select);
		select.setFont(Typeface.create("Arial", CSSStyle.BOLD), 15);
		select.setColor(0, 0, 0);		
		HTMLUtil.addCSSStyle(select);
		
		CSSStyle list = new CSSStyle(TAGS.CSS_List);
		list.setFont(Typeface.create("Arial", CSSStyle.BOLD), 14);
		list.setColor(0, 0, 0);	
		list.setBackGroundColor(255, 255, 255);
		HTMLUtil.addCSSStyle(list);
		
		CSSStyle check = new CSSStyle(TAGS.CSS_Checkbox);
		check.setFont(Typeface.create("Arial", CSSStyle.NORMAL), 14);
		check.setColor(0, 0, 0);
		
		HTMLUtil.addCSSStyle(check);
		
		CSSStyle anchor = new CSSStyle(TAGS.CSS_Href);
		anchor.setColor(0, 0, 255);
		anchor.setFont(Typeface.create("Arial", CSSStyle.ITALIC), 15);
			
		HTMLUtil.addCSSStyle(anchor);
		
		CSSStyle statictext = new CSSStyle(TAGS.CSS_StaticText);
		statictext.setFont(Typeface.create("Arial", CSSStyle.NORMAL), 15);
		statictext.setColor(10, 10, 10);
		HTMLUtil.addCSSStyle(statictext);

		CSSStyle buttons = new CSSStyle(TAGS.CSS_ButtonBar);
		buttons.setTextAlignment("right");
		buttons.setBackGroundColor(250, 200, 200);
		buttons.setSpacing(3, 2);
		HTMLUtil.addCSSStyle(buttons);

		CSSStyle button = new CSSStyle(TAGS.CSS_Button);
		button.setTextAlignment("right");
		button.setImage(getIcon("exit"));
		button.setFont(Typeface.create("Arial", CSSStyle.BOLD), 18);
		button.setBackGroundColor(100, 100, 100);
		button.setColor(Color.WHITE);
		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       -         -           -           - 
  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           -           -
  CSS_Label              x       x      -      x      x       x       -         -           -           -
  CSS_LabelCell          x       x      -      x      x       x       x         -           x           x
  CSS_Section            x       x      -      x      x       x       x         -           x           x  
  CSS_Text               x       x      -      x      x       x       -         -           x           x  
  CSS_TextArea           x       x      -      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       -         -           -           -
  
  */
	
}