////////////////////////////////////////////////////////////////////////////////
// 
// ConfData.cc
//
//    produced: 08/08/25 jr
// 
////////////////////////////////////////////////////////////////////////////////
#include <iostream>

#include <set>

#include "ConfData.hh"
#include "CheckSymmetries.hh"
#include "CheckTriang.hh"

namespace topcom {

  // functions:
  const std::string ConfData::_dump_startline = "TOPCOM ConfData dump start:";
  const std::string ConfData::_dump_endline   = "TOPCOM ConfData dump end.";

  
  // stream output/input:
  std::ostream& ConfData::write(std::ostream& ost) const {
    ost << _dump_startline << std::endl;
    if (_pointsptr) {
      ost << "_points                                ";
      _pointsptr->write(ost);
      ost << '\n';
    }
    if (_chiroptr) {
      ost << "_chiro                                 ";
      _chiroptr->write_string(ost);
    }
    if (_symmetriesptr) {
      ost << "_symmetries                            ";
      _symmetriesptr->write_generators(ost);
      ost << '\n';
    }
    if (_required_symmetriesptr) {
      ost << "_required symmetries                   ";
      _required_symmetriesptr->write_generators(ost);
      ost << '\n';
    }
    if (_seedptr) {
      ost << "_seed                                  ";
      _seedptr->write(ost);
      ost << '\n';
    }
    if (_circuitsptr) {
      ost << "_circuits                              ";
      _circuitsptr->write(ost);
      ost << '\n';
    }
    if (_cocircuitsptr) {
      ost << "_cocircuits                            ";
      _cocircuitsptr->write(ost);
      ost << '\n';
    }
    if (_poscocircuitsptr) {
      ost << "_poscocircuits                            ";
      _poscocircuitsptr->write(ost);
      ost << '\n';
    }
    if (_facetsptr) {
      ost << "_facets                                ";
      _facetsptr->write(ost);
      ost << '\n';
    }
    if (_inctableptr) {
      ost << "_inctable                              ";
      _inctableptr->write(ost);
      ost << '\n';
    }
    if (_admtableptr) {
      ost << "_admtable                              ";
      _admtableptr->write(ost);
      ost << '\n';
    }
    if (_voltableptr) {
      ost << "_voltable                              ";
      _voltableptr->write(ost);
      ost << '\n';
    }
    if (_volumeptr) {
      ost << "_volume                                ";
      ost << *_volumeptr;
      ost << '\n';
    }
    if (_valid_symmetriesptr) {
      ost << "_valid_symmetries                      ";
      _valid_symmetriesptr->write(ost);
      ost << '\n';
    }
    if (_simpidx_symmetriesptr) {
      ost << "_simpidx_symmetries                    ";
      _simpidx_symmetriesptr->write(ost);
      ost << '\n';
    }
    if (_extension_switchtableptr) {
      ost << "_extension_switchtable                           ";
      _extension_switchtableptr->sparse_write(ost);
      ost << '\n';
    }
    if (_subset_switchtableptr) {
      ost << "_subset_switchtable                           ";
      _subset_switchtableptr->sparse_write(ost);
      ost << '\n';
    }

    // it is debatable whether the following should really be written since it is never read anyway:

    if (false) {
      if (_seed_symmetryptrsptr) {
	ost << "_seed_symmetryptrs                      ";
	ost << *_seed_symmetryptrsptr;
	ost << '\n';
      }
      if (_points_simpidx_symmetriesptr) {
	ost << "_points_simpidx_symmetries             ";
	ost << *_points_simpidx_symmetriesptr;
	ost << '\n';
      }
      if (_classified_extension_symmetriesptr) {
	ost << "_classified_extension_symmetries                 ";
	_classified_extension_symmetriesptr->write(ost);
	ost << '\n';
      }
      if (_classified_subset_symmetriesptr) {
	ost << "_classified_subset_symmetries                 ";
	_classified_subset_symmetriesptr->write(ost);
	ost << '\n';
      }
    }
    ost << _dump_endline << std::endl;
    return ost;
  }

  // the following method can read whatever data has been dumped before;
  // in order to be able to make consistency checks, the input file has to be read first:
  std::istream& ConfData::read(std::istream& ist) {
    std::string dump_line;
    std::string last_dump_line;
    
    std::getline(ist, dump_line);

    MessageStreams::debug() << "dump start line         : " << dump_line << std::endl;
    MessageStreams::debug() << "required dump start line: " << _dump_startline << std::endl;

    // first, check if the standard-first-line was found to make sure the file is a TOPCOM dump:
    if (_dump_startline.compare(0, _dump_startline.length(), dump_line) != 0) {
      MessageStreams::forced() << "ConfData::read(std::istream& ist): not a TOPCOM dump file - exiting" << std::endl;
      exit(1);
    }

    MessageStreams::verbose() << "before read:" << std::endl;
    MessageStreams::verbose() << *this << std::endl;
    
    // next, check for data in key-value format:
    while ((std::getline(ist, dump_line))) {
      std::string::size_type lastPos = dump_line.find_first_not_of(" ", 0);
      std::string::size_type pos     = dump_line.find_first_of(" ", lastPos);
      std::string keyword            = dump_line.substr(lastPos, pos - lastPos);
	  
      // next, parse the partial computational result from the dump file:
      if (keyword == "_points") {
	PointConfiguration points_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> points_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _points - exiting" << std::endl;
	  exit(1);
	}
	if (*_pointsptr != points_reader) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): dump file _points do not coincide with input points - exiting" << std::endl;
	}
      }
      if (keyword == "_chiro") {
	Chirotope chiro_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(chiro_reader.read_string(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _chiro - exiting" << std::endl;
	  exit(1);
	}
	if (*_chiroptr != chiro_reader) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): dump file _chiro does not coincide with input chiro - exiting" << std::endl;
	}
      }
      if (keyword == "_symmetries") {
	SymmetryGroup sym_reader(no());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(sym_reader.read_generators(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _symmetries - exiting" << std::endl;
	  exit(1);
	}
	if (_symmetriesptr->generators() != sym_reader.generators()) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): dump file _symmetries does not coincide with input symmetries - exiting" << std::endl;
	}
      }
      if (keyword == "_required_symmetries") {
	SymmetryGroup reqsym_reader(no());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(reqsym_reader.read_generators(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _required_symmetries - exiting" << std::endl;
	  exit(1);
	}
	if (_required_symmetriesptr->generators() != reqsym_reader.generators()) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): dump file _required_symmetries does not coincide with input required symmetries - exiting" << std::endl;
	}
      }
      if (keyword == "_seed") {
	SimplicialComplex seed_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> seed_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _seed - exiting" << std::endl;
	  exit(1);
	}
	if (*_seedptr != seed_reader) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): dump file _seed does not coincide with input seed - exiting" << std::endl;
	}
      }
      if (keyword == "_circuits") {
	Circuits circuits_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> circuits_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _circuits - exiting" << std::endl;
	  exit(1);
	}
	_circuitsptr = new Circuits(std::move(circuits_reader));
	MessageStreams::debug() << "_circuits initialized with " << *_circuitsptr << std::endl;
      }
      if (keyword == "_cocircuits") {
	Cocircuits cocircuits_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> cocircuits_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _cocircuits - exiting" << std::endl;
	  exit(1);
	}
	_cocircuitsptr = new Cocircuits(std::move(cocircuits_reader));
	MessageStreams::debug() << "_cocircuits initialized with " << *_cocircuitsptr << std::endl;
      }
      if (keyword == "_poscocircuits") {
	Cocircuits poscocircuits_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> poscocircuits_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _poscocircuits - exiting" << std::endl;
	  exit(1);
	}
	_poscocircuitsptr = new Cocircuits(std::move(poscocircuits_reader));
	MessageStreams::debug() << "_poscocircuits initialized with " << *_poscocircuitsptr << std::endl;
      }
      if (keyword == "_facets") {
	Facets facets_reader(no(), rank());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> facets_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _facets - exiting" << std::endl;
	  exit(1);
	}
	_facetsptr = new Facets(std::move(facets_reader));
	MessageStreams::debug() << "_cocircuits initialized with " << *_facetsptr << std::endl;
      }
      if (keyword == "_inctable") {
	Incidences inctable_reader(chiro());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> inctable_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _inctable - exiting" << std::endl;
	  exit(1);
	}
	_inctableptr = new Incidences(std::move(inctable_reader));
	MessageStreams::debug() << "_inctable initialized with " << *_inctableptr << std::endl;
      }
      if (keyword == "_admtable") {
	Admissibles admtable_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> admtable_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _admtable - exiting" << std::endl;
	  exit(1);
	}
	_admtableptr = new Admissibles(std::move(admtable_reader));
	MessageStreams::debug() << "_admtable initialized with " << *_admtableptr << std::endl;
      }
      if (keyword == "_voltable") {
	Volumes voltable_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> voltable_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _voltable - exiting" << std::endl;
	  exit(1);
	}
	_voltableptr = new Volumes(std::move(voltable_reader));
	MessageStreams::debug() << "_voltable initialized with " << *_voltableptr << std::endl;
      }
      if (keyword == "_volume") {
	Field volume_reader;
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(istrst >> volume_reader)) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _volume - exiting" << std::endl;
	  exit(1);
	}
	_volumeptr = new Field(std::move(volume_reader));
	MessageStreams::debug() << "_volume initialized with " << *_volumeptr << std::endl;
      }
      if (keyword == "_valid_symmetries") {
	SymmetryGroup valsym_reader(no());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(valsym_reader.read(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _valid_symmetries - exiting" << std::endl;
	  exit(1);
	}
	_valid_symmetriesptr = new SymmetryGroup(std::move(valsym_reader));
	MessageStreams::debug() << "_valid_symmetries initialized with " << *_valid_symmetriesptr << std::endl;
      }
      if (keyword == "_simpidx_symmetries") {
	SymmetryGroup simpidxsym_reader(SimplicialComplex::no_of_simplices(rank()));
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(simpidxsym_reader.read_generators(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _simpidx_symmetries - exiting" << std::endl;
	  exit(1);
	}
	_simpidx_symmetriesptr = new SymmetryGroup(std::move(simpidxsym_reader));
	MessageStreams::debug() << "_simpidx_symmetries initialized with " << *_simpidx_symmetriesptr << std::endl;
      }
      if (keyword == "_extension_switchtable") {
	SwitchTable<IntegerSet,lexmin_mode> switchtable_reader(no());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(switchtable_reader.sparse_read(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _extension_switchtable - exiting" << std::endl;
	  exit(1);
	}
	_extension_switchtableptr = new SwitchTable<IntegerSet,lexmin_mode>(std::move(switchtable_reader));
	MessageStreams::debug() << "_extension_switchtable initialized with " << *_extension_switchtableptr << std::endl;
      }
      if (keyword == "_subset_switchtable") {
	SwitchTable<IntegerSet,colexmax_mode> switchtable_reader(no());
	lastPos = dump_line.find_first_not_of(" ", pos);
	std::string value = dump_line.substr(lastPos, dump_line.length());      
	std::istringstream istrst (value, std::ios::in);      
	if (!(switchtable_reader.sparse_read(istrst))) {
	  MessageStreams::forced() << "ConfData::read(std::istream& ist): error while reading _subset_switchtable - exiting" << std::endl;
	  exit(1);
	}
	_subset_switchtableptr = new SwitchTable<IntegerSet,colexmax_mode>(std::move(switchtable_reader));
	MessageStreams::debug() << "_subset_switchtable initialized with " << *_subset_switchtableptr << std::endl;
      }

      // it does not make sense to read points_simpidx_symmetries or classified_symmetries.
      last_dump_line = dump_line;
    }

    // finally, check last line for the standard end line in order
    // to make sure that the file is complete:
    if (_dump_endline.compare(0, _dump_endline.length(), last_dump_line) != 0) {
      MessageStreams::forced() << "last dump_line: " << last_dump_line << std::endl;
      MessageStreams::forced() << "ConfData::read(std::istream& ist): TOPCOM dump file is incomplete - exiting" << std::endl;
      exit(1);
    }

    return ist;
  }

  // the following method will only read a standard TOPCOM input file with four data fields in the order
  // 1. points or chirotope as a string of signs
  // 2. symmetries (default: trivial)
  // 3. required symmetries (default: trivial)
  // 4. seed triangulation (optional):
  std::istream& ConfData::read_input(std::istream& ist) {
    CommentGrinder commentgrinder(CommandlineOptions::verbose() || CommandlineOptions::debug());
    ist >> commentgrinder;
    
    if (_options.input_chiro()) {

      // here, the input is given as a chirotope:
      MessageStreams::verbose() << "checking for chirotope ..." << std::endl;
      Chirotope chiro_reader;
      if (CommandlineOptions::output_asy()) {
	MessageStreams::forced() << "graphics output cancelled because of chirotope input." << std::endl;
      }
      if (!chiro_reader.read_string(ist)) {
	MessageStreams::forced() << "error while reading chirotope - exiting" << std::endl;
	exit(1);
      }
      _chiroptr = new Chirotope(std::move(chiro_reader)); // from now on, the chirotope data stays const
      MessageStreams::verbose() << "read chirotope with " << _chiroptr->no()
				<< " elements in rank " << _chiroptr->rank() << std::endl;
    }
    else {

      // here, the input is given as vector coordinates:
      MessageStreams::verbose() << "checking for points ..." << std::endl;
      PointConfiguration points_reader;
      if (!points_reader.read(ist)) {
	MessageStreams::forced() << "error while reading point configuration - exiting" << std::endl;
	exit(1);
      }
      if (points_reader.rank() < points_reader.rowdim()) {
	MessageStreams::forced() << "point configuration has "
				 << points_reader.rowdim()
				 << " rows of rank "
				 << points_reader.rank() << std::endl;
	if (!_options.show_input_only()) {
	  MessageStreams::debug() << "original point configuration read:" << std::endl;
	  points_reader.pretty_print(MessageStreams::debug());
	  points_reader.transform_to_full_rank();
	  MessageStreams::forced() << "resulting no of rows after transformation: " << points_reader.rank() << std::endl;
	}
      }
      if ((points_reader.no() < 1) || (points_reader.rank() < 1)) {
	std::cerr << "no of points and rank must be at least one - exiting" << std::endl;
	exit(1);
      }
      if (points_reader.rank() > points_reader.no()) {
	std::cerr << "rank must not be larger than no of points - exiting" << std::endl;
	exit(1);
      }
      if (CommandlineOptions::preprocess_points()) {
	_transformationptr = new Symmetry(points_reader.no());
	points_reader.preprocess(*_transformationptr);
      }
      _pointsptr = new PointConfiguration(std::move(points_reader)); // from now on, the pointconfiguration data stays const
      MessageStreams::verbose()  << "read point configuration with " << _pointsptr->no()
				 << " points in rank " << _pointsptr->rank() << std::endl;

      // if points have been given, the chirotope has to be generated:
      _chiroptr = new Chirotope(*_pointsptr, _options.preprocess_chiro());
    }

    // grind-off comments:
    ist >> commentgrinder;

    // try to read symmetries:
    MessageStreams::verbose() << "checking for symmetries ..." << std::endl;
    SymmetryGroup symmetries_reader(make_no());
    
    if (!CommandlineOptions::ignore_symmetries()) {

      // first, read generators:
      if (symmetries_reader.read_generators(ist)) {
	MessageStreams::verbose() << "read " << symmetries_reader.generators().size()
				  << " generators for symmetries" << std::endl;
	if (CommandlineOptions::debug()) {
	  MessageStreams::debug() << "symmetries_reader.generators():" << std::endl;
	  MessageStreams::debug() << symmetries_reader.generators() << std::endl;
	}

	// check whether all elements or only generators of the symmetry group are needed:
	if (!_options.show_input_only() || CommandlineOptions::check_triang()) {
	  if (_options.compute_all()) {
	    if (CommandlineOptions::admissibles_restricted()
		||
		CommandlineOptions::check_nonregular_comp()
		||
		!CommandlineOptions::use_switch_tables()) {
	      
	      // in these cases, compute all elements in the group:
	      symmetries_reader.closure();
	      MessageStreams::verbose() << "... generated symmetry group of order "
					<< symmetries_reader.size() + 1 << std::endl;
	    }
	  }
	  else {
	    if (!CommandlineOptions::use_switch_tables()) {
	      
	      // in these cases, compute all elements in the group:
	      symmetries_reader.closure();
	      MessageStreams::verbose() << "... generated symmetry group of order "
					<< symmetries_reader.size() + 1 << std::endl;
	    }
	  }
	}
      }
      if (CommandlineOptions::preprocess_points() && _transformationptr) {
	symmetries_reader.transform(*_transformationptr);
      }
      if (CommandlineOptions::check_symmetries()) {
	MessageStreams::verbose() << "checking symmetries ..." << std::endl;
	make_cocircuits();
	if (!CheckSymmetries(*this, symmetries_reader)()) {
	  MessageStreams::verbose() << "read symmetries " << std::endl
				    << symmetries_reader.generators() << std::endl
				    << "not valid - exiting." << std::endl;
	  exit(1);
	}
	MessageStreams::verbose() << "... ok - done." << std::endl;
      }
    }
    else {
      
      // read symmetries anyway into dummy structure to be able to read seed later:
      SymmetryGroup dummy_symmetries(make_no());
      dummy_symmetries.read_generators(ist);
      MessageStreams::verbose() << "symmetry generators ignored." << std::endl;
    }
    _symmetriesptr = new SymmetryGroup(std::move(symmetries_reader)); // from now on, the symmetry data stays const
    MessageStreams::verbose() << "... done." << std::endl;

    // grind-off comments:
    ist >> commentgrinder;
    
    // try to read required symmetries:
    MessageStreams::verbose() << "checking for required symmetries for triangulations ..." << std::endl;
    SymmetryGroup required_symmetries_reader(make_no());
    if (CommandlineOptions::observe_required_symmetries()) {
      if (required_symmetries_reader.read(ist)) {
	MessageStreams::verbose() << "read "
				  << required_symmetries_reader.generators().size()
				  << " generators for required symmetries and generated group of order "
				  << required_symmetries_reader.size() + 1 << std::endl;
      }
      else {
	MessageStreams::verbose() << "no required symmetry generators found." << std::endl;
      }
      if (CommandlineOptions::preprocess_points() && _transformationptr) {
	required_symmetries_reader.transform(*_transformationptr);
      }
      if (CommandlineOptions::check_symmetries()) {
	MessageStreams::verbose() << "checking required symmetries ..." << std::endl;
	make_cocircuits();
	if (!CheckSymmetries(*this, required_symmetries_reader)()) {
	  MessageStreams::verbose() << "read required symmetries " << std::endl
				    << required_symmetries_reader.generators() << std::endl
				    << "not valid - exiting." << std::endl;
	  exit(1);
	}
	MessageStreams::verbose() << "... ok - done." << std::endl;
      }
    }
    else {
	
      // read required symmetries anyway into dummy structure to be able to read seed later:
      SymmetryGroup dummy_symmetries(make_no());
      dummy_symmetries.read_generators(ist);
      MessageStreams::verbose() << "required symmetry generators ignored." << std::endl;
    }
    _required_symmetriesptr = new SymmetryGroup(std::move(required_symmetries_reader)); // from now on, the required-symmetry data stays const
    MessageStreams::verbose() << "... done." << std::endl;

    if (_options.no_simplicial_complex()) {
      MessageStreams::verbose() << "no simplicial complexes needed, thus, no preprocessing of simplex tables" << std::endl;
    }
    else {

      // before the first SimplicialComplex is used, the preprocessing of
      // the simplex-index table has to be performed
      // (some algorithms rely on a special order):
      if (!_options.show_input_only()) {
	if (!CommandlineOptions::memopt() || _options.compute_all()) {
	  if (has_points()
	      && (CommandlineOptions::output_gkzvecs()
		  || CommandlineOptions::use_gkz()
		  || CommandlineOptions::use_volumes()
		  || CommandlineOptions::use_volume_order())) {
	    
	    // only in these cases, the volume table can be computed and is useful:
	    MessageStreams::verbose() << "computing volumes table ..." << std::endl;
	    make_voltable();
	    make_volume();
	    MessageStreams::verbose() << "... done." << std::endl;
	  }
	  if (has_voltable()) {
	    MessageStreams::verbose() << "preprocessing simplex table sorted according to command-line options for all full-dimensional simplices up to rank "
				      << std::min<parameter_type>(no(), rank() + 1) << " ..." << std::endl;
	    SimplicialComplex::reset_index_table();
	    SimplicialComplex::preprocess_index_table(no(), 0, std::min<parameter_type>(no(), rank() + 1), voltable(), true);
	  }
	  else {
	    if (CommandlineOptions::use_random_order()) {
	      MessageStreams::verbose() << "preprocessing simplex table sorted randomly for all simplices up to rank "
					<< rank() + 1 << " ..." << std::endl;
	    }
	    else {
	      MessageStreams::verbose() << "preprocessing simplex table sorted lexicographically for all full-dimensional simplices up to rank "
					<< std::min<parameter_type>(no(), rank() + 1) << " ..." << std::endl;
	    }
	    SimplicialComplex::reset_index_table();
	    SimplicialComplex::preprocess_index_table(no(), 0, std::min<parameter_type>(no(), rank() + 1), chiro(), true);
	  }
	}
	if (!CommandlineOptions::use_volume_order()
	    && !CommandlineOptions::use_volumes()
	    && !CommandlineOptions::use_gkz()
	    && !CommandlineOptions::output_gkzvecs()) {
	  
	  // volumes were only used to sort preprocessing simplex table; dump the volumes now:
	  remove_voltable();
	}

	// if any kind of parallel processing is demanded,
	// make SimplicialComplex thread-safe:
	if (CommandlineOptions::multithreading_needed()) {
	  SimplicialComplex::start_multithreading();
	}
      }
      if (!_options.compute_all()) {
	if (_options.no_seed()) {
	  MessageStreams::verbose() << "ignoring any seed triangulation" << std::endl;
	}
	else {
	  
	  // grind-off comments:
	  ist >> commentgrinder;
	  
	  // finally, try to read a seed (which is a SimplicialComplex):
	  MessageStreams::verbose() << "checking for seed triangulation ..." << std::endl;
	  SimplicialComplex seed_reader;
	  if (!seed_reader.read(ist) || seed_reader.empty()) { // empty seed encodes no seed
	    MessageStreams::verbose() << "... no non-empty seed given ..." << std::endl;
	  }
	  else {
	    MessageStreams::verbose() << "... found seed " << seed_reader << std::endl;
	    if (CommandlineOptions::check_triang()) {
	      MessageStreams::verbose() << "checking seed triangulation ..." << std::endl;
	      if (!CheckTriang(*this,
			       seed_reader,
			       symmetryptr_datapair(symmetries().stabilizer_ptrs(seed_reader)))()) {
		MessageStreams::verbose() << "read seed triangulation " << std::endl
					  << seed_reader << std::endl
					  << "not valid - exiting." << std::endl;
		exit(1);
	      }
	      MessageStreams::verbose() << "... done." << std::endl;
	    }
	    _seedptr = new SimplicialComplex(seed_reader); // only here, a seed is given in the input
	  }
	  MessageStreams::verbose() << "... done." << std::endl;
	}
      }
    }
    return ist;
  }
  
}; // namespace topcom

// eof ConfData.cc
