/*------------------------------------------------------------------------------
 src/bin/djview/imageOpStackWidget.cxx

 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

//#define DJ_DBG
#include "djImageOpStackWidget.h"
#include <djImageOpStack.h>
#include <djTabWidget.h>
#include <djApp.h>

namespace dj {

ImageOpStackWidget::ImageOpStackWidget() :
  _callbacks(true)
{
  DJ_DBG_FNC("dj::ImageOpStackWidget::ImageOpStackWidget");
  
  // Widgets.
  //
  color(FL_BACKGROUND2_COLOR);
  _tabWidget = new TabWidget;
  
  // Layout.
  //
  VLayout * layout = new VLayout(this);
  layout->spacing(0);
  layout->margin(0);
  layout->add(_tabWidget);
  layout->stretch(_tabWidget);
  
  // Callbacks.
  //
  _tabWidget->sig().set(this, stackActiveCallback);
}

ImageOpStackWidget::~ImageOpStackWidget()
{
  DJ_DBG_FNC("dj::ImageOpStackWidget::~ImageOpStackWidget");
  
  _tabWidget->tabDel();
}

void ImageOpStackWidget::set(ImageOpStack * in)
{
  _imageOpStack = in;
  widgetUpdate();
}

bool ImageOpStackWidget::stackActive(int in)
{
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackActive");
  DJ_DBG_PRN("in = " << in);

  return _tabWidget->tab(in);
}

int ImageOpStackWidget::stackActive() const
{
  return _tabWidget->tab();
}

void ImageOpStackWidget::stackActiveCallback(int in)
{
  if (! _callbacks) return;
  _stackActiveSig.emit(in);
}

// XXX Static variable.
//
static int _stackNameCount = 1;

void ImageOpStackWidget::stackNew(const Str & name)
{
  if (! _imageOpStack) return;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackNew");
  DJ_DBG_PRN("name = " << name);
  
  _imageOpStack->stackNew(
    ! name.isNull() ? name : Str("stack %1").arg(_stackNameCount++)
  );
  
  widgetUpdate();
  _tabWidget->tab(_tabWidget->tabSize() - 1);
  _updateSig.emit(true);
}

bool ImageOpStackWidget::stackCopy(int in)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackCopy");
  DJ_DBG_PRN("in = " << in);
  
  if (! _imageOpStack->stackCopy(in)) return false;
  
  widgetUpdate();
  _tabWidget->tab(_tabWidget->tabSize() - 1);
  _updateSig.emit(true);
  return true;
}

bool ImageOpStackWidget::stackDel(int in)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackDel");
  DJ_DBG_PRN("in = " << in);
  
  if (! _imageOpStack->stackDel(in)) return false;
  
  widgetUpdate();
  if (_tabWidget->tabSize()) {
    const int stack = min(in, _tabWidget->tabSize() - 1);
    _tabWidget->tab(stack);
  }
  _updateSig.emit(true);
  return true;
}

bool ImageOpStackWidget::stackName(const Str & name, int stack)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackName");
  DJ_DBG_PRN("name = " << name);
  DJ_DBG_PRN("stack = " << stack);
  
  if (! _imageOpStack->stackName(name, stack)) return false;
  
  widgetUpdate();
  _updateSig.emit(true);
  return true;
}

bool ImageOpStackWidget::stackLeft(int in)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackLeft");
  DJ_DBG_PRN("in = " << in);
  
  if (! _imageOpStack->stackLeft(in)) return false;
  
  widgetUpdate();
  _tabWidget->tab(in - 1);
  _updateSig.emit(true);
  return true;
}

bool ImageOpStackWidget::stackRight(int in)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::stackRight");
  DJ_DBG_PRN("in = " << in);
  
  if (! _imageOpStack->stackRight(in)) return false;
  
  widgetUpdate();
  _tabWidget->tab(in + 1);
  _updateSig.emit(true);
  return true;
}

void ImageOpStackWidget::stackUpdateCallback(bool)
{
  if (! _callbacks) return;
  _stackUpdateSig.emit(_tabWidget->tab());
}

bool ImageOpStackWidget::opNew(const Str & name, int stack)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::opNew");
  DJ_DBG_PRN("name = " << name);
  DJ_DBG_PRN("stack = " << stack);
  
  if (! _imageOpStack->stackSize()) {
    _imageOpStack->stackNew(name);
    stack = 0;
  }
  if (! _imageOpStack->opNew(name, stack)) return false;
  
  widgetUpdate();
  _tabWidget->tab(stack);
  _widgetList[stack]->tab(_widgetList[stack]->tabSize() - 1);
  _updateSig.emit(true);
  //_stackUpdateSig.emit(stack);
  return true;
}

bool ImageOpStackWidget::opCopy(int in, int stack)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::opCopy");
  DJ_DBG_PRN("in = " << in);
  DJ_DBG_PRN("stack = " << stack);
  
  if (! _imageOpStack->opCopy(in, stack)) return false;
  
  widgetUpdate();
  _tabWidget->tab(stack);
  _widgetList[stack]->tab(_widgetList[stack]->tabSize() - 1);
  _stackUpdateSig.emit(stack);
  return true;
}

bool ImageOpStackWidget::opDel(int in, int stack)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::opDel");
  DJ_DBG_PRN("in = " << in);
  DJ_DBG_PRN("stack = " << stack);
  
  if (! _imageOpStack->opDel(in, stack)) return false;
  
  widgetUpdate();
  _tabWidget->tab(stack);
  _widgetList[stack]->tab(in);
  _stackUpdateSig.emit(stack);
  return true;
}

bool ImageOpStackWidget::opLeft(int in, int stack)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::opLeft");
  DJ_DBG_PRN("in = " << in);
  DJ_DBG_PRN("stack = " << stack);
  
  if (! _imageOpStack->opLeft(in, stack)) return false;
  
  widgetUpdate();
  _tabWidget->tab(stack);
  _widgetList[stack]->tab(in - 1);
  _stackUpdateSig.emit(stack);
  return true;
}

bool ImageOpStackWidget::opRight(int in, int stack)
{
  if (! _imageOpStack) return false;
  
  DJ_DBG_FNC("dj::ImageOpStackWidget::opRight");
  DJ_DBG_PRN("in = " << in);
  DJ_DBG_PRN("stack = " << stack);
  
  if (! _imageOpStack->opRight(in, stack)) return false;
  
  widgetUpdate();
  _tabWidget->tab(stack);
  _widgetList[stack]->tab(in + 1);
  _stackUpdateSig.emit(stack);
  return true;
}

int ImageOpStackWidget::opActive() const
{
  const int stack = stackActive();
  if (-1 == stack) return -1;
  return _widgetList[stack]->tab();
}

void ImageOpStackWidget::widgetUpdate()
{
  DJ_DBG_FNC("dj::ImageOpStackWidget::widgetUpdate");
  
  _callbacks = false;
  
  _tabWidget->tabDel();
  _widgetList.del();
  
  if (_imageOpStack)
    for (int i = 0; i < _imageOpStack->stackSize(); ++i) {    
      TabWidget * tabWidget = new TabWidget;
      _widgetList += tabWidget;
      _tabWidget->tabAdd(_imageOpStack->stackName(i), tabWidget);
      for (
        ConstListIt<ImageOp *> it = _imageOpStack->stack(i); it.isValid(); ++it
      ) {
        ImageOpWidget * widget =
          djApp->imageOpWidget().pluginCopy(it()->name());
        tabWidget->tabAdd(it()->name(), widget);
        if (widget) {
          widget->set(it());
          widget->sig().set(this, stackUpdateCallback);
        }
      }
    }

  _callbacks = true;
}

void prefs(ImageOpStack * in, const Str & name, const Prefs & prefs)
{
  DJ_DBG_FNC("dj::prefs(ImageOpStack)");
  
  Prefs prefsThis(prefs, name);
  
  const StrList stacks = prefsThis.groupList();
  for (int i = 0; i < stacks.size(); ++i) {
    Prefs stackPrefs(prefsThis, Str("stack %1").arg(i));
    Str name;
    stackPrefs.get("name", &name);
    DJ_DBG_PRN("name = " << name);
    in->stackNew(name);
  
    const StrList ops = stackPrefs.groupList();
    for (int j = 0; j < ops.size(); ++j) {
      Prefs opPrefs(stackPrefs, Str("op %1").arg(j));
      Prefs attrPrefs(opPrefs, "attr");
      Str name;
      opPrefs.get("name", &name);
      if (! in->opNew(name, i)) continue;
      ImageOp * op = in->stack(i)[j];
      
      const StrList attr = attrPrefs.nameList();
      StrList data;
      for (ConstStrListIt it = attr; it.isValid(); ++it) {
        attrPrefs.get(it(), &data);
        op->attr(it(), data);
      }
    }
  }
}

void prefs(const ImageOpStack & in, const Str & name, Prefs * prefs)
{
  DJ_DBG_FNC("dj::prefs(ImageOpStack)");

  prefs->groupDel(name);
  Prefs prefsThis(prefs, name);
  
  for (int i = 0; i < in.stackSize(); ++i) {
    
    Prefs stackPrefs(prefsThis, Str("stack %1").arg(i));
    stackPrefs.set("name", in.stackName(i));
    for (ConstListIt<ImageOp *> it = in.stack(i); it.isValid(); ++it) {
      ImageOp * op = it();
      
      Prefs opPrefs(stackPrefs, Str("op %1").arg(it.count()));
      opPrefs.set("name", op->name());
      Prefs attrPrefs(opPrefs, "attr");
      const StrList attr = op->attrNameList();
      for (ConstStrListIt it = attr; it.isValid(); ++it)
        attrPrefs.set(it(), op->attr(it()));
    }
  }
}

}
