/****************************************************************************
* VCGLib                                                            o o     *
* Visual and Computer Graphics Library                            o     o   *
*                                                                _   O  _   *
* Copyright(C) 2004                                                \/)\/    *
* Visual Computing Lab                                            /\/|      *
* ISTI - Italian National Research Council                           |      *
*                                                                    \      *
* All rights reserved.                                                      *
*                                                                           *
* This program is free software; you can redistribute it and/or modify      *
* it under the terms of the GNU General Public License as published by      *
* the Free Software Foundation; either version 2 of the License, or         *
* (at your option) any later version.                                       *
*                                                                           *
* This program is distributed in the hope that it will be useful,           *
* but WITHOUT ANY WARRANTY; without even the implied warranty of            *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
* for more details.                                                         *
*                                                                           *
****************************************************************************/

#ifndef BRIDGE_H
#define BRIDGE_H

#include <qstring.h>
#include <utility>
#include <vcg/simplex/face/topology.h>
#include "vcg/space/line2.h"
#include "vcg/space/triangle3.h"
#include "fgtHole.h"
#include "holeSetManager.h"
#include <ctime>

template <class MESH> class FgtHole;
template <class MESH> class HoleSetManager;

/* Struct rappresenting the mesh edge where the bridge starts/ends. */
template <class MESH>
struct BridgeAbutment
{
public:
    BridgeAbutment() { f=0; z=0; h=0; };

    BridgeAbutment(typename MESH::FacePointer pface, int edgeIndex, FgtHole<MESH>* phole)
    {
        f = pface;
        z = edgeIndex;
        h = phole;
    };

    inline void SetNull() { f=0; };
    inline bool IsNull() const { return f==0; };

    typename MESH::FacePointer f;
    int z;
    FgtHole<MESH>* h;
};

/*  Class rappresenting callback for feedback while auto bridging is running.
 *  It's necessary because auto bridging can spent a lot of time computing
 *  and user must know it is working.
 */
class AutoBridgingCallback
{
public:
    inline int GetOffset() const { return offset; };
    virtual void Invoke(int) = 0;

protected:
    int offset; // minor time before 2 calling (in ms)
};

template <class MESH>
class FgtBridgeBase
{
public:
    typedef typename MESH::FaceType							FaceType;
    typedef typename MESH::FacePointer					FacePointer;
    typedef typename vcg::face::Pos<FaceType>		PosType;

public:
    virtual ~FgtBridgeBase() = default;
    virtual PosType GetAbutmentA() const =0;
    virtual PosType GetAbutmentB() const =0;

    virtual void ResetFlag() = 0;
    virtual void DeleteFromMesh() = 0;
    virtual inline void AddFaceReference(std::vector<FacePointer*> & /* facesReferences */) {};

    virtual inline bool IsNull() const = 0;
    virtual inline bool IsDeleted() const = 0;

protected:
    HoleSetManager<MESH>* parentManager;
};


/** Bridge between different FgtHoles or into the same one.
 *  Bridges represent connection between two border edges of different faces.
 *  Connection consists in 2 face adjacent each other over an edge and adjacent
 *  with a mesh face over another edge, so both faces have a border edge.
 *
 *  Bridge can connect 2 edge belong the same hole, result are 2 new holes.
 *  In this case bridge could be adjacent to mesh if edge are next, so this
 *  bridge could not been build.
 *
 *  Bridge can also connect 2 or more different holes in only one hole.
 *
 *                   \ / B \ /                  \ / B \ /
 *             +------+-----+------+      +------+-----+------+
 *             |                   |			|      |\ f1 |      |
 *             |                   |			|      | \   |      |
 *             |       hole        |      | hole |  \  | hole |
 *             |                   |      |      |   \ |      |
 *             |                   |      |      | f0 \|      |
 *             +------+-----+------+      +------+-----+------+
 *                   / \ A / \                  / \ A / \
 *                                             GOOD BRIDGE
 *                             f0 and f1 are adjacent only with one mesh face
 *
 *   \ / B \ /       \ / B \ /           |
 *    +-----+---      +-----+---         |    ---+------+------      ---+------+--------
 *   /|              /| f1 /|            |	      \ A  /                 \ A  /|\
 *  / |             / |   / |            |         \  /                   \  / | \
 *  C |  hole       C |  /  | hole       |     hole \/    hole     hole    \/  |  \  hole
 *  \ |             \ | /   |            |          /\                     /\f0|   \
 *   \|              \|/ f0 |            |         /  \                   /  \ | f1 \
 *    +-----+---      +-----+---         |        / B  \                 / B  \|     \
 *   / \ A / \       / \ A / \           |    ---+------+------      ---+------+------+---
 *                  NO GOOD BRIDGE	     |     Hole Non-Manifold         NO GOOD BRIDGE
 *               f1 adjacent to B and C                               f0 adjacent to A and B
 */

#define SIDE_EDGE_OPTA	2
#define ADJ_EDGE_OPTA		1

#define SIDE_EDGE_OPTB	1
#define ADJ_EDGE_OPTB		2

template <class MESH>
class FgtBridge: public FgtBridgeBase<MESH>
{
  typedef BridgeAbutment<MESH>        				                AbutmentType;
  typedef typename MESH::FaceType							                FaceType;
    typedef typename MESH::ScalarType						                ScalarType;
    typedef typename vcg::face::Pos<FaceType>               		PosType;
    typedef FgtHole<MESH>											                	HoleType;
    typedef typename std::vector<HoleType>			                HoleVector;
    typedef typename MESH::FacePointer					                FacePointer;
  typedef typename MESH::FaceIterator					                FaceIterator;
  typedef typename vcg::GridStaticPtr<FaceType, ScalarType >	GridType;
    typedef typename std::vector< FgtBridge<MESH> >							BridgeVector;
    typedef typename BridgeVector::iterator											BridgeIterator;
  typedef typename MESH::VertexType						                VertexType;

public:
    enum BridgeOption {NoOne, OptA, OptB};

    FgtBridge(HoleSetManager<MESH>* parent)
    {
        f0=0;
        f0=0;
        this->parentManager = parent;
    };

    inline void AddFaceReference(std::vector<FacePointer*> &facesReferences)
    {
        assert(!IsNull());
        assert(!IsDeleted());
        facesReferences.push_back(&f0);
        facesReferences.push_back(&f1);
    };

    inline PosType GetAbutmentA() const {
        return PosType( f0->FFp(0), f0->FFi(0) );
    };
    inline PosType GetAbutmentB() const {
        return PosType( f1->FFp(0), f1->FFi(0) );
    };

    inline PosType GetSideA() const{
        if( opt==OptA )	return PosType(f0, SIDE_EDGE_OPTA);
        else return PosType(f0, SIDE_EDGE_OPTB);
    };

    inline PosType GetSideB() const{
        if( opt==OptA )	return PosType(f1, SIDE_EDGE_OPTA);
        else return PosType(f1, SIDE_EDGE_OPTB);
    };

    inline bool IsNull() const { return f0==0 && f1==0; };
    inline bool IsDeleted() const { return f0->IsD() && f1->IsD(); };

    void ResetFlag()
    {
        assert( !IsNull() );
        assert( this->parentManager->IsBridgeFace( f0 ) );
        assert( this->parentManager->IsBridgeFace( f1 ) );

        this->parentManager->ClearBridgeAttr( f0 );
        this->parentManager->ClearBridgeAttr( f1 );
    };

    void DeleteFromMesh()
    {
        assert(!IsNull() && !IsDeleted());
        if( !f0->IsD() )
        vcg::tri::Allocator<MESH>::DeleteFace(*this->parentManager->mesh, *f0);
        if( !f1->IsD() )
            vcg::tri::Allocator<MESH>::DeleteFace(*this->parentManager->mesh, *f1);

        // update mesh topology after bridge faces removal, restore border
        for(int e=0; e<3; e++)
        {
            if(!vcg::face::IsBorder<FaceType>(*f0, e))
            {
                FacePointer adjF = f0->FFp(e);
                if(!this->parentManager->IsBridgeFace(adjF))
                {
                    int adjEI = f0->FFi(e);
                    adjF->FFp( adjEI ) = adjF;
                    adjF->FFi( adjEI ) = adjEI;
                    assert(vcg::face::IsBorder<FaceType>(*adjF, adjEI));
                }
            }

            if(!vcg::face::IsBorder<FaceType>(*f1, e))
            {
                FacePointer adjF = f1->FFp(e);
                if(!this->parentManager->IsBridgeFace(adjF))
                {
                    int adjEI = f1->FFi(e);
                    adjF->FFp( adjEI ) = adjF;
                    adjF->FFi( adjEI ) = adjEI;
                    assert(vcg::face::IsBorder<FaceType>(*adjF, adjEI));
                }
            }
        }
    };

private:

    void build(AbutmentType sideA, AbutmentType sideB, BridgeOption o, std::vector<FacePointer *> &app, bool test=false)
    {
        opt = o;
        if(test)
            if(!testAbutmentDistance(sideA, sideB) &&  (opt=computeBestBridgeOpt(sideA, sideB)) == NoOne)
            {
                f0 = 0;	f1 = 0;
                opt = NoOne;
                return;
            }

        assert(testAbutmentDistance(sideA, sideB));
        assert(opt!=NoOne);

        app.push_back(&sideA.f);
        app.push_back(&sideB.f);
        FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(*this->parentManager->mesh, 2, app);
        this->parentManager->faceAttr->UpdateSize();
        app.pop_back();
        app.pop_back();

        f0 = &*fit;
        f1 = &*(fit+1);

        this->parentManager->SetBridgeAttr(f0);
        this->parentManager->SetBridgeAttr(f1);
        this->parentManager->SetHoleBorderAttr(f0);
        this->parentManager->SetHoleBorderAttr(f1);

        this->parentManager->ClearHoleBorderAttr(sideA.f);
        this->parentManager->ClearHoleBorderAttr(sideB.f);

        // the index of edge adjacent between new 2 face, is the same for both new faces
        int adjEdgeIndex = -1;

        // the index of edge adjacent between new 2 face, is the same for both new faces
        int sideEdgeIndex = -1;

        setVertexByOption(sideA, sideB, opt, *f0, *f1);
        if( opt == OptA )
        {
            adjEdgeIndex = ADJ_EDGE_OPTA;
            sideEdgeIndex = SIDE_EDGE_OPTA;
        }
        else
        {
            adjEdgeIndex = ADJ_EDGE_OPTB;
            sideEdgeIndex = SIDE_EDGE_OPTB;
        }

        f0->N() = vcg::TriangleNormal(*f0);
        f1->N() = vcg::TriangleNormal(*f1);

        //edges delle facce adiacenti alla mesh
        f0->FFp(0) = sideA.f;
        f0->FFi(0) = sideA.z;
        f1->FFp(0) = sideB.f;
        f1->FFi(0) = sideB.z;

        sideA.f->FFp(sideA.z) = f0;
        sideA.f->FFi(sideA.z) = 0;
        sideB.f->FFp(sideB.z) = f1;
        sideB.f->FFi(sideB.z) = 0;

        // edges adiacenti tra le 2 facce appena inserite, edge "condiviso"
        f0->FFp(adjEdgeIndex) = f1;
        f0->FFi(adjEdgeIndex) = adjEdgeIndex;
        f1->FFp(adjEdgeIndex) = f0;
        f1->FFi(adjEdgeIndex) = adjEdgeIndex;

        //edges laterali del ponte, quelli che restano di bordo
        f0->FFp(sideEdgeIndex) = f0;
        f0->FFi(sideEdgeIndex) = sideEdgeIndex;
        f1->FFp(sideEdgeIndex) = f1;
        f1->FFi(sideEdgeIndex) = sideEdgeIndex;

        assert( vcg::face::BorderCount(*f0)==1 );
        assert( vcg::face::BorderCount(*f1)==1 );
        assert( this->parentManager->IsBridgeFace( f0 ) );
        assert( this->parentManager->IsBridgeFace( f1 ) );
    };

/*** funzioni statiche ***/

public:

    /*  Build a bridge between 2 border edge.
     *  If the bridge is inside the same hole it cannot be adjacent the hole border,
     *  this means fill another sub hole.
     */
    static bool CreateBridge(AbutmentType &sideA, AbutmentType &sideB, HoleSetManager<MESH>* holesManager, QString &err)
    {
        assert( vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z) &&
                        vcg::face::IsBorder<FaceType>(*sideB.f, sideB.z));
        assert(!sideA.h->IsFilled() && !sideB.h->IsFilled());

        std::vector<FacePointer *> tmpFaceRef;
        //if(app!=0)
        //	tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
        //holesManager->AddFaceReference(tmpFaceRef);

        ScalarType q;
        BridgeOption opt = computeBestBridgeOpt(sideA, sideB, &q);
        if(opt == NoOne)
        {
            err = QString("Bridge is compenetrating with mesh.");
            return false;
        }

        if(sideA.h == sideB.h)
        {
            if( testAbutmentDistance(sideA, sideB) )
                subdivideHoleWithBridge(sideA, sideB, opt, holesManager, tmpFaceRef);
            else
            {
                err = QString("Bridge has sides adjacent to mesh.");
                return false;
            }
        }
        else
            unifyHolesWithBridge(sideA, sideB, opt, holesManager, tmpFaceRef);
        return true;
    };


    /*  Build a bridge inner to the same hole. It chooses the best bridge computing quality
     *  of 2 faces and similarity (as number of edge) of two next hole. Bridge is build follow
     *  bridge's rule, bridge must have 2 border edge.
     *  infoLabel parameter is used to show work progress.
     *  Return number of bridge built.
     */
     static bool AutoSelfBridging(HoleSetManager<MESH>* holesManager, double dist_coeff=0.0, std::vector<FacePointer *> *app=0)
    {
        bool err = false;
        time_t timer;
        if(holesManager->autoBridgeCB != 0)
        {
            holesManager->autoBridgeCB->Invoke(0);
            timer = clock();
        }
        GridType gM;
        gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());

        std::vector<FacePointer *> tmpFaceRef;
        AbutmentType sideA, sideB;
        BridgeOption bestOpt;

        int nh = holesManager->holes.size();
        for(int h=0; h<nh; ++h)
        {
            HoleType &thehole = holesManager->holes.at(h);
            if(!thehole.IsSelected() || thehole.Size()<6 )
                continue;
            assert(!thehole.IsFilled());

            ScalarType maxQuality = -1;

            // initP: first bridge abutment
            PosType initP = thehole.p;
            for(int i=0; i<thehole.Size();i++)
            {
                // initP: second bridge abutment
                PosType endP = initP;
                endP.NextB();endP.NextB();
                for(int j=3; j<=thehole.Size()/2; j++)
                {
                    endP.NextB();

                    // two edge used as bridge abutment are adjacent to the same face... bridge can't be build
                    // i due edge di bordo sono gia' collegati da 2 triangoli adiacenti,
                    // il bridge si sovrapporrebbe a questi 2 triangoli
                    if( endP.f->FFp(0) == initP.f ||
                        endP.f->FFp(1) == initP.f ||
                        endP.f->FFp(2) == initP.f )
                        continue;

                    AbutmentType a(initP.f, initP.z, &thehole);
                    AbutmentType b(endP.f, endP.z, &thehole);
                    if(!testAbutmentDistance(a,b))
                        continue;

                    ScalarType q;
                    BridgeOption opt = computeBestBridgeOpt(a, b, &q, &gM);
                    if(opt != NoOne)
                    {
                        q += dist_coeff * j; // add distance weight
                        if(  q > maxQuality)
                        {
                            maxQuality = q;
                            bestOpt = opt;
                            sideA.f=initP.f; sideA.z=initP.z; sideA.h=&thehole;
                            sideB.f=endP.f; sideB.z=endP.z; sideB.h=&thehole;
                        }
                    }

                    if(holesManager->autoBridgeCB != 0)
                    {
                        if(int(clock()) - timer > holesManager->autoBridgeCB->GetOffset())
                        {
                            float progress = (float)(((float)( ((float)j/(thehole.Size()-3)) + i) / thehole.Size()) + h) / nh;
                            holesManager->autoBridgeCB->Invoke(progress*100);
                            timer = clock();
                        }
                    }
                }// scansione del edge di arrivo

                initP.NextB();
            }// scansione dell'edge di partenza

            assert(vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z));
            assert(vcg::face::IsBorder<FaceType>(*sideB.f, sideB.z));

            if( maxQuality > -1)
            {
                tmpFaceRef.clear();
                if(app!=0)
                    tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
                holesManager->AddFaceReference(tmpFaceRef);
                subdivideHoleWithBridge(sideA, sideB, bestOpt, holesManager, tmpFaceRef);
                gM.Set(holesManager->mesh->face.begin(), holesManager->mesh->face.end());
            }
            else
                err = true;
        } //scansione degli holes
        if(err) return false;
        else return true;
    };


    /*  It connects iteratively selected holes with the best bridge.
     *  Result is unique hole instead of init holes.
     *  Return number of bridges built.
     */
    static void AutoMultiBridging(HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> *app=0 )
    {
        int timer;
        if(holesManager->autoBridgeCB != 0)
        {
            holesManager->autoBridgeCB->Invoke(0);
            timer = clock();
        }

        GridType gM;

        std::vector<FacePointer *> tmpFaceRef;
        AbutmentType sideA, sideB;
        BridgeOption bestOpt;

        std::vector<HoleType*> selectedHoles;
        typename std::vector<HoleType*>::iterator shit1, shit2;
        typename HoleVector::iterator hit;

        int nIteration = -1;
        int iteration = 0;
        // iterate, unify holes, until selected hole is only one
        do{
            sideA.SetNull();
            sideB.SetNull();

            // prendo gli hole selezionati
            selectedHoles.clear();
            for(hit=holesManager->holes.begin(); hit!=holesManager->holes.end(); hit++)
                if(hit->IsSelected())
                    selectedHoles.push_back(&*hit);

            if(selectedHoles.size() < 2)
                return;
            gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());

            float casesViewed = 0, cases2View = 0;
            for(shit1=selectedHoles.begin(); shit1!=selectedHoles.end(); shit1++)
                for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
                    cases2View += (*shit1)->Size() * (*shit2)->Size();

            if(nIteration == -1)
                nIteration = selectedHoles.size()-1;

            // cerco la miglior combinazione tra le facce di un hole con quelle di un'altro
            ScalarType maxQuality = -1;
            for(shit1=selectedHoles.begin(); shit1!=selectedHoles.end(); shit1++)
            {
                for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
                {
                    PosType ph1((*shit1)->p.f, (*shit1)->p.z);
                    PosType ph2((*shit2)->p.f, (*shit2)->p.z);
                    do{	//scansione edge di bordo del primo buco
                        do{
                            ScalarType q;
                            AbutmentType a( ph1.f, ph1.z, *shit1 );
                            AbutmentType b( ph2.f, ph2.z, *shit2 );
                            BridgeOption opt = computeBestBridgeOpt(a, b, &q, &gM);
                            if(opt != NoOne)
                                if(q > maxQuality)
                                {
                                    maxQuality = q;
                                    sideA = a;
                                    sideB = b;
                                    bestOpt = opt;
                                }

                            if(holesManager->autoBridgeCB != 0)
                            {
                                if(int(clock()) - timer > holesManager->autoBridgeCB->GetOffset())
                                {
                                    int progress = ( (100 * ( iteration +(casesViewed/cases2View)))/nIteration );
                                    holesManager->autoBridgeCB->Invoke(progress);
                                    timer = clock();
                                }
                            }

                            casesViewed++;
                            ph2.NextB();
                        }while(ph2 != (*shit2)->p);

                        ph1.NextB();
                    }while(ph1 != (*shit1)->p);
                } // for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
            }

            // adesso ho la miglior coppia di edge si deve creare il bridge
            assert(!sideA.IsNull() && !sideB.IsNull());

            // la rimozione di hole dovuta alla unifyHoles.. provoca l'aggiornamento della lista di holes
            // pertanto si deve avere sempre aggiornata la lista dei riferimenti alle facce
            // la quale dipende anche dagli holes
            tmpFaceRef.clear();
            if(app!=0)
                tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
            holesManager->AddFaceReference(tmpFaceRef);

            if(maxQuality > -1)
                unifyHolesWithBridge(sideA, sideB, bestOpt, holesManager, tmpFaceRef);
            else
                return;
            iteration ++;
        }while(true);
        return;
    };


private:
    /*  Compute distance between bridge side to allow no bridge adjacent to hole border.
     *  A bridge must have 2 border faces.
     */
    static bool testAbutmentDistance(const AbutmentType &sideA, const AbutmentType &sideB)
    {
        if(sideA.h != sideB.h) return true;

        // at least 2 edges have to be between 2 bridge side.
        if(!sideA.h->IsNonManifold())
        {
            // so adjacent edges of a side haven't to share a vertex with other side.
            PosType pos(sideA.f, sideA.z);
            assert(pos.IsBorder());
            pos.NextB();
            if(pos.v == sideB.f->V0(sideB.z)) return false;
            if(pos.v == sideB.f->V1(sideB.z)) return false;

            pos = PosType(sideA.f, sideA.z);
            pos.FlipV();
            pos.NextB();
            if(pos.v == sideB.f->V0(sideB.z)) return false;
            if(pos.v == sideB.f->V1(sideB.z)) return false;
        }
        else
        {
            // if exist a face which share a vertex with each side then the bridge cannot be built
            PosType initPos(sideA.f, sideA.z);
            PosType curPos=initPos;

            VertexType* va0=sideA.f->V0(sideA.z);
            VertexType* va1=sideA.f->V1(sideA.z);
            VertexType* vb0=sideB.f->V0(sideB.z);
            VertexType* vb1=sideB.f->V1(sideB.z);

            do{
                VertexType* cv0=curPos.f->V0(curPos.z);
                VertexType* cv1=curPos.f->V1(curPos.z);
                if(	cv0 == va0 || cv1 == va0 ||
                      cv0 == va1 || cv1 == va1 )
                    if( cv0 == vb0 || cv1 == vb0 ||
                        cv0 == vb1 || cv1 == vb1 )
                        return false;

                curPos.NextB();
            }while( curPos != initPos );
        }
        return true;
    };

    static void subdivideHoleWithBridge(AbutmentType &sideA, AbutmentType &sideB,
        BridgeOption bo, HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> &app)
    {
        assert(sideA.h==sideB.h);
        assert(testAbutmentDistance(sideA, sideB));
        FgtBridge<MESH>* b = new FgtBridge<MESH>(holesManager);
        b->build(sideA, sideB, bo, app);
        holesManager->bridges.push_back(b);

        sideA.h->SetStartPos(b->GetSideA());
        sideA.h->SetBridged(true);
        FgtHole<MESH> newHole(b->GetSideB(), QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), holesManager);
        if(sideA.h->IsSelected())
            newHole.SetSelect(true);
        newHole.SetBridged(true);
        holesManager->holes.push_back( newHole );
    };

    static void unifyHolesWithBridge(AbutmentType &sideA, AbutmentType &sideB,
                BridgeOption bo, HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> &app)
    {
        assert(vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z));
        assert(vcg::face::IsBorder<FaceType>(*sideB.f, sideB.z));
        assert( sideA.h!=sideB.h);

        FgtBridge<MESH>* b = new FgtBridge<MESH>(holesManager);
        b->build(sideA, sideB, bo, app);
        holesManager->bridges.push_back(b);

        sideA.h->SetStartPos(b->GetSideA());
        assert( sideA.h->p.IsBorder() );
        if(sideB.h->IsSelected())
            sideA.h->SetSelect(true);
        sideA.h->SetBridged(true);
            typename HoleVector::iterator hit = holesManager->holes.begin();
            //for(hit=holesManager->holes.begin(); hit!=holesManager->holes.end(); ++hit)
            while(hit!=holesManager->holes.end())
            {
                if(&*hit == sideB.h)
                {
                    holesManager->holes.erase(hit++);
                    return;
                }
                else
                    hit++;
            }
    };

    /*  Set bridge vertices according bridge build option
     */
    static void setVertexByOption(AbutmentType &sideA, AbutmentType &sideB, BridgeOption o,
        FaceType &bf0, FaceType &bf1)
    {
        VertexType* vA0 = sideA.f->V0( sideA.z ); // first vertex of pos' 1-edge
        VertexType* vA1 = sideA.f->V1( sideA.z ); // second vertex of pos' 1-edge
        VertexType* vB0 = sideB.f->V0( sideB.z ); // first vertex of pos' 2-edge
        VertexType* vB1 = sideB.f->V1( sideB.z ); // second vertex of pos' 2-edge

        // Quality
        if(o==OptA)
        {
            bf0.V(0) = vA1; bf0.V(1) = vA0;	bf0.V(2) = vB0;
            bf1.V(0) = vB1; bf1.V(1) = vB0; bf1.V(2) = vA0;
        }
        else
        {
            bf0.V(0) = vA1; bf0.V(1) = vA0;	bf0.V(2) = vB1;
            bf1.V(0) = vB1; bf1.V(1) = vB0; bf1.V(2) = vA1;
        }
    }

    /*  Find how triangolate two bridge faces.
     *  If return "NoOne" means bridge is compenetrating with mesh for both option
     */
    static BridgeOption computeBestBridgeOpt(AbutmentType sideA,
        AbutmentType sideB, ScalarType* quality=0, GridType* gM=0)
    {
        HoleSetManager<MESH>* hm = sideA.h->parentManager;
        bool delgm = false;
        if(gM==0)
        {
            gM = new GridType();
            gM->Set(hm->mesh->face.begin(),hm->mesh->face.end());
            delgm = true;
        }

        FaceType bf0, bf1;
        ScalarType qA = -1;
        // Caso A
        setVertexByOption(sideA, sideB, OptA, bf0, bf1);
        if( !HoleType::TestFaceMeshCompenetration(*hm->mesh, *gM, &bf0) &&
                !HoleType::TestFaceMeshCompenetration(*hm->mesh, *gM, &bf1) )
                    qA = QualityFace(bf0)+ QualityFace(bf1);

        // Caso B
        ScalarType qB = -1;
        setVertexByOption(sideA, sideB, OptB, bf0, bf1);
        if( !HoleType::TestFaceMeshCompenetration(*hm->mesh, *gM, &bf0) &&
                !HoleType::TestFaceMeshCompenetration(*hm->mesh, *gM, &bf1) )
                    qB = QualityFace(bf0)+ QualityFace(bf1);

        if(delgm)
        {
            delete gM;
            gM=0;
        }

        if(quality!=0)
        {
            if(qA>qB) *quality = qA;
            else *quality = qB;
        }

        if(qA==-1 && qB==-1)
            return NoOne;	// both autocompenetrant with mesh
        else if(qA>qB)
            return OptA;
        else
            return OptB;
    };


private:
    BridgeOption opt;

public:
    FacePointer f0;
    FacePointer f1;
};



/*  "Bridge" (face) added to close non manifold holes
 *
 *
 *	  -----+------+------      ----+------+--------
 *		      \ A  /                  \ A  /|
 *	         \  /                    \  / |
 *		 holeX  \/  holeX        holeX  \/  |  holeY
 *	          /\                      /\f0|
 *	         /  \                    /  \ |
 *	        / B  \                  / B  \|
 *	  -----+------+------      ----+------+--------
 *   HoleX is Non-Manifold     HoleX and HoleY aren't
 *	                                Non-Manifold
 */
template <class MESH>
class FgtNMBridge: public FgtBridgeBase<MESH>
{
  typedef typename MESH::FaceType							FaceType;
    typedef typename MESH::FacePointer					FacePointer;
  typedef typename vcg::face::Pos<FaceType>		PosType;
  typedef FgtHole<MESH>												HoleType;
  typedef typename MESH::FaceIterator					FaceIterator;

public:

    FgtNMBridge(FacePointer f, HoleSetManager<MESH>* parent)
    {
        f0 = f;
        this->parentManager = parent;
    };

    inline PosType GetAbutmentA() const {
        return PosType( f0->FFp(0), f0->FFi(0));
    };
    inline PosType GetAbutmentB() const {
        return PosType( f0->FFp(2), f0->FFi(2));
    };

    inline bool IsNull() const { return f0==0; };
    inline bool IsDeleted() const { return f0->IsD(); };

    inline void AddFaceReference(std::vector<FacePointer*> &facesReferences)
    {
        assert(!IsNull());
        assert(!IsDeleted());
        facesReferences.push_back(&f0);
    };


    void ResetFlag()
    {
        assert( !IsNull() );
        assert(this->parentManager->IsBridgeFace(f0) );
        this->parentManager->ClearBridgeAttr(f0);
    };

    void DeleteFromMesh()
    {
        assert( !IsNull() );
        assert( this->parentManager->IsBridgeFace(f0) );
        if( !f0->IsD() )
            vcg::tri::Allocator<MESH>::DeleteFace(*this->parentManager->mesh, *f0);

        // update mesh topology after bridge faces removal, restore border
        for(int e=0; e<3; e++)
        {
            if(!vcg::face::IsBorder<FaceType>(*f0, e))
            {
                FacePointer adjF = f0->FFp(e);
                if(!this->parentManager->IsBridgeFace(adjF))
                {
                    int adjEI = f0->FFi(e);
                    adjF->FFp( adjEI ) = adjF;
                    adjF->FFi( adjEI ) = adjEI;
                    assert(vcg::face::IsBorder<FaceType>(*adjF, adjEI));
                }
            }
        }
    };

    /* Walk over selected non-manifold holes, find vertex visited more times,
     * add face adjacent to non-manifold vertex.
     */
    static void CloseNonManifoldVertex(HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> *app=0)
    {
        int startNholes = holesManager->holes.size();

        std::vector<FacePointer *> tmpFaceRef;

        for(int i=0; i<startNholes; i++)
        {
            HoleType *h = &holesManager->holes.at(i);
            if(!(h->IsNonManifold() && h->IsSelected()))
                continue;

            // walk the border, mark as visit each vertex. If walk twice over the same vertex go back over the border
            // to find other edge sharing this vertex
            PosType curPos = h->p;
            assert(curPos.IsBorder());
            assert(!h->IsFilled());
            PosType p0, p1;
            p0.SetNull();
            p1.SetNull();
            do{
                assert(p0.IsNull());
                if(curPos.v->IsV())
                    p0.Set(curPos.f, curPos.z, curPos.v);
                else
                    curPos.v->SetV();
                curPos.NextB();
                assert(curPos.IsBorder());

                if(!p0.IsNull())
                {
                    tmpFaceRef.clear();
                    if(app!=0)
                        tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
                    holesManager->AddFaceReference(tmpFaceRef);

                    // faces allocation and local face reference management
                    tmpFaceRef.push_back(&p0.f);
                    tmpFaceRef.push_back(&curPos.f);
                    FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(*holesManager->mesh, 1, tmpFaceRef);
                    holesManager->faceAttr->UpdateSize();
                    tmpFaceRef.pop_back();
                    tmpFaceRef.pop_back();


                    // non-manifold vertex found, go back over the border to find other edge share the vertex with p0
                    int dist = 0;
                    p1 = p0;
                    p1.FlipV();
                    do{
                        dist++;
                        p1.v->ClearV();
                        p1.NextB();
                    }while(p0.v != p1.v);

                    // p2 is used only in case face added close sub-hole, sub-hole distance is 2
                    // p2 is half-edge adjacent to connect to patch edge which usually is border
                    PosType p2 = p0;
                    p2.FlipV();
                    p2.NextB();

                    // face is build to have as vertex 0 the non-manifold vertex, so it have adge 1 as border edge
                    fit->V(0) = p0.v;
                    if( p0.VInd() == p0.z)
                    {
                        fit->V(1) = p1.f->V(p1.z);
                        fit->V(2) = p0.f->V1(p0.z);

                        fit->FFp(0) = p1.f;
                        fit->FFi(0) = p1.z;
                        fit->FFp(2) = p0.f;
                        fit->FFi(2) = p0.z;

                        p0.f->FFp(p0.z) = &*fit;
                        p0.f->FFi(p0.z) = 2;
                        p1.f->FFp(p1.z) = &*fit;
                        p1.f->FFi(p1.z) = 0;
                    }
                    else
                    {
                        fit->V(1) = p0.f->V(p0.z);
                        fit->V(2) = p1.f->V1(p1.z);

                        fit->FFp(0) = p0.f;
                        fit->FFi(0) = p0.z;
                        fit->FFp(2) = p1.f;
                        fit->FFi(2) = p1.z;

                        p0.f->FFp(p0.z) = &*fit;
                        p0.f->FFi(p0.z) = 0;
                        p1.f->FFp(p1.z) = &*fit;
                        p1.f->FFi(p1.z) = 2;
                    }

                    fit->N() = TriangleNormal(*fit);

                    holesManager->SetBridgeAttr(&*fit);
                    holesManager->bridges.push_back( new FgtNMBridge(&*fit, holesManager) );

                    if(dist==2)
                    {
                        // face used to close non-manifold holes, close entirely a "sub-hole" (sub-hole has
                        // only 3 border edge). This face become a patch face which fill an invisible subhole.
                        holesManager->SetPatchAttr(&*fit);
                        fit->FFp(1) = p2.f;
                        fit->FFi(1) = p2.z;
                        p2.f->FFp(p2.z) = &*fit;
                        p2.f->FFi(p2.z) = 1;
                    }
                    else
                    {
                        fit->FFp(1) = &*fit;
                        fit->FFi(1) = 1;

                        HoleType newhole(PosType(&*fit, 1), QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), holesManager);
                        if(h->IsSelected())
                            newhole.SetSelect(true);
                        newhole.SetBridged(true);
                        holesManager->holes.push_back(newhole);
                    }
                    p0.SetNull();
                }
            }while( curPos != h->p );

            // hole now is divided intosub hole
            curPos = h->p;
            do{
                curPos.v->ClearV();
                curPos.NextB();
            }while( curPos!= h->p);

            //forzo l'aggiornamento delle info dell'hole
            h->SetStartPos(h->p);
            h->SetBridged(true);
        }// for(int i=0; i<startNholes...
    };

public:
    FacePointer f0;
};

#endif
