/*
 * ADAPT2D : a software for automatic mesh adaptation in 2D
 *
 * AUTHOR : Manuel J. Castro Diaz(e-mail:castro@gamba.cie.uma.es)
 * ADAPTED FOR FREEFEM : Prud'homme Christophe (e-mail:prudhomm@ann.jussieu.fr)
 *
 * this code is public domain
 * 
 * You may copy freely these files and use it for    
 * teaching or research. These or part of these may   
 * not be sold or used for a commercial purpose without
 * our consent
 * 
 * Any problems should be reported to the AUTHOR
 * at the following address : castro@gamba.cie.uma.es
 */



#ifndef _malladoT0_h
#define _malladoT0_h


#include <header.hxx>
#include <t_t0.hxx>
#include <t_t0_dl.hxx>
#include <v_t0.hxx>
#include <a_t0.hxx>
#include <r2.hxx> 
#include <metric.hxx>
#include <front_t0.hxx>
#include <at0_l.hxx>
#include <integ.hxx>
#include <triangl.hxx>
   
extern int carete(int*,int,int,int*,int&,int&,int*);
extern void orienta2D(int*,R2*,int);
extern int indet (R2,int,int,R2,int,int);
                
class Mallado_T0 {
  friend ostream& operator<<(ostream&, Mallado_T0&);
  
  int nbsx,nbtx,nbax;
  int nbs,nbt,nba;
  Scalar factor;
  
  Vertice_T0*   s; // Puntero al primer vertice del tablero.
  Triangulo_T0* t; // Puntero al primer triangulo del tablero.
  Arista_T0*    a; // Puntero a la primera arista del tablero.
  
  
  Frontera_T0* frontera;  // Aristas que constituyen la
  //   frontera.
  Scalar paso_malla;
  long int   clave;      // clave para determinar en la sub localiza
  // si por ese triangulo he pasado ya o no.
public:
  Metrica*            m;  // Puntero a la primera metrica del tablero.
  Mallado_T0 (): nbsx(7000), nbtx(14000), nbax(21000), nbs(0), nbt(0),\
  nba(0),factor(0),clave(0) {s=NIL; t=NIL; a=NIL;m=NIL;
  frontera=NIL; paso_malla=0;}
  Mallado_T0 (int nnbs, int nnbt, int nnba): nbsx(7000), nbtx(14000),\
  nbax(21000),nbs(nnbs), nbt(nnbt),nba(nnba)
  { 
    s=new Vertice_T0[nbs];
    t=new Triangulo_T0[nbt];
    a=new Arista_T0[nba];
    m=new Metrica[nbs];
    if (s==NIL || t==NIL || a==NIL || m==NIL) ERROR();
    paso_malla=0;
    clave=0;
    factor=0;
    frontera=NIL;
  }
  
  // ADD THESE THREE ROUTINES
  Mallado_T0 (const int&, const int&, R2 *, int *, int *, int *, Metrica*, Scalar&, Scalar&);
  // nbs,nbt,cr,refs,nu,refe
  void build (const int&, const int&, R2 *, int *, int *, int *, Metrica*, Scalar&, Scalar&);
  // nbs,nbt,cr,refs,nu,refe
   void build (const int&, const int&, rpoint *, int *, triangle *, int *);
  // np,nt,rp,refs,tr,refe 
   void build (const int&, const int&, rpoint *, int *, triangle *, int *,Scalar);
  // np,nt,rp,refs,tr,refe,escale  
  void write (ostream&);
  void write (char*);
  void set (int nnbs, int nnbt, int nnba)  {
    this->clear();
    nbs=nnbs; nbt=nnbt; nba=nnba;
    if (nbs>nbsx || nbt>nbtx || nba>nbax) {
      cout <<"ATENCION, MALLADO DEMASIADO GRANDE."<<endl;}
    a=new Arista_T0[nba];
    s=new Vertice_T0[nbs];
    t=new Triangulo_T0[nbt];
    m=new Metrica[nbs];
    if (a==NIL || s==NIL || t==NIL || m==NIL) ERROR();
    paso_malla=0;
    clave=0;
    frontera=NIL;
  }  
  void write_all();
  Scalar factr() const {return factor;}
  int nbss() const { return nbs;}
  int nbtt() const { return nbt;}
  int nbaa() const { return nba;}
  Vertice_T0* sommet()  {return &s[0];}
  Arista_T0* arete()  {return &a[0];}
  Triangulo_T0*  Triangle()  {return &t[0];}
  Metrica* metrica() {return &m[0];}
  Frontera_T0* front() {return frontera;}
  Scalar   eps_malla() {return paso_malla;}
  void set_nba (int nn) {
    if (nba!=0) {
      if (nn>nba ) {
        cerr<<"Error. Tablero de aristas mas grande de lo esperado."
            <<endl<<"Cambiar NBTROUX en header por un numero mayor."
            <<endl;
        exit(1);
      }
      else {nba=nn;}
    }
  }
  void add_sommet(Vertice_T0& ss,int pos)
  { s[pos].set(ss);}
  void add_arete(Arista_T0& aa, int pos)
  { a[pos].set(aa);}
  void add_triangle(Triangulo_T0& tt, int pos)
  { t[pos].set(tt);}
  void add_metrica(Metrica& mm,int pos)
  { m[pos]=mm;}
  Vertice_T0* saca_sommet(int pos)
  { if (pos<nbs)
    return &s[pos];
  else return NIL; }
  Arista_T0*  saca_arete(int pos)
  { if (pos<nba) 
    return &a[pos];
  else return NIL;}
  Triangulo_T0* saca_triangle (int pos)
  { if (pos<nbt)
    return &t[pos];
  else return NIL;}
  Metrica* saca_metrica (int pos)
  { if (pos<nbs)
    return &m[pos];
  else return NIL;}
  
  void crea_eps_malla (); 
  void crea_frontera();
  void set_factor(Scalar fact) {factor=fact;}
  Triangulo_T0* localiza (R2, R2&, Triangulo_T0*,\
                          const Scalar&);
  Metrica  metrica(R2,int,int&);
  void interpola_sol(R2,Triangulo_T0*,Scalar*,Scalar*,\
                     int,int);
  int calculo_factor();
  Boolean cambio_factor(int,int);
  int nbt_appx();
  void p_fijos (int);
  void clear () {
    if (nbs) {
      if (frontera) delete frontera;
      if (m) delete[] m;
      if (t) delete[] t;
      if (s) delete[] s;
      if (a) delete[] a;
    }
    frontera=NIL;m=NIL;t=NIL;s=NIL;a=NIL;
    nbs=nba=nbt=0;
    clave=0;
    paso_malla=0;
  }
  ~Mallado_T0() {this->clear();}
  void operator delete (void* p) {
    if (p) {
      ((Mallado_T0*)p)->clear();
      delete p; p=NIL;
    }
  } 
};


#endif

