//
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology 
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.


#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "Debug.h"
#include "DOFVector.h"
#include "MacroElement.h"
#include "ElementDofIterator.h"
#include "io/VtkWriter.h"
#include "io/ElementFileWriter.h"

namespace AMDiS {

  namespace debug {

#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
    void writeLocalElementDofs(int rank, int elIdx, 
			       const FiniteElemSpace *feSpace)
    {
      using boost::lexical_cast;
      
      if (MPI::COMM_WORLD.Get_rank() == rank) {
	DOFVector<double> tmp(feSpace, "tmp");
	colorDofVectorByLocalElementDofs(tmp, feSpace->getMesh(), elIdx);
	VtkWriter::writeFile(tmp, "tmp" + lexical_cast<std::string>(elIdx) + ".vtu");
      }
    }

    
    void writeDofMesh(int rank, DegreeOfFreedom dof, 
		      const FiniteElemSpace *feSpace)
    {
      using boost::lexical_cast;

      if (MPI::COMM_WORLD.Get_rank() == rank) {
	DOFVector<double> tmp(feSpace, "tmp");
	tmp.set(0.0);
	tmp[dof] = 1.0;
	VtkWriter::writeFile(tmp, "dofmesh" + lexical_cast<std::string>(rank) + ".vtu");
      }    
    }

    
    void writeMesh(const FiniteElemSpace *feSpace, int rank, std::string filename)
    {
      using boost::lexical_cast;
      
      int myRank = MPI::COMM_WORLD.Get_rank();
      if (rank == -1 || myRank == rank) {
	DOFVector<double> tmp(feSpace, "tmp");
	VtkWriter::writeFile(tmp, filename + lexical_cast<std::string>(myRank) + ".vtu", 
			     false);
      }
    }
#endif

    
    void writeDofIndexMesh(const FiniteElemSpace *feSpace)
    {
      DOFVector<double> tmp(feSpace, "tmp");
      DOFIterator<double> it(&tmp, USED_DOFS);
      for (it.reset(); !it.end(); ++it)
	*it = it.getDOFIndex();
      VtkWriter::writeFile(tmp, "dofindex.vtu");
    }


    void colorEdgeInMesh(const FiniteElemSpace *feSpace,
			 Element *el, 
			 int localEdgeNo, 
			 std::string filename)
    {
      DOFVector<double> tmp(feSpace, "tmp");
      tmp.set(0.0);
      tmp[el->getEdge(localEdgeNo).first] = 1.0;
      tmp[el->getEdge(localEdgeNo).second] = 1.0;
      VtkWriter::writeFile(tmp, filename);
    }


    void writeElementIndexMesh(Mesh *mesh, std::string filename, int level)
    {
      FUNCNAME("debug::writeElementIndexMesh()");

      std::map<int, double> vec;    
      TraverseStack stack;
      ElInfo *elInfo = 
	level == -1 ? 
	stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL) :
	stack.traverseFirst(mesh, level, Mesh::CALL_EL_LEVEL);
      
      while (elInfo) {		  
	int index = elInfo->getElement()->getIndex();
	vec[index] = index;
	elInfo = stack.traverseNext(elInfo);
      }

      ElementFileWriter::writeFile(vec, mesh, filename, level);
    }


    void highlightElementIndexMesh(Mesh *mesh, int idx, std::string filename)
    {
      std::map<int, double> vec;    
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      bool markChildren = false;
      int markLevel = -1;

      while (elInfo) {		  
	if (markChildren && elInfo->getLevel() <= markLevel)
	  markChildren = false;

	int index = elInfo->getElement()->getIndex();
	if (index == idx) {
	  markChildren = true;
	  markLevel = elInfo->getLevel();
	}
  
	if (elInfo->getElement()->isLeaf())
	  vec[index] = (markChildren ? 1.0 : 0.0);

	elInfo = stack.traverseNext(elInfo);
      }

      ElementFileWriter::writeFile(vec, mesh, filename);
    }


    void colorMeshByMacroIndex(Mesh *mesh, std::string filename)
    {
      FUNCNAME("debug::colorMeshByMacroIndex()");

      std::map<int, double> vec;    
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
      
      while (elInfo) {		  
	int index = elInfo->getElement()->getIndex();
	vec[index] = elInfo->getMacroElement()->getIndex();
	elInfo = stack.traverseNext(elInfo);
      }

      ElementFileWriter::writeFile(vec, mesh, filename);
    }


    void colorDofVectorByLocalElementDofs(DOFVector<double>& vec, Element *el)
    {
      // === Get local indices of the given element. ===
      
      const BasisFunction *basisFcts = vec.getFeSpace()->getBasisFcts();
      int nBasisFcts = basisFcts->getNumber();
      std::vector<DegreeOfFreedom> localDofs(nBasisFcts);
      basisFcts->getLocalIndices(el, vec.getFeSpace()->getAdmin(), localDofs);
      
      // === Set the values of the dof vector. ===
      
      vec.set(0.0);
      for (int i = 0; i < nBasisFcts; i++)
	vec[localDofs[i]] = static_cast<double>(i);
    }

    
    bool colorDofVectorByLocalElementDofs(DOFVector<double>& vec, Mesh *mesh, 
					  int elIndex)
    {
      FUNCNAME("debug::colorDofVectorByLocalElementDofs()");
      
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
      while (elInfo) {
	if (elInfo->getElement()->getIndex() == elIndex) {
	  colorDofVectorByLocalElementDofs(vec, elInfo->getElement());
	  return true;
	}
	elInfo = stack.traverseNext(elInfo);
      }
      
      return false;
    }

    
    Element* getDofIndexElement(const FiniteElemSpace *feSpace, 
				DegreeOfFreedom dof)
    {
      const BasisFunction* basFcts = feSpace->getBasisFcts();
      int nBasFcts = basFcts->getNumber();
      std::vector<DegreeOfFreedom> dofVec(nBasFcts);
      
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, Mesh::CALL_LEAF_EL);
      while (elInfo) {
	basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), dofVec);
	for (int i = 0; i < nBasFcts; i++) 
	  if (dofVec[i] == dof)
	    return elInfo->getElement();	  
	
	elInfo = stack.traverseNext(elInfo);
      }
      
      return NULL;
    }

    
    Element* getLevel0ParentElement(Mesh *mesh, Element *el)
    {    
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (elInfo->getElement() == el)
	  return elInfo->getMacroElement()->getElement();      
	
	elInfo = stack.traverseNext(elInfo);
      }
      
      return NULL;
    }


    Element* getLevel0ParentElement(Mesh *mesh, int elIndex)
    {    
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (elInfo->getElement()->getIndex() == elIndex)
	  return elInfo->getMacroElement()->getElement();      
	
	elInfo = stack.traverseNext(elInfo);
      }
      
      return NULL;
    }


    Element* getParentElement(Mesh *mesh, Element *el)
    {
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (elInfo->getElement()->getChild(0) == el || 
	    elInfo->getElement()->getChild(1) == el)
	  return elInfo->getElement();      
	
	elInfo = stack.traverseNext(elInfo);
      }
      
      return NULL;
    }


    Element* getElement(Mesh *mesh, int elIndex)
    {
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (elInfo->getElement()->getIndex() == elIndex)
	  return elInfo->getElement();      
	
	elInfo = stack.traverseNext(elInfo);
      }
      
      return NULL;      
    }


    Element* getParentElement(Mesh *mesh, int elIndex)
    {
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (elInfo->getElement()->isLeaf() == false) 
	  if (elInfo->getElement()->getChild(0)->getIndex() == elIndex || 
	      elInfo->getElement()->getChild(1)->getIndex() == elIndex)
	    return elInfo->getElement();
	
	elInfo = stack.traverseNext(elInfo);
      }
      
      return NULL;

    }


    void printElementInfo(Element *el)
    {
      FUNCNAME("printElementInfo()");
      
      if (el->isLeaf()) {
	MSG("el %d is leaf!\n", el->getIndex());
      } else {
	MSG("el child0 %d    child1 %d\n", 
	    el->getChild(0)->getIndex(),
	    el->getChild(1)->getIndex());
	printElementInfo(el->getChild(0));
	printElementInfo(el->getChild(1));
      }
    }

    
    void printElementCoords(const FiniteElemSpace *feSpace, Element *el)
    {
      FUNCNAME("debug:printElementCoords()");
      
      Mesh *mesh = feSpace->getMesh();

      for (int i = 0; i <= mesh->getDim(); i++) {
	DegreeOfFreedom dof = el->getDof(i, 0);
	WorldVector<double> coords;
	mesh->getDofIndexCoords(dof, feSpace, coords);
	MSG("%d-th DOF of element %d: %f %f %f\n", 
	    i, el->getIndex(), coords[0], coords[1], coords[2]);
      }
    }


    void printInfoByDof(const FiniteElemSpace *feSpace, DegreeOfFreedom dof)
    {
      FUNCNAME("debug::printInfoByDof()");

      Element *el = getDofIndexElement(feSpace, dof);
      Element *parEl = getLevel0ParentElement(feSpace->getMesh(), el);
      
      MSG("[DBG] DOF-INFO:  dof = %d  elidx = %d  pelidx = %d\n", 
	  dof, el->getIndex(), parEl->getIndex());
      
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, 
					   Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (elInfo->getElement()->getIndex() == parEl->getIndex()) {
	  MSG("[DBG] EL INFO TO %d: type = %d\n", parEl->getIndex(), elInfo->getType());
	}

	elInfo = stack.traverseNext(elInfo);
      }	  
    }


    void printMatValuesStatistics(Matrix<DOFMatrix*> *mat)
    {
      std::map<int, int> counter;
      int counter0 = 0;

      for (int i = 0; i < mat->getNumRows(); i++) {
	for (int j = 0; j < mat->getNumCols(); j++) {
	  DOFMatrix *dofMat = (*mat)[i][j];
	  if (dofMat) {

	    using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end;
	    namespace traits = mtl::traits;
	    typedef DOFMatrix::base_matrix_type base_matrix_type;
	    
	    traits::const_value<base_matrix_type>::type value(dofMat->getBaseMatrix());
	    typedef traits::range_generator<major, base_matrix_type>::type cursor_type;
	    typedef traits::range_generator<nz, cursor_type>::type icursor_type;
    
	    for (cursor_type cursor = begin<major>(dofMat->getBaseMatrix()), 
		   cend = end<major>(dofMat->getBaseMatrix()); cursor != cend; ++cursor)
	      for (icursor_type icursor = begin<nz>(cursor), 
		     icend = end<nz>(cursor); icursor != icend; ++icursor) {
		if (value(*icursor) == 0.0) {
		  counter0++;
		} else {
		  int a = static_cast<int>(floor(log10(fabs(value(*icursor)))));
		  counter[a]++;
		}
	      }
		
	  }
	}
      }

      std::cout << "value = 0: " << counter0 << std::endl;
      for (std::map<int, int>::iterator it = counter.begin(); it != counter.end(); ++it)
	std::cout << pow(10.0, it->first) << " <= values <= " 
		  << pow(10.0, it->first + 1.0) << ": " 
		  << it->second << std::endl;
    }


    void printAllDofCoords(const FiniteElemSpace *feSpace)
    {
      FUNCNAME("printAllDofCoords()");

      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, 
					   Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS);
      while (elInfo) {
	Element *el = elInfo->getElement();
	for (int i = 0; i <= feSpace->getMesh()->getDim(); i++) {
	  MSG("Coords for DOF %d = %f %f\n", 
	      *(el->getDof(i)), (elInfo->getCoord(i))[0], (elInfo->getCoord(i))[1]);
	}
	elInfo = stack.traverseNext(elInfo);
      }      
    }


    void getAllDofs(const FiniteElemSpace *feSpace, 
		    std::set<const DegreeOfFreedom*>& dofs)
    {
      FUNCNAME("getAllDofs()");

      ElementDofIterator elDofIter(feSpace);
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, Mesh::CALL_LEAF_EL);
      while (elInfo) {	
	elDofIter.reset(elInfo->getElement());
	do {
	  dofs.insert(elDofIter.getDofPtr());
	} while (elDofIter.next());
	elInfo = stack.traverseNext(elInfo);
      }      
    }


    void writeMatlabMatrix(DOFMatrix &mat, std::string filename)
    {
      using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end;
      namespace traits = mtl::traits;
      typedef DOFMatrix::base_matrix_type Matrix;

      traits::row<Matrix>::type row(mat.getBaseMatrix());
      traits::col<Matrix>::type col(mat.getBaseMatrix());
      traits::const_value<Matrix>::type value(mat.getBaseMatrix());

      typedef traits::range_generator<major, Matrix>::type cursor_type;
      typedef traits::range_generator<nz, cursor_type>::type icursor_type;

      std::ofstream out;
      out.open(filename.c_str());
      out.precision(20);
    
      for (cursor_type cursor = begin<major>(mat.getBaseMatrix()), 
	     cend = end<major>(mat.getBaseMatrix()); cursor != cend; ++cursor)
	for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); icursor != icend; ++icursor)
	  out << row(*icursor) + 1 << " " 
	      << col(*icursor) + 1 << " " 
	      << value(*icursor) << "\n";

      out.close();
    }


    void writeMatlabMatrix(Matrix<DOFMatrix*> &mat, std::string filename)
    {
      using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end;
      namespace traits = mtl::traits;
      typedef DOFMatrix::base_matrix_type Matrix;

      std::ofstream out;
      out.open(filename.c_str());

      for (int i = 0; i < mat.getNumRows(); i++) {
	for (int j = 0; j < mat.getNumCols(); j++) {
	  if (!mat[i][j])
	    continue;

	  traits::row<Matrix>::type row(mat[i][j]->getBaseMatrix());
	  traits::col<Matrix>::type col(mat[i][j]->getBaseMatrix());
	  traits::const_value<Matrix>::type value(mat[i][j]->getBaseMatrix());
	  
	  typedef traits::range_generator<major, Matrix>::type cursor_type;
	  typedef traits::range_generator<nz, cursor_type>::type icursor_type;	  

	  for (cursor_type cursor = begin<major>(mat[i][j]->getBaseMatrix()), 
		 cend = end<major>(mat[i][j]->getBaseMatrix()); cursor != cend; ++cursor)
	    for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); icursor != icend; ++icursor)
	      out << i * num_rows(mat[i][j]->getBaseMatrix()) + row(*icursor) + 1 << " " 
		  << j * num_cols(mat[i][j]->getBaseMatrix()) + col(*icursor) + 1 << " " 
		  << value(*icursor) << "\n";
	}
      }
    
      out.close();
    }


    void writeMatlabVector(DOFVector<double> &vec, std::string filename)
    {
      std::ofstream out;    
      out.open(filename.c_str());

      DOFIterator<double> it(&vec, USED_DOFS);
      for (it.reset(); !it.end(); ++it)
	out << *it << "\n";

      out.close();      
    }

    
    void writeMatlabVector(SystemVector &vec, std::string filename)
    {
      std::ofstream out;    
      out.open(filename.c_str());

      for (int i = 0; i < vec.getSize(); i++) {
	DOFIterator<double> it(vec.getDOFVector(i), USED_DOFS);
	for (it.reset(); !it.end(); ++it)
	  out << *it << "\n";
      }

      out.close();            
    }


    void writeCoordsFile(const FiniteElemSpace* feSpace, std::string filename)
    {
      FUNCNAME("debug::writeCoordsFile()");

      DOFVector<WorldVector<double> > coords(feSpace, "tmp");
      feSpace->getMesh()->getDofIndexCoords(feSpace, coords);

      std::ofstream file;
      file.open(filename.c_str());
      file << coords.getUsedSize() << "\n";
      DOFIterator<WorldVector<double> > it(&coords, USED_DOFS);
      for (it.reset(); !it.end(); ++it) {
	file << it.getDOFIndex();
	for (int i = 0; i < feSpace->getMesh()->getDim(); i++)
	  file << " " << (*it)[i];
	file << "\n";
      }
      file.close();
    }


    void printElementHierarchie(Mesh *mesh, int elIndex)
    {
      FUNCNAME("debug::printElementHierarchie()");

      bool printInfo = false;
      int elLevel = -1;

      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
      while (elInfo) {
	if (printInfo && elInfo->getLevel() <= elLevel)
	  return;

	if (elInfo->getElement()->getIndex() == elIndex) {
	  printInfo = true;
	  elLevel = elInfo->getLevel();
	  MSG(" Hierarchie for elIdx = %d\n", elIndex);
	} else {
	  if (printInfo) {
	    std::stringstream oss;
	    for (int i = 0; i < (elInfo->getLevel() - elLevel); i++)
	      oss << "   ";
	    oss << "|--" << elInfo->getElement()->getIndex();
	    if (oss.str().length() >= 255) {
	      WARNING("String is to long! Element index is %d.\n", elInfo->getElement()->getIndex());
	    } else {
	      MSG("%s\n", oss.str().c_str());
	    }
	  }
	}

	elInfo = stack.traverseNext(elInfo);
      }

      if (!printInfo) {
	MSG("Could not find element with index %d\n", elIndex);
      }
    }


    void printElementRefinementSequence(Mesh *mesh, Element *el)
    {
      FUNCNAME("printElementRefinementSequence()");

      int elIndex = el->getIndex();
      std::vector<int> refSeq;
      Element *parent = getParentElement(mesh, el);

      while (parent) {
	if (parent->getChild(0) == el)
	  refSeq.push_back(0);
	else
	  refSeq.push_back(1);

	el = parent;
	parent = getParentElement(mesh, el);
      }

      std::stringstream oss;
      for (int i = refSeq.size() - 1; i >= 0; i--)
	oss << refSeq[i];
      
      MSG("Ref-Seq for element %d: %s\n", elIndex, oss.str().c_str());
    }


    int getLocalNeighbourIndex(Mesh *mesh, int elIndex, int neighIndex)
    {
      FUNCNAME("debug::getLocalNeighbourIndex()");

      TraverseStack stack;
      ElInfo *elInfo = 
	stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER | Mesh::FILL_NEIGH);
      while (elInfo) {
	if (elInfo->getElement()->getIndex() == elIndex) {
	  int returnValue = -1;
	  for (int i = 0; i <= mesh->getDim(); i++) {
	    if (elInfo->getNeighbour(i)) {
	      MSG("NEIGH %d of El-Idx %d: %d\n", i, elIndex, elInfo->getNeighbour(i)->getIndex());
	    } else {
	      MSG("NEIGH %d of El-Idx %d: %d\n", i, elIndex, -1);
	    }
	    
	    if (elInfo->getNeighbour(i) && 
		elInfo->getNeighbour(i)->getIndex() == neighIndex)
	      returnValue = i;
	  }

	  return returnValue;	  
	}
	elInfo = stack.traverseNext(elInfo);
      }      

      return -2;
    }


    void importDofVectorByCoords(DOFVector<double>* vec, std::string filename)
    { 
      DOFVector<WorldVector<double> > coords(vec->getFeSpace(), "dofCoords");
      vec->getFeSpace()->getMesh()->getDofIndexCoords(vec->getFeSpace(), coords);
      int dim = vec->getFeSpace()->getMesh()->getDim();

      std::ifstream file;
      file.open(filename.c_str());
      
      int nEntries;
      file >> nEntries;

      for (int i = 0; i < nEntries; i++) {
	WorldVector<double> dofCoords;
	for (int j = 0; j < dim; j++)
	  file >> dofCoords[j];

	double value;
	file >> value;

      
	DOFIterator<WorldVector<double> > it(&coords, USED_DOFS);
	for (it.reset(); !it.end(); ++it) {
	  bool found = true;
	  for (int j = 0; j < dim; j++) {
	    if (fabs((*it)[j] - dofCoords[j]) > 1e-8) {
	      found = false;
	      break;
	    }
	  }

	  if (found) {
	    (*vec)[it.getDOFIndex()] = value;
	    break;
	  }
	}	
      }

      file.close();
    }


    void exportDofVectorByCoords(const DOFVector<double>* vec, 
				 std::string filename)
    {
      DOFVector<WorldVector<double> > coords(vec->getFeSpace(), "dofCoords");
      vec->getFeSpace()->getMesh()->getDofIndexCoords(vec->getFeSpace(), coords);
      int dim = vec->getFeSpace()->getMesh()->getDim();

      std::ofstream file;
      file.open(filename.c_str());
      file << vec->getUsedSize() << "\n";

      DOFIterator<WorldVector<double> > it(&coords, USED_DOFS);
      for (it.reset(); !it.end(); ++it) {
        for (int i = 0; i < dim; i++)
	  file << (*it)[i] << " ";
        file << (*vec)[it.getDOFIndex()] << "\n";
      }
    
      file.close();
    }


    void createSortedDofs(Mesh *mesh, ElementIdxToDofs &elMap)
    {
      FUNCNAME("debug::dbgCreateElementMap()");
      
      int dim = mesh->getDim();
      elMap.clear();
      
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
      while (elInfo) {
	Element *el = elInfo->getElement();
	switch (dim) {
	case 2:
	  sortDofs(el->getDof(0), el->getDof(1), el->getDof(2), elMap[el->getIndex()]);
	  break;
	case 3:
	  sortDofs(el->getDof(0), el->getDof(1), el->getDof(2), el->getDof(3), elMap[el->getIndex()]);
	  break;
	default:
	  ERROR_EXIT("What is this?\n");
	}
	elInfo = stack.traverseNext(elInfo);
      }
    }


    void testSortedDofs(Mesh *mesh, ElementIdxToDofs &elMap)
    {
      FUNCNAME("debug::dbgTestElementMap()");
      
      int dim = mesh->getDim();
      int nVertex = Global::getGeo(VERTEX, dim);
      DofContainer vec(nVertex);
      
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
      while (elInfo) {
	Element *el = elInfo->getElement();
	
	switch (dim) {
	case 2:
	  sortDofs(el->getDof(0), el->getDof(1), el->getDof(2), vec);
	  break;
	case 3:
	  sortDofs(el->getDof(0), el->getDof(1), el->getDof(2), el->getDof(3), vec);
	  break;
	default:
	  ERROR_EXIT("What is this?\n");
	}
	
	for (int i = 0; i < nVertex; i++) {
	  if (elMap[el->getIndex()][i] != vec[i]) {
	    MSG("[DBG] Wrong new dof numeration in element = %d\n!", el->getIndex());
	    std::cout << "[DBG]: Old numeration was: ";
	    for (int j = 0; j < nVertex; j++)
	      std::cout << elMap[el->getIndex()][j] << " = " 
			<< *(elMap[el->getIndex()][j]) << "  ";
	    std::cout << std::endl;
	    std::cout << "[DBG]: New numeration is:  ";
	    for (int j = 0; j < nVertex; j++)
	      std::cout << vec[j] << " = "  << *(vec[j]) << "  ";
	    std::cout << std::endl;
	    ERROR_EXIT("WRONG NEW DOF NUMERATION!\n");
	  }
	}
	elInfo = stack.traverseNext(elInfo);
      }
    }


    void sortDofs(const DegreeOfFreedom* dof0,
		  const DegreeOfFreedom* dof1,
		  const DegreeOfFreedom* dof2,
		  DofContainer &vec)
    {
      DofPtrSortFct dofPtrSort;
      vec.resize(3);
      vec[0] = dof0; 
      vec[1] = dof1; 
      vec[2] = dof2;
      sort(vec.begin(), vec.end(), dofPtrSort);
    }

    void sortDofs(const DegreeOfFreedom* dof0,
		  const DegreeOfFreedom* dof1,
		  const DegreeOfFreedom* dof2,
		  const DegreeOfFreedom* dof3,
		  DofContainer &vec)
    {
      DofPtrSortFct dofPtrSort;
      vec.resize(4);
      vec[0] = dof0; 
      vec[1] = dof1; 
      vec[2] = dof2;
      vec[3] = dof3;
      sort(vec.begin(), vec.end(), dofPtrSort);
    }


    void testDofsByCoords(const FiniteElemSpace *feSpace,
			  DofContainer &dofs0, DofContainer &dofs1)
    {
      FUNCNAME("debug::testDofsByCoords()");

      TEST_EXIT(dofs0.size() == dofs1.size())
	("The dof containers have different sizes %d %d!\n",
	 dofs0.size(), dofs1.size());

      DOFVector<WorldVector<double> > coords(feSpace, "dofCorrds");
      feSpace->getMesh()->getDofIndexCoords(feSpace, coords);

      for (unsigned int i = 0; i < dofs0.size(); i++) {
	WorldVector<double> tmp = coords[*(dofs0[i])];
	tmp -= coords[*(dofs1[i])];

	TEST_EXIT(norm(tmp) < 1e-13)
	  ("DOFs %d and %d (i = %d) have different coords!\n", 
	   *(dofs0[i]), *(dofs1[i]), i);
      }
      
    }


  } // namespace debug
  
} // namespace AMDiS