#include <iostream>
#include <unistd.h>
#include <ubit/ubit.hpp>
using namespace std;


class Events : public UAppli {
  UBgcolor bgcolor;
  UColor   fgcolor;
  UStr     bgcolor_str;
  UStr     fgcolor_str;
  UStr mess1, mess2, mess3, mess4;
  UStr timeout_delay1, timeout_delay2, timeout_times1, timeout_times2; 
  int timeout_no;

public:
  Events(int *argc, char *argv[]);

  // 0 to 4 arguments for member function callbacks
  // (but 1 to 4 for ordinary functions)
  void startTimeOut1();
  void startTimeOut2();

  // the UEvent& argument is optionnal
  // it must be the 1st arg when present
  void pmess(UStr *mess, const char *s);
  void pclickcount(UEvent&, UStr *mess, const char *s);
  void ptimeout(UEvent&, const char *s, int no);
  void pinput(UEvent&, const char *s, int fd);
};

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */

int main(int argc, char *argv[]) {
  Events appli(&argc, argv);
  return appli.mainLoop();
}

void Events::startTimeOut1() {
  timeout_no++;

  // creates a new Timer:
  // - 1st arg is the delay (in milliseconds)
  // - 2nd arg is the number of times (-1 means always)
  // NB: the timer will be deleted when over

  UTimer* t = openTimer(atoi(timeout_delay1.chars()),
			atoi(timeout_times1.chars()));

  // add a callback to this timer
  t->onAction(ucall(this,"- First Timeout #",timeout_no,&Events::ptimeout));
}

void Events::startTimeOut2() {
  timeout_no++;
  UTimer* t = openTimer(atoi(timeout_delay2.chars()),
			atoi(timeout_times2.chars()));
  t->onAction(ucall(this,"- Second Timeout #",timeout_no,&Events::ptimeout));
}


Events::Events(int* argc, char *argv[]) : UAppli(argc, argv) {
  timeout_no = 0;
  bgcolor_str = "orange";
  fgcolor_str = "blue";

  // input callback:
  // - 1st arg is the source (stdin = the standard input in this case)
  int fd = 0;
  UInput* input = openInput(fd);
  input->onAction(ucall(this, "> Input from: ", fd, &Events::pinput));

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UButton& multiclick_btn = ubutton
    (
     UColor::orange + UFont::bold + UOrient::vertical + uhcenter()
     + "MULTI CLICK" + "button"
     + UOn::action  / ucall(this, &mess3, "UOn::action", &Events::pmess)
     + UOn::mclick  / ucall(this, &mess1, "UOn::mclick", &Events::pclickcount)
     + UOn::mbiclick / ucall(this, &mess2, "UOn::mbiclick", &Events::pmess)
     + UOn::mtriclick / ucall(this, &mess2, "UOn::mtriclick", &Events::pmess)
     + UOn::mquadclick / ucall(this, &mess2, "UOn::mquadclick", &Events::pmess)
     );

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UCheckbox& select_btn = ucheckbox
    (
     UMode::selected + UOrient::vertical + uhflex()
     + "select" + "button"
     + UOn::action   / ucall(this, &mess3, "UOn::action", &Events::pmess)
     + UOn::change   / ucall(this, &mess2, "UOn::change", &Events::pmess)
     + UOn::select   / ucall(this, &mess1, "UOn::select", &Events::pmess)
     + UOn::unselect / ucall(this, &mess1, "UOn::unselect", &Events::pmess)
     );

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UBox& background_ctrl = uhbox
    (
     "Background: "
     + uhflex()
     + utextbox(uedit()
		+ bgcolor_str
		+ UOn::kpress   / ucall(this, &mess1,"UOn::kpress", &Events::pmess)
		+ UOn::krelease / ucall(this, &mess1,"UOn::krelease", &Events::pmess)
		+ UOn::change   / ucall(this, &mess2,"UOn::change", &Events::pmess)
		+ UOn::ktype    / ucall(this, &mess3,"UOn::ktype", &Events::pmess)
		
		+ UOn::mpress   / ucall(this, &mess1,"UOn::mpress", &Events::pmess)
		+ UOn::mrelease / ucall(this, &mess2,"UOn::mrelease", &Events::pmess)
		
		+ UOn::action   / ucall(this, &mess1,"UOn::action", &Events::pmess)
		+ UOn::action   / usetref(&bgcolor, bgcolor_str)
		)

     + ulinkbutton("Ok"
	     + UOn::mpress / ucall(this, &mess1,"UOn::mpress", &Events::pmess)
	     + UOn::mrelease/ucall(this, &mess2,"UOn::mrelease", &Events::pmess)
	     + UOn::action / ucall(this, &mess3,"UOn::action", &Events::pmess)
	     + UOn::action / usetref(&bgcolor, bgcolor_str)
	     )
     );

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UBox& foreground_ctrl = uhbox
    (
     "Foreground: "
     + uhflex()
     + utextbox(uedit()
		+ fgcolor_str
		+ UOn::kpress   / ucall(this, &mess1,"UOn::kpress", &Events::pmess)
		+ UOn::krelease / ucall(this, &mess1,"UOn::krelease", &Events::pmess)
		+ UOn::change   / ucall(this, &mess2,"UOn::change", &Events::pmess)
		+ UOn::ktype    / ucall(this, &mess3,"UOn::ktype", &Events::pmess)
		
		+ UOn::mpress   / ucall(this, &mess1,"UOn::mpress", &Events::pmess)
		+ UOn::mrelease / ucall(this, &mess2,"UOn::mrelease", &Events::pmess)
		
		+ UOn::action   / ucall(this, &mess1,"UOn::action", &Events::pmess)
		+ UOn::action   / usetref(&fgcolor, fgcolor_str)
		)
     + ulinkbutton("Ok" 
	     + UOn::mpress / ucall(this, &mess1,"UOn::mpress", &Events::pmess)
	     + UOn::mrelease/ucall(this, &mess2,"UOn::mrelease", &Events::pmess)
	     + UOn::action / ucall(this, &mess3,"UOn::action", &Events::pmess)
	     + UOn::action / usetref(&fgcolor, fgcolor_str)
	     )
     );

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UBox& button_area = uvbox
    (
     UBorder::etchedIn + bgcolor + fgcolor
     + uhmargin(6) + uvmargin(6) + uhspacing(4) + uvspacing(5)

     + uhbox(uscale(+2) + UFont::bold + uhflex()
	     + multiclick_btn
	     + " "
	     + select_btn
	     + " "
	     + uvbox(UBorder::etchedIn + uhflex()
		     + background_ctrl 
		     + foreground_ctrl 
		     )
	     )

     + ulabel(uhspacing(4) + uhflex()
	      + " Events: " + utextbox(mess1)
	      + "then"      + utextbox(mess2)
	      + "then"      + utextbox(mess3)
	      )
     );


  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  timeout_delay1 = "500";
  timeout_times1 = "10";  // ten times
  timeout_delay2 = "3000";
  timeout_times2 = "-1";  // infinity

  UTable& tab = utable
      ( 
       utrow( ulabel(UFont::bold + "First TimeOut: ") 
	      + utextbox(uedit() + timeout_delay1) 
	      + ulabel("mS ") 
	      + utextbox(uedit() + timeout_times1)
	      + ulabel(" times (-1 for infinity) ") 
	      + ubutton(UFont::bold + " Start " + ucall(this, &Events::startTimeOut1))
	     )

       + utrow( ulabel(UFont::bold + "Second TimeOut: ") 
		+ utextbox(uedit() + timeout_delay2) 
		+ ulabel("mS ") 
		+ utextbox(uedit() + timeout_times2)
		+ ulabel(" times (-1 for infinity) ") 
		+ ubutton(UFont::bold + " Start " + ucall(this, &Events::startTimeOut2))
	     )

      + utrow(ulabel(UFont::bold + "Input Callback: ") 
	      + utcell(5,1, 
		       ulinkbutton("Type text in the xterm then press Return"))
	      )
       );


  UBox& timeout_area = uvbox
    (
     UBorder::etchedIn + UBgcolor::lightgrey
     + uhmargin(6) + uvmargin(6)
     + tab
     );

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UBox& text_area = uvbox
    (
     UBorder::etchedIn
     + uhmargin(6) + uvmargin(6) + uhspacing(4) + uvspacing(5)
     + utextbox(uedit() + "abcdefghijklmnopqrstu" 
		+ utextbox(uedit()
			   + UFont::bold
			   + "sub textbox"
			   )
		+ "12345678901234567890" + "1234567890AZERTTYUIOPP")
     + " "
     + utextbox(uedit() + "1234567890AZERTTYUIOPP"
		+ ulinkbutton(" inserted href ")
		+ "abcdefghijklmnopqrstu" 
		+ ubutton("button")
		+ "12345678901234567890")
     );
    
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  // allocate enough space for display
  mess4 = "                         ";

  UBox& mouse_area = uvbox
    (
     UBorder::etchedIn
     + uhmargin(6) + uvmargin(6) + uhspacing(4) + uvspacing(5)
     
     + uvbox( uheight(80) + UBorder::shadowIn 
	      + uhcenter() + uvcenter()
	      + UBgcolor::lightgrey + UFont::italic + UFont::bold
	      + "Press and drag mouse in this box"
	      + UOn::mpress  / ucall(this, &mess4, "UOn::mpress", &Events::pmess)
	      + UOn::mrelease/ ucall(this, &mess4, "UOn::mrelease", &Events::pmess) 
	      + UOn::mdrag   / ucall(this, &mess4, "UOn::mdrag", &Events::pmess)
	      + UOn::mmove   / ucall(this, &mess4, "UOn::mmove", &Events::pmess)    
	      )
     + ubox(uhcenter() + UFont::bold 
	    + USymbol::right + " Last Mouse Event: "
	    + utextbox(UColor::red + mess4)
	    )
     );
    
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  UFrame& frame = uframe
    (
     uwidth(600)
     + uhmargin(6) + uvmargin(6) + uhspacing(4) + uvspacing(5)


     + button_area
     + " "
     + timeout_area
     + " "
     + text_area
     + " "
     + mouse_area
     );

  // add the UFrame to the UAppli
  add(frame);
  frame.show(true);
}

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */

void Events::pmess(UStr *mess, const char *s) {
  cerr << s << endl;
  if (mess == &mess1) {mess2.set(""); mess3.set("");}
  if (mess == &mess2) {mess3.set("");}
  mess->set(s);
}

void Events::pclickcount(UEvent& e, UStr *mess, const char *s) {
  cerr << s << " time " << e.getTime() << endl;
  mess->set(s);
  mess2.set(""); mess3.set("");
}


void Events::pinput(UEvent& e, const char *s, int fd) {
  char buffer[] = "        ";
  int n = read(fd, buffer, sizeof(buffer)-1);
  cout << s << fd << " time: " << e.getTime() << " - "<<n<<" chars: " << buffer<< "\n";
}

void Events::ptimeout(UEvent& e, const char *s, int no) {
  cout << s << no << " time: " << e.getTime() << "\n";
}

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */
