/****************************************************************************
 * This file is part of the project AqDiagram.
 * AqDiagram (c) by 2023 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 "./layout.h"

#include <gwenhywfar/debug.h>


static int _getSumOfElementWidths(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements);
static int _getStretchableElements(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements);
static int _getMaxElementWidth(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements);
static void _placeAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing, int stretch);
static void _placeAndStretchWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
                                            int borderBegin, int spacing, int itemLength, int stretch);
static void _place(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing);




void AQDG_Placement_LayoutAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
                                     int destLength, int borderBegin, int borderEnd, int spacing)
{
  if (numElements) {
    int w;
    int stretchables;

    w=borderBegin+_getSumOfElementWidths(ptrElements, numElements)+borderEnd+(numElements-1)*spacing;
    stretchables=_getStretchableElements(ptrElements, numElements);
    if (stretchables && w<destLength) {
      int d;

      d=(destLength-w)/stretchables;
      if (d)
        _placeAndStretch(ptrElements, numElements, borderBegin, spacing, d);
      else
        _place(ptrElements, numElements, borderBegin, spacing);
    }
    else
      _place(ptrElements, numElements, borderBegin, spacing);
  }
}



void AQDG_Placement_LayoutWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
                                          int destLength,  int borderBegin, int borderEnd, int spacing)
{
  if (numElements) {
    int maxElementWidth;
    int w;
    int stretch=0;

    maxElementWidth=_getMaxElementWidth(ptrElements, numElements);
    w=borderBegin+maxElementWidth+borderEnd+(numElements-1)*spacing;
    if (w<destLength)
      stretch=(destLength-w)/numElements;
    _placeAndStretchWithEqualLength(ptrElements, numElements, borderBegin, spacing, maxElementWidth, (stretch>0)?stretch:0);
  }
}



void AQDG_Placement_LayoutSecondaryAxis(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
                                        int destLength,  int borderBegin, int borderEnd)
{
  if (numElements) {
    int i;
    int rawLength;
    AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;

    rawLength=destLength-borderBegin-borderEnd;

    /* stretch on request */
    ptr=ptrElements;
    for (i=0; i<numElements; i++) {
      if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH)
        ptr->length=rawLength;
      ptr++;
    }

    /* place children */
    ptr=ptrElements;
    for (i=0; i<numElements; i++) {
      int pos;

      if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT) {
        pos=destLength-borderEnd-ptr->length;
      }
      else if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER) {
        pos=borderBegin+(rawLength-ptr->length)/2;
      }
      else
        pos=borderBegin;

      ptr->pos=(pos<borderBegin)?borderBegin:pos;
      ptr++;
    }
  }
}






int _getSumOfElementWidths(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements)
{
  int i;
  int w=0;

  for (i=0; i<numElements; i++)
    w+=(ptrElements++)->length;
  return w;
}



int _getStretchableElements(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements)
{
  int i;
  int n=0;

  for (i=0; i<numElements; i++)
    if (((ptrElements++)->opts) & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH)
      n++;
  return n;
}



int _getMaxElementWidth(const AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements)
{
  int i;
  int w=-1;

  for (i=0; i<numElements; i++) {
    w=(ptrElements->length>w)?(ptrElements->length):w;
    ptrElements++;
  }
  return w;
}



void _placeAndStretch(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing, int stretch)
{
  int i;
  int pos=0;
  AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;

  pos=borderBegin;
  ptr=ptrElements;
  for (i=0; i<numElements; i++) {
    ptr->pos=pos;
    if (ptr->opts & AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH)
      ptr->length+=stretch;
    pos+=ptr->length+spacing;
    ptr++;
  }
}



void _placeAndStretchWithEqualLength(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements,
                                     int borderBegin, int spacing, int itemLength, int stretch)
{
  int i;
  int pos=0;
  AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;

  pos=borderBegin;
  ptr=ptrElements;
  for (i=0; i<numElements; i++) {
    ptr->pos=pos;
    ptr->length=itemLength;
    pos+=itemLength+spacing+stretch;
    ptr++;
  }
}



void _place(AQDG_PLACEMENT_LAYOUT_ELEMENT *ptrElements, int numElements, int borderBegin, int spacing)
{
  int i;
  int pos=0;
  AQDG_PLACEMENT_LAYOUT_ELEMENT *ptr;

  pos=borderBegin;
  ptr=ptrElements;
  for (i=0; i<numElements; i++) {
    ptr->pos=pos;
    pos+=ptr->length+spacing;
    ptr++;
  }
}



