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

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

//#define DJ_DBG
#include "colorSampleTool.h"
#include "widget.h"
#include <djLabelWidget.h>
#include <djButtonWidget.h>
#include <djNumWidget.h>
#include <djColorWidget.h>
#include <djImageWidget.h>

namespace djview {

ColorSampleTool::ColorSampleTool() :
  DialogBase("Color Sample Tool"),
  _value(PIXEL_RGBA, PIXEL_F32),
  _width(15),
  _lock(false),
  _callbacks(true)
{
  // Widgets.
  //
  Widget * frameWidget = new Widget;
  frameWidget->box(FL_THIN_UP_BOX);
  _widget = new ColorWidget;
  _swatchWidget = new ColorSwatchWidget;
  LabelWidget * widthLabel = new LabelWidget("Width:");
  _widthWidget = new IntWidget;
  _widthWidget->min(1);
  _lockWidget = new CheckButtonWidget("Lock");
  Widget * dialogFrameWidget = new Widget;
  dialogFrameWidget->box(FL_THIN_UP_BOX);
  PushButtonWidget * closeWidget = new PushButtonWidget("Clos&e");
  
  // Layout.
  //
  VLayout * windowLayout = new VLayout(this);
  windowLayout->spacing(0);
  windowLayout->margin(0);
  windowLayout->add(frameWidget);
  windowLayout->stretch(frameWidget);
  HLayout * layout = new HLayout(frameWidget);
  layout->add(_swatchWidget);
  VLayout * subLayout = new VLayout(layout);
  layout->stretch(subLayout);
  subLayout->margin(0);
  subLayout->add(_widget);
  subLayout->stretchAdd();
  windowLayout->add(dialogFrameWidget);
  HLayout * dialogFrameLayout = new HLayout(dialogFrameWidget);
  dialogFrameLayout->add(widthLabel);
  dialogFrameLayout->add(_widthWidget);
  dialogFrameLayout->add(_lockWidget);
  dialogFrameLayout->stretchAdd();
  dialogFrameLayout->add(closeWidget);
  
  // Initialize.
  //
  widgetUpdate();
  size(sizeHint());
  
  // Callbacks.
  //
  _widget->sig().set(this, widgetCallback);
  _widthWidget->sig().set(this, widthCallback);
  _lockWidget->sig().set(this, lockCallback);
  closeWidget->sig().set(this, closeCallback);
}

void ColorSampleTool::set(const ViewWidget * in)
{
  DJ_DBG_FNC("ColorSampleTool::set");
  
  _value.set(_widget->get().pixel());

  const Image * image = in->image();
  if (image) {

    if (! _lock) _value.set(image->pixel());
    
    const int proxyScale = imageProxyScale(image->proxy());
    const Vec2i position =
      (in->mouse() - in->viewPosition()) /
      ImageWidget::zoomToFloat(in->viewZoom());
    DJ_DBG_PRN("position = " << position);
      
    //image->pixel(position / proxyScale, &_value);
      
    Box2i area(
      floor((position.x() - _width / 2) / double(proxyScale)),
      floor((position.y() - _width / 2) / double(proxyScale)),
      ceil(_width / double(proxyScale)),
      ceil(_width / double(proxyScale))
    );
    area = intersect(area, Box2i(image->size()));
    DJ_DBG_PRN("area = " << area);
    if (areaIsValid(area)) {
      Color pixel(_value.pixel());
      Color accum(_value.format(), PIXEL_F32);
      Color accumTotal(_value.format(), PIXEL_F32);
      const int channels = pixelSize(_value.format());
      for (int y = 0; y < area.height(); ++y) {
        accum.zero();
        for (int x = 0; x < area.width(); ++x) {
          image->pixel(area.x() + x, area.y() + y, &pixel);
          for (int c = 0; c < channels; ++c)
            accum.f32(accum.f32(c) + pixel.f32(c), c);
        }
        for (int c = 0; c < channels; ++c)
          accumTotal.f32(
            accumTotal.f32(c) +
            accum.f32(c) / double(area.width()),
            c
          );
      }
      for (int c = 0; c < channels; ++c)
        accumTotal.f32(accumTotal.f32(c) / double(area.height()), c);
      convert(accumTotal, &_value);
    }
  }

  widgetUpdate();
}

void ColorSampleTool::widgetCallback(const Color & in)
{
  if (! _callbacks) return;
  _swatchWidget->set(in);
}

void ColorSampleTool::widthCallback(int in)
{
  if (! _callbacks) return;
  _width = in;
  widgetUpdate();
}

void ColorSampleTool::lockCallback(bool in)
{
  if (! _callbacks) return;
  _lock = in;
  widgetUpdate();
}

void ColorSampleTool::closeCallback(bool)
{
  if (! _callbacks) return;
  hide();
}

void ColorSampleTool::widgetUpdate()
{
  DJ_DBG_FNC("ColorSampleTool::widgetUpdate");
  
  _callbacks = false;
  
  _widget->set(_value);
  _swatchWidget->set(_value);
  _widthWidget->set(_width);
  _lockWidget->set(_lock);

  _callbacks = true;
}

void ColorSampleTool::prefs(const Prefs & in)
{
  Prefs prefs(in, "colorSampleTool");
  
  prefs.get("width", &_width, _width);
  prefs.get("lock", &_lock, _lock);
  
  widgetUpdate();
}

void ColorSampleTool::prefs(Prefs * in)
{
  Prefs prefs(in, "colorSampleTool");
  
  prefs.set("width", _width);
  prefs.set("lock", _lock);
}

}
