#include <iostream>
#include "ubuilder.hpp"
using namespace std;

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

int main(int argc, char* argv[]) {

  UConf conf(argc, argv);
  conf.transp_scrollbars = true;
		conf.double_buffering = true;
		
  UAppli appli(conf);
  Builder builder;

  UFrame frame(uheight(380) + builder);
  appli.add(frame);
  frame.show();

  return appli.mainLoop();
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

Builder::Builder() :
  controls(this),
  infos(this),
  status(this),
  bboard(this),
  classes(this)
{
  UBox& harea = uhbox
    (
     uvflex()
     + uleft() + classes.panel
     + uhflex()	+ uvbox( utop() + infos.panel
			 + uvflex() + bboard.spane
			 )
     );

  addlist
    (
     UOrient::vertical + uhflex()
     + utop() + controls.menubar + controls.toolbar
     + uvflex() + harea
     + ubottom() + status.panel
     );

  initTree();
}
	
/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

Builder::Controls::Controls(Builder* bld) {
  new_btn.addlist("New Gui");
  open_btn.addlist("Open Gui");
  save_btn.addlist("Save Gui");
  sketch_btn.addlist("Sketch");
  quit_btn.addlist(UColor::red + "Quit" + ucall(0, UAppli::quit));

  unlink_btn.addlist("Unlink");
  undel_btn.addlist("Undelete");
  del_btn.addlist("Delete" + ucall(bld, &Builder::removeCurrentNode));

  rebuild_btn.addlist("Rebuild");
  code_btn.addlist("Source Code");
  prop_btn.addlist("Properties");
  connex_btn.addlist("Connections");

  UMenu& file_menu = umenu
    (
     new_btn
     + open_btn
     + save_btn
     + uhsepar()
     + sketch_btn
     + uhsepar()
     + quit_btn
     );

  UMenu& gui_menu = umenu
    (
     new_btn
     );

  UMenu& edit_menu = umenu
    (
     unlink_btn
     + undel_btn
     + del_btn
     );

 UMenu& view_menu = umenu
    (
     ubutton("Widget")
     + code_btn
     + uhsepar()
     + prop_btn
     + connex_btn
     );

  UMenu& option_menu = umenu
    (
     ubutton("Preferences...")
     + ubutton("Pathnames...")
     );

  UMenu& help_menu = umenu
    (
     ubutton("Web Site")
     + ubutton("Help Index")
     + ubutton("Version")
     + ubutton("About")
     );

  menubar.addlist
    (
     ubutton("File" + file_menu)
     + ubutton("Gui" + gui_menu)
     + ubutton("Edit" + edit_menu)
     + ubutton("View" + view_menu)
     + ubutton("Option" + option_menu)
     + ubutton(UPix::question + help_menu)
     );

  toolbar.addlist
    (
     new_btn
     + open_btn
     + save_btn
     + sketch_btn
     + uvsepar()
     + unlink_btn
     + undel_btn
     + del_btn
     + uvsepar()
/*
     + rebuild_btn
     + code_btn
     + uvsepar()
	*/
     + prop_btn
     + connex_btn
     );
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

Builder::Infos::Infos(Builder* bld) {
	panel.addlist
	(
		UOrient::horizontal + uvflex() + UBorder::etchedOut
		+ uleft() + ulabel("Infos: ")
		+ uhflex() + utextfield("")
	);
}
	
/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

Builder::Status::Status(Builder* bld) {
  panel.addlist
    (
     UOrient::horizontal + uvflex()
     + UBgcolor::white + UFont::small
     + uleft() + " " + USymbol::right + " " + ulabel("Ready")
     );
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

Builder::BBoard::BBoard(Builder* bld) {
  canvas.addAttr(UBgcolor::white);
  canvas.addlist(utop() + uleft() + uhmargin(20) + uvmargin(20));	
  spane.add(canvas);
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

void Builder::initTree() {
  // BUG ABSURDE: n'apparait pas ensuite si size=0
  tree = new UTreebox(UFont::small + "");
  bboard.canvas.add(*tree);

  preview = udialog
    (
     utop() + uleft() 
     + uhmargin(10) + uvmargin(10)
     + uwidth(400) + uheight(350)
     + UBgcolor::darkgrey
     );
  add(*preview);
}
/* ==================================================== ======== ======= */

BNode* Builder::getCurrentNode() const {
  UGroup* _sel = tree->node_sel.getItem();
  return(_sel ? dynamic_cast<BNode*>(_sel) : null); 
}
  
/* ==================================================== ======== ======= */

void Builder::removeCurrentNode() {
  removeNode(getCurrentNode());  
}

void Builder::removeNode(BNode* node) {
  if (!node) return;
  if (node->getObj()) node->getObj()->removeFromParents();
  node->setObj(null);
  node->removeFromParents();
  //delete node;
}

/* ==================================================== ======== ======= */

void Builder::addToCurrentNode(BNode* child) {
  addToNode(getCurrentNode(), child);  
}

// parent can be null
void Builder::addToNode(BNode* parent, BNode* child) {
  if (!child) return;

  if (parent) {
    parent->addChild(child);

    // if parent's obj is a group, add child's obj to it
    UGroup* par_obj = null;
    if (parent->getObj()
        && (par_obj = dynamic_cast<UGroup*>(parent->getObj()))
        )
      par_obj->add( child->getObj() );
  }

  else {   // no parent => add to the tree
    tree->add(child);
    tree->update();
    child->select(true);

    // if it is meaningful to add child's obj to the preview
    if (dynamic_cast<UGroup*>(child->getObj())) {
      preview->add(child->getObj());
      preview->show();
    }
  }
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

BNode::BNode(class UTreebox& _t, const UArgs& _a,
             class ClassDef* _def, UBrick* _obj) :
UNode(_t, _a), obj(_obj), def(_def) {
}

BNode::~BNode() {
  cerr << "BNode deleted" << endl;
}

void BNode::setObj(UBrick* _obj) {
  obj = _obj;
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

BrickClassDef::BrickClassDef(Builder* bld, const char* _name,
                             UBrick& (*_obj_constr)()) :
ClassDef(_name), obj_constr(_obj_constr)
{
  addlist(name + ucall(this, bld, &BrickClassDef::createNode));
}

void BrickClassDef::createNode(Builder* bld) {
  UBrick* obj = &obj_constr();
  BNode* node = new BNode(*bld->tree, name, this, obj);
  bld->addToCurrentNode(node);
}

/* ==================================================== ======== ======= */

GroupClassDef::GroupClassDef(Builder* bld, const char* _name,
                             UGroup& (*_obj_constr)(const UArgs&),
                             bool _add_name) :
ClassDef(_name), obj_constr(_obj_constr), add_name(_add_name)
{
  addlist(name + ucall(this, bld, &GroupClassDef::createNode));
}

void GroupClassDef::createNode(Builder* bld) {
  UGroup* obj = null;
  BNode* node = null;
  UStr* str = &ustr(name & " " & UIntg(no));
  no++;
  
  if (add_name) {
    obj = &obj_constr(str);
    node = new BNode(*bld->tree, uedit() + str, this, obj);
  }
  else {
    obj = &obj_constr(UArgs::none);
    node = new BNode(*bld->tree, str, this, obj);
    //node->select(true);
  }
  bld->addToCurrentNode(node);
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

#define BrickFun(XXX) ((UBrick& (*)())(XXX))
#define GroupFun(XXX) ((UGroup& (*)(const UArgs&))(XXX))

Builder::Classes::Classes(Builder* bld) {
  UTable& table = utable
  (
   UBorder::etchedIn + UBgcolor::white + UFont::small
   +
   utrow(*new GroupClassDef(bld, "vbox", GroupFun(uvbox))
         +new GroupClassDef(bld, "hbox", GroupFun(uhbox)))
   +
   utrow(*new GroupClassDef(bld, "box", GroupFun(ubox))
         +new GroupClassDef(bld, "bar", GroupFun(ubar)))
   +
   utrow(*new GroupClassDef(bld, "flowbox", GroupFun(uflowbox))
         +new GroupClassDef(bld, "listbox", GroupFun(ulistbox)))
   +
   utrow(usepar() + usepar())
   +
   utrow(*new GroupClassDef(bld, "item", GroupFun(uitem), true)
         +new GroupClassDef(bld, "button", GroupFun(ubutton), true))
   +
   utrow(*new GroupClassDef(bld, "checkbox", GroupFun(ucheckbox), true)
         +new GroupClassDef(bld, "textfield", GroupFun(utextfield), true))
   +
   utrow(*new GroupClassDef(bld, "label", GroupFun(ulabel), true)
         +new GroupClassDef(bld, "textbox", GroupFun(utextbox), true))
   +
   utrow(usepar() + usepar())
   +
   utrow (*new GroupClassDef(bld, "frame", GroupFun(uframe))
          +new GroupClassDef(bld, "dialog", GroupFun(udialog)))
   +
   utrow(usepar() + usepar())
   +
   utrow(*new GroupClassDef(bld, "menubar", GroupFun(umenubar))
         +new GroupClassDef(bld, "menu", GroupFun(umenu)))
   +
   utrow(*new GroupClassDef(bld, "popmenu", GroupFun(upopmenu))
         +new GroupClassDef(bld, "combo", GroupFun(ucombobox)))
   +
   utrow(usepar() + usepar())
   +
   utrow(*new GroupClassDef(bld, "filebox", GroupFun(ufilebox))
         +new GroupClassDef(bld, "popmenu", GroupFun(upopmenu)))
   );

  panel.addlist
    (
     UOrient::vertical + utop() + uhflex()
      + " " + table
     );
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */


