/**
 * demo program for issue #5482 revised
 * revised to eliminate almost all the garbagex
 */

package com.test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Vector;

import com.codename1.io.Log;
import com.codename1.system.Lifecycle;
import com.codename1.ui.Button;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.Font;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Toolbar;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.layouts.Layout;
import com.codename1.ui.plaf.Style;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;


class G {
	
static boolean time_changed = false;
    private static Object dateCheck = new Object();
    static long last_time = -1;
    public static long time_offset = 0;
    static public long Date() 
    {	
    	synchronized (dateCheck)
    	{
    	long this_time = System.currentTimeMillis();
    	if(this_time<last_time)
    		{ time_changed=true; 
    		  time_offset += (last_time-this_time); 
    		}
    	last_time = this_time;

    	return(time_offset+this_time);
    	}
    }
        static public String[] split(String msg,char ch)
    {	
    	return(split(msg,ch,0));
    }
    // recursive split depth first. Adjusted to return the same as line.split(","), the 
    // boundary case is trailing separators
    static private String[] split(String msg,char ch,int depth)
    {
    	int idx = msg.indexOf(ch);
    	if(idx < 0) 
    		{ 
    		  String res[] = new String[depth+1];
    		  res[depth] =  msg;
    		  return(res);
    		}
     	else
    	{	String [] res = split(msg.substring(idx+1),ch,depth+1);
    		res[depth] = msg.substring(0,idx);
        	return(res);
    	}
    }

	static Vector<String> messages = new Vector<String>();
	public static void print(String ms)
	{	if(ms!=null)
		{for(String m : split(ms,'\n'))
		{
		messages.addElement(m);
		}}
	}
	public static void showMessages(Graphics gc,int x,int y,int w,int h)
	{
		gc.setColor(0xff0000);
	 	gc.fillRect(0,0,w,h);
	  	{
	  	try {	
	  		gc.setColor(0);
	  		gc.fillRect(x,y,w,h);
	  		gc.setColor(0xffffff);
	  		int step = gc.getFont().getHeight()*3/2;
	  		int idx = messages.size()-1;
	  		for(int yy=h-step*2; yy>0 && idx>=0;yy -= step,idx--)
	  		{
	  		gc.drawString(messages.elementAt(idx),10,y+yy);
           	}}
           	catch(Throwable err)
           	{
           		gc.setColor(0);
           		gc.drawString("arithmetic #3108 "+err,100,150);
           	}
        }
	}
	
	public static void waitForEdt()
	{	// the first process will hold the lock, others will pile up
	
	}

	
	public static void runInEdt(Runnable r)
    {	
    	if(isEdt())
    		{
    		r.run();
    		}
    	else
    		{
    		waitForEdt();
    		Display.getInstance().callSeriallyAndWait(r); 
    		}
    }
			 public static long nanoTime()
		{	
			long tim = System.currentTimeMillis();
			return((tim)*1000000);
			
		}
	public static boolean isEdt()
    {
    	Display dis = Display.getInstance();
    	return(dis.isEdt());
    }
	public static String getStackTrace(Throwable t)
	{	G.print("getstack trace "+t);
		int level = LogCapture.getLevel();
		try {
		LogCapture cap = new LogCapture();
		LogCapture.setLevel(99);
		Log.e(t);
		LogCapture.setLevel(level);
		return cap.dispose();	
		}
		catch (Throwable err)
		{
			G.print("error in getStackTrace "+err);
		}
		return "failed stack trace";
	}
		//
	// temporary adjustments to the buildable vm
	//
	public static void printStackTrace(Throwable t,PrintStream s)
	{	
		s.println(getStackTrace(t));
	}
	

   /** get the current stack trace as a String */
    public static String getStackTrace()
    {
    	ByteArrayOutputStream b = new Utf8OutputStream();
        PrintStream os = Utf8Printer.getPrinter(b);
        try { throw new ErrorTrace("Stack trace");
        } catch (Error e)
        {	Plog.log.addLog("stack trace ",e);
        	try {
        	printStackTrace(e,os);
        	}
        	catch (Throwable er)
        	{
        		Plog.log.addLog("error getting stack trace "+er);
        	}
        	os.flush();
        }
    	return b.toString();
   }
	    /**
     * G.Assert returns true, or throws an Error.  This provides a
     *   convenient place to place a breakpoint for any kind of internally
     *   detected error.  This should be the only "throw ErrorX" in the system.
     *   @param condition a boolean that was evaluated in the caller's context
     *   @param message a message {@link #format} string
     *   @param args... optional args for the format string
     *   @return true, or throws an error. 
     */
    public static boolean Assert(boolean condition, String message)
    {	if (!condition)
        {
        	throw new ErrorX(message);
        }
        return (true);
    }
}
class ErrorX extends Error {
	/**
	 * 
	 */
	static final long serialVersionUID = 1L;
	String extraInfo="";
	public void addExtraInfo(String more) { extraInfo += more + "\n"; }
	public ErrorX(String m) { super(m); }
	public ErrorX(Throwable m) { super(m.toString()); }
	
	public void printStackTrace()
	{
		super.printStackTrace();
		if(!"".equals(extraInfo)) { G.print(extraInfo); }
	}
	// note that because of the way codenameone structures printStackTrace,
	// if we implement it here a stack overflow will result
	//public void printStackTraceX(PrintStream s)
	//{	super.printStackTrace(s);
	//	if(!"".equals(extraInfo)) { s.println(extraInfo); }
	//}
	

}

class ErrorTrace extends Error 
{ 	public ErrorTrace(String n) { super(n); }
	public void printStackTrace() { }
}

class Plog {
	String events[] = null;
	int index = 0;
	int totalEvents = 0;
	int startingEvent = 0;
	public boolean verbose = false;
	public Thread logThread = null;
	StringBuilder eventLog = null;
	
	public Plog(int size)
	{
		events = new String[size];
		index = 0;
		totalEvents = 0;
	}
	
	// start a new event, add timestamps and thread stamps
	public synchronized StringBuilder startEvent()
	{
	    finishEvent();
		setLogThread();
		StringBuilder el = eventLog = new StringBuilder();
		long now60 = G.nanoTime()%60000000000l;			// 60 seconds
		int secs = (int)(now60/1000000000l);			//
		int nanos = (int)(now60%1000000000l);
	    if(isLogThread()) {el.append("E "); }
	    else { el.append(Thread.currentThread().getName()); el.append(" "); }
	   
		int micros = (int)((nanos+500)/1000);
		int millis = micros/1000;
		micros=micros%1000;
		if(secs<10) { el.append(' '); }
		el.append(secs);
		el.append('+');
   		el.append(millis);
   		el.append('.');
   		if(micros<10) { el.append("00"); }
   		else if(micros<100) { el.append("0");}
   		el.append(micros);
		el.append(" ");
		return(el);
	}
	/**
	 * start a new event and leave it open for additional data
	 * @param msg
	 */
	public synchronized StringBuilder appendNewLog(String msg)
	   {		
	    StringBuilder ev = startEvent();	    
   		ev.append(msg);
   		return(ev);
  	   }
	/**
	 * clear the event log
	 */
	public synchronized void restartLog()
	   {	finishEvent();
	   		totalEvents = index = 0;
	   		AR.setValue(events,null);
	   }

	/**
	 * add a complete event
	 * 
	 * @param msg
	 */
	public synchronized void addLog(String msg)
	   {
			appendNewLog(msg);
			finishEvent();
	   }
	public synchronized void addLog(String msg,Object ...args)
	{
		appendNewLog(msg);
		if(args!=null)
		{
		for(int i=0; i<args.length;i++) 
			{ Object ai = args[i];
			  appendLog(ai==null ? "null" : ai.toString());
			}
		}
		finishEvent();
	}
	/** 
	 * true of the current thread is the expected thread for this log
	 * 
	 * @return
	 */
	public boolean isLogThread() { return(Thread.currentThread()==logThread); }
	/**
	 * set the expected thread for this log to the current thread
	 */
	private void setLogThread()
	   {
	   	if(logThread==null) {  logThread = Thread.currentThread(); }
	   }
	
	public synchronized void finishEvent()
	   {StringBuilder ev = eventLog;
		if(ev!=null)
		{	eventLog = null;	
			String msg = events[index++] = ev.toString();
			totalEvents++;
			if(index>=events.length) { index = 0;}		
			if(verbose) { G.print(msg); }
		}
	   }
	/**
	 * append to the current event
	 * @param msg
	 */
	public synchronized void appendLog(String msg)
	   {	StringBuilder ev = eventLog;
	   		if(ev!=null) { ev.append(msg); }
	   }
	/**
	 * append to the current event
	 * @param msg
	 */
	public synchronized void appendLog(int msg)
	   {	StringBuilder ev = eventLog;
  			if(ev!=null) { ev.append(msg); }
	   }
	/**
	 * append to the current event
	 * @param msg
	 */
	public synchronized void appendLog(char msg)
	   {StringBuilder ev = eventLog;
  		if(ev!=null) { ev.append(msg); }
	   }
	public synchronized void appendLog(Object s)
	{	StringBuilder ev = eventLog;
		if(ev!=null) { ev.append(s.toString()); };
	}
	/**
	 * append to the current event
	 * @param msg
	 */
	public synchronized void appendLog(double msg)
	   {	StringBuilder ev = eventLog;
  			if(ev!=null) { ev.append(msg); }
	   }
	/**
	 * get the current event log as a single string with line breaks
	 * @return
	 */
	public synchronized String getLog()
	   {	
		return(getLog(0));
	   }
	public synchronized String getUnseen()
	{	int se = startingEvent;
		startingEvent = totalEvents;
		return getLog(se);
	}
	private synchronized String getLog(int from)
	   {	finishEvent();
			int size = events.length;
			int idx = (totalEvents-from)>=size
							? (index+1)%size		// log is full, we lost some events
							: from%size;	// recent events only
			if(idx!=index)
			{
			StringBuilder b = new StringBuilder();
			while(idx!=index)
			{
				b.append(events[idx]);
				b.append('\n');
				idx++;
				if(idx>=size) { idx = 0; }
			}
			return(b.toString());
			}
			return(null);
		}

	/**
	 * close,restart, and return the current log as a single string
	 * optionally just discard the log
	 * @param discard
	 * @return
	 */
	public synchronized String finishLog(boolean discard)
	{
		String m = discard ? null : getLog();
		if(discard) { restartLog(); }
		return(m);	
	}
	/**
	 * close,restart, and return the current log as a single string
	 * @param discard
	 * @return
	 */
	public String finishLog() { return finishLog(false); }
	/** this is intended to be the permanent system level log
	 * of events, which can be attached to bug reports etc.
	 * this is incorporated into most bug reports automatically
	 * by http.getErrorMessage()
	 */
	public static Plog log = new Plog(100);
	public static Plog messages = new Plog(500);

}
class AR {

	/**
	    * @param c1
	    * @param c2
	    * @return true if two integer arrays contain the same integers
	    */
	   static public boolean sameArrayContents(int c1[],int c2[])
		{	int len = c1.length;
			if(len==c2.length)
			{	for(int i=0;i<len;i++) { if(c1[i]!=c2[i]) { return(false); }}
				return(true);
			}
			return(false);
		}

	/**
	    * @param c1
	   * @param c2
	   * @return true if two integer arrays contain the same integers
	   */
	  static public boolean sameArrayContents(long c1[],long c2[])
		{	int len = c1.length;
			if(len==c2.length)
			{	for(int i=0;i<len;i++) { if(c1[i]!=c2[i]) { return(false); }}
				return(true);
			}
			return(false);
		}

	/**
	    * @param c1
	   * @param c2
	   * @return true if two byte arrays contain the same integers
	   */
	  static public boolean sameArrayContents(byte c1[],byte c2[])
		{	int len = c1.length;
			if(len==c2.length)
			{	for(int i=0;i<len;i++) { if(c1[i]!=c2[i]) { return(false); }}
				return(true);
			}
			return(false);
		}

	/**
	    * @param c1
	    * @param c2
	    * @return true if two boolean arrays contain the same sequence of booleans
	    */
	   static public boolean sameArrayContents(boolean c1[],boolean c2[])
		{	int len = c1.length;
			if(len==c2.length)
			{	for(int i=0;i<len;i++) { if(c1[i]!=c2[i]) { return(false); }}
				return(true);
			}
			return(false);
		}

	static public boolean sameArrayContents(char c1[],char c2[])
	{	int len = c1.length;
		if(len==c2.length)
		{	for(int i=0;i<len;i++) { if(c1[i]!=c2[i]) { return(false); }}
			return(true);
		}
		return(false);
	}

	static public boolean sameArrayContents(double c1[],double c2[])
	{	int len = c1.length;
		if(len==c2.length)
		{	for(int i=0;i<len;i++) 
				{ if(c1[i]!=c2[i])
					{ return(false); 
					}
				}
			return(true);
		}
		return(false);
	}

	/**
	    * @param c1
	    * @param c2
	    * @return true if two boolean arrays contain the same sequence of Objects
	    */
	   static public boolean sameArrayContents(Object c1[],Object c2[])
		{	int len = c1.length;
			if(len==c2.length)
			{	for(int i=0;i<len;i++) { if(c1[i]!=c2[i]) { return(false); }}
				return(true);
			}
			return(false);
		}

	/**
	    * copy the contents of one integer array into another.  If the
	    * destination is null, create a copy of the source.
	    * @param to the destination array
	    * @param from the source array
	    * @return to or the new array
	    */
	   static public int[] copy(int to[],int from[])
	   {	if(from!=null)
		    {int len = from.length;
		     if(to==null) { to = new int[len]; }
		     else { G.Assert(len==to.length,"same length"); }
	   	     for(int i=0;i<len;i++) { to[i]=from[i]; }
	   }
	   		return(to);
	   }

	/**
	    * copy the contents of one integer array into another, if the destination
	    * is null, create a copy of the source.
	    * @param to the destination array
	    * @param from the source array
	    * @return to or the new array
	    */
	   static public long[] copy(long to[],long from[])
	   {	if(from!=null)
		    {int len = from.length;
		    if(to==null) { to = new long[len]; }
		    else { G.Assert(len==to.length,"same length");}
	   	    for(int i=0;i<len;i++) { to[i]=from[i]; }
	   }
	   	return(to);
	   }

	/**
	    * copy the contents of one double array into another, if the 
	    * destination is null, create a copy of the source.
	    * @param to the destination array
	    * @param from the source array
	    * @return to or the new array
	    */
	   static public double[] copy(double to[],double from[])
	   {	if(from!=null)
		    {int len = from.length;
		     if(to==null) { to = new double[len]; }
		     else { G.Assert(len==to.length,"same length"); }
	   	     for(int i=0;i<len;i++) { to[i]=from[i]; }
	   }
	   		return(to);
	   }

	/**
	    * copy the contents of one integer array into another
	    * @param to the destination array
	    * @param from the source array
	    * @return to or the new array
	    */
	   static public char[] copy(char to[],char from[])
	   {	if(from!=null)
		   	{ int len = from.length;
		   	if(to==null) { to = new char[len]; }
		   	else { G.Assert(len==to.length,"same length"); }
	   	    for(int i=0;i<len;i++) { to[i]=from[i]; }
	   }
	   		return(to);
	   }

	/**
	    * copy the contents of one array of objects to another
	    * @param to the destination array
	    * @param from the source array
	    */
	   static public void copy(Object to[],Object from[])
	   {	int len = to.length;
	   		G.Assert(len==from.length,"same length");
	   	    for(int i=0;i<len;i++) 
	   	    { Object s = from[i];
	   	      // limits to java type system.  Object[][] gets here too, and end up copying
	   	      // the structure.  Trying to cast Object[][] to Object[] fails because arrays
	   	      // are not the type of their contents.  The best we can do is scream.
	   	      G.Assert(s==null || !s.getClass().isArray(),"can't be an array[][]");
	   	      to[i]=from[i]; 
	   	    }
	   }

	/**
	    * copy an array of arrays of integers
	    * @param to
	    * @param from
	    */
	   static public void copy(int [][]to,int [][]from)
	   {
		   int len = to.length;
		   G.Assert(len==from.length,"same length");
		   for(int i=0;i<len;i++) { copy(to[i],from[i]); }
	   }

	/**
	    * create a copy of an integer array
	    * @param from
	    * @return a new array
	    */
	   static public int[]copy(int from[])
	   {	int val[] = null;
		    if(from!=null)
		    {
		    	val = new int[from.length];
		    	copy(val,from);
		    }
		    return(val);
	   }

	/**
	    * create a copy of an double array
	    * @param from
	    * @return a new array
	    */
	   static public double []copy(double from[])
	   {	double val[] = null;
		    if(from!=null)
		    {
		    	val = new double[from.length];
		    	copy(val,from);
		    }
		    return(val);
	   }

	/**
	    * set each cell of a boolean array to a fixed value
	   */
	   static public void setValue(boolean c1[],boolean v)
	   {
		   for(int lim=c1.length-1; lim>=0; lim--) { c1[lim]=v; }
		}

	   /**
	    * set each cell of an array to a fixed value
	    */
	   static public void setValue(int c1[],int v)
	   {
		   for(int lim=c1.length-1; lim>=0; lim--) { c1[lim]=v; }
		}

	/**
	    * set each cell of an array to a fixed value
	   */
	   static public void setValue(Object c1[],Object v)
	   {
		   for(int lim=c1.length-1; lim>=0; lim--) { c1[lim]=v; }	   
		}

	static public void setValue(Object c1[][],Object v)
	   {
		   for(Object cv[] : c1) { setValue(cv,v); }	   
		}

	/**
	    * set each cell of an array to a fixed value
	    * @param speed
	    * @param d
	    */
	   public static void setValue(double[] speed, double d) {
			for(int lim=speed.length-1; lim>=0; lim--) { speed[lim] = d; }
	   }

	/**
	    * copy the contents of one boolean array into another
	    * @param c1 the destination array
	    * @param c2 the source array
	    */
	   static public void copy(boolean c1[],boolean c2[])
	   {	int len = c1.length;
	   		G.Assert(len==c2.length,"same length");
	   	    for(int i=0;i<len;i++) { c1[i]=c2[i]; }
	   }

	/**
	    * utility to allocate an array length n containing integers 0-n-1
	    * @param n
	    * @return an array of integers
	    */
	   static public int[]intArray(int n)
	   {
		   int ar[] = new int[n];
		   for(int i=0;i<n;i++) { ar[i]=i; }
		   return(ar);
	   }
/**
 * return the index of content "i" in array a, or -1 if its not there
 * 
 * @param a
 * @param i
 * @return
 */
	   static public int indexOf(Object []a,Object i)
	   {
		   for(int lim = a.length-1; lim>=0; lim--) { if (a[lim]==i) return lim; }
		   return(-1);
	   }
	   
	   static public int indexOf(int[]a,int i)
	   {
		   for(int lim = a.length-1; lim>=0; lim--) { if (a[lim]==i) return lim; }
		   return(-1);		   
	   }
	   public static String toString(Object []a)
	   {	StringBuilder b = new StringBuilder("[");
	   		if(a!=null)
	   		{
	   		for(int i=0,lim=a.length-1;i<=lim; i++)
	   			{ if(i>20 && lim>i)
	   				{ b.append( "... + "); 
	   				  b.append((lim-i)); 
	   				  i=lim; 
	   				}
	   			else 
	   				{ b.append(" "); 
	   				  b.append(a[i]); 
	   				}
	   			}}
	   		b.append("]");
	   		return b.toString();
	   }
	   public static String toString(int []a)
	   {	StringBuilder b = new StringBuilder("[");
	   		if(a!=null)
	   		{
	   		for(int i=0,lim=a.length-1;i<=lim; i++)
	   			{ if(i>20 && lim>i)
	   				{ b.append( "... + "); 
	   				  b.append((lim-i)); 
	   				  i=lim; 
	   				}
	   			else 
	   				{ b.append(" "); 
	   				  b.append(a[i]); 
	   				}
	   			}}
	   		b.append("]");
	   		return b.toString();
	   }
	/**
	 * @param list
	 * @param c
	 * @param max
	 * @return  true if the array contains the specified object
	 */
	public static boolean arrayContains(Object list[],Object c,int max)
	{	for(int i=0;i<max;i++) { if(list[i]==c) { return(true); }}
		return(false);
	}

	/**
	  * @param list
	 * @param c
	 * @return true if the object contains the specified object.
	 */
	public static boolean arrayContains(Object list[],Object c)
	{	return((list==null)?false : arrayContains(list,c,list.length));
	}
}

class Utf8Printer extends PrintStream {
	public Utf8Printer(OutputStream ss,String encod) throws UnsupportedEncodingException
	{	
			super(ss);
	}
	public Utf8Printer(OutputStream ss) { super(ss); }
	
	//
	// use this static instead of "new" so you don't have to 
	// catch UnsupportedEncodingException
	//
	public static Utf8Printer getPrinter(OutputStream ss)
	{
		try {
			return new Utf8Printer(ss,"UTF-8");
		}
		catch (UnsupportedEncodingException e)
		{
			return(new Utf8Printer(ss));
		}
	}

	public void print(String s)
	{
        try {
        	byte bs[] = s.getBytes("UTF-8");
        	write(bs,0,bs.length);
		} catch (UnsupportedEncodingException e) {
			super.print(s);
		}
    }
	public void println(String s)
	{
        print(s);print('\n');
    }
	public void print(char s)
	{	print(""+s);
	}
	public void println(char s)
	{
		println(""+s);
	}
   
}

class LogCapture extends Log
{	Log oldLog;
	StringWriter myWriter;
	LogCapture() 
	{ oldLog = Log.getInstance();
	  G.print("install "+this);
	  install(this);  
	}
	protected Writer createWriter() throws IOException 
	{	return(myWriter = new StringWriter());
	}
	
	public String dispose()
	{
		install(oldLog);
		String str = myWriter.toString();
		G.print("dispose log "+str.length());
		return(myWriter==null ? "" : str);
	}
 
}
class Utf8OutputStream extends ByteArrayOutputStream 
{
	public String toString() 
	{	byte ba[] = toByteArray();
		String ss=null;
		try {
			ss = new String(ba, 0, ba.length, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			ss = super.toString();
		}
		return(ss);
	} 
	public String toString(boolean utf8)
	{
		return(utf8 ? toString() : super.toString());
	}
}


interface TestAble
{
	public void runTest(Graphics gc,int x,int y,int w,int h);
}

@SuppressWarnings("rawtypes")
class Test extends Component implements ActionListener<ActionEvent>
{	Form form = null;
	TestAble current = null;
	Test(Form f)
	{	form = f;		
		Toolbar tb = f.getToolbar();
		Dimension tbd = tb.getPreferredSize();
		setPreferredSize(new Dimension(f.getWidth(),f.getHeight()-tbd.getHeight()));
		current = new Dtest_dictionary();
	}

	boolean change = false;
	int changes = 0;
	public static int step =0;
	
	public void paint(Graphics g)
	{	int w = getWidth();
		int h = getHeight();
		current.runTest(g,0,0,w,h);
		G.showMessages(g,0,0,w,h);
	}
	public int getAbsoluteX()
	{	return getAbsoluteX(getParent());
	}
	public int getAbsoluteY()
	{	return getAbsoluteY(getParent());
	}
	public int getAbsoluteX(Container p)
	{	return (p==null) ? 0 : p.getX() + getAbsoluteX(p.getParent());
	}
	public int getAbsoluteY(Container p)
	{	return (p==null) ? 0 : p.getY() + getAbsoluteY(p.getParent());
	}
	public void actionPerformed(ActionEvent evt) {
		if(changes==0) {		change = true; }
		changes++;
	}
	public void pointerPressed(int x,int y)
	{
		if(changes==0) {		change = true; }
		changes++;
		step++;
	}
}

class Dtest_dictionary implements TestAble
{
	 int pass = 1;
	 public void runTest(Graphics gc,int x,int y,int w,int h)
	 {  
	 	G.print("test pass "+pass++);
	 	G.print(G.getStackTrace());
	 }
	
}

class BorderLayout extends com.codename1.ui.layouts.BorderLayout
{
	
}

class Panel extends Container
{
	public Panel(Layout flowLayout,String uid)
	{	setLayout(flowLayout);
		setUIID(uid);
	}
}

class MasterToolBar extends Toolbar
{
	MasterToolBar()
	{
		super();
		setLayout(new BorderLayout());
		setUIID("TitleAreaMasterForm");	// our own structure with a margin on top

	}
}

class TabLayout extends com.codename1.ui.layouts.Layout
{	private int spacing = (int)(4*1.5);
	public void layoutContainer(Container parent) {
        int w = parent.getWidth();
        int h = parent.getHeight()-spacing*2;
        int nc = parent.getComponentCount();
		int sum = getFullWidth(parent);
		int squeeze = nc==0 ? 0 : (sum>w) ? (sum-w+nc)/nc : 0;
		int deficit = 0;
		for(int i=0,xpos=spacing;i<nc;i++) 
		{ com.codename1.ui.Component p = parent.getComponentAt(i);
		  p.setX(xpos);
		  p.setY(spacing);
		  p.setHeight(h);
		  int ww2 = prefw(parent,i);
		  int desired = ww2-squeeze+deficit;
		  int actual = Math.max(20, desired);
		  p.setWidth(actual);
		  deficit = desired-actual;
		  xpos += actual+spacing;
		}
	}
	
	int getFullWidth(Container parent)
	{	int nc = parent.getComponentCount();
		int h = parent.getHeight()-spacing*2;
		int sum = h/2;
		for(int i=0;i<nc;i++) 
		{ 
		  sum += prefw(parent,i)+spacing; 
		}
		return(sum);
	}
	// this is an ad-hoc calculation to find the preferred width for an icon
	// assuming it will be scaled to the height of the parent.  The h/6 factor
	// accounts for wider horizontal margins than vertical, not sure where they
	// come from.
	int prefw(Container parent, int i)
	{	int h = parent.getHeight()-spacing*2;
		Dimension dim = parent.getComponentAt(i).getPreferredSize();
		int inc = (int)(h*((double)dim.getWidth()/dim.getHeight())+h/6);
		return inc;
	}
	int getFullHeight(Container parent)
	{	int nc = parent.getComponentCount();
		// use font height as the basic scale metric
		Font f = parent.getStyle().getFont();
		int fs = f.getSize();
		int max = (int)(fs*2.2);
		//G.print("FontManager "+f+" sz ",fs," h ",max);
		for(int i=0;i<nc;i++) { max = Math.max(parent.getComponentAt(i).getPreferredSize().getHeight(),max); }
		return(max);
	}
	public Dimension getPreferredSize(Container parent) {
		
		Dimension dim =new Dimension(getFullWidth(parent),getFullHeight(parent));
		return(dim);
	}

}

@SuppressWarnings("rawtypes")
class MasterForm extends Form 
{	static MasterForm masterForm = null;
	public MasterForm()
	{	
	}
	
}
class NoLayout extends Layout
{

	public void layoutContainer(Container parent) {
		for(int i=0;i<parent.getComponentCount();i++)
		{
			Component c = parent.getComponentAt(i);
			c.setWidth(parent.getWidth());
			c.setHeight(parent.getHeight());
		}
	}

	public Dimension getPreferredSize(Container parent) {
		return new Dimension(parent.getWidth(),parent.getHeight());
	}
	
};

@SuppressWarnings("rawtypes")
public class Dtest  extends Lifecycle 
{

private Form current;
@SuppressWarnings("unused")
private Resources theme;



public void init(Object context) {
    theme = UIManager.initFirstTheme("/theme");
    // Pro only feature, uncomment if you have a pro subscription
    // Log.bindCrashProtection(true);
}
public Toolbar toolbar = null;

public void start() {
    
    if(current != null){
        current.show();
    }
    MasterForm hi = new MasterForm();
    MasterToolBar toolBar = new MasterToolBar();
    hi.setToolbar(toolBar);
	Panel tabs = new Panel(new TabLayout(),"ContainerMasterForm");
	Panel menus = new Panel(new TabLayout(),"ContainerMasterForm");
	Panel centers = new Panel(new TabLayout(),"ContainerMasterForm");

	Style s = toolBar.getStyle();
	s.setMargin(0,0,0,0);			// remove the margin except on ios
	s.setPadding(0,0,0,0);

	toolBar.add("West",tabs);
	toolBar.add("East",menus);
	toolBar.add("Center",centers);  
	

	
	
    
	Button b1 = new Button("1 button 1");
	Button b2 = new Button("2 button 2");
	tabs.add(b1);
	tabs.add(b2);
    Test can = new Test(hi);
    hi.show();
    b1.addActionListener(can);
    b2.addActionListener(can);
    hi.addComponent(can);
    can.setVisible(true);

}
public void stop() {
    current = Display.getInstance().getCurrent();
}

public void destroy() {
}
}



