/* Copyright (c) 1997-2004
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  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: http://www.gnu.org/licenses/gpl.txt.

   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.
*/

#ident "$Project: polymake $$Id: facets_consistency.cc,v 1.16 2004/11/17 13:10:20 witte Exp $"

#include <Poly.h>
#include <Array.h>
#include <FacetList.h>
#include <Set.h>
#include <argv_options.h>

#include <list>

namespace polymake {
namespace topaz {

void facets_consistency(std::ostream& os, Poly& p, const char* complex_section, const bool auto_corr)
{
   typedef Array< std::list<int> > facet_list;
   const facet_list F_in = p.give(complex_section);
   
   if (F_in.empty()) {
      os << complex_section << " is empty.\n" << complex_section << " is inconsistent.\n\n";
      if (auto_corr)
	 p.take("FACETS") << Set<int>();  // the empty complex is encoded as an empty set

   } else {
      FacetList F;
      Set<int> V;
      bool consistent=true;
      
      for (Entire<facet_list>::const_iterator f_it=entire(F_in); !f_it.at_end(); ++f_it) {
	 // checking whether facets are ordered sets
	 facet_list::value_type::const_iterator v_it=f_it->begin(), v_end=f_it->end();
	 if (v_it == v_end) {
	    if (F.size() > 1) {
	       os << "empty facet in a non-empty complex.\n";
	       consistent=false;
	       continue;
	    }
	 }
	 int prev_vertex=*v_it;
	 Set<int> facet;  
	 facet+=*v_it;  ++v_it;
	 
	 for (; v_it != v_end; ++v_it) {
	    if (prev_vertex > *v_it) {
	       wrap(os) << "facet " << *f_it << " is not ordered.\n";
	       consistent=false;
	    }
	    prev_vertex=*v_it;
	    facet+=*v_it;
	 }
	 
	 if ( (size_t)facet.size() < f_it->size() ) {
	    wrap(os) << "facet " << *f_it << " is not a set.\n"; 
	    consistent=false;
	 }
	 
	 // add facet to vertex set
	 V+=facet;
	 
	 // checking for redundancies
	 int size=F.size();
	 if (! F.insertMax(facet)) {
	    wrap(os) << "facet " << *f_it << " is redundant." << endl; 
	    consistent=false;
	 } else if (F.size() != size+1) {
	    wrap(os) << "facet " << *f_it << " contains at least one redundant facet." << endl; 
	    consistent=false;
	 }
      }
      
      // checking numbering
      bool renumber = false;
      if (!V.empty() && V.front()!=0) {
	 os << "\nNumbering of VERTICES does not start with 0.\n";
	 consistent = false;
	 renumber = true;
      }
      if (!V.empty() && V.back()+1!=V.size()) {
	 os << "\nNumbering of VERTICES is not in consecutive order.\n";
	 consistent = false;
	 renumber = true;
      }
      
      if (renumber) F.squeeze();
      
      if (consistent)
	 os << complex_section << " is consistent." << endl;
      else {
	 os << "\n" << complex_section << " is NOT consistent.\n\n"
	    << (renumber ? "The correctly numbered and " : "The ")
	    << "inclusion maximal faces are:\n";
	 wrap(os) << F << endl;
      }

      if (auto_corr) {
	 p.take("FACETS") << F;
	 
	 if (renumber)
	    p.take("VERTEX_LABELS") << as_array(V);
      }
   }
}   
   
} }

using namespace polymake;
   
/** @file facets_consistency
 *
 *  Verifies whether a complex has any redundandent facets,
 *  whether the facets are ordered sets and if the vertices are numbered 0..n-1.
 *
 *  The default for the @c complex_section is @see FACETS.
 *
 *  If the @c -auto flag is set
 *  the client writes the correct facets into @see FACETS and the old numbering
 *  (if the numbering has changed at all) into @see VERTEX_LABELS. The @c complex_section must
 *  not equal @see FACETS.
 *
 *  @synopsis facets_consistency <file> [ <complex_section> [ -auto ] ]
 *
 *  @reading  <complex_section>
 *  @writing  may write FACETS, may write VERTEX_LABELS
 *
 *  @index clients Consistency checks
 */

int main(int argc, const char* argv[])
{
   argv_option options[]={ { "-auto" } };
   enum { auto_corr };
   if (!extract_options(argc,argv,1,options) || argc>3 || argc<2) {
      cerr << "usage: " << argv[0] << " <file> [ <complex_section> [ -auto ] ]" << endl;
      return 1;
   }

   try {
      Poly p(argv[1], ios::in|ios::out, "topaz::default");

      const char* complex_section = argc==2 ? "FACETS" : argv[2]; 

      if (options[auto_corr] && (!strcmp(complex_section,"FACETS")) ) {
	 cerr << argv[0] << ": FACETS can only be checked for consistency but not corrected." << endl;
	 return 1;
      }
      
      topaz::facets_consistency(std::cout, p, complex_section, options[auto_corr]);
   }
   catch (const std::exception& e) {
     cerr << e.what() << endl;
     return 1;
   }
   return 0;
}


// Local Variables:
// mode:C++
// c-basic-offset:3
// End:
