// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2013 Emweb bvba, Leuven, Belgium.
 *
 * See the LICENSE file for terms of use.
 */

#include "Wt/Chart/WChart3DImplementation"

#include "Wt/Chart/WCartesian3DChart"
#include "Wt/Chart/WGridData"
#include "Wt/WAbstractItemModel"
#include "Wt/WBoostAny"

namespace Wt {
  namespace Chart {

WChart3DImplementation::WChart3DImplementation(WCartesian3DChart *chart)
  : chart_(chart)
{}

ChartType WChart3DImplementation::chartType() const
{
  return chart_->type();
}

Orientation WChart3DImplementation::orientation() const
{
  return Vertical;
}

int WChart3DImplementation::axisPadding() const
{
  return 0;
}

int WChart3DImplementation::numberOfCategories(Axis axis) const
{
  if (chart_->dataSeries().size() == 0)
    return 10;

  WAbstractGridData *first;
  if (axis == XAxis_3D) {
    first = dynamic_cast<WAbstractGridData*>(chart_->dataSeries()[0]);
    if (first == 0) {
      throw WException("WChart3DImplementation: can only count the categories in WAbstractGridData");
    } else {
      return first->nbXPoints();
    }
  } else if (axis == YAxis_3D) {
    first = dynamic_cast<WAbstractGridData*>(chart_->dataSeries()[0]);
    if (first == 0) {
      throw WException("WChart3DImplementation: can only count the categories in WAbstractGridData");
    } else {
      return first->nbYPoints();
    }
  } else {
    throw WException("WChart3DImplementation: don't know this type of axis");
  }
}

WString WChart3DImplementation::categoryLabel(int u, Axis axis) const
{
  if (chart_->dataSeries().size() == 0)
    return WString(boost::lexical_cast<std::string>(u));

  WAbstractGridData *first = dynamic_cast<WAbstractGridData*>(chart_->dataSeries()[0]);
  if (!first) {
    throw WException("WChart3DImplementation: can only count the categories in WAbstractGridData");
  }

  return first->axisLabel(u, axis);
}

WAbstractChartImplementation::RenderRange WChart3DImplementation::computeRenderRange(Axis axis, AxisScale scale) const
{
  WAbstractChartImplementation::RenderRange range;
  
  const std::vector<WAbstractDataSeries3D*> series = chart_->dataSeries();
  if (series.size() == 0) {
    range.minimum = 0;
    range.maximum = 100;
    return range;
  }

  double min=std::numeric_limits<double>::max();
  double max=std::numeric_limits<double>::min();
  int xDim = 0, yDim = 0;
  double stackedBarsHeight = 0.0;
  WAbstractGridData* griddata;
  switch (chart_->type()) {
  case ScatterPlot:
    for (unsigned i = 0; i < series.size(); i++) {
      double seriesMin = series[i]->minimum(axis);
      double seriesMax = series[i]->maximum(axis);
      if (seriesMin < min) {
	min = seriesMin;
      }
      if (seriesMax > max) {
	max = seriesMax;
      }
    }
    range.minimum = min;
    range.maximum = max;
    return range;
  case CategoryChart:
    for (unsigned k = 0; k < series.size(); k++) {
      griddata = dynamic_cast<WAbstractGridData*>(series[k]);
      if ( griddata == 0 
	   || griddata->type() != BarSeries3D) {
	throw WException("WChart3DImplementation: not all data is categorical");
      }
    }
    xDim = dynamic_cast<WAbstractGridData*>(series[0])->nbXPoints();
    yDim = dynamic_cast<WAbstractGridData*>(series[0])->nbYPoints();
    min = 0.0;

    for (int i=0; i < xDim; i++) {
      for (int j=0; j < yDim; j++) {
	for (unsigned k = 0; k < series.size(); k++) {
	  if (series[k]->isHidden())
	    continue;
	  griddata = dynamic_cast<WAbstractGridData*>(series[k]);
	  stackedBarsHeight += Wt::asNumber(griddata->data(i,j));
	}
	if (stackedBarsHeight > max) {
	  max = stackedBarsHeight;
	}
	stackedBarsHeight = 0;
      }
    }
    if (max == std::numeric_limits<double>::min()) {
      max = 100.0;
    }
    range.minimum = min;
    range.maximum = max;
    return range;
  default:
    throw WException("WChart3DImplementation: don't know this axis-type");
  }
}

void WChart3DImplementation::update()
{
  chart_->updateChart(GLContext |
		      GLTextures);
}


  }
}
