/*
 * 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
 */


#include <m_t1.hxx>

void Mallado_T1::build(Mallado_T0* malla) {

  Vertice_T1_dlink* Ls_lk;
  Vertice_T0* som0,*so_0;
  Vertice_T1* som;
  Vertice_T1* s0,*s1,*s2;
  Arista_T1_dlink* La_lk;
  Arista_T0* are0,*ar_0;
  Arista_T1* are;
  Arista_T1* a0,*a1,*a2;
  Triangulo_T1_dlink* Lt_lk;
  Triangulo_T0* tri0, *tr_0;
  Triangulo_T1* tri,*tr;
  Triangulo_T1* t0,*t1,*t2;
  p_Triangle* t_aux;
  p_Sommet* s_aux;
  p_Arete* a_aux;
  int nbs0,nbt0,nba0;
  int i,pos;       
  
  
#ifdef DEBUG
  cout<<"================================================="<<endl;
  cout<<"          BUILDING MESH_T1 FROM MESH_T0"<<endl;
  cout<<"================================================="<<endl;
#endif /* DEBUG */
  Ltriangle=new Triangulo_T1_dlist;
  Larete=new Arista_T1_dlist;
  Lsommet=new Vertice_T1_dlist;
  if(Ltriangle==NIL || Larete==NIL || Lsommet==NIL) ERROR();
  
  nbs0=malla->nbss();  // Numero de vertices del mallado inicial.
  nba0=malla->nbaa();  // Numero de aristas del mallado inicial.
  nbt0=malla->nbtt();  // Numero de triangulos del mallado inicial.

  som0=malla->saca_sommet(0);  //puntero inicial de vertices
  are0=malla->saca_arete(0);   //puntero inicial de aristas
  tri0=malla->saca_triangle(0); //puntero inicial de trianglulos
   
  s_aux=new p_Sommet[nbs0];
  a_aux=new p_Arete[nba0];
  t_aux=new p_Triangle[nbt0];
  if (s_aux==NIL || a_aux==NIL || t_aux==NIL) ERROR();  
  for (i=0; i<nbs0; i++) {
    som=new Vertice_T1;
    if (som==NIL) ERROR();
    s_aux[i]=som;
  }
  for (i=0; i<nba0; i++) {
    are=new Arista_T1;
    if (are==NIL) ERROR();
    a_aux[i]=are;
  }
  for (i=0; i<nbt0; i++) {
    tri=new Triangulo_T1;
    if (tri==NIL) ERROR();
    t_aux[i]=tri;
  }
  for (i=0; i<nbs0; i++) {
    som=s_aux[i];
    so_0=malla->saca_sommet(i);
    pos=so_0->t-tri0;
    tr=t_aux[pos];
    som->set(so_0->c,so_0->ref,so_0->front,tr,so_0->t);
    som->mtr=*malla->saca_metrica(i);
    Ls_lk=new Vertice_T1_dlink;
    if (Ls_lk==NIL) ERROR();             
    Ls_lk->set(som,NIL,NIL);
    Lsommet->append(Ls_lk);
    som->set_lk(Ls_lk);
  }
  for (i=0; i<nba0; i++) {
    are=a_aux[i];
    ar_0=malla->saca_arete(i);
    s0=s_aux[(ar_0->s[0]-som0)];
    s1=s_aux[(ar_0->s[1]-som0)];
    t0=t_aux[(ar_0->tr)-tri0];
    are->set(s0,s1,t0,ar_0->ref,ar_0->front);
    La_lk=new Arista_T1_dlink;
    if (La_lk==NIL) ERROR();
    La_lk->set(are,NIL,NIL);
    Larete->append(La_lk);
    are->set_lk(La_lk);
  }
  for (i=0; i<nbt0; i++) {
    tri=t_aux[i];
    tr_0=malla->saca_triangle(i);
    s0=s_aux[(tr_0->s[0])-som0];
    s1=s_aux[(tr_0->s[1])-som0];
    s2=s_aux[(tr_0->s[2])-som0];

    pos=(tr_0->a[0]-are0);
    a0=a_aux[pos];
    pos=(tr_0->a[1]-are0);
    a1=a_aux[pos];
    pos=(tr_0->a[2]-are0);
    a2=a_aux[pos];

    pos=tr_0->t[0]-tri0;
    t0=NIL;
    if (tr_0->t[0]) t0=t_aux[pos];
    pos=tr_0->t[1]-tri0;
    t1=NIL;
    if (tr_0->t[1]) t1=t_aux[pos];
    pos=tr_0->t[2]-tri0;
    t2=NIL;
    if (tr_0->t[2]) t2=t_aux[pos];

    tri->set(s0,s1,s2,t0,t1,t2,a0,a1,a2,tr_0->ref);
    Lt_lk=new Triangulo_T1_dlink;
    if (Lt_lk==NIL) ERROR();
    Lt_lk->set(tri,NIL,NIL);
    Ltriangle->append(Lt_lk);
    tri->set_lk(Lt_lk);
  }
  delete[] t_aux;
  delete[] a_aux;
  delete[] s_aux;
  scale=malla->factr();
}
int 
Mallado_T1::write(char* name)
{
  Triangulo_T1_dlink* Lt_lk;
  Triangulo_T1* t0;
  Vertice_T1_dlink* Ls_lk;
  Vertice_T1**vert;
  Vertice_T1* so;
  R2 cor;
  int i,j,reft=0;
  int refs=0;
  int paso=0;
  int nbs=Lsommet->num_elem();
  int nbt=Ltriangle->num_elem();

#ifdef DEBUG
  cout<<"======================================="<<endl;
  cout<<"         SAVING TRIANGULATON"<<endl;
  cout<<"======================================="<<endl;
#endif /* DEBUG */
  vert=new Vertice_T1*[nbs];
  if (vert==NIL) ERROR();

  Ls_lk=Lsommet->principio();
  while (Ls_lk) {
    vert[Ls_lk->pos-1]=Ls_lk->s;
    Ls_lk=Ls_lk->sig();
  }
  OPEN(escritura, name);
  
  //  Escritura del N. de vertices y triangulos.
  escritura <<" "<<nbs<<" "<<nbt<<"  -- nbs,nbt"<<endl; 
  
  Lt_lk=Ltriangle->principio();
  while (Lt_lk) {
    t0=Lt_lk->t;
    for (j=0; j<3; j++) {
      escritura <<setw(7)<<t0->s[j]->lk->pos;
    }
    escritura<<"     ";
    if (paso) {
      paso=0; escritura<<endl;}
    else
      paso++;
    Lt_lk=Lt_lk->sig();
  }
  if (paso) escritura<<endl;
  
  paso=0;
  escritura.setf(ios::scientific,ios::floatfield); 
  for (i=0; i<nbs; i++) {
    so=vert[i];
    cor=so->c/scale;
    escritura<<setw(15)<<cor.x<<setw(15)<<cor.y<<"       ";
    if (paso) {
      paso=0; escritura<<endl;}
    else
      paso++;
  }
  if (paso) escritura<<endl;
  
  paso=0;
  Lt_lk=Ltriangle->principio();
  while (Lt_lk) {
    t0=Lt_lk->t;
    reft=t0->ref;
    if (reft<0) reft=-reft;
    if (reft==999) reft=0;
    escritura<<setw(8)<< reft;
    if (paso==9) {
      paso=0; escritura<<endl;}
    else
      paso++;
    Lt_lk=Lt_lk->sig();
  }
  if (paso) escritura<<endl;
  
  paso=0;
  for (i=0; i<nbs; i++) {
    so=vert[i];
    refs=so->ref;
    if (refs<0 && refs!=-999) refs=-refs;
    if (refs==-999 || refs==999) refs=0;
    escritura<<setw(8)<< refs;
    if (paso==9) {
      paso=0; escritura<<endl;}
    else
      paso++;
  }
  if (paso) escritura<<endl;
  
  escritura.close();
  delete[] vert;
  return 0;
}
Triangulation* 
Mallado_T1::write() 
{
  Triangulation* t_fin;
  Triangulo_T1_dlink* Lt_lk;
  Triangulo_T1* t0;
  Vertice_T1_dlink* Ls_lk;
  Vertice_T1**vert;
  Vertice_T1* so;
  R2 cor;
  int i,j,reft=0,refs=0;
  int nbs=Lsommet->num_elem();

#ifdef DEBUG
  cout<<"==============================================================="<<endl;
  cout<<"         COPING MESH_T1 INTO TRIANGULATION STRUCTURE."<<endl;
  cout<<"==============================================================="<<endl;
#endif /* DEBUG */
  vert=new Vertice_T1*[nbs];
  t_fin=new Triangulation;
  if (vert==NIL|| t_fin==NIL) ERROR();
  Ls_lk=Lsommet->principio();
  while (Ls_lk) {
    vert[Ls_lk->pos-1]=Ls_lk->s;
    Ls_lk=Ls_lk->sig();
  }
  /*
   *      Creating t mesh size
   */
  t_fin->set(Lsommet->num_elem(),Ltriangle->num_elem());
  /*
   *      Creating triangles
   */
  Lt_lk=Ltriangle->principio();
  i=0;
  while (Lt_lk) {
    t0=Lt_lk->t;
    for (j=0; j<3; j++) {
      t_fin->tr[i][j]=t0->s[j]->lk->pos-1;
    }
    Lt_lk=Lt_lk->sig();
    i++;
  }
  /*
   *     Creating coordenates of points
   */
  for (i=0; i<t_fin->np; i++) {
    so=vert[i];
    cor=so->c/scale;
    t_fin->rp[i].x=float(cor.x);
    t_fin->rp[i].y=float(cor.y);
  }
  /*
   *    Creating triangle references
   */
  i=0;
  Lt_lk=Ltriangle->principio();
  while (Lt_lk) {
    t0=Lt_lk->t;
    reft=t0->ref;
    if (reft<0) reft=-reft;
    if (reft==999) reft=0;
    t_fin->ngt[i]=reft;
    Lt_lk=Lt_lk->sig();
    i++;
  }
  /*
   *  Creating vertex references
   */
  for (i=0; i<t_fin->np; i++) {
    so=vert[i];
    refs=so->ref;
    if (refs<0 && refs!=-999) refs=-refs;
    if (refs==-999 || refs==999) refs=0;
    t_fin->ng[i]=refs;
  }
  delete[] vert;
  return t_fin;
}
