/*
 * 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 _FronteraT1_h
#define _FronteraT1_h

#include <a_t1.hxx>
#include <at1_l.hxx>
#include <t_t1.hxx>

struct FraristaT1_link {
  
  AristaT1_list* Aretelist;
  FraristaT1_link* suc;
  FraristaT1_link* prev;
  
  FraristaT1_link() {Aretelist=NIL; suc=NIL; prev=NIL;}
  FraristaT1_link(AristaT1_list* Al, FraristaT1_link* ss,\
                  FraristaT1_link* pp)
  {Aretelist=Al; suc=ss; prev=pp;}
  FraristaT1_link(AristaT1_list& Al, FraristaT1_link* ss,\
                  FraristaT1_link* pp)
  {Aretelist=&Al; suc=ss; prev=pp;}
  
  void set(AristaT1_list* Al, FraristaT1_link* ss,\
           FraristaT1_link* pp)
  {Aretelist=Al; suc=ss; prev=pp;}
  void set(AristaT1_list& Al, FraristaT1_link* ss,\
           FraristaT1_link* pp)
  {Aretelist=&Al; suc=ss; prev=pp;}
  FraristaT1_link* sig() {return suc;}
  FraristaT1_link* ant() {return prev;}
  void operator delete (void* p) 
  {
    if (p) {
      AristaT1_list* aux=((FraristaT1_link*)p)->Aretelist;
      if (aux) {delete aux; aux=NIL;}
      delete p;
      p=NIL;
    }
  }   
  int operator<(const FraristaT1_link& a)
  {return ((*Aretelist)<(*(a.Aretelist)));}
  
};

class Frontera_T1 {
  
  FraristaT1_link* last;
  FraristaT1_link* begin;
  
  friend ostream& operator<<(ostream&,Frontera_T1&);
  
public:
//    ***** Constructores ******
  
  Frontera_T1 () {last=NIL; begin=NIL;}
  Frontera_T1 (FraristaT1_link* f) {last=begin=f;}
  
//   ******     Creacion de la lista *****
  
  void insert (FraristaT1_link* f) { //add at head of list
    if (begin) {
      begin->prev=f;
      f->suc=begin;
      begin=f;
    }
    else  {
      last=f;
      begin=f;
    }
  }
  void append (FraristaT1_link* f) {  //add at end of list
    if (last)  {
      last->suc=f;
      f->prev=last;
      last=f;
    }
    else {
      last=f;
      begin=f;
    }
  }
  void enlaza(FraristaT1_link* f1, FraristaT1_link* f2,int od)
  {
    /* une f1->Aretelist+f2->Aretelist si od=1.
       Si od=-1 enlaza f2->Aretelist+f1->Aretelist.
       despues debes destruir f2.
       */
    // ***** En laza las dos listas  *****
    AristaT1_list* aux;
    if (od==1) 
      (f1->Aretelist)->enlaza(f2->Aretelist);
    else { 
      aux=f1->Aretelist;
      (f2->Aretelist)->enlaza(f1->Aretelist);
      f1->Aretelist=f2->Aretelist;
      f2->Aretelist=aux;
    }
    if (f2==begin) {
      begin=f2->suc;
      begin->prev=NIL;
    }
    else {
      if (f2==last) {
        last=f2->prev;
        last->suc=NIL;
      }
      else {
        (f2->prev)->suc=f2->suc;
        (f2->suc)->prev=f2->prev;
      }
    }
  }
  
  
  void testeo(); 
  
//  ***** Dan los parametros de la lista  ****
  
  FraristaT1_link* principio() {return begin;}
  FraristaT1_link* fin () {return last;}
  int num_elem() {
    int num=0;
    FraristaT1_link* aux=begin;
    while (aux) {
      num++;
      aux=aux->suc;
    }
    return num;
  }
  
  Scalar d_frontera(R2,R2&,Arista_T1&,Triangulo_T1&,\
                    const Scalar&,int);
  
// ******    Destructores    ******
  
  void clear () {
    FraristaT1_link* aux;
    while(begin) {
      aux=begin->suc;
      delete begin;
      begin=aux;
    }
    last=begin=NIL;
  }
  
  void operator delete (void* p)
  {  
    if (p) {
      ((Frontera_T1*)p)->clear();
      delete p;p=NIL;
    }
  }  
  void write(ostream&);
};


#endif
