/****************************************************************************/
/* This file is part of FreeFEM.                                            */
/*                                                                          */
/* FreeFEM is free software: you can redistribute it and/or modify          */
/* it under the terms of the GNU Lesser General Public License as           */
/* published by the Free Software Foundation, either version 3 of           */
/* the License, or (at your option) any later version.                      */
/*                                                                          */
/* FreeFEM is distributed in the hope that it will be useful,               */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/* GNU Lesser General Public License for more details.                      */
/*                                                                          */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with FreeFEM. If not, see <http://www.gnu.org/licenses/>.          */
/****************************************************************************/
/* SUMMARY : ...                                                            */
/* LICENSE : LGPLv3                                                         */
/* ORG     : LJLL Universite Pierre et Marie Curie, Paris, FRANCE           */
/* AUTHORS : Pascal Frey                                                    */
/* E-MAIL  : pascal.frey@sorbonne-universite.fr                             */

#ifdef __cplusplus
extern "C" {
#endif

#include "medit.h"
#include "extern.h"
#include "sproto.h"

extern void resetLists(pScene, pMesh);
static int getmesh(pMesh mesh, int range) {
  int ret;
  static char base[256];

  /* allocate mesh structure */
  if (ddebug) fprintf(stdout, "getmesh: create mesh %d\n", range);

  if (mesh->tria) M_free(mesh->tria);
  if (mesh->quad) M_free(mesh->quad);
  if (mesh->edge) M_free(mesh->edge);
  if (mesh->tetra) M_free(mesh->tetra);
  if (mesh->hexa) M_free(mesh->hexa);
  if (mesh->adja) M_free(mesh->adja);
  if (mesh->voy) M_free(mesh->voy);
  if (mesh->point) M_free(mesh->point);

  if (mesh->extra) {
    if (mesh->extra->iv) M_free(mesh->extra->nv);
    if (mesh->extra->it) M_free(mesh->extra->nt);
    if (mesh->extra->iq) M_free(mesh->extra->nq);
    if (mesh->extra->n) M_free(mesh->extra->n);
    M_free(mesh->extra);
    mesh->extra = (void *)0;
  }

  if (mesh->sol && mesh->nbb) {
    if ((mesh->dim == 2 && mesh->nfield == 3) || (mesh->dim == 3 && mesh->nfield == 6)) {
      int k;
      for (k = 1; k <= mesh->nbb; k++) free(mesh->sol[k].m);
    }

    M_free(mesh->sol);
    mesh->sol = (void *)0;
  }

  mesh->point = (void *)0;
  mesh->tria = (void *)0;
  mesh->quad = (void *)0;
  mesh->edge = (void *)0;
  mesh->tetra = (void *)0;
  mesh->hexa = (void *)0;
  mesh->adja = (void *)0;
  mesh->voy = (void *)0;
  mesh->np = mesh->nt = mesh->nq = mesh->ne = 0;
  mesh->ntet = mesh->nhex = mesh->nbb = 0;

  if (animdep == range) strcpy(base, mesh->name);

  /* adjust file name */
  sprintf(mesh->name, "%s.%d", base, range);
  if (ddebug) fprintf(stdout, "load %s\n", mesh->name);

  /* read mesh */
  if (quiet) {
    fprintf(stdout, "  Loading %s     \r", mesh->name);
    fflush(stdout);
  }

  mesh->typ = 0;
  ret = loadMesh(mesh);
  if (ret < 1) {
    mesh->typ = 1;
    ret = inmsh2(mesh);
    if (!ret) {
      mesh->typ = 2;
      ret = loadGIS(mesh);
      if (!ret) return (0);
    }
  }

  if ((mesh->ntet && !mesh->nt) || (mesh->nhex && !mesh->nq)) meshSurf(mesh);

  meshBox(mesh, animdep == range);
  if (!quiet) meshInfo(mesh);

  /* read metric */
  if (!loadSol(mesh, mesh->name, 1)) bbfile(mesh);

  if (!quiet && mesh->nbb) fprintf(stdout, "    Solutions  %8d\n", mesh->nbb);

  return (1);
}

int loadNextMesh(pMesh mesh, int k, int parse) {
  pScene sc;
  int is;

  if (!getmesh(mesh, k)) return (0);

  if (ddebug) printf("loadNextMesh: create %d window(s)\n", cv.nbs);

  /* compute mesh box */
  is = currentScene( );
  if (!cv.scene[is]) {
    cv.scene[is] = (pScene)M_calloc(1, sizeof(Scene), "loadNextMesh.scene");
    if (!cv.scene[is]) return (0);
  }

  sc = cv.scene[is];
  if (parse) parsop(sc, mesh);

  setupPalette(sc, mesh);
  meshRef(sc, mesh);
  matSort(sc);

  return (1);
}

int playAnim(pScene sc, pMesh mesh, int deb, int fin) {
  int k;
  char *ptr, data[512], base[256];

  /* get basename */
  sprintf(data, ".%d", deb);
  ptr = (char *)strstr(mesh->name, data);
  if (ptr) *ptr = '\0';

  strcpy(base, mesh->name);

  if (saveimg) glDrawBuffer(GL_BACK_LEFT);

  /* start animation */
  for (k = deb; k <= fin; k++) {
    strcpy(mesh->name, base);

    resetLists(sc, mesh);
    if (!loadNextMesh(mesh, k, 0)) return (0);

    doLists(sc, mesh);
    sc->glist = geomList(sc, mesh);
    if (sc->mode & S_MAP) doMapLists(sc, mesh, 1);

    if (sc->isotyp) doIsoLists(sc, mesh, 1);

    if (!saveimg) {
      snprintf(data, 512, "Medit - [%s] #%d", mesh->name, sc->idwin);
      glutSetWindowTitle(data);
    }

    glClearColor(sc->par.back[0], sc->par.back[1], sc->par.back[2], sc->par.back[3]);
    if (sc->type & S_SCISSOR)
      scissorScene( );
    else
      redrawScene( );
  }

  fprintf(stdout, "\n  Done.\n");
  strcpy(mesh->name, base);

  if (saveimg) {
    glDrawBuffer(GL_FRONT | GL_BACK);
    if (saveimg) {
      snprintf(data, 512, "Medit - [%s] #%d", mesh->name, sc->idwin);
      glutSetWindowTitle(data);
    }

    glutPostRedisplay( );
    saveimg = 0;
  }

  return (1);
}

int animParticle(pScene sc, pMesh mesh) {
  int cur;
  char *ptr, data[256], base[256];

  /* get basename */
  strcpy(base, mesh->name);
  ptr = (char *)strstr(base, ".");
  sscanf(ptr, ".%d", &cur);
  cur++;
  if (cur > animfin) return (0);

  if (ptr) ptr[0] = '\0';

  sprintf(data, "%s.%.3d", base, cur);
  strcpy(mesh->name, base);

  resetLists(sc, mesh);
  if (!loadNextMesh(mesh, cur, 1)) return (0);

  doLists(sc, mesh);
  sc->glist = geomList(sc, mesh);
  if (sc->mode & S_MAP) doMapLists(sc, mesh, 1);

  if (sc->isotyp) doIsoLists(sc, mesh, 2);

  if (!advectParticle(sc, mesh)) return (0);

  return (1);
}

int animat( ) {
  pMesh mesh;
  pScene sc;

  /* default */
  if (ddebug) printf("animat: read file(s)\n");

  /* enter basename */
  if (!cv.nbm) {
    char data[128], *name, *res;
    int ret;

    fprintf(stdout, "  File name(s) missing. Please enter : ");
    fflush(stdout);
    while (fgetc(stdin) != EOF)
      ;    // fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux
           // systems
    res = fgets(data, 120, stdin);
    if (!strlen(data) || res == NULL) {
      fprintf(stdout, "  ## Error\n");
      return (0);
    }

    fprintf(stdout, "  Enter range [start,end] :");
    fflush(stdout);
    while (fgetc(stdin) != EOF)
      ;    // fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux
           // systems
    ret = fscanf(stdin, "%d %d", &animdep, &animfin);
    if (ret == EOF) {
      fprintf(stdout, "  ## Error\n");
      return (0);
    }

    /* parse file name(s) */
    name = strtok(data, " \n");

    while (name) {
      if (!cv.mesh[cv.nbm]) {
        cv.mesh[cv.nbm] = (pMesh)M_calloc(1, sizeof(Mesh), "animat.mesh");
        if (!cv.mesh[cv.nbm]) return (0);
      }

      /*(cv.mesh[cv.nbm])->name = calloc(strlen(name)+15,sizeof(char));*/
      strcpy(cv.mesh[cv.nbm]->name, name);
      break;
    }

    if (!cv.nbm) return (0);
  }

  cv.nbs = cv.nbm;

  /* read initial mesh */
  mesh = cv.mesh[0];
  if (!loadNextMesh(mesh, animdep, 1)) return (0);

  /* create grafix */
  sc = cv.scene[0];
  if (!createScene(sc, 0)) {
    fprintf(stderr, "  ## Unable to create scene\n");
    return (0);
  }

  quiet = 1;
  return (1);
}

#ifdef __cplusplus
}
#endif
