/* Copyright (c) 1997-2002
   Technische Universitaet Berlin, Germany
   Department of Mathematics,
   Research Group Algorithmic and Discrete Mathematics
   mailto:polymake@math.tu-berlin.de

   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, 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 for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA.
*/

#include <ext/hash_map>

#include <Integer.h>
#include <Poly.h>
#include <HasseDiagram.h>
#include <Array.h>
#include <Map.h>
#include <list>
#include <sstream>

namespace polymake { namespace surface {

   void rotation_scheme(Poly& p) {

   const HasseDiagram<> HD = p.give("HASSE_DIAGRAM");
   const int n_vertices = p.give("N_VERTICES");
   Array<std::list<int> > rotation_list(n_vertices);
   Array<int> first_edges(n_vertices, -1);                // Kante an der die Rotation anfaengt (im HD)
   Array<int> first_faces(n_vertices, -1);                // Flaeche, gibt die Richtung vor (im HD)
   std::list<int> vertex_list;                      // noch nicht besuchte Ecken
 
   int vertex = HD.nodes_of_dim(0).front();          // aktuelle Ecke (im HD)
   int vertex_index = HD.node(vertex).front();      // aktuelle Ecke (richtige Nummer)

   // Initialisierung mit einer beliebigen Ecke
   vertex_list.push_back(vertex);                  
   first_edges[vertex_index] = HD.out_neighbors(vertex).front();
   first_faces[vertex_index] = HD.out_neighbors(first_edges[vertex_index]).front();


   while (vertex_list.size() > 0 ){


     // naechste noch nicht besuchte Ecke
     vertex = vertex_list.front();
     vertex_index = HD.node(vertex).front();
     vertex_list.pop_front();
    
     // Kanten, die von der aktuellen Ecke ausgehen
     Set<int> edge_set = HD.out_neighbors(vertex);

     int first_edge = first_edges[vertex_index];
     int edge = first_edge;
     int face = first_faces[vertex_index]; 

        do {

          Set<int> vertices_of_edge = HD.in_neighbors(edge);
          vertices_of_edge -= vertex;
          
          int index = HD.node(vertices_of_edge.front()).front();
          rotation_list[vertex_index].push_back(index);
 
         
	  // anderen Endpunkt der Kante in dei Eckenliste aufnehmen
	  if (first_edges[index] == -1){
	    Set<int> face_set = HD.out_neighbors(edge);
	    face_set -= face;
	    vertex_list.push_back(vertices_of_edge.front());
            first_edges[index] = edge;
            first_faces[index] = face_set.front();
	  }  
        
          // naechste Kante aufsuchen

          Set<int> next_edge_set = HD.in_neighbors(face);
          next_edge_set *= edge_set;
          next_edge_set -= edge;

	  edge = next_edge_set.front();


          Set<int> face_set = HD.out_neighbors(edge);
          face_set -= face;
          face = face_set.front();

 
        }
        while (!(edge==first_edge));

   }
   p.take("ROTATION_SCHEME") << rotation_list;
}

} }

using namespace polymake;

/** @file rotation_scheme
 *
 *  Calculates the rotation of all vertices, i.e. the neighbors of each vertex in cyclic order, in a way,
 *  that is compatible with the orientation 
 *
 *  @synopsis rotation_scheme <file>
 *
 *  @reading  HASSE_DIAGRAM, N_VERTICES
 *  @writing  ROTATION_SCHEME
 *
 *  @author Dagmar Timmreck
 *
 */

int main(int argc, const char *argv[]) {
   if (argc != 2) {
      cerr << "usage: " << argv[0] << " <file> " << endl;
      return 1;
   }
   try {
      Poly p(argv[1], ios::in | ios::out);
      surface::rotation_scheme(p);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
