/* stateNode.c */

#include "stateNode.h"
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stddef.h>


/*
 * Kreiere ein Objekt vom Typ StateNode auf dem Heap mit Namen name (ebenfalls
 * auf dem Heap), anfaenglich ohne Verknuepfung zu andern Knoten (= kein Array).
 * Rueckgabewert NULL, false Objekt nicht vollstaendig kreiert werden konnte.
 */
StateNode *createStateNode(char *name) {
  StateNode *sn = (StateNode *)malloc(sizeof(StateNode));
  if (sn == NULL) {
    return NULL;
  }
  sn->name = (char *)malloc((strlen(name) + 1) * sizeof(char));
  if (sn->name == NULL) {
    free(sn);
    return NULL;
  }
  strcpy(sn->name, name);
  sn->stateNodes = NULL;
  sn->numStateNodes = 0;
  return sn;
}



/*
 * Stelle Namen des StateNode sn am stdout dar. Fuer NULL stelle
 * nichts dar.
 */
void printStateNodeName(StateNode *sn) {
  if (sn) {
    printf("StateNode: %s\n", sn->name);
  }
}



/*
 * Stelle textliche Repraesentation des StateNode sn am stdout dar.
 * Fuer NULL stelle nichts dar.
 */
void printStateNode(StateNode *sn) {
  StateNode **snp;
  int n = sn->numStateNodes;

  if (!sn) {
    return;
  }

  printStateNodeName(sn);
  printf("  connected to:\n");

  if (!n) {
    printf("    no StateNode\n");
    return;
  }

  snp = sn->stateNodes;
  while (n) {
    printf("    %s\n", (*snp)->name);
    snp++;
    n--;
  }
}



/*
 * Teste, ob der StateNode source bereits mit dem StateNode dest ver-
 * bunden ist.
 * Rueckgabewert TRUE, falls ja, sonst FALSE.
 */
boolean isStateNodeConnected(StateNode *dest, StateNode *source) {
  StateNode **snp;
  int n = source->numStateNodes;

  if (dest == NULL || source == NULL) {
    return FALSE;
  }

  if (source->stateNodes == NULL) {
    return FALSE;
  }
  else {
    snp = source->stateNodes;
    while (n--) {
      if (*snp == dest) {
        return TRUE;
      }
      snp++;
    }
    return FALSE;
  }
}



/*
 * Verknuepfe den StateNode source mit dem StateNode dest, falls nicht
 * bereits frueher geschehen.
 * Alloziere noetigen Speicherplatz auf dem Heap.
 * Rueckgabewert FALSE, falls kein Memory (re)alloziert werden konnte
 * oder NULL-Pointer uebergeben wurden, sonst TRUE.
 */
boolean connectStateNode(StateNode *dest, StateNode *source) {
  StateNode **snp;

  if (isStateNodeConnected(dest, source)) {
    return FALSE;
  }

  if (source->stateNodes == NULL) {
    snp = (StateNode **)malloc(sizeof(StateNode *));
    if (snp == NULL) {
      return FALSE;
    }
    *snp = dest;
  }
  else {
    snp =
      (StateNode **)realloc(source->stateNodes, sizeof(StateNode *) * (source->numStateNodes + 1));
    if (snp == NULL) {
      return FALSE;
    }
    *(snp + source->numStateNodes) = dest;
  }
  source->stateNodes = snp;
  source->numStateNodes++;
  return TRUE;
}



/*
 * Hebe die Verknuepfung vom StateNode source zum StateNode dest auf.
 * Gib unbenoetigte Memoryplaetze auf dem Heap frei.
 * Rueckgabewert FALSE, falls Enfernen der Knotenverbindung nicht erfolgreich war.
 */
boolean disconnectStateNode(StateNode *dest, StateNode *source) {
  StateNode **snp;
  int n;

  if (!isStateNodeConnected(dest, source)) {
    return FALSE;
  }

  // Spezialbehandlung, falls nur 1 Verbindung existiert:
  if (source->numStateNodes == 1) {
    free(source->stateNodes);
    source->stateNodes = NULL;
    source->numStateNodes = 0;
    return TRUE;
  }

  // Mehrere Verbindungen existieren:
  snp = source->stateNodes;
  n = source->numStateNodes;
  while (n) {
    if (*snp == dest) {
      break;
    }
    else {
      snp++;
      n--;
    }
  }
  // Gefunden, verschiebe Pointer um eine Position Richtung Anfang:
  while (n--) {
    *snp = *(snp + 1);
    snp++;
  }
  // Verkleinere Array um eine Position:
  snp =
    (StateNode **)realloc(source->stateNodes, sizeof(StateNode *) * (source->numStateNodes - 1));
//  if (snp == NULL) {      // Verkleinern immer moeglich
//    return FALSE;
//  }
  source->stateNodes = snp;
  source->numStateNodes--;
  return TRUE;
}



/*
 * Dealloziere StateNode sn vom Heap.
 */
void deleteStateNode(StateNode *sn) {
  if (sn) {
    free(sn->name);
    free(sn->stateNodes);
    free(sn);
  }
}
