/****************************************************************************
 * 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 "./date.h"

#include <gwenhywfar/gwendate.h>
#include <gwenhywfar/debug.h>

#include <math.h>



AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DaySums(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
  if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
    AQDG_GRAPH_DATAPAIR_LIST *newList;
    const AQDG_GRAPH_DATAPAIR *dp;
    GWEN_DATE *lastDate=NULL;
    AQDG_GRAPH_DATAPAIR *newDp=NULL;

    newList=AQDG_Graph_DataPair_List_new();
    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      double v;

      v=AQDG_Graph_DataPair_GetValueY(dp);
      if (lastDate==NULL) {
        /* first value */
        lastDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));
        newDp=AQDG_Graph_DataPair_new();
        AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate));
        AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp));
        AQDG_Graph_DataPair_List_Add(newDp, newList);
      }
      else {
        GWEN_DATE *newDate;

        newDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));
        if (GWEN_Date_Compare(newDate, lastDate)!=0) {
          /* new date */
          GWEN_Date_free(lastDate);
          lastDate=newDate;
          newDp=AQDG_Graph_DataPair_new();
          AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate));
          AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp));
          AQDG_Graph_DataPair_List_Add(newDp, newList);
        }
        else {
          double v2;

          /* add to existing date value */
          v2=AQDG_Graph_DataPair_GetValueY(newDp);
          v2+=v;
          AQDG_Graph_DataPair_SetValueY(newDp, v2);
          GWEN_Date_free(newDate);
        }
      }
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
    GWEN_Date_free(lastDate);
    return newList;
  }
  return NULL;
}



AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_MonthSums(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
  if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
    AQDG_GRAPH_DATAPAIR_LIST *newList;
    const AQDG_GRAPH_DATAPAIR *dp;
    GWEN_DATE *lastDate=NULL;
    AQDG_GRAPH_DATAPAIR *newDp=NULL;

    newList=AQDG_Graph_DataPair_List_new();
    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      double v;

      v=AQDG_Graph_DataPair_GetValueY(dp);
      if (lastDate==NULL) {
        GWEN_DATE *dt;

        /* first value */
        dt=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));
        lastDate=GWEN_Date_GetThisMonthStart(dt);
        GWEN_Date_free(dt);
        newDp=AQDG_Graph_DataPair_new();
        AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate));
        AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp));
        AQDG_Graph_DataPair_List_Add(newDp, newList);
      }
      else {
        GWEN_DATE *dt;
        GWEN_DATE *newDate;

        dt=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));
        newDate=GWEN_Date_GetThisMonthStart(dt);
        GWEN_Date_free(dt);
        if (GWEN_Date_Compare(newDate, lastDate)!=0) {
          /* new date */
          GWEN_Date_free(lastDate);
          lastDate=newDate;
          newDp=AQDG_Graph_DataPair_new();
          AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate));
          AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp));
          AQDG_Graph_DataPair_List_Add(newDp, newList);
        }
        else {
          double v2;

          /* add to existing date value */
          v2=AQDG_Graph_DataPair_GetValueY(newDp);
          AQDG_Graph_DataPair_SetValueY(newDp, v2+v);
          GWEN_Date_free(newDate);
        }
      }
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
    GWEN_Date_free(lastDate);
    return newList;
  }
  return NULL;
}



AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DayAverage(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
  if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
    AQDG_GRAPH_DATAPAIR_LIST *newList;
    const AQDG_GRAPH_DATAPAIR *dp;
    GWEN_DATE *currentDate=NULL;
    double currentSum;
    int currentCount;

    newList=AQDG_Graph_DataPair_List_new();
    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      if (currentDate==NULL) {
        /* first value */
        currentDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));
        currentSum=AQDG_Graph_DataPair_GetValueY(dp);
        currentCount=1;
      }
      else {
        GWEN_DATE *newDate;

        newDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));
        if (GWEN_Date_Compare(newDate, currentDate)!=0) {
          AQDG_GRAPH_DATAPAIR *newDp;

          /* new date */
          newDp=AQDG_Graph_DataPair_new();
          AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(currentDate));
          AQDG_Graph_DataPair_SetValueY(newDp, currentSum/(double)currentCount);
          AQDG_Graph_DataPair_List_Add(newDp, newList);

          currentSum=AQDG_Graph_DataPair_GetValueY(dp);
          currentCount=1;
          GWEN_Date_free(currentDate);
          currentDate=newDate;
        }
        else {
          /* add to existing date value */
          currentSum+=AQDG_Graph_DataPair_GetValueY(dp);
          currentCount++;
          GWEN_Date_free(newDate);
        }
      }
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
    if (currentCount && currentDate) {
      AQDG_GRAPH_DATAPAIR *newDp;

      /* store data for last value */
      newDp=AQDG_Graph_DataPair_new();
      AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(currentDate));
      AQDG_Graph_DataPair_SetValueY(newDp, currentSum/(double)currentCount);
      AQDG_Graph_DataPair_List_Add(newDp, newList);
    }
    GWEN_Date_free(currentDate);
    return newList;
  }
  return NULL;
}



AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_MinutesAverage(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int minutes)
{
  if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
    AQDG_GRAPH_DATAPAIR_LIST *newList;
    const AQDG_GRAPH_DATAPAIR *dp;
    double currentTimeMinutes=0;
    double currentTimeValue;
    double currentSum;
    int currentCount=0;

    newList=AQDG_Graph_DataPair_List_new();
    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      if (currentCount==0) {

        /* first value */
        currentTimeValue=AQDG_Graph_DataPair_GetValueX(dp);
        currentTimeMinutes=floor(currentTimeValue/60.0);
        currentSum=AQDG_Graph_DataPair_GetValueY(dp);
        currentCount=1;
      }
      else {
        double newTimeValue;
        double newTimeMinutes;

        newTimeValue=AQDG_Graph_DataPair_GetValueX(dp);
        newTimeMinutes=floor(newTimeValue/60.0);
        if ((newTimeMinutes-currentTimeMinutes)<(double)minutes) {
          /* add to existing sum */
          currentSum+=AQDG_Graph_DataPair_GetValueY(dp);
          currentCount++;
        }
        else {
          AQDG_GRAPH_DATAPAIR *newDp;

          /* new date */
          newDp=AQDG_Graph_DataPair_new();
          AQDG_Graph_DataPair_SetValueX(newDp, (floor(currentTimeMinutes/(double) minutes)*(double) minutes)*60.0);
          AQDG_Graph_DataPair_SetValueY(newDp, currentSum/(double)currentCount);
          AQDG_Graph_DataPair_List_Add(newDp, newList);

          currentSum=AQDG_Graph_DataPair_GetValueY(dp);
          currentCount=1;
          currentTimeValue=newTimeValue;
          currentTimeMinutes=newTimeMinutes;
        }
      }
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
    if (currentCount) {
      AQDG_GRAPH_DATAPAIR *newDp;

      /* store data for last value */
      newDp=AQDG_Graph_DataPair_new();
      AQDG_Graph_DataPair_SetValueX(newDp, (floor(currentTimeMinutes/(double) minutes)*(double) minutes)*60.0);
      AQDG_Graph_DataPair_SetValueY(newDp, currentSum/(double)currentCount);
      AQDG_Graph_DataPair_List_Add(newDp, newList);
    }
    return newList;
  }
  return NULL;
}



AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_MinutesMax(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int minutes)
{
  if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
    AQDG_GRAPH_DATAPAIR_LIST *newList;
    const AQDG_GRAPH_DATAPAIR *dp;
    double currentTimeMinutes=0;
    double currentTimeValue;
    double currentMax;
    int currentCount=0;

    newList=AQDG_Graph_DataPair_List_new();
    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      if (currentCount==0) {

        /* first value */
        currentTimeValue=AQDG_Graph_DataPair_GetValueX(dp);
        currentTimeMinutes=floor(currentTimeValue/60.0);
        currentMax=AQDG_Graph_DataPair_GetValueY(dp);
        currentCount=1;
      }
      else {
        double newTimeValue;
        double newTimeMinutes;

        newTimeValue=AQDG_Graph_DataPair_GetValueX(dp);
        newTimeMinutes=floor(newTimeValue/60.0);
        if ((newTimeMinutes-currentTimeMinutes)<(double)minutes) {
          double v;

          v=AQDG_Graph_DataPair_GetValueY(dp);
          currentMax=(v>currentMax)?v:currentMax;
          currentCount++;
        }
        else {
          AQDG_GRAPH_DATAPAIR *newDp;

          /* new date */
          newDp=AQDG_Graph_DataPair_new();
          AQDG_Graph_DataPair_SetValueX(newDp, (floor(currentTimeMinutes/(double) minutes)*(double) minutes)*60.0);
          AQDG_Graph_DataPair_SetValueY(newDp, currentMax);
          AQDG_Graph_DataPair_List_Add(newDp, newList);

          currentMax=AQDG_Graph_DataPair_GetValueY(dp);
          currentCount=1;
          currentTimeValue=newTimeValue;
          currentTimeMinutes=newTimeMinutes;
        }
      }
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
    if (currentCount) {
      AQDG_GRAPH_DATAPAIR *newDp;

      /* store data for last value */
      newDp=AQDG_Graph_DataPair_new();
      AQDG_Graph_DataPair_SetValueX(newDp, (floor(currentTimeMinutes/(double) minutes)*(double) minutes)*60.0);
      AQDG_Graph_DataPair_SetValueY(newDp, currentMax);
      AQDG_Graph_DataPair_List_Add(newDp, newList);
    }
    return newList;
  }
  return NULL;
}



AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_MinutesMin(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int minutes)
{
  if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
    AQDG_GRAPH_DATAPAIR_LIST *newList;
    const AQDG_GRAPH_DATAPAIR *dp;
    double currentTimeMinutes=0;
    double currentTimeValue;
    double currentMin;
    int currentCount=0;

    newList=AQDG_Graph_DataPair_List_new();
    dp=AQDG_Graph_DataPair_List_First(dpList);
    while(dp) {
      if (currentCount==0) {

        /* first value */
        currentTimeValue=AQDG_Graph_DataPair_GetValueX(dp);
        currentTimeMinutes=floor(currentTimeValue/60.0);
        currentMin=AQDG_Graph_DataPair_GetValueY(dp);
        currentCount=1;
      }
      else {
        double newTimeValue;
        double newTimeMinutes;

        newTimeValue=AQDG_Graph_DataPair_GetValueX(dp);
        newTimeMinutes=floor(newTimeValue/60.0);
        if ((newTimeMinutes-currentTimeMinutes)<(double)minutes) {
          double v;

          v=AQDG_Graph_DataPair_GetValueY(dp);
          currentMin=(v<currentMin)?v:currentMin;
          currentCount++;
        }
        else {
          AQDG_GRAPH_DATAPAIR *newDp;

          /* new date */
          newDp=AQDG_Graph_DataPair_new();
          AQDG_Graph_DataPair_SetValueX(newDp, (floor(currentTimeMinutes/(double) minutes)*(double) minutes)*60.0);
          AQDG_Graph_DataPair_SetValueY(newDp, currentMin);
          AQDG_Graph_DataPair_List_Add(newDp, newList);

          currentMin=AQDG_Graph_DataPair_GetValueY(dp);
          currentCount=1;
          currentTimeValue=newTimeValue;
          currentTimeMinutes=newTimeMinutes;
        }
      }
      dp=AQDG_Graph_DataPair_List_Next(dp);
    }
    if (currentCount) {
      AQDG_GRAPH_DATAPAIR *newDp;

      /* store data for last value */
      newDp=AQDG_Graph_DataPair_new();
      AQDG_Graph_DataPair_SetValueX(newDp, (floor(currentTimeMinutes/(double) minutes)*(double) minutes)*60.0);
      AQDG_Graph_DataPair_SetValueY(newDp, currentMin);
      AQDG_Graph_DataPair_List_Add(newDp, newList);
    }
    return newList;
  }
  return NULL;
}



