//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2016 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
//

#include <iostream>
#include <cstdio>
#include <cmath>

#include <Function.hpp>
#include <Contour.hpp>
#include <Information.hpp>

#include "DynamXProcessUniformGrowth.hpp"

namespace mgx
{
  // Initialize 
  bool UniformGrowth::initialize(QStringList &parms, QWidget * /*parent*/)
  {
    // If there is parent, then we are in gui mode
    //if(parent) ;

    // Set the static class variables each time
    mesh = currentMesh();
    T = &mesh->tissue();

    // Read the parms from the GUI
    processParms(parms);

    return true;
  } 

  // For now do nothing, maybe create an initial cell?
  bool UniformGrowth::rewind(QStringList &parms, QWidget *parent)
  {
    return true;
  } 

  // Process model parameters
  void UniformGrowth::processParms(const QStringList &parms)
  {
		// Get model parms
    dt = parms[pDt].toDouble();
    drawSteps = parms[pDrawSteps].toInt();
    growthRate.x() = parms[pXGrowth].toDouble();
    growthRate.y() = parms[pYGrowth].toDouble();
    growthRate.z() = parms[pZGrowth].toDouble();
    QString tissueParmsProc = parms[pTissueParmsProc];

    QStringList tissueParms;
    if(!getLastParms(tissueParmsProc, tissueParms))
      throw(QString("Cannot get tissue parameters"));
    T->processParms(tissueParms);
  }

  // Main model step
	bool UniformGrowth::step(const QStringList &parms)
  {    
    for(int i = 0; i < drawSteps; i++) {
      // Advance time
      time() += dt;
  
      // Grow the cells, avoid the centers
      forall(vertex v, T->S) {
        v->pos.x() *= 1.0 + growthRate.x() * dt;
        v->pos.y() *= 1.0 + growthRate.y() * dt;
        v->pos.z() *= 1.0 + growthRate.z() * dt;
      }

      // Update normals, area, centers, and length of cell walls
      if(T->meshType() == "MGX2D")
        T->updGeometry(); 
    }
		
		// Update mesh points, edges, surfaces
    mesh->updateAll();   
    return true;
  }

  bool UniformInitialCell::run(Mesh* mesh, double size, int walls) 
  {
    if(size <= 0)
      throw(QString("Size must be > 0"));
    if(walls < 3)
      throw(QString("There must be at least 3 walls"));

    CellTissue &T = mesh->tissue();
    mesh->reset();
    T.setMeshType("MGX2D");

    std::vector<vertex> poly;
    // Center
    vertex c; 
    c->type = 'c';
    c->pos = Point3d(0,0,0);
    c->nrml = Point3d(0,0,1);
    poly.push_back(c);

    // Cell junctions
    for(int i = 0; i < walls; i++) {
      vertex v; 
      double s = (double)i/(double)walls * M_PI * 2;
      v->type = 'j';
      v->pos = Point3d(size * sin(s), size * cos(s), 0);
      v->nrml = Point3d(0,0,1);
      poly.push_back(v);
    }
    T.addCell(poly);
    T.updGeometry();
    mesh->updateAll();

    return true;
  }
}
