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

#include <a_cad.hxx>

class Arista_CAD_dlist;

struct Arista_CAD_dlink {
  Arista_CAD* a;
  Arista_CAD_dlink* suc;
  Arista_CAD_dlink* prev;
  Arista_CAD_dlist* dlist;
  
  Arista_CAD_dlink () {a=NIL; suc=NIL; prev=NIL; dlist=NIL;}
  Arista_CAD_dlink (Arista_CAD& ar, Arista_CAD_dlink* ss,\
                    Arista_CAD_dlink* pp)
  {a=&ar;suc=ss;prev=pp; dlist=NIL;}
  Arista_CAD_dlink (Arista_CAD* ar, Arista_CAD_dlink* ss,\
                    Arista_CAD_dlink* pp) {
    a=ar; suc=ss; prev=pp; dlist=NIL;} 
  
  void set (Arista_CAD& ar, Arista_CAD_dlink* ss, Arista_CAD_dlink* pp)
  {a=&ar; suc=ss;prev=pp;}
  void set (Arista_CAD* ar, Arista_CAD_dlink* ss, Arista_CAD_dlink* pp) {
    a=ar; suc=ss; prev=pp;} 
  
  Arista_CAD_dlink* sig() {return suc;}
  Arista_CAD_dlink* ant() {return prev;}
  void operator delete (void* p) {
    Arista_CAD* aux;
    if (p) {
      aux=((Arista_CAD_dlink*)p)->a;
      if (aux) {delete aux; aux=NIL;}
      delete p;
      p=NIL;
    }
  }
  int operator<(Arista_CAD_dlink& aa)
  {return ((*a)<(*(aa.a)));}
};

class Arista_CAD_dlist {
public:
  Arista_CAD_dlink* last;
  Arista_CAD_dlink* begin;
  friend ostream& operator<<(ostream&, Arista_CAD_dlist&);
  Arista_CAD_dlist () {last=NIL; begin=NIL;}
  Arista_CAD_dlist (Arista_CAD_dlink* r) {last=begin=r;}
  void insert (Arista_CAD_dlink* r) {//pega en cabeza de dlist
    if (r) {
      if (begin) {
        r->suc=begin;
        begin->prev=r;
        begin=r;
        
      }
      else {
        last=r;
        begin=r;
      }
    }
  }
  void append(Arista_CAD_dlink* r) {//pega al final de dlist
    if (r) {
      if (last) {
        last->suc=r;
        r->prev=last;
        last=r;
      }
      else {
        last=r;
        begin=r;
      }
    }
  }
  void  enlaza (Arista_CAD_dlist* rll) {  //une this+rll
    if (rll) {
      if (begin) {
        if (rll->begin) {
          last->suc=rll->begin;
          (rll->begin)->prev=last;
          last=rll->last;
          rll->begin=NIL;
          rll->last=NIL;
        }
      }
      else {
        begin=rll->begin;
        last=rll->last;
        rll->begin=NIL;
        rll->last=NIL;
      }
    }
  }
  void  enlaza (Arista_CAD_dlist& rll) {  //une this+rll
    if (begin) {
      if (rll.begin) {
        last->suc=rll.begin;
        (rll.begin)->prev=last;
        last=rll.last;
        rll.begin=NIL;
        rll.last=NIL;
      }
    }
    else {
      begin=rll.begin;
      last=rll.last;
      rll.begin=NIL;
      rll.last=NIL;
    }
    
  }
  void kill (Arista_CAD_dlink* r) { //elimina un elmento de la dlista
    if (r) {
      if (r==begin) {
        begin=r->suc;
        if (begin) begin->prev=NIL;
      }
      else {
        if (r==last) {
          last=r->prev;
          if (last) last->suc=NIL;
        }
        else {
          if (r->prev) (r->prev)->suc=r->suc;
          if (r->suc) (r->suc)->prev=r->prev;
        }
      }
      delete r;
    }
    r=NIL;
  }
  int operator<(Arista_CAD_dlist& a)
  {return ((*last)<(*(a.begin)));}
  Arista_CAD_dlink* principio () {return begin;}
  Arista_CAD_dlink* fin () {return last;}
  int num_elem () {
    int num=0;
    Arista_CAD_dlink* aux=begin;
    while (aux) {
      num++;
      aux=aux->suc;
    }
    return num;
  } 
  void lazos_lk () {
    Arista_CAD_dlink* aux=begin;
    while (aux) {
      aux->dlist=this;
      aux=aux->suc;
    }
  }
  void clear () {
    Arista_CAD_dlink* aux;
    while (begin) {
      aux=begin->suc;
      delete begin;
      begin=aux;
    }
    last=begin=NIL;
  }                             
  void operator delete (void* p){
    if (p) {
      ((Arista_CAD_dlist*)p)->clear();
      delete p; p=NIL;
    }
  }
  void write (ostream&);
  
};
#endif       
