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



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

static void _setElementFromObjectX(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, AQDG_OBJECT *object);
static void _setElementFromObjectY(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, const AQDG_OBJECT *object);
static void _setObjectFromElementX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr);
static void _setObjectFromElementY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr);



/* ------------------------------------------------------------------------------------------------
 * implementations
 * ------------------------------------------------------------------------------------------------
 */


int AQDG_LayoutObject_CountDirectChildren(const AQDG_OBJECT *object)
{
  int c=0;
  const AQDG_OBJECT *child;

  child=AQDG_Object_Tree2_GetFirstChild(object);
  while(child) {
    c++;
    child=AQDG_Object_Tree2_GetNext(child);
  }

  return c;
}



AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_Children2ElementsX(const AQDG_OBJECT *object, int num)
{
  if (object && num)
    return AQDG_LayoutObject_ObjectList2ElementsX(AQDG_Object_Tree2_GetFirstChild(object), num);
  return NULL;
}



AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_ObjectList2ElementsX(AQDG_OBJECT *object, int num)
{
  if (object && num) {
    AQDG_PLACEMENT_LAYOUT_ELEMENT *elements;

    elements=(AQDG_PLACEMENT_LAYOUT_ELEMENT*) malloc(num*sizeof(AQDG_PLACEMENT_LAYOUT_ELEMENT));
    if (elements) {
      AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;

      eptr=elements;
      while(object && num) {
        _setElementFromObjectX(eptr, object);
        object=AQDG_Object_Tree2_GetNext(object);
        eptr++;
        num--;
      }
      return elements;
    }
  }

  return NULL;
}



AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_Children2ElementsY(const AQDG_OBJECT *object, int num)
{
  if (object && num)
    return AQDG_LayoutObject_ObjectList2ElementsY(AQDG_Object_Tree2_GetFirstChild(object), num);
  return NULL;
}



AQDG_PLACEMENT_LAYOUT_ELEMENT *AQDG_LayoutObject_ObjectList2ElementsY(const AQDG_OBJECT *object, int num)
{
  if (object && num) {
    AQDG_PLACEMENT_LAYOUT_ELEMENT *elements;

    elements=(AQDG_PLACEMENT_LAYOUT_ELEMENT*) malloc(num*sizeof(AQDG_PLACEMENT_LAYOUT_ELEMENT));
    if (elements) {
      AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;

      eptr=elements;
      while(object && num) {
        _setElementFromObjectY(eptr, object);
        object=AQDG_Object_Tree2_GetNext(object);
        eptr++;
        num--;
      }
      return elements;
    }
  }

  return NULL;
}



void AQDG_LayoutObject_ChildrenFromElementsX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num)
{
  if (num && elements)
    AQDG_LayoutObject_Elements2ObjectListX(AQDG_Object_Tree2_GetFirstChild(object), elements, num);
}



void AQDG_LayoutObject_Elements2ObjectListX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num)
{
  if (object && num && elements) {
    const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;

    eptr=elements;
    while(object && num) {
      _setObjectFromElementX(object, eptr);
      eptr++;
      num--;
      object=AQDG_Object_Tree2_GetNext(object);
    }
  }
}



void AQDG_LayoutObject_ChildrenFromElementsY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num)
{
  if (num && elements)
    AQDG_LayoutObject_Elements2ObjectListY(AQDG_Object_Tree2_GetFirstChild(object), elements, num);
}



void AQDG_LayoutObject_Elements2ObjectListY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *elements, int num)
{
  if (object && num && elements) {
    const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr;

    eptr=elements;
    while(object && num) {
      _setObjectFromElementY(object, eptr);
      eptr++;
      num--;
      object=AQDG_Object_Tree2_GetNext(object);
    }
  }
}



void AQDG_LayoutObject_SetChildrenWidths(AQDG_OBJECT *object)
{
  AQDG_OBJECT *child;

  child=AQDG_Object_Tree2_GetFirstChild(object);
  while(child) {
    if (!(AQDG_Object_GetOptions(child) & AQDG_OBJECT_OPTIONS_FIXEDWIDTH))
      AQDG_Object_SetWidth(child, AQDG_Object_GetDefaultWidth(child));
    child=AQDG_Object_Tree2_GetNext(child);
  }
}



void AQDG_LayoutObject_SetChildrenHeights(AQDG_OBJECT *object)
{
  AQDG_OBJECT *child;

  child=AQDG_Object_Tree2_GetFirstChild(object);
  while(child) {
    if (!(AQDG_Object_GetOptions(child) & AQDG_OBJECT_OPTIONS_FIXEDHEIGHT))
      AQDG_Object_SetHeight(child, AQDG_Object_GetDefaultHeight(child));
    child=AQDG_Object_Tree2_GetNext(child);
  }
}



void _setElementFromObjectX(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, AQDG_OBJECT *object)
{
  uint32_t opts;

  opts=AQDG_Object_GetOptions(object);
  eptr->pos=0;
  eptr->length=AQDG_Object_GetDefaultWidth(object);
  eptr->opts=(opts  & AQDG_OBJECT_OPTIONS_STRETCHX)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH:0;
  eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_HALIGNCENTER)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER:0;
  eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_HALIGNRIGHT)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT:0;
}



void _setElementFromObjectY(AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr, const AQDG_OBJECT *object)
{
  uint32_t opts;

  opts=AQDG_Object_GetOptions(object);
  eptr->pos=0;
  eptr->length=AQDG_Object_GetHeight(object);
  eptr->opts=(opts  & AQDG_OBJECT_OPTIONS_STRETCHY)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_STRETCH:0;
  eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_VALIGNCENTER)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_CENTER:0;
  eptr->opts|=(opts & AQDG_OBJECT_OPTIONS_VALIGNBOTTOM)?AQDG_PLACEMENT_LAYOUT_ELEMENT_OPTS_RIGHT:0;
}



void _setObjectFromElementX(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr)
{
  AQDG_Object_SetRelativeX(object, eptr->pos);
  AQDG_Object_SetWidth(object, eptr->length);
}



void _setObjectFromElementY(AQDG_OBJECT *object, const AQDG_PLACEMENT_LAYOUT_ELEMENT *eptr)
{
  AQDG_Object_SetRelativeY(object, eptr->pos);
  AQDG_Object_SetHeight(object, eptr->length);
}




void AQDG_LayoutObject_LayoutChildren(AQDG_OBJECT *o)
{
  if (o) {
    AQDG_OBJECT *child;

    child=AQDG_Object_Tree2_GetFirstChild(o);
    while(child) {
      AQDG_Object_Layout(child);
      child=AQDG_Object_Tree2_GetNext(child);
    }
  }
}


