//package coco;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.io.Serializable;

/*simple submit button; designer should add such a component to the page to let
  the watchers send data back to the server; watcher can then submit either a
  signal that this button has been pressed or data coming from a form on the
  page; the form is one or more widgets (text input fields, selections, etc.)
  that are added to the page and associated with this submit button*/
public final class CocoSubmitButton extends Button implements CocoSubmitter,Serializable{
  /*action command substrings*/
  private String addressee,request;

  /*request string will represent and follow the state of the widgets included
    in this vector (if any)*/
  private Vector param=new Vector();

  /*mark string beginning and end with quotation marks; use backslash as
    escape char to make it exact even if the original string contained
    quotation marks*/
  public static String quote(String in){
    StringBuffer out=new StringBuffer("\""); //start with a quotation mark
    int len=in.length(); //store input length
    char ch; //character currently processed
    for(int i=0;i<len;i++){ //take the input chars one by one
      ch=in.charAt(i);
      if(ch=='\\'||ch=='"'){ //if char needs to be escaped
	out.append("\\"); //insert a backslash first
      }
      out.append(ch); //output anyway
    }
    out.append("\""); //close with a quotation mark
    return out.toString(); //tada.wav
  }

  /*invert quote*/
  public static String unquote(String in){
    /*state machine*/
    StringBuffer out=new StringBuffer(""); //output string
    int len=in.length(); //store input length
    char ch; //currently processed input char
    boolean escaped=false; //state: after escape char (backslash)
    boolean inside=false; //state: inside quotation marks
    for(int i=0;i<len;i++){ //take input chars one by one
      ch=in.charAt(i);
      if(inside){
	if(!escaped){
	  if(ch=='\\')escaped=true; //next char escaped
  	  else if(ch=='"')inside=false; //quotation closed
	  else out.append(ch); //normal char quoted
	}else{
 	  out.append(ch); //escaped char quoted
          escaped=false; //escape char affects only one char
	}
      }else{ //outside quotation marks
        if(ch=='"')inside=true; //ignore all chars until a quotation mark comes
      }
    }
    return out.toString(); //tada.wav
  }

  /*return the request string that represents the current state of all
    the registered widgets*/
  public String getParams(){
    int size=param.size(); //how many widgets belong to this
    if(size==0)return null;

    StringBuffer request=new StringBuffer(""); //the new request string
    Component c; //widget currently enqiried
    for(int i=0;i<size;i++){ //take them one by one
      c=(Component)param.elementAt(i);

      /*use a silly but relatively compact format on some known types*/
      if(c instanceof ItemSelectable){
	/*store number of selected items*/
        Object[] so=((ItemSelectable)c).getSelectedObjects();
        int length=so==null?0:so.length;
	for(int j=0;j<length;j++){
	  /*quote one of the selected items as a string*/
	  try{
	    request.append(
	      quote(
		(String)((ItemSelectable)c).getSelectedObjects()[j]
	      )
	    );
	  }catch(ClassCastException e){
	    request.append(
	      quote(
		((ItemSelectable)c).getSelectedObjects()[j].toString()
	      )
	    );
	  }

	  /*plus between multiple selected items*/
          if(j<length-1)request.append("+");
	}
      }else if(c instanceof TextComponent){
        request.append(quote(((TextComponent)c).getText()));
      }else{
	/*given up to know the type, dump and quote full state*/
        request.append(quote(c.toString()));
      }

      /*comma between component state strings;
        priority lower than that of plus*/
      if(i<size-1)request.append(",");
    }

    /*now that it's built up, return the request string*/
    return(addressee+":"+request.toString());
  }

  /*register a widget as a part of the form to be submitted when
    this button is pressed*/
  public void addParameter(Component c){
    param.add(c);
  }

  /*name the coco component that will receive the request submitted by
    this button*/
  public void setCocoAddressee(String id){
    addressee=id;
    setActionCommand(addressee+":"+request);
  }

  /*set the request string to send to that component*/
  public void setCocoRequest(String request){
    this.request=request;
    setActionCommand(addressee+":"+request);
  }

  /*after downloading the page, this method should be called by the
    downloader client to set local listener*/
  public void setCocoSubmitListener(ActionListener l){
    addActionListener(l);
  }
}

