/****************************************************************************
 * This file is part of the project AqDiagram.
 * AqDiagram (c) by 2025 Martin Preuss, all rights reserved.
 *
 * The license for this file can be found in the file COPYING which you
 * should have received along with this file.
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "./bargraph.h"

#include <aqdiagram/data/date.h>
#include <aqdiagram/data/floatingavg.h>
#include <aqdiagram/data/accumulate.h>
#include <aqdiagram/data/negate.h>

#include <gwenhywfar/debug.h>

#include <ctype.h>


/* ------------------------------------------------------------------------------------------------
 * definitions
 * ------------------------------------------------------------------------------------------------
 */

#define AQDG_BARGRAPH_MARGINSPERCENT_X 1.0
#define AQDG_BARGRAPH_MARGINSPERCENT_Y 10.0



/* ------------------------------------------------------------------------------------------------
 * forward declarations
 * ------------------------------------------------------------------------------------------------
 */

static void _setDataTicks(const AQDG_GRAPH *g, AQDG_GRAPH_AXIS *axis);
static void _setValuesX(AQDG_GRAPH_DATAPAIR_LIST *dpList);



/* ------------------------------------------------------------------------------------------------
 * code
 * ------------------------------------------------------------------------------------------------
 */


AQDG_GRAPH *AQDG_BarGraph_new(const char *sTitle,
                              const char *sSubTitle,
                              const char *sYLabel,
                              const char *sYUnits,
                              int yPrecision)
{
  AQDG_GRAPH *g;
  AQDG_GRAPH_AXIS *xAxis;
  AQDG_GRAPH_AXIS *yAxis;
  AQDG_GRAPH_SUBGRAPH *subGraph;

  g=AQDG_Graph_new();
  AQDG_Graph_SetTitle(g, sTitle);
  AQDG_Graph_SetSubTitle(g, sSubTitle);

  xAxis=AQDG_Graph_Axis_new();
  AQDG_Graph_Axis_SetLabel(xAxis, "Category");
  AQDG_Graph_Axis_SetPrecision(xAxis, 0);
  AQDG_Graph_SetAxis(g, AQDG_GRAPH_AXISPOS_BOTTOM, xAxis);

  yAxis=AQDG_Graph_Axis_new();
  AQDG_Graph_Axis_SetLabel(yAxis, sYLabel);
  AQDG_Graph_Axis_SetPrecision(yAxis, yPrecision);
  AQDG_Graph_Axis_SetUnits(yAxis, sYUnits);
  AQDG_Graph_SetAxis(g, AQDG_GRAPH_AXISPOS_LEFT, yAxis);

  subGraph=AQDG_Graph_SubGraph_new();
  AQDG_Graph_SubGraph_SetIndexAxisX(subGraph, AQDG_GRAPH_AXISPOS_BOTTOM);
  AQDG_Graph_SubGraph_SetIndexAxisY(subGraph, AQDG_GRAPH_AXISPOS_LEFT);
  AQDG_Graph_AddSubGraph(g, subGraph);

  return g;
}



void AQDG_BarGraph_AddCurve(AQDG_GRAPH *g, const char *sLabel, int graphType, AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
  AQDG_GRAPH_SUBGRAPH *subGraph;

  _setValuesX(dpList);
  subGraph=AQDG_Graph_GetFirstSubGraph(g);
  if (subGraph) {
    AQDG_GRAPH_CURVE *curve;

    curve=AQDG_Graph_Curve_new();
    AQDG_Graph_Curve_SetLabel(curve, sLabel);
    AQDG_Graph_Curve_SetGraphType(curve, graphType);
    AQDG_Graph_Curve_SetDataPairs(curve, dpList);
    AQDG_Graph_SubGraph_AddCurve(subGraph, curve);
  }
}



void AQDG_BarGraph_SetupTicks(AQDG_GRAPH *g, uint32_t flags, double minY, double maxY)
{
  AQDG_GRAPH_AXIS *axis;

  AQDG_Graph_CalcMinMaxValues(g);

  /* create ticks for X axis */
  axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_BOTTOM);
  if (axis) {
    AQDG_Graph_Axis_SetMinValue(axis, AQDG_Graph_Axis_GetMinValue(axis)-0.5);
    AQDG_Graph_Axis_SetMaxValue(axis, AQDG_Graph_Axis_GetMaxValue(axis)+0.5);
    _setDataTicks(g, axis);
  }

  /* create ticks for Y axis */
  axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_LEFT);
  if (axis) {
    AQDG_Graph_Axis_AddMargins(axis, AQDG_BARGRAPH_MARGINSPERCENT_Y);
    if (flags & AQDG_BARGRAPH_SETUPTICKS_FLAGS_MINY)
      AQDG_Graph_Axis_SetMinValue(axis, minY);
    if (flags & AQDG_BARGRAPH_SETUPTICKS_FLAGS_MAXY)
      AQDG_Graph_Axis_SetMaxValue(axis, maxY);
    AQDG_Graph_Axis_GenLog10Ticks(axis);
  }
}



void _setDataTicks(const AQDG_GRAPH *g, AQDG_GRAPH_AXIS *axis)
{
  const AQDG_GRAPH_SUBGRAPH *subGraph;
  const AQDG_GRAPH_CURVE_LIST *curveList;
  const AQDG_GRAPH_CURVE *curve;
  const AQDG_GRAPH_DATAPAIR_LIST *dpList;
  const AQDG_GRAPH_DATAPAIR *dp;

  subGraph=AQDG_Graph_GetFirstSubGraph(g);
  curveList=subGraph?AQDG_Graph_SubGraph_GetCurves(subGraph):NULL;
  curve=curveList?AQDG_Graph_Curve_List_First(curveList):NULL;
  dpList=curve?AQDG_Graph_Curve_GetDataPairs(curve):NULL;
  dp=dpList?AQDG_Graph_DataPair_List_First(dpList):NULL;
  while(dp) {
    AQDG_Graph_Axis_AddNewTick(axis, AQDG_Graph_DataPair_GetLabel(dp), AQDG_Graph_DataPair_GetValueX(dp), 0, 0, 1);
    dp=AQDG_Graph_DataPair_List_Next(dp);
  }
}



void _setValuesX(AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
  if (dpList) {
    AQDG_GRAPH_DATAPAIR *dp;
    int idx;

    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      AQDG_Graph_DataPair_SetValueX(dp, (double)(idx++));
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
  }
}




