#include <iostream>
#include <ubit/ubit.hpp>
#include <ubit/ugraph.hpp>
#include "persp.hpp"
using namespace std;


//================================================================

PerspBar::PerspBar(UArgs a) {
  // false = dont update now (to avoid multi-updates and flicking)
  colscale.setAutoUpdate(false);

  // add at the beginning of the list
  addlist(colscale + UBgcolor::black + 
	  UOrient::vertical + uhcenter() + uvcenter()
	  );
  addlist(a);
  //add(bgcolor);
}

void PerspBar::setScale(int sc) {
  // cf.   colscale.setAutoUpdate(false); fait plus haut
  // (to avoid multi-updates and flicking)
  colscale.set(sc);
}

void PerspBar::setBgcolor(const UColor& col) {
  bgcolor.set(col);
}

//================================================================

Persp::Persp(UArgs a) : UPane(a) {
  mode = movingFocusBar;
  focus      = 0;
  mag_more   = 5;
  mag_factor = 3;

  barBgcolor = &UBgcolor::black;
  focusBarBgcolor = &UBgcolor::white;
  focusBarOffset = 0;
  //!watch: add has been redefined!
  UPane::addlist(UBgcolor::black +  uscale(-6) + bar_container);
}

void Persp::addBar(PerspBar &bar, int pos) {
  // add to subcomponent 'box' not to pane itself
  bar.add(UOn::action / ucall(this, &bar, &Persp::goSelf));
  bar.add(UOn::enter  / ucall(this, &bar, &Persp::goSelf));
  bar_container.insert(pos, bar); 
}
void Persp::addBar(PerspBar *box, int pos) {
  addBar(*box, pos);
}

void Persp::setMagFactor(int ds) {
  mag_factor = ds;
}

void Persp::setFocusBarOffset(u_pos offset) {
  focusBarOffset = offset;
}

void Persp::goLeft() {
  setFocus(focus-1);
}

void Persp::goRight() {
  setFocus(focus+1);
}

void Persp::goSelf(UEvent& e, PerspBar *bar) {
  int count = 0;
  UBrick **children = bar_container.getChildren(count);
  for (int k = 0; k < count; k++)
    if (children[k] == bar) {
      setFocus(k);
      replace(e);
      return;
    } 
}

void Persp::setMode(Mode m) {
  mode = m;
  setFocus(focus);
}

void Persp::setFocus(int new_focus) {
  // nothing to change si !!!
  //if (new_focus == focus) return;
  int count = 0;
  UBrick **children = bar_container.getChildren(count);
  if (count == 0) {
    update();
    return;
  }

  if (new_focus < 0) focus = 0;
  else if (new_focus >= count) focus = count-1;
  else focus = new_focus;

  for (int k = 0; k < count; k++) {
    int sc; 
    if (mode == flat) sc = 0;
    else {
     if (k < focus) sc = (k-focus) * mag_factor + mag_more;
     else sc = (focus-k) * mag_factor + mag_more;;
     if (sc < 0) sc = 0;
    }

    ((PerspBar*)children[k])->setScale(sc);

    /*
    if (k == focus) {
      if (focusBarBgcolor)
	((PerspBar*)children[k])->setBgcolor(focusBarBgcolor, false);
    }
    else {
      if (barBgcolor)
	  ((PerspBar*)children[k])->setBgcolor(barBgcolor, false);
    }
    */
  }
  // free memory
  delete[] children;
}

void Persp::replace(UEvent& e) {
  // Pane's view
  UPaneView *pane_view = (UPaneView*)getView(0);
  // Focused Column's View
  UView *view = ((UBox*)bar_container.getChild(focus))->getView(0);

  u_pos x_in_view = e.getX();
  u_pos x_in_win =  e.getXwin();

  //invariants= x_in_win / x_percent
  float x_percent = (float)x_in_view / view->getWidth();
  /*
  cout << "x_in_view= " << x_in_view << "\n";
  cout << "x_in_win= " <<  x_in_win << "\n";
  cout << "x_view= " << view->getX() << "\n";
  cout << "2x_scroll " << pane_view->getXScroll() << "\n\n";
  */
  if (pane_view && view) {
    //if (mode != fixedFocusBar) pane_view->setXScroll(0);
    //else {
      pane_view->setXScroll(0);

      //recompute sizes but do not draw now
      UUpdate upd(UUpdate::LAYOUT);
      this->update(upd);

      x_in_view = int(x_percent * view->getWidth());
      //x_in_view + x_view_in_pane + x_scroll = x_in_pane;
      // int x_scroll = -(x_in_pane - view->getX() - x_in_view);

      //x_in_view + x_view_in_win + x_scroll = x_in_win;
      int x_scroll = -(x_in_win - view->getXwin() - x_in_view);
      /*
      cout << "2x_in_view= " << x_in_view << "\n";
      cout << "2x_view= " << view->getX() << "\n";
      cout << "2x_scroll " << x_scroll << "\n\n";
      */
      pane_view->setXScroll(x_scroll);
      //}

    // redraw everything NOW
    bar_container.update();
  }

  focus_str.setNum(focus);  
}

//================================================================
//================================================================

void increaseScale(UScale *scale, UStr *scale_val) {
  scale->incr(1);
  scale_val->setNum(scale->getValue());
}
void decreaseScale(UScale *scale, UStr *scale_val) {
  scale->incr(-1);
  scale_val->setNum(scale->getValue());
}

//================================================================

int main(int argc, char *argv[]) {
  UConf conf(argc, argv);
  conf.double_buffering = true;  // double buffering mode

  UAppli appli(conf);
  appli.setImaPath("../images");

  UScale globscale;
  // the string that will display the current scale value
  UStr globscale_str(" 0");

  Persp persp(globscale + UBgcolor::black);

  persp.setMagFactor(2);
  persp.setFocusBarOffset(200);

  // this str is shared by all columns
  UStr shared_str("editable text\n\n");

  //===========================================

  UButton &special_btn = ubutton
    (
     UOn::idle/UBgcolor::orange + UFont::bold + UFont::italic
     + ubutton(UBorder::none + UBgcolor::none
	       + ucall(&persp, &Persp::goLeft)
	       + USymbol::left)
     + " # "
     + ubutton(UBorder::none + UBgcolor::none
	       + ucall(&persp, &Persp::goRight)
	       + USymbol::right)
     );

  //===========================================

  persp.addBar(new PerspBar(" "
			    + uima("galeries-lafayettes.gif")
			    + uima("bon-marche.gif")
			    + uima("printemps.gif")
			    + uima("samaritaine.gif")
			    )
	       );

  persp.addBar(new PerspBar(" " 
			    + uima("tour-eiffel.gif")
			    + uima("saint-germain.gif")
			    + uima("emacs.gif")
			    + uima("forum-des-halles.gif")
			    )
	       );

  persp.addBar(new PerspBar(" " 
			    + uima("louvre.gif")
			    + uima("louvre2.gif")
			    + uima("saint-germain.gif")
			    + uima("pompidou.gif")
			    + uima("orsay.gif")
			    )
	       );

  persp.addBar(new PerspBar(" " 
			     + uima("picasso.gif")
			     + special_btn 
			     + uima("notre-dame.gif")
			     + uima("cluny.gif")
			     + uhbox(UBorder::shadowIn+UBgcolor::white + uedit() + shared_str)
			     + uima("world.gif")
			     )
		);

  persp.addBar(new PerspBar(" " 
			    + uima("tour-eiffel.gif")
			    + uima("sainte-chapelle.gif")
			    + uima("orsay.gif")
			    + uima("bhv.gif")
			    )
	       );

  persp.addBar(new PerspBar(" " 
			    + ubox(uima("sacre-coeur.gif"))
			    + ubox(uima("madeleine.gif"))
			    + ubox(uima("saint-germain.gif"))
			    + ubox(uima("mosquee.gif"))
			    )
	       );

  persp.addBar(new PerspBar(" " 
			    + ubox(uima("mosquee.gif"))
			    + ubox(uima("xfig2.gif"))
			    + ubox(uima("bhv.gif"))
			    + ubox(uima("notre-dame.gif"))
			    )
	       );
 
  //===========================================
  
  //URadioSelect &radio = uradioSelect();

  UBox& control = umenubar
    (
     uleft()
     + UFont::bold 
     + uhbox( UBorder::etchedOut
	      + uwidth(UWidth::KEEP_SIZE) + uheight(UHeight::KEEP_SIZE)
	      + UFont::x_large
	      + " Focus: "
	      + ubutton(UBorder::none + USymbol::left 
			+ ucall(&persp, &Persp::goLeft))
	      + ubutton(UBorder::none + USymbol::right 
			+ ucall(&persp, &Persp::goRight))
	      + " " 
	      + persp.getFocusStr()
	      + " "
	      )
     /*
     + "  "
     + uhbox( UBorder::etchedOut
	      + ucheckbox("Flat Mode" + radio
			  + UOn::select / ucall(persp, Persp::flat, &Persp::setMode)
			  )
	      + ucheckbox("Moving Persp" + radio
			  + UOn::select / ucall(persp, Persp::movingFocusBar, &Persp::setMode)
			  )
	      + ucheckbox("Fixed Persp" + radio
			  + UOn::select / ucall(persp, Persp::fixedFocusBar, &Persp::setMode)
			  )
	      )
     */
     + "  "
     + uhbox( UBorder::etchedOut
	      + UFont::x_large
	      + " Global Scale:" + globscale_str

	      //decreases scale and scale_val 
	      + ubutton(UBgcolor::blue + UColor::white + " - "
			+ ucall(&globscale, &globscale_str, decreaseScale))

	      //increases scale and scale_val 
	      + ubutton(UBgcolor::orange + UColor::white + " + " 
			+ ucall(&globscale, &globscale_str, increaseScale))
	      )
     
     + uhflex() + ulabel(" ")
     + uright() + ubutton(UFont::xx_large + UColor::orange
			  + ucall(0, UAppli::quit) + "Exit")
     );


  UFrame &frame = 
    uframe(uheight(350)
	   +utop() + control
	   + uvflex() + persp //+ uscrollpane(persp)
	   );

  appli.add(frame);
  frame.show(true);
  return appli.mainLoop();
}
