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

#include <is_sphere_h.h>

namespace polymake { namespace topaz {

bool is_sphere_h(const HasseDiagram<>& HD, const int seed, int strategy, const int n_stable_rounds)
{
  const int dim = HD.dim()-1;

  // strategic options
  int max_relax=0, heating=0, preheat=0;
  
  if (strategy == 0) {
    max_relax= 70;
    heating= 30;
    preheat= 30;
  }
  
  if (strategy == 1) {
    max_relax= 120;
    heating= 50;
    preheat= 70;
  }
  
  BistellarComplex BC(HD,seed,false,true);
  
  int stable_rounds = 0;
  int relax = 0;
  int neg_relax = 0;
  int full_dim_move = preheat;
  int chilly_moves = 0;
  int up_moves = 0;
  int warm_moves = preheat;
  int min_facets = BC.n_facets();
  
  for ( ; stable_rounds<n_stable_rounds; ++stable_rounds) {
    //    cerr << "stable_rounds: " << stable_rounds << "     min_facets: " << min_facets << endl;

    const int facets = BC.n_facets();
    if (facets < min_facets) {
      min_facets = facets;
      stable_rounds = 0;
    }

    if (facets == dim+2)  // is sphere
      return true;
    
    if (relax < neg_relax)
      relax = 0;
    
    if (relax > max_relax) {  // heating up
      relax = 0;
      up_moves = heating;
      warm_moves = heating;
      if (strategy == 1)
	chilly_moves = heating;
    }
    
    if (full_dim_move > 0) {
      --full_dim_move;	
      BC.zero_move();
      continue;
    }
    
    if (chilly_moves > 0) {
      --chilly_moves;	
      BC.min_rev_move(dim-1);  // very hot move indeed
      continue;
    }
    
    if (up_moves > 0) {
      --up_moves;	
      BC.min_rev_move(dim/2 + 1);  // up move
      continue;
    }
    
    if (warm_moves > 0) {
      --warm_moves;
      BC.min_rev_move(dim/2);  // up or eaven move
      continue;
    }
    
    // make smallest reversed move
    const int move = BC.min_rev_move();
    
    if ( move >= (dim+1)/2 && move != 0 ) {  // up or eaven move
      neg_relax = 0;
      ++relax;
    }
    
    else
      ++neg_relax;
  }
  
  return false;
}  

bool is_ball_or_sphere_h(const HasseDiagram<>& HD, const int seed, const int strategy, const int n_stable_rounds)
{
  const Boundary_of_PseudoManifold B=boundary_of_pseudo_manifold(HD);
  if (B.empty())
    return is_sphere_h(HD, seed, strategy, n_stable_rounds);

  // compute C + cone(bound(C))
  std::list< Set<int> > S;
  int v=0;
  
  for (Entire<sequence>::const_iterator f=entire(HD.nodes_of_dim(HD.dim()-1));
       !f.at_end(); ++f) {
    S.push_back(HD.node(*f));
    const int w=HD.node(*f).back();
    if (w>=v)
      v=w+1;
  }
  
  for (Entire<Boundary_of_PseudoManifold>::const_iterator b=entire(B);
       !b.at_end(); ++b)
    S.push_back(*b+v);
  
  return is_sphere_h(S, seed, strategy, n_stable_rounds);
}

} }
