#include "precomp.h"
#include "tabsheet.h"
#include "buttwnd.h"
#include "buttbar.h"
#include "tabsheetbar.h"

#include <bfc/wasabi_std.h>
#include <api/wnd/notifmsg.h>
#include <api/script/objects/c_script/c_text.h>
#include <api/script/objects/c_script/c_group.h>
#include <api/wnd/PaintCanvas.h>

TabSheet::TabSheet(int bbtype) {
  leftscroll = rightscroll = NULL;
  background = NULL;
  tabrowmargin = 0;
  active = NULL;
  type = bbtype;
  bb = NULL;
  tsb = NULL;
  content_margin_top = content_margin_right = content_margin_left = content_margin_bottom = 0;
  contentwnd = NULL;

  if (bbtype == TABSHEET_GROUPS) {
    tsb = new TabSheetBar();
    tsb->setParent(this);
  } else {	// schweitn rulz
    bb = new ButtBar((bbtype == -1) ? ButtBar::NORMAL : bbtype);
    bb->setParent(this);
    if (bbtype == TABSHEET_NOTABS)
      bb->setStartHidden(1);
  }
}

TabSheet::~TabSheet() {
  delete bb;		// kills tabs and child wnds
  delete tsb;
  delete leftscroll;
  delete rightscroll;
  delete background;
  delete contentwnd; 
}

void TabSheet::setButtonType(int _type) {
  type = _type;
  if (contentwnd != NULL) {
    if (type == ButtBar::STACK)
      contentwnd->setContent(L"wasabi.tabsheet.content.noborder");
    else if (type != TABSHEET_NOTABS)
      contentwnd->setContent(L"wasabi.tabsheet.content");
    else
      contentwnd->setContent(NULL);
  }
  if (_type == TABSHEET_GROUPS && bb != NULL) {
    PtrList<BaseWnd> l;
    foreach(tabs)
      l.addItem(tabs.getfor()->getBaseWnd());
      tabs.getfor()->setNoDeleteLinked(1);
    endfor;
    delete bb; bb = NULL;
    tabs.removeAll();
    tsb = new TabSheetBar();
    tsb->setParent(this);
    if (isInited())
      tsb->init(this);
    foreach(l)
      addChild(l.enumItem(foreach_index));
    endfor;
  } else if (_type != TABSHEET_GROUPS && tsb != NULL) {
    PtrList<BaseWnd> l;
    foreach(tabs)
      l.addItem(tabs.getfor()->getBaseWnd());
      tabs.getfor()->setNoDeleteLinked(1);
    endfor;
    delete tsb; tsb = NULL;
    tabs.removeAll();
    bb = new ButtBar((type == -1) ? ButtBar::NORMAL : type);
    bb->setParent(this);
    if (type == TABSHEET_NOTABS)
      bb->setStartHidden(1);
    if (isInited())
      bb->init(this);
    foreach(l)
      addChild(l.enumItem(foreach_index));
    endfor;
  }
  if (bb != NULL) bb->setResizeMode(type);
}

void TabSheet::killChildren() {
  if (bb) {
    delete bb;		// kills tabs and child wnds
    bb = new ButtBar((type == -1) ? ButtBar::NORMAL : type);
    bb->setParent(this);
    if (type == TABSHEET_NOTABS)
      bb->setStartHidden(1);
    bb->init(this);
  }
  if (tsb) {
    delete tsb;		// kills tabs and child wnds
    tsb = new TabSheetBar;
    tsb->setParent(this);
    tsb->init(this);
  }

  // mig: if you don't do this, you crash changing tabsheets at runtime.
  tabs.removeAll();
  active = NULL;
}

int TabSheet::onInit() {
  TABSHEET_PARENT::onInit();

  contentwnd = new GuiObjectWnd;
  if (type == ButtBar::STACK)
    contentwnd->setContent(L"wasabi.tabsheet.content.noborder");
  else if (type != TABSHEET_NOTABS)
    contentwnd->setContent(L"wasabi.tabsheet.content");
  else
    contentwnd->setContent(NULL);
  contentwnd->setParent(this);
  contentwnd->init(this);
  rootwndholder_setRootWnd(contentwnd);

  if (leftscroll != NULL) {
    leftscroll->init(this);
    leftscroll->setParent(this);
  }
  if (rightscroll != NULL) {
    rightscroll->init(this);
    rightscroll->setParent(this);
  }

  // init the windows
  foreach(tabs)
    if (foreach_index != 0) tabs.getfor()->getBaseWnd()->setStartHidden(TRUE);
    tabs.getfor()->getBaseWnd()->init(this);
  endfor

  if (bb) {
    bb->setParent(this);
    if (type == TABSHEET_NOTABS)
      bb->setStartHidden(1);
    bb->init(this);	// inits the tabs
  }
  if (tsb) {
    tsb->setParent(this);
    tsb->init(this);	// inits the tabs
  }

  if (tabs.getNumItems() > 0) {
    active = tabs[0]->getBaseWnd();
    //tabs[0]->setHilite(TRUE); // FG: FIX!
  }

  if (isPostOnInit())
    onResize();

  return 1;
}

void TabSheet::getClientRect(RECT *r) {
  TABSHEET_PARENT::getClientRect(r);
  if (bb) {
    if (type != TABSHEET_NOTABS)
      r->top += bb->getHeight();
  } else
    r->top += tsb->getHeight();

  r->left += content_margin_left;
  r->top += content_margin_top;
  r->right -= content_margin_right;
  r->bottom -= content_margin_bottom;
}

#ifdef WASABI_COMPILE_IMGLDR
void TabSheet::setBackgroundBmp(const wchar_t *name) 
{
  if (background) delete background;
  background = NULL;
  if (name && *name)
    background = new SkinBitmap(name);
}
#endif

SkinBitmap *TabSheet::getBackgroundBitmap() {
  return background;
}

int TabSheet::onPaint(Canvas *canvas) {

  PaintBltCanvas paintcanvas;
  if (canvas == NULL) {
    if (!paintcanvas.beginPaintNC(this)) return 0;
    canvas = &paintcanvas;
  }
  TABSHEET_PARENT::onPaint(canvas);
 
  RECT r;
  TABSHEET_PARENT::getClientRect(&r);

  if (bb) {
    if (type != TABSHEET_NOTABS)
      r.bottom = r.top + bb->getHeight();
  }
  else if (tsb)
    r.bottom = r.top + tsb->getHeight();

  RECT br = r;
  if (leftscroll) br.left += leftscroll->getWidth();
  if (rightscroll) br.right -= rightscroll->getWidth();

  if (br.right <= br.left) return 1;

  if (background != NULL) {
#if 0
    int i, x = tilex;
    for (i = 0; ; i++) {
      tile->stretch(canvas, x, 0, tile->getWidth(), tabrowheight);
      x += tile->getWidth();
      if (x >= r.right) break;
    }
#else
#if 0
    if (background->getAlpha()) api->skin_renderBaseTexture(canvas, br);
    background->stretchToRectAlpha(canvas, &br);
#else
    background->stretchToRect(canvas, &br);
#endif
#endif
  } else {
#if 0
    r.top = 0;
    r.bottom = tabrowheight;
    r.left = tilex;
    r.right = tilex + tilew;
    canvas->fillRect(&r, RGB(64, 64, 64));
#else
//    api->skin_renderBaseTexture(canvas, r);
#endif
  }

  return 1;
}

void TabSheet::setTabRowMargin(int newmargin) {
  ASSERT(newmargin >= 0);
  tabrowmargin = newmargin;
  onResize();
}

int TabSheet::addChild(BaseWnd *newchild, const wchar_t *tip) {

  ASSERT(newchild != NULL);

  int first=0;
  if (tabs.getNumItems() == 0) first = 1;

  if (isInited() && !newchild->isInited()) {
    if (!first) newchild->setStartHidden(TRUE);

    ifc_window *holder = this;
    if (contentwnd != NULL) {
      if (contentwnd->getContentRootWnd() != NULL) {
        GuiObject *o = contentwnd->getContent()->guiobject_findObject(L"content");
        if (o != NULL)
          holder = o->guiobject_getRootWnd();
      }
    }
    newchild->setParent(holder);
    newchild->init(holder);
  }

  if (bb) 
	{
    TabButton *tab = new TabButton(newchild, this, tip);
    tabs.addItem(tab);
    bb->addChild(tab);
  }
	else if (tsb) 
	{
    GroupTabButton *tab = new GroupTabButton(newchild, this, tip);
    tabs.addItem(tab);
    tsb->addChild(tab);
  }
  if (isInited()) {
    if (first) {
      activateChild(newchild);
    }
  }
  if (isPostOnInit()) onResize(); 
  return tabs.getNumItems()-1;
}

void TabSheet::activateChild(BaseWnd *newactive) {
  BaseWnd *prevactive = active;
  if (newactive == NULL) newactive = active;

  if (prevactive == newactive) return;	// not a switch

#if 0
  RECT r = clientRect();

  int w = r.right - r.left + 1;
  int h = r.bottom - r.top + 1;
#endif

  int prevpos=-1, nextpos=-1;

  for (int i = 0; i < tabs.getNumItems(); i++) {
    if (prevactive == tabs[i]->getBaseWnd()) prevpos = i;
    if (newactive == tabs[i]->getBaseWnd()) nextpos = i;
  }

  if (prevpos != -1) tabs[prevpos]->btn_setHilite(FALSE);
  if (nextpos < tabs.getNumItems()) tabs[nextpos]->btn_setHilite(TRUE);

#if 0
  // reveal tha new winder
  if (newactive!= NULL) newactive->setVisible(TRUE);

  enable(FALSE);
  if (prevactive!= NULL) prevactive->enable(FALSE);
  if (newactive!= NULL) newactive->enable(FALSE);

#define STEPS 6

  // find which window is now active
  for (int c = 0; c < STEPS; c++) {
    int x;
    if (prevpos > nextpos) x = (w * c) / STEPS;	// right to left
    else x = (w * (STEPS - c)) / STEPS;		// left to right
    int y = r.top;
    if (prevpos > nextpos) {
      if (newactive!= NULL) newactive->move(x - w, y);
      if (prevactive!= NULL) prevactive->move(x, y);
    } else {
      if (newactive!= NULL) newactive->move(x, y);
      if (prevactive!= NULL) prevactive->move(x - w, y);
    }
    if (newactive!= NULL) newactive->repaint();
    if (prevactive!= NULL) prevactive->repaint();
    Sleep(15);
  }
#endif

  if (newactive!= NULL) newactive->setVisible(TRUE);

  if (prevactive!= NULL) prevactive->setVisible(FALSE);

#if 0
  enable(TRUE);
  if (prevactive!= NULL) prevactive->enable(TRUE);
  if (newactive!= NULL) newactive->enable(TRUE);
#endif

  if (bb && newactive) 
		bb->setGroupLabel(newactive->getName());
  active = newactive;
  onSetPage(nextpos);  
}

int TabSheet::onResize() {
  TABSHEET_PARENT::onResize();

  if (!isInited()) return 1;

  RECT r = clientRect();

  // put buttbar at the top
  if (bb) bb->resize(r.left, r.top-bb->getHeight(), r.right-r.left, bb->getHeight()+1);
  if (tsb) tsb->resize(r.left, r.top-tsb->getHeight(), r.right-r.left, tsb->getHeight()+1);

  // resize content group if it's there
  if (contentwnd) {
    contentwnd->resize(&r);
    // since its holder is not resizing its content, we need to do it ourselves
    foreach(tabs)
      BaseWnd *c = tabs.getfor()->getBaseWnd();
      if (c->getParent() != NULL && c->getParent() != this && c->getParent()->getParent() == contentwnd->getContentRootWnd()) {
        RECT r;
        c->getParent()->getClientRect(&r);
        c->resize(&r);
      } else {
        // if we're holding it directly, resize it to our rect
        c->resize(&r);
      }
    endfor
  }

  invalidate();
  if (leftscroll)
    leftscroll->invalidate();
  if (rightscroll)
    rightscroll->invalidate();

  return 1;
}

BaseWnd *TabSheet::enumChild(int child) {
  TabButtonBase *tb = tabs[child];
  if (tb == NULL) return NULL;
  return tb->getBaseWnd();
}

int TabSheet::getNumChild() {
  return tabs.getNumItems();
}

void TabSheet::setCurPage(int page) {
  BaseWnd *e = enumChild(page);
  if (e != NULL) activateChild(e);
}

TabButtonBase *TabSheet::enumButton(int i) {
  if (i < tabs.getNumItems())
    return tabs[i];
  else
    return NULL;
}

int TabSheet::childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2) {
  if (msg == ChildNotify::NAMECHANGED) 
	{
    foreach(tabs)
      ifc_window *w = tabs.getfor()->getBaseWnd();
      if (w == child || w == child->getParent()) {
        const wchar_t *name = child->getRootWndName();
        tabs.getfor()->btn_setText(name && *name ? name : L"[?]");
      }
    endfor;
  }
  if (msg == ChildNotify::GROUPRELOAD && child == contentwnd) {
    foreach(tabs)
      ifc_window *holder = this;
      if (contentwnd->getContentRootWnd() != NULL) {
				GuiObject *o = contentwnd->getContent()->guiobject_findObject(L"content");
        if (o != NULL)
          holder = o->guiobject_getRootWnd();
      }
      tabs.getfor()->getBaseWnd()->reparent(holder);
    endfor;
  }
  return TABSHEET_PARENT::childNotify(child, msg, param1, param2);
}


void TabSheet::setContentMarginLeft(int cm) {
  content_margin_left = cm;
  if (isInited())
    onResize();
}

void TabSheet::setContentMarginTop(int cm) {
  content_margin_top = cm;
  if (isInited())
    onResize();
}

void TabSheet::setContentMarginRight(int cm) {
  content_margin_right = cm;
  if (isInited())
    onResize();
}

void TabSheet::setContentMarginBottom(int cm) {
  content_margin_bottom = cm;
  if (isInited())
    onResize();
}

int TabSheet::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) {
  if (!WCSICMP(action, L"Tabsheet:NextPage")) { nextPage(); return 1; }
  if (!WCSICMP(action, L"Tabsheet:PreviousPage")) { previousPage(); return 1; }
  return TABSHEET_PARENT::onAction(action, param, x, y, p1, p2, data, datalen, source);
}

// TabButton

TabButtonBase::TabButtonBase(BaseWnd *linkwnd, TabSheet *par, const wchar_t *tip) 
: linked(linkwnd), parent(par) {
  nodeletelinked = 0;
  ASSERT(linked != NULL);
}

TabButtonBase::~TabButtonBase() {
  if (!nodeletelinked) delete linked;
}

int TabButton::onInit() 
{
  TABBUTTON_PARENT::onInit();
  setButtonText(linked->getNameSafe(L"[?]"));
  return 1;
}

void TabButton::onLeftPush(int x, int y) {
  ASSERT(parent != NULL);
  ASSERT(linked != NULL);
  parent->activateChild(linked);
}

void TabButton::btn_setHilite(int tf) {
  setHilite(tf);
}

void TabButton::btn_setText(const wchar_t *text) 
{
  setButtonText(text);
}

// GroupTabButton

void GroupTabButton::grouptoggle_onLeftPush() {
  GROUPTABBUTTON_PARENT::grouptoggle_onLeftPush();
  ASSERT(parent != NULL);
  ASSERT(linked != NULL);
  parent->activateChild(linked);
}

void GroupTabButton::btn_setHilite(int tf) {
  setStatus(tf ? STATUS_ON : STATUS_OFF);
}

void GroupTabButton::btn_setText(const wchar_t *text)
{
  for (int i=0;i<getNumGroups();i++) {
    GuiObject *grp = enumGroups(i)->getContent();
    if (grp != NULL) {
      GuiObject *o = grp->guiobject_findObject(L"text");
      if (o != NULL) {
        C_Text txt(o->guiobject_getScriptObject());
        txt.setText(text);
      }
    }
  }
}

int GroupTabButton::onInit() {
  int rt = GROUPTABBUTTON_PARENT::onInit();
  btn_setText(linked->getNameSafe(L"[?]"));
  return rt;
}