#include <stdio.h>
#include "GR_BFace.h"
#include "GR_Mesh2D.h"
#include "GR_events.h"
#include "GR_misc.h"

/***************************************************************************
                          LSVertsCheck.cpp  -  description 
                             ------------------- 
    begin                : Tue Aug 3 1999 
    copyright            : (C) 1999 by Charles Boivin                         
    email                : cboivin@mech.ubc.ca 
 ***************************************************************************/

static Vert *
pVGetOtherVertex (Vert * pV, Face * pF)
{

  // Returns the vertex different from pV
  // from the face pF
  // If both are different, then it returns NULL

  Vert *pV0 = pF->pVVert (0);
  Vert *pV1 = pF->pVVert (1);

  if (pV == pV0) {
    assert (pV1 != pV);
    return pV1;
  }
  else {
    if (pV == pV1)
      return pV0;
  }
  return NULL;
}

static Face *
pFGetOtherFace (Vert * pV, Face * pF, Cell * pC)
{

  // Returns the other face from pC connected to
  // pV (i.e. it returns something different than pF)

  bool qFaceFound = false;
  int i = -1;
  Face *pTheF;
  while (!qFaceFound) {
    i++;
    pTheF = pC->pFFace (i);

    if (pTheF != pF) {
      if (pVGetOtherVertex (pV, pTheF) != NULL) {
	qFaceFound = true;
      }
    }
  }

  return pTheF;
}

void Mesh2D::
vGetNeighborVertsAndFaces (Vert * pV,
			   List < Vert * >& LpVNear,
			   List < Face * >& LpFNear)
{
  // Returns a list of neighbor verts and originating faces..
  // Both can be done at the same time..

  bool qWentAround = false;
  bool qHitFace = false;
  bool qCanAdd = true;

  Face *pF, *pOriginalF;
  Cell *pCLeft, *pCRight;
  Face *OldpF;


  pOriginalF = pV->pFHintFace ();
  pF = pOriginalF;
  pCLeft = pF->pCCellLeft ();

//  vMessage(3, "Going left\n");
//  vMessage(3, "Original Face is %p\n", pF);

  // Go left...
  while ((!qWentAround) && (!qHitFace)) {
//  	vMessage(4, "Now looking at face %d\n", pF);
    if (qCanAdd) {
      // Add the face to the list..
      LpFNear.vAppendItem (pF);
//      vMessage(4, "Adding %d to face list\n", pF);
      // Add the other vertex to list
      Vert *pVOtherV = pVGetOtherVertex(pV, pF);
      LpVNear.vAppendItem (pVOtherV);
    }
    else {
      // Not allowed to add because it was an interior boundary
    }				// if qCanAdd

    // Get the left cell
    // Check if it's a BFace we just went across..
  if (pCLeft->eType () == Cell::eBdryEdge) {
      qHitFace = true;
//      vMessage(4, "Face was a boundary face\n");
      // No need to get another face..
    }
    else {
      // Must find the other face connected to the same vertex
      // If you hit an internal boundary, go through it..
      if (pCLeft->eType () == Cell::eIntBdryEdge) {
	// vMessage(4, "Face is an internal boundary face\n");
	// Only want to have one of the two faces around an internal
	// boundary in the list..
	OldpF = pF;
	pF = dynamic_cast<IntBdryEdge *>(pCLeft)->pFOtherFace (OldpF);
	// vMessage(4, "Changing face %d to face %d\n", OldpF, pF);
	// Only want one of the two faces in the list,
	// and only want the vertex once..
	// so this one won't be added
	qCanAdd = false;
      }
      else {
//      	vMessage(4, "Regular face, getting new one...\n");
				pF = pFGetOtherFace (pV, pF, pCLeft);
//				vMessage(4, "New face is %d\n", pF);
				qCanAdd = true;
      }				// if it's an eIntBdryEdge

      Cell *OldpC = pCLeft;
      pCLeft = pF->pCCellOpposite (OldpC);
      // check if it's the same..
      if (pF == pOriginalF) {
				qWentAround = true;
//				vMessage(4, "Same as original face -- done\n");
				// If the first face was an interior boundary face, then
				// the two faces around the interior boundary would be first
				// and last, and we only want one of them in the list. So remove
				// the last one inserted
				
				if (OldpC->eType() == Cell::eIntBdryEdge) {
//					vMessage(4, "Last cell was an interior boundary, removing last face inserted\n");
					LpFNear.vDelete(OldpF);
					LpVNear.vDelete(pVGetOtherVertex(pV, OldpF));
//					vMessage(4, "Removed last vertex too\n");
				}
				
      }				// if it's the original face
    }				// if it's an eBdryEdge
  }				// while

//  vMessage(4, "Now out of first loop\n");

  qHitFace = false;
  qCanAdd = true;

  pF = pOriginalF;
  pCRight = pF->pCCellRight ();

//  vMessage(4, "Starting right with OriginalpF = %p\n", pF);


  if (pCRight->eType () == Cell::eBdryEdge) {
    qHitFace = true;
    //    vMessage(4, "Hit Bdry right away, done\n");
  }
  else {
    if (pCRight->eType () == Cell::eIntBdryEdge) {
      // vMessage(4, "Int Bdry right away....\n");
      OldpF = pF;
      pF = dynamic_cast<IntBdryEdge *>(pCRight)->pFOtherFace (OldpF);
      // vMessage(4, "Changing %d with %d\n", OldpF, pF);
      qCanAdd = false;
    }
    else {
      //    	vMessage(4, "Getting adjacent face to the right\n");
      pF = pFGetOtherFace (pV, pOriginalF, pCRight);
      qCanAdd = true;
    }
    pCRight = pF->pCCellOpposite (pCRight);
  }

//  vMessage(4, "Starting right with pF = %d\n", pF);

  // Go right...
  while ((!qWentAround) && (!qHitFace)) {
    if (qCanAdd) {
      // Add the face to the list..
      LpFNear.vAppendItem (pF);
//      vMessage(4, "Adding face %d to list\n");
      // Add the other vertex to list
      Vert *pVOtherV = pVGetOtherVertex(pV, pF);
      LpVNear.vAppendItem (pVOtherV);
    }
    else {
      // Not allowed to add..
    }
    // Get the left cell
    // Check if it's a BFace we just went across..
    if (pCRight->eType () == Cell::eBdryEdge) {
//      vMessage(4, "Face is a bdry\n");
      qHitFace = true;
      // No need to get another face..
    }
    else {
      // Must find the other face connected to the same vertex
      // Make sure to go through internal boundaries..
      if (pCRight->eType () == Cell::eIntBdryEdge) {
	OldpF = pF;
	pF = dynamic_cast<IntBdryEdge *>(pCRight)->pFOtherFace (OldpF);

//	vMessage(4, "Face is an internal bdry\n");
//	vMessage(4, "Swapping %p for %p\n", OldpF, pF);
	qCanAdd = false;
      }
      else {
	pF = pFGetOtherFace (pV, pF, pCRight);
//	vMessage(4, "Getting new face %d (%p)\n", iFaceIndex(pF), pF);
	qCanAdd = true;
      }

      Cell *OldpC = pCRight;
      pCRight = pF->pCCellOpposite (OldpC);
      // check if it's the same..
      if (pF == pOriginalF) {
//      	vMessage(4, "Same as original face..\n");
	qWentAround = true;
      }
    }
  }
//  vMessage(4, "Exiting from GetNeighborVertsAndFaces()\n");
}

