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

#include <a_t0.hxx>
#include <at0_l.hxx>
#include <t_t0.hxx>

struct FraristaT0_link {

     AristaT0_list* Aretelist;
     FraristaT0_link* suc;
     FraristaT0_link* prev;

     FraristaT0_link() {Aretelist=NIL; suc=NIL; prev=NIL;}
     FraristaT0_link(AristaT0_list* Al, FraristaT0_link* ss,\
                      FraristaT0_link* pp)
                 {Aretelist=Al; suc=ss; prev=pp;}
     FraristaT0_link(AristaT0_list& Al, FraristaT0_link* ss,\
                      FraristaT0_link* pp)
                 {Aretelist=&Al; suc=ss; prev=pp;}

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

};

class Frontera_T0 {

     FraristaT0_link* last;
     FraristaT0_link* begin;

     friend ostream& operator<<(ostream&,Frontera_T0&);

public:
//    ***** Constructores ******

     Frontera_T0 () {last=NIL; begin=NIL;}
     Frontera_T0 (FraristaT0_link* f) {last=begin=f;}

//   ******     Creacion de la lista *****

     void insert (FraristaT0_link* f) { //add at head of list
           if (begin) {
                 begin->prev=f;
                 f->suc=begin;
                 begin=f;
           }
           else  {
                last=f;
                begin=f;
           }
      }
      void append (FraristaT0_link* f) {  //add at end of list
           if (last)  {
               last->suc=f;
               f->prev=last;
               last=f;
           }
           else {
               last=f;
               begin=f;
           }
      }
      void enlaza(FraristaT0_link* f1, FraristaT0_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  *****
          AristaT0_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  ****

      FraristaT0_link* principio() {return begin;}
      FraristaT0_link* fin () {return last;}
      int num_elem() {
           int num=0;
           FraristaT0_link* aux=begin;
              while (aux) {
                 num++;
                 aux=aux->suc;
              }
            return num;
         }
      
    Scalar d_frontera(R2,R2&,Arista_T0&,Triangulo_T0&,\
               const Scalar&);

// ******    Destructores    ******

      void clear () {
             FraristaT0_link* aux;
             while(begin) {
               aux=begin->suc;
               delete begin;
               begin=aux;
             }
             last=begin=NIL;
         }

    void operator delete (void* p)
      {  
        if (p) {
          ((Frontera_T0*)p)->clear();
          delete p;p=NIL;
        }
      }  
    void write(ostream&);
};


#endif
