import java.awt.*;
import java.util.*;
import java.net.*;

class CELLDISP{
	public mform_c item;
	public int used;	// Une cellule multi-colonne ou multi-ligne
						// occupe l'espace, voir USED_XXX
	public Dimension d;
	public CELLDISP(){
		used = 0;
		item = null;
		d = null;
	}
}

class mform_layout implements LayoutManager {
	static  int MAX_COL = 20;
	static  int USED_TOP=1;	// On est sur la première ligne d'un multi-ligne
	static  int USED_LEFT=2;		// On est sur la première colonne d'un multi-colonne
	static  int USED_MULTICOL=4;	// Ce champs occupe plusieurs colonnes
	static  int USED_MULTILINE=8;	// Ce champs occupe plusieurs lignes

	private int preferredWidth,preferredHeight;
    private int minWidth = 0, minHeight = 0;
    private boolean sizeUnknown = true;
    private boolean DEBUG = false;
	mform fl;

	public mform_layout(mform _fl) {
		fl = _fl;
	}

	/* Required by LayoutManager. */
	public void addLayoutComponent(String name, Component comp) {
		System.err.println ("addLayoutComponent");
	}

	/* Required by LayoutManager. */
	public void removeLayoutComponent(Component comp) {
		System.err.println ("removeLayoutComponent");
	}


	private Dimension FitStrategie_marge(
		int gauche,
		int droit,
		int haut,
		int bas,
		boolean use_cur_size){
		// if (fl.parent == null) System.err.println ("fit start");
		System.err.flush();
		//System.err.println ("Fitstrategie " + mform.getabspath(fl) + " " + fl.was_modified());
		//if (!fl.was_modified()) return;
		int nb = fl.nbc;
		gauche += fl.marge_gauche;
		droit += fl.marge_droite;
		haut += fl.marge_haut;
		bas += fl.marge_bas;

		FontMetrics met = fl.getGraphics().getFontMetrics();
		CELLDISP tbcell[][] = new CELLDISP[100][20];
		for (int i=0; i<100; i++){
			for (int j=0; j<20; j++) tbcell[i][j] = new CELLDISP();
		}
		int noline = 0;
		int nocol = 0;
		int has_fill = 0;
		for (int i=0; i<nb; i++){
			mform_c item = fl.getitem(i);
			while (tbcell[noline][nocol].used != 0) nocol++;
			if (item.type == mform_c.T_NEWLINE){
				noline++;
				nocol = 0;
			}else if (item.type == mform_c.T_SKIP){
				int used = USED_LEFT | USED_TOP;
				tbcell[noline][nocol].item = item;
				for (int sk=0; sk<item.h_cells; sk++,nocol++){
					tbcell[noline][nocol].used = used;
					used &= ~USED_LEFT;
				}
			}else if (item.type == mform_c.T_FILL){
				if (fl.stretch_mode == formbase.STRETCH_NONE){
					fl.stretch_mode = formbase.STRETCH_LOOK;
				}
				tbcell[noline][nocol].item = item;
				tbcell[noline][nocol].used = USED_LEFT | USED_TOP;
				nocol++;
			}else{
				tbcell[noline][nocol].item = item;
				int used = USED_LEFT | USED_TOP;
				if (item.is_hcontrib){
					int nbcol = item.h_cells;
					if (nbcol > 1) used |= USED_MULTICOL;
					if (item.v_cells > 1) used |= USED_MULTILINE;
					for (; nbcol>0; nbcol--,nocol++){
						int nol = noline;
						used |= USED_TOP;
						for (int l=0; l<item.v_cells; l++,nol++){
							tbcell[nol][nocol].item = item;
							tbcell[nol][nocol].used = used;
							used &= ~USED_TOP;
						}
						used &= ~USED_LEFT;
					}
				}else{
					tbcell[noline][nocol].used = used;
					nocol++;
				}
			}
		}
		int colwidth[] = new int[MAX_COL];
		int lineheight[] = new int[noline+1];
		for (int i=0; i<MAX_COL; i++) colwidth[i] = 0;
		for (int i=0; i<=noline; i++) lineheight[i] = 0;
		// Dans un premier temps, on calcule la largeur de chaque
		// colonne et la hauteur de chaque ligne en ne tenant compte
		// que des items simple (non multi-ligne ou non-multicolonne)
		// Pour chaque colonne, on trouve l'item le plus large.
		// Pour chaque ligne, on trouve l'item le plus haut.
		for (int i=0; i<=noline; i++){
			for (int c=0; c<MAX_COL; c++){
				mform_c item = tbcell[i][c].item;
				if (item != null && item.is_hcontrib){
					int nbcol = item.h_cells;
					int nbline = item.v_cells;
					char dhori = item.h_align;
					char dverti = item.v_align;
					Dimension d = null;
					if (item.c != null){
						d = use_cur_size
							? item.c.size()
							: item.c.preferredSize();
					}else if (item.type == mform_c.T_LABEL){
						d = new Dimension (met.stringWidth(item.s)+4
							,met.getHeight()+4);
					}
					tbcell[i][c].d = d;
					if (d != null){
						if (nbcol == 1){
							if (colwidth[c] < d.width) colwidth[c] = d.width;
						}
						if (nbline == 1){
							if (lineheight[i] < d.height) lineheight[i] = d.height;
						}
					}
				}
			}
		}
		// On recommence le processus, mais ce coup ci, en ne tenant
		// compte que des items multi-colonnes et multi-ligne.
		// Ce qui nous interesse, c'est la largeur totale des X colonnes
		// occupé par l'item vs sa propre largeur. Si sa largeur excede
		// alors, on augmentera artificiellement la largeur de la dernière
		// colonne. On pourrait aussi repartir l'excédant entre les colonnes
		// On fait la même chose pour les multi-lignes
		for (int i=0; i<=noline; i++){
			for (int c=0; c<MAX_COL; c++){
				mform_c item = tbcell[i][c].item;
				if (item != null && item.is_hcontrib){
					int used = tbcell[i][c].used;
					int nbcol = item.h_cells;
					int nbline = item.v_cells;
					char dhori = item.h_align;
					char dverti = item.v_align;
					Dimension d = tbcell[i][c].d;
					if (d != null){
						if (nbcol > 1 && (used & USED_LEFT) != 0){
							int total = 0;
							for (int x=0; x<nbcol; x++) total += colwidth[x+c];
							if (total < d.width){
								colwidth[c+nbcol-1] += d.width-total;
							}
						}
						if (nbline > 1 && (used & USED_TOP) != 0){
							int total = 0;
							for (int x=0; x<nbline; x++) total += lineheight[x+i];
							if (total < d.height) lineheight[i+nbline-1]
								+= d.height-total;
						}
					}
				}
			}
		}
		// On connait maintenant les spécifications de chaque colonnes
		// et chaque ligne, donc la taille maximum de chaque cellule.
		// On va repasser au travers du design une fois de plus et
		// demander à tous les items extensibles de bien vouloirs
		// s'étirer pour occuper leur cellule complètement.
		for (int i=0; i<=noline; i++){
			for (int c=0; c<MAX_COL; c++){
				if ((tbcell[i][c].used & (USED_TOP | USED_LEFT))
					 == (USED_TOP | USED_LEFT)){
					mform_c item = tbcell[i][c].item;
					if (item != null && item.type == mform_c.T_FORM){
						formbase b = (formbase)item.c;
						if (b.may_stretch()){
							int nbcol = item.h_cells;
							int nbline = item.v_cells;
							int cwidth = 0;
							int cheight = 0;
							for (int ci=0; ci<nbcol; ci++){
								cwidth += colwidth[c+ci];
							}
							for (int ci=0; ci<nbline; ci++){
								cheight += lineheight[i+ci];
							}
							Dimension d = item.c.preferredSize();
							if (cwidth > d.width || cheight > d.height){
								b.stretch (cwidth,cheight);
							}
						}
					}
				}
			}
		}
		// On peut maitenant disposer les items
		int v_pos = haut;
		int h_pos = gauche;
		for (int i=0; i<=noline; i++){
			h_pos = gauche;
			String disp = fl.dispstr;
			for (int c=0; c<MAX_COL; c++){
				mform_c item = tbcell[i][c].item;
				if (item != null){
					int used = tbcell[i][c].used;
					if((used & USED_LEFT) != 0
						&& (used & USED_TOP) != 0
						&& tbcell[i][c].d != null){
						int nbcol = item.h_cells;
						int nbline = item.v_cells;
						char dhori = item.h_align;
						char dverti = item.v_align;
						Dimension d = tbcell[i][c].d;
						if (item.c != null){
							d = item.c.size();
							if (d.width == 0) d = item.c.preferredSize();
						}
						int total_width = 0;
						for (int x=0; x<nbcol; x++) total_width += colwidth[x+c];
						int total_height = 0;
						for (int y=0; y<nbline; y++) total_height += lineheight[y+i];
						if (dhori == ' ') dhori = disp.charAt(c);
						if (dverti == ' ') dverti = 't';
						int xpos = h_pos;
						int ypos = v_pos;
						if (dhori == 'r'){
							xpos += total_width - d.width;
						}else if (dhori == 'c'){
							xpos += (total_width - d.width)/2;
						}
						if (dverti == 'b'){
							ypos += total_height - d.height;
						}else if (dverti == 'c'){
							ypos += (total_height - d.height)/2;
						}
						if (item.type == mform_c.T_LABEL){
							item.x = xpos;
							item.y = ypos;
						}else if (item.type == mform_c.T_HLINE){
							//item.c.reshape (xpos,ypos,d.width,d.height);
							item.c.reshape(xpos,ypos,total_width,d.height);
						}else{
							item.c.reshape (xpos,ypos,d.width,d.height);
						}
						//if (item->is_vline()) item->setspec(-1,-1,-1,total_height);
					}
				}
				h_pos += colwidth[c];
			}
			v_pos += lineheight[i];
		}
		//stretch_last(h_pos);
	 	// Peut-etre que dans windows il faut un chiffre different que 18.
		//	 	if (menu_is_set){
		//			#if defined(UNIX_LINUX)
		//				v_pos += GetCharHeight() + 18 ;
		//			#else
		//				if(!getframe_mode_resize())
		//					v_pos += GetCharHeight() + 5;
		//			#endif
		//		}

		Dimension ret = new Dimension (h_pos+droit, v_pos + bas);
		if (ret.width < fl.min_width) ret.width = fl.min_width;
		fl.modified = false;
		// if (fl.parent == null) System.err.println ("fit end");
		return ret;
	}

	// Compute the layout of the dialog with existing item size
	// prefered size

	public Dimension setsizes (Container parent, boolean use_cur_size){
		//System.err.println ("setsizes");
		Insets insets = parent.insets();
		int left = insets.left;
		if (fl.sidetitle != null) left += 20;
		Dimension ret = FitStrategie_marge(left,0,insets.top,0,use_cur_size);
		//Always add the container's insets!
		ret.width += insets.right;
		ret.height += insets.bottom;
		return ret;
	}
	/* Required by LayoutManager. */
	public Dimension preferredLayoutSize(Container parent) {
		// if (fl.parent == null) System.err.println ("preferredLayoutSize");
		if (sizeUnknown || fl.was_modified()){
			Dimension ret = setsizes (parent,false);
			minWidth = preferredWidth = ret.width;
			minHeight = preferredHeight = ret.height;
			sizeUnknown = false;
		}
		// if (fl.parent == null) System.err.println ("fin preferredLayoutSize");
		return new Dimension (preferredWidth, preferredHeight);
	}

	/* Required by LayoutManager. */
	public Dimension minimumLayoutSize(Container parent) {
		//System.err.println ("minimumLayoutSize");
		Dimension dim = new Dimension(0, 0);
		//Always add the container's insets!
		Insets insets = parent.insets();
		dim.width = minWidth + insets.left + insets.right;
		dim.height = minHeight + insets.top + insets.bottom;
		sizeUnknown = false;
		return dim;
	}

	/* Required by LayoutManager. */
	/* This is called when the panel is first displayed, 
	 * and every time its size changes. 
	 * Note: You CAN'T assume preferredLayoutSize() or minimumLayoutSize()
	 * will be called -- in the case of applets, at leas, they probably
	 * won't be. */
	public void layoutContainer(Container parent) {
		//System.err.println ("layoutContainer");
		Dimension pref = preferredLayoutSize(parent);
		Dimension cur = parent.size();
		int diffx = cur.width - pref.width;
		int diffy = cur.height - pref.height;
		//System.err.println ("layoutContainer " + fl.id + " " + diffx + " " + diffy);
		if (diffx > 0 || diffy > 0){
			fl.resizeitems(diffx,diffy);
			setsizes (parent,true);
		}
    }
    
	public String toString() {
		System.err.println ("toString");
		String str = "";
		return getClass().getName() + "[" + str + "]";
	}
}

class mform_c{
	public boolean is_hcontrib;	// Contribue à la disposition horizontale
	public char h_align;	// Alignement à l'intérieur de la cellule
							// l=left, c=center, r=right
	public char v_align;	// Alignement à l'intérieur de la cellule
							// t=top, c=center, b=bottom
	public int h_cells;		// Number of cells used horizontally (colspan)
	public int v_cells;		// Number of cells used vertically (rowspan)
	public String s;		// Input buffer is needed or label
	public String id;		// Widget identifier
	public Component c;
	int weightx;			// relative weight of the component for
	int weighty;			// dialog resizing. 0 for fixed elements
	int x;					// Position for T_LABEL
	int y;
	static final int T_UNKNOWN=0;
	static final int T_STRING=1;
	static final int T_BUTTON=2;
	static final int T_FORM=3;
	static final int T_CHECKBOX=4;
	static final int T_RADIO=5;
	static final int T_CHOICE=6;
	static final int T_HLINE=7;
	static final int T_VLINE=8;
	static final int T_SKIP=9;
	static final int T_NEWLINE=10;
	static final int T_COMBO=11;
	static final int T_LIST=12;
	static final int T_ICON=13;
	static final int T_FILL=14;
	static final int T_TEXT=15;
	static final int T_LABEL=16;
	static final int T_BOOK=17;
	static final int T_CLIST=18;
	public int type;
	public mform_c(String _id){
		weightx = weighty = 0;
		h_align = ' ';
		v_align = 't';
		is_hcontrib = true;
		v_cells = h_cells = 1;
		s = null;
		c = null;
		id = _id;
		type = T_UNKNOWN;
	}
}

class Checkbox_val extends Checkbox{
	public int instance;
	public Checkbox_val (String str, CheckboxGroup g, boolean state, int instance){
		super(str,g,state);
		this.instance = instance;
	}
}


class mform extends formbase{
	mform_c tbc[];
	public int nbc;
	public String dispstr;
	public int marge_haut;
	public int marge_bas;
	public int marge_gauche;
	public int marge_droite;
	public int min_width;
	String tbgid[];
	String sidetitle;
	CheckboxGroup tbg[];
	int nbgroup;

	public mform (formbase _parent, String _id){
		super(_parent,_id);
		tbc = new mform_c[400];
		marge_gauche = marge_droite = marge_haut = marge_bas = 0;
		min_width = 0;
		nbc = 0;
		dispstr = "llllllllllllllllllllllllllllllllllllllllllllllllll";
		setLayout(new mform_layout(this));
		nbgroup = 0;
		tbgid = new String[30];
		tbg = new CheckboxGroup[30];
	}
	public void reset(){
		for (int i=0; i<nbc; i++) tbc[i] = null;
		nbc = 0;
		set_modified();
	}

	public boolean action(Event e, Object arg) {
		boolean ret = false;
		if (e.id == Event.WINDOW_DESTROY) {
			System.err.println ("destroy");
		}else if (id != null && id.compareTo("")!=0){
			Object target = e.target;
    	    for (int i=0; i<nbc; i++){
				if (target == tbc[i].c && tbc[i].type == mform_c.T_BUTTON){
					//Button b = (Button)target;
					// Send the content of all fields
					formbase mainf = this;
					while (mainf.parent != null) mainf = mainf.parent;
					mainf.dump();
					String path = getabspath(this);
System.err.println ("action " + path + " " + tbc[i].id);
					mformscript.out.println ("action " + path + " " + tbc[i].id);
					mformscript.out.flush();
					ret = true;
					break;
				}
			}
		}
		return ret;
	}


	public mform_c alloc_mf(String _id){
		set_modified();
		mform_c m = new mform_c(_id);
		tbc[nbc++] = m;
		return m;
	}
	public mform_c alloc_mf(){
		return alloc_mf(null);
	}
	public void Newline(){
		mform_c m = alloc_mf();
		m.type = mform_c.T_NEWLINE;
	}
	// Affect the colspan and rowspan of the previously added dialog item
	public void Dispolast(
		char h_align,	// Horizontal disposition 'l', 'c', 'r'
		int h_cells,
		char v_align,	// Vertical disposition 't', 'c', 'b'
		int v_cells){
		mform_c m = tbc[nbc-1];
		m.h_align = h_align;
		m.h_cells = h_cells;
		m.v_align = v_align;
		m.v_cells = v_cells;
	}
	// Affect the weight (resizing importance) of the previously added item
	// wx and wy are number >= 0. They are meaningless, except the
	// available space will be given to dialog items according to their
	// relative weight. A fixed item has 0,0
	public void Setweightlast(int wx, int wy){
		mform_c m = tbc[nbc-1];
		m.weightx = wx;
		m.weighty = wy;
	}
	public void New_label(String str){
		mform_c m = alloc_mf();
		m.type = mform_c.T_LABEL;
		m.s = str;
	}
	public void New_richtext(String str){
		mform_c m = alloc_mf();
		m.type = mform_c.T_LABEL;
		m.s = str;
	}
	public Label New_wlabel(String str){
		mform_c m = alloc_mf();
		Label ret = new Label (str);
		m.c = ret;
		add(m.c);
		return ret;
	}
	public TextField New_string (String _id, int len, String initval){
		mform_c m = alloc_mf(_id);
		m.s = initval;
		TextField ret = new TextField(m.s,len);
		m.c = ret;
		m.type = mform_c.T_STRING;
		add(m.c);
		return ret;
	}
	public TextField New_password (String _id, int len){
		mform_c m = alloc_mf(_id);
		m.s = "";
		TextField ret = new TextField(m.s,len);
		m.c = ret;
		m.type = mform_c.T_STRING;
		add(m.c);
		return ret;
	}
	public TextField New_string (int len, String initval){
		return New_string ("",len,initval);
	}
	public TextArea New_text (String _id, int rows, int cols){
		mform_c m = alloc_mf(_id);
		m.s = "";
		TextArea ret = new TextArea("",rows,cols);
		m.c = ret;
		m.type = mform_c.T_TEXT;
		add(m.c);
		return ret;
	}
	public void Skip (int n){
		mform_c m = alloc_mf();
		m.type = mform_c.T_SKIP;
		m.h_cells = n;
	}
	public void Fill (){
		mform_c m = alloc_mf();
		m.type = mform_c.T_FILL;
		m.h_cells = 1;
	}
	public void New_hline (String s){
		mform_c m = alloc_mf();
		m.c = new hline (s);
		add (m.c);
		m.type = mform_c.T_HLINE;
		Dispolast ('l',1,'c',1);
	}
	public void New_hline (){
		New_hline (null);
	}
	public void New_vline (){
		mform_c m = alloc_mf();
		m.type = mform_c.T_VLINE;
	}
	public Button New_button(String _id, boolean dodump, String str){
		mform_c m = alloc_mf(_id);
		Button ret = new Button(str);
		m.c = ret;
		m.type = mform_c.T_BUTTON;
		add (ret);
		return ret;
	}
	public Button New_button(String _id, String str){
		return New_button (_id,false,str);
	}
	public Button New_button(String str){
		return New_button ("",false,str);
	}
	public Choice New_choice(String _id, String val){
		mform_c m = alloc_mf (_id);
		Choice ret = new Choice();
		m.c = ret;
		m.s = val;
		m.type = mform_c.T_CHOICE;
		add (ret);
		return ret;
	}
	public void New_choice_item(String _id, String val){
		for (int i=0; i<nbc; i++){
			mform_c m = tbc[i];
			if (m.type == mform_c.T_CHOICE && m.id.compareTo(_id)==0){
				Choice c = (Choice)m.c;
				c.addItem(val);
				if (m.s.compareTo(val)==0) c.select(val);
				break;
			}
		}
	}
	public java.awt.List New_list(String _id, int nbvisible, String val){
		mform_c m = alloc_mf (_id);
		java.awt.List ret = new java.awt.List (nbvisible,false);
		m.c = ret;
		m.s = val;
		m.type = mform_c.T_LIST;
		add (ret);
		return ret;
	}
	public void New_list_item(String _id, String val){
		for (int i=0; i<nbc; i++){
			mform_c m = tbc[i];
			if (m.type == mform_c.T_LIST && m.id.compareTo(_id)==0){
				java.awt.List c = (java.awt.List)m.c;
				c.addItem(val);
				if (m.s.compareTo(val)==0) c.select(c.countItems()-1);
				break;
			}
		}
	}
	public combo New_combo(String _id, int len, String val){
		mform_c m = alloc_mf (_id);
		combo ret = new combo(this,val,len);
		m.c = ret;
		m.s = val;
		m.type = mform_c.T_COMBO;
		add (ret);
		return ret;
	}
	public void New_combo_item(String _id, String val1, String val2){
		for (int i=0; i<nbc; i++){
			mform_c m = tbc[i];
			if (m.type == mform_c.T_COMBO && m.id.compareTo(_id)==0){
				combo c = (combo)m.c;
				c.addItem(val1,val2);
				break;
			}
		}
	}
	public void New_form(mform sub){
		mform_c m = alloc_mf();
		m.c = sub;
		m.type = mform_c.T_FORM;
		add(sub);
	}
	public mform New_form(String _id){
		mform_c m = alloc_mf(_id);
		mform ret = new mform (this,_id);
		m.c = ret;
		m.type = mform_c.T_FORM;
		add(m.c);
		return ret;
	}
	public void New_book(book sub){
		mform_c m = alloc_mf();
		m.c = sub;
		m.type = mform_c.T_BOOK;
		add(sub);
	}
	public void New_clist(clist sub){
		mform_c m = alloc_mf();
		m.c = sub;
		m.type = mform_c.T_CLIST;
		add(sub);
	}
	public formbutton New_formbutton(String _id){
		formbutton ret = new formbutton (this,_id);
		New_form (ret);
		return ret;
	}
	public formbutton New_formbutton(){
		return New_formbutton ("");
	}
	public Checkbox New_checkbox(String _id, boolean state,String str){
		mform_c m = alloc_mf(_id);
		Checkbox ret = new Checkbox (str);
		ret.setState (state);
		m.c = ret;
		m.type = mform_c.T_CHECKBOX;
		add (ret);
		return ret;
	}
	private CheckboxGroup locate_group(String _id){
		CheckboxGroup ret = null;
		for (int i=0; i<nbgroup; i++){
			if (tbgid[i].compareTo(_id)==0){
				ret = tbg[i];
				break;
			}
		}
		if (ret == null){
			ret = new CheckboxGroup();
			tbg[nbgroup] = ret;
			tbgid[nbgroup] = new String(_id);
			nbgroup++;
		}
		return ret;
	}
	public Checkbox New_radio(
		String _id,
		int instance,
		boolean state,
		String str){
		mform_c m = alloc_mf(_id);
		CheckboxGroup g = locate_group(_id);
		Checkbox ret = new Checkbox_val (str,g,state,instance);
		m.c = ret;
		m.type = mform_c.T_RADIO;
		add (ret);
		return ret;
	}

	public mform_c getitem (int n){
		mform_c ret = null;
		if (n >= 0 && n < nbc) ret = tbc[n];
		return ret;
	}
	public void New_component (Component comp){
		mform_c m = alloc_mf();
		m.c = comp;
		add(comp);
	}
	// Display the current value of each field of the dialog
	public void dump(){
		for (int i=0; i<nbc; i++){
			mform_c c = tbc[i];
			if (c.type == mform_c.T_FORM){
				mform m = (mform)c.c;
				m.dump();
			}else if (c.type != mform_c.T_UNKNOWN
				&& c.type != mform_c.T_BUTTON
				&& c.type != mform_c.T_SKIP
				&& c.type != mform_c.T_ICON
				&& c.type != mform_c.T_NEWLINE
				&& c.type != mform_c.T_HLINE
				&& c.type != mform_c.T_VLINE
				&& c.type != mform_c.T_FILL
				&& c.type != mform_c.T_LABEL){
				String val = "";
				if (c.type == mform_c.T_STRING){
					val = ((TextField)c.c).getText();
				}else if (c.type == mform_c.T_CHECKBOX){
					val = ((Checkbox)c.c).getState() ? "1" : "0";
				}else if (c.type == mform_c.T_RADIO){
					Checkbox_val cv = (Checkbox_val)c.c;
					if (cv.getState()){
						val = String.valueOf(cv.instance);
					}else{
						continue;
					}
				}else if (c.type == mform_c.T_COMBO){
					val = ((combo)c.c).getText();
				}else if (c.type == mform_c.T_LIST){
					int sel = ((java.awt.List)c.c).getSelectedIndex();
					val = String.valueOf(sel);
				}else{
					System.err.println ("code dump " + c.type);
				}
				mformscript.out.println ("dump " + getabspath(this)
					+ " " + c.id + " " + val);
			}
		}
	}
	public void setsidetitle (String s){
		sidetitle = s;
	}
	public void paint (Graphics g){
		{
			FontMetrics met = g.getFontMetrics();
			int asc = met.getMaxAscent()+2;
			for (int i=0; i<nbc; i++){
				mform_c c = tbc[i];
				if (c.type == mform_c.T_LABEL){
					g.drawString (c.s,c.x+2,c.y+asc);
				}
			}
		}
		if (sidetitle != null){
			Dimension d = size();
			int miny = 20;
			int maxy = d.height - 20;
			g.setColor (Color.white);
			g.fillRect (0,0,20,miny);
			g.fillRect (0,maxy,20,20);
			g.setColor (Color.white);
			if (false){
				for (int i=1; i<miny; i += 2){
					g.drawLine (0,i,20,i);
				}
				for (int i=maxy+1; i<d.height; i += 2){
					g.drawLine (0,i,20,i);
				}
			}
			g.fillRect (0,miny,20,d.height-40);
			g.fillRect (0,maxy,d.width,20);


			g.setFont (new Font("helvetica",Font.BOLD,24));
			FontMetrics met = g.getFontMetrics();
			int charh = met.getHeight();
			int len = sidetitle.length();
			int y = maxy  - 3;
			g.setColor (Color.lightGray);
			int limity = miny + charh-3;
			int diffy = maxy - miny;
			int htext = len * charh;
			if (htext < diffy){
				y = maxy - (diffy - htext)/2;
			}
			for (int i=0; i<len && y > limity; i++, y -= charh){
				g.drawString (sidetitle.substring(i,i+1),1,y);
			}
		}
	}
	private void distribute (
		int start,
		int end,
		int nbfill,
		int diffx){
		if (nbfill > 0){
			int space = diffx/nbfill;
			int newx = 0;
			for (int i=start; i<end; i++){
				mform_c item = getitem(i);
				if (item.type == mform_c.T_FILL){
					newx += space;
				}else if (item.c != null){
					Dimension d = item.c.size();
					item.c.reshape (newx,0,d.width,d.height);
					newx += d.width;
				}
			}
		}
	}
	// Enlarge a dialog so it fits a constraint
	public void stretch (int new_width, int new_height){
		Dimension r = preferredSize();
		int diffx = new_width - r.width;
		if (diffx > 0){
			int start = 0;
			int nbfill = 0;
			for (int i=0; i<nbc; i++){
				mform_c item = getitem(i);
				if (item.type == mform_c.T_NEWLINE){
					distribute (start,i,nbfill,diffx);
					start = i+1;
					nbfill = 0;
				}else if (item.type == mform_c.T_FILL){
					nbfill++;
				}
			}
			distribute (start,nbc,nbfill,diffx);
			reshape (0,0,new_width,r.height);
		}
	}
	// Enlarge the items of a dialog after the user has resized the window
	// Use the standard strategy of the weights to distribute the
	// available space to each components. For complex layout, it is
	// much easier to redefine resizeitems().
	public void resizeitems(int diffx, int diffy){
		mform_c tbexph[] = new mform_c[20];	// Item we may expand horizontally
		mform_c tbexpv[] = new mform_c[20];	// Item we may expand vertically
		int nbexpv=0;
		int nbexph=0;
		int totalh = 0;
		int totalv = 0;
		for (int i=0; i<nbc; i++){
			mform_c item = getitem(i);
			if (item.weightx > 0){
				tbexph[nbexph++] = item;
				totalh += item.weightx;
			}
			if (item.weighty > 0){
				tbexpv[nbexpv++] = item;
				totalv += item.weighty;
			}
		}
		for (int i=0; i<nbexph; i++){
			mform_c item = tbexph[i];
			Dimension d = item.c.preferredSize();
			item.c.resize(d.width+diffx*item.weightx/totalh,d.height);
		}
		for (int i=0; i<nbexpv; i++){
			mform_c item = tbexpv[i];
			Dimension d = item.c.preferredSize();
			item.c.resize(d.width,d.height+diffy*item.weighty/totalv);
		}
	}
	public boolean locate (String _id, mformctx ctx){
		boolean ret = false;
		for (int i=0; i<nbc; i++){
			mform_c item = getitem(i);
			if (item.type == mform_c.T_FORM){
				mform m = (mform)item.c;
				if (m.id.compareTo(_id)==0){
					ctx.fl = m;
					ctx.bk = null;
					ret = true;
					break;
				}
			}else if (item.type == mform_c.T_BOOK){
				book m = (book)item.c;
				if (m.id.compareTo(_id)==0){
					ctx.fl = null;
					ctx.bk = m;
					ret = true;
					break;
				}
			}
		}
		return ret;
	}
}



