////////////////////////////////////////////////////////////////////////////////
// 
// CommandlineOptions.cc
//
//    produced: 04 Oct 1999 jr
//
////////////////////////////////////////////////////////////////////////////////

#include "CommandlineOptions.hh"

namespace topcom {

  // switches and parameters:
  bool           CommandlineOptions::_verbose                     = false;
  bool           CommandlineOptions::_debug                       = false;
  bool           CommandlineOptions::_preprocess_points           = false;
  bool           CommandlineOptions::_simpidx_symmetries          = false;
  bool           CommandlineOptions::_full_extension_check        = false;
  bool           CommandlineOptions::_no_extension_check          = false;
  bool           CommandlineOptions::_extension_check_first       = false;
  bool           CommandlineOptions::_memopt                      = false;
  bool           CommandlineOptions::_parallel_enumeration        = false;
  bool           CommandlineOptions::_workbuffercontrol           = true;
  bool           CommandlineOptions::_parallel_symmetries         = false;
  bool           CommandlineOptions::_use_random_order            = false;
  bool           CommandlineOptions::_use_volume_order            = false;
  bool           CommandlineOptions::_use_volumes                 = false;
  bool           CommandlineOptions::_use_gkz                     = false;
  bool           CommandlineOptions::_use_switch_tables           = false;
  bool           CommandlineOptions::_use_classified_symmetries   = false;
  bool           CommandlineOptions::_use_naive_symmetries        = false;
  bool           CommandlineOptions::_check                       = false;
  bool           CommandlineOptions::_neighborcount               = false;
  bool           CommandlineOptions::_input_chiro                 = false;
  bool           CommandlineOptions::_fine_only                   = false;
  bool           CommandlineOptions::_reduce_points               = false;
  bool           CommandlineOptions::_dont_add_points             = false;
  bool           CommandlineOptions::_dont_change_card            = false;
  bool           CommandlineOptions::_output_triangs              = false;
  bool           CommandlineOptions::_output_flips                = false;
  bool           CommandlineOptions::_output_asy                  = false;
  bool           CommandlineOptions::_output_stats                = false;
  bool           CommandlineOptions::_compute_all                 = false;
  bool           CommandlineOptions::_preprocess_chiro            = false;
  bool           CommandlineOptions::_check_regular               = false;
  bool           CommandlineOptions::_check_regular_early         = false;
  bool           CommandlineOptions::_check_unimodular            = false;
  bool           CommandlineOptions::_check_nonregular            = false;
  bool           CommandlineOptions::_check_sometimes             = false;
  bool           CommandlineOptions::_require_point               = false;
  bool           CommandlineOptions::_skip_orbitcount             = false;
  bool           CommandlineOptions::_ignore_symmetries           = false;
  bool           CommandlineOptions::_observe_required_symmetries = false;
  bool           CommandlineOptions::_symmetries_are_affine       = false;
  bool           CommandlineOptions::_symmetries_are_isometric    = false;
  bool           CommandlineOptions::_output_heights              = false;
  bool           CommandlineOptions::_use_soplex                  = false;
  bool           CommandlineOptions::_use_qsopt_ex                = false;
  bool           CommandlineOptions::_dump_status                 = false;
  bool           CommandlineOptions::_read_status                 = false;
  parameter_type CommandlineOptions::_required_point              = 0;
  size_type      CommandlineOptions::_report_frequency            = 100000UL;
  size_type      CommandlineOptions::_sometimes_frequency         = 1000000UL;
  size_type      CommandlineOptions::_chirocache                  = 12582917UL;
  size_type      CommandlineOptions::_localcache                  = 12582917UL;
  size_type      CommandlineOptions::_no_of_simplices             = 0UL;
  size_type      CommandlineOptions::_max_no_of_simplices         = 0UL;
  size_type      CommandlineOptions::_dump_frequency              = 10000000UL;
  size_type      CommandlineOptions::_min_nodebudget              = 1UL;
  size_type      CommandlineOptions::_max_nodebudget              = std::numeric_limits<size_type>::max();
  int            CommandlineOptions::_scale_nodebudget            = 100; // in percent
  int            CommandlineOptions::_no_of_threads               = 1;
  int            CommandlineOptions::_min_workbuffersize          = std::max<int>(std::thread::hardware_concurrency() - 1, 1);
  int            CommandlineOptions::_max_workbuffersize          = 2 * _min_workbuffersize;
  int            CommandlineOptions::_dump_rotations              = 2;
  int            CommandlineOptions::_no_of_symtables             = 1;
  const char*    CommandlineOptions::_input_file                  = 0;
  const char*    CommandlineOptions::_dump_file                   = "TOPCOM.dump";
  const char*    CommandlineOptions::_read_file                   = "TOPCOM.dump";
  const char*    CommandlineOptions::_asy_file                    = "TOPCOM_graphics.asy";
  const char*    CommandlineOptions::_stats_file                  = "TOPCOM_stats.txt";

  const char*    CommandlineOptions::_client                      = "TOPCOM unknown client";

  // auxiliary information:
  bool      CommandlineOptions::_lp_solver_needed          = false;
  int       CommandlineOptions::_user_no_of_threads        = -1;

  //polymake:Poly CommandlineOptions::_polymakeobj;

  void CommandlineOptions::init(const int argc, const char** argv) {

    // write TOPCOM header with version information:
    MessageStreams::forced().print_topcomheader();
    
    MessageStreams::forced() << "Evaluating Commandline Options ..." << std::endl;

    for (int i = 1; i < argc; ++i) {

      // print usage message:
      if ((strcmp(argv[i], "--help") == 0) || (strcmp(argv[i], "-h") == 0)) {
	MessageStreams::result() << "--help or -h: \t help requested:" << std::endl;

	MessageStreams::result() << "usage:" << std::endl;
	MessageStreams::result() << argv[0] << "[options]" << std::endl;
	MessageStreams::result() << "where the input is read from stdin" << std::endl;
	MessageStreams::result() << "and the output is written to stdout." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options concerning input/output from files:" << std::endl;
	MessageStreams::result() << "-i [filename]        : read input from [filename] instead of stdin." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options concerning output of information:" << std::endl;
	MessageStreams::result() << "-h or --help         : print this help message" << std::endl;
	MessageStreams::result() << "-v                   : write verbose information to stderr." << std::endl;
	MessageStreams::result() << "--reportfrequency [n]: report every [n]th generated object." << std::endl;
	MessageStreams::result() << "-d                   : write debug information to stderr." << std::endl;
	MessageStreams::result() << "--heights            : write height vectors for triangulations to stdout (implies --regular)." 
		  << std::endl;
	MessageStreams::result() << "--flips              : write flips as pairs of triangulation IDs to stdout." 
		  << std::endl;
	MessageStreams::result() << "--asy                : write asymptote graphics commands into file (in rank-3 triangulations, points are drawn as well)."
		  << std::endl;
	MessageStreams::result() << "--stats              : write some statistics into file."
		  << std::endl;
	MessageStreams::result() << std::endl;
     
	MessageStreams::result() << "options for checking input:" << std::endl;
	MessageStreams::result() << "--checktriang        : check any given triangulations for correctness." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options for reporting properties of discovered triangulations:" << std::endl;
	MessageStreams::result() << "--flipdeficiency     : report flip deficiency in triangulations to stderr." << std::endl;
	MessageStreams::result() << "--findregular [n]    : check for regularity every [n]th triangulation and exit if regular." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options concerning which triangulations are output (no influence on exploration):" << std::endl;
	MessageStreams::result() << "--noorbitcount       : skip the enumaration of orbits (total number of objects is unavailable)" << std::endl;
	MessageStreams::result() << "--cardinality [n]    : count/output only triangulations of cardinality [n]." << std::endl;
	MessageStreams::result() << "--maxcardinality [n] : count/output only triangulations of cardinality at most [n]." << std::endl;
	MessageStreams::result() << "--nonregular         : count/output only non-regular triangulations." << std::endl;
	MessageStreams::result() << "--unimodular         : count/output only unimodular triangulations (assumes isometric symmetries; correct only if there is a unimodular simplex)." << std::endl;
	MessageStreams::result() << "--requirepoint [k]   : allow only simplices containing point [k]." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options concerning which triangulations are explored:" << std::endl;
	MessageStreams::result() << "--regular            : consider only regular triangulations" << std::endl;
	MessageStreams::result() << "--regularearly       : consider only regular partial triangulations (implies --regular)" << std::endl;
	MessageStreams::result() << "--noinsertion        : never use a point that is unused in the seed triangulation." << std::endl;
	MessageStreams::result() << "--reducepoints       : try to remove the number of use points, reported to stderr." << std::endl;
	MessageStreams::result() << "--keepcard           : never change the cardinality of triangulations by flipping." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options concerning symmetries:" << std::endl;
	MessageStreams::result() << "--affinesymmetries   : assume that given symmetries are affine." << std::endl;
	MessageStreams::result() << "--isometricsymmetries: assume that given symmetries are isometric." << std::endl;
	MessageStreams::result() << "--nosymmetries       : ignore symmetries." << std::endl;
	MessageStreams::result() << "--triangsymmetries   : observe symmetries required for triangulations." << std::endl;
	MessageStreams::result() << "--notriangsymmetries : ignore symmetries required for triangulations (default)." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options for dumping and reading the status of an interrupted computation (only for flip graph exploration):" << std::endl;
	MessageStreams::result() << "--dump               : dump status of previous computation into file" << std::endl;
	MessageStreams::result() << "--dumpfile [filename]: set dump base file name to [filename] (default: TOPCOM.dump)" << std::endl;
	MessageStreams::result() << "--dumpfrequency [n]  : dump each [n]th completed BFS round (default: 1)" << std::endl;
	MessageStreams::result() << "--dumprotations [n]  : dump into [n] rotating files (default: 2)" << std::endl;
	MessageStreams::result() << "--read               : read status of previous computation from file" << std::endl;
	MessageStreams::result() << "--readfile [filename]: set dump file name to read to [filename] (default: TOPCOM.dump)" << std::endl;
	MessageStreams::result() << std::endl;
      

	MessageStreams::result() << "options concerning internal behaviour:" << std::endl;
	MessageStreams::result() << "--memopt             : try to reduce memory consumption." << std::endl;
	MessageStreams::result() << "--usegkz             : use GKZ vectors as a finger print in symmetry handling (only for points with isometric symmetries)." << std::endl;
	MessageStreams::result() << "--usenaivesymmetries : use naive full scan of all symmetries for symmetry handling." << std::endl;
	MessageStreams::result() << "--useswitchtables    : use Jordan-Joswig-Kastner switch tables for symmetry handling." << std::endl;
	MessageStreams::result() << "--usesymmetrytables  : use tables of classified symmetries for symmetry handling." << std::endl;
	MessageStreams::result() << "--symtables [n]      : use [n] symtables for preprocessing symmetries." << std::endl;
	MessageStreams::result() << "--preprocesschiro    : preprocess the chirotope (default for points2[n]alltriangs)." << std::endl;
	MessageStreams::result() << "--preprocesspoints   : heuristically transform points (only relevant for (co)circuit enumeration)." << std::endl;
	MessageStreams::result() << "--simpidxsymmetries  : preprocess a representation of the symmetry group on simplex indices (only relevant for triangulation enumeration)." << std::endl;
	MessageStreams::result() << "--userandomorder     : sort simplices in preprocessed index table randomly (only for points with isometric symmetries)." << std::endl;
	MessageStreams::result() << "--usevolumeorder     : sort simplices in preprocessed index table by volume (only for points with isometric symmetries)." << std::endl;
	MessageStreams::result() << "--usevolumes         : use volumes to check extendability of partial triangulations (only for points with isometric symmetries)." << std::endl;
	MessageStreams::result() << "--fullextensioncheck : put more effort in the check of extendability of a partial triangulation." << std::endl;
	MessageStreams::result() << "--noextensioncheck   : skip the check of extendability of a partial triangulation." << std::endl;
	MessageStreams::result() << "--extensioncheckfirst: check extendability prior to symmetry." << std::endl;
	MessageStreams::result() << "--chirocache [n]     : set the chirotope cache to [n] elements." << std::endl;
	MessageStreams::result() << "--localcache [n]     : set the cache for local data to [n] elements ." << std::endl;
	MessageStreams::result() << "--qsopt_ex           : use QSopt_ex for regularity checks." << std::endl;
	MessageStreams::result() << "--soplex             : use soplex for regularity checks." << std::endl;
	MessageStreams::result() << std::endl;

	MessageStreams::result() << "options concerning multi-threading:" << std::endl;
	MessageStreams::result() << "--parallelenumeration: use multiple threads for enumeration." << std::endl;
	MessageStreams::result() << "--workbuffercontrol  : control interrupt of workers by size of the current workbuffer." << std::endl;
	MessageStreams::result() << "--nodebudgeting      : control interrupt of workers by node budget." << std::endl;
	MessageStreams::result() << "--parallelsymmetries : use multiple threads for symmetry checks." << std::endl;
	MessageStreams::result() << "--threads [n]        : use [n] threads (if possible)." << std::endl;      
	MessageStreams::result() << "--minnodebudget [n]  : let each thread process at least [n] nodes (to avoid multi-threading overhead)." << std::endl;      
	MessageStreams::result() << "--maxnodebudget [n]  : let each thread process at most [n] nodes (to avoid thread starving)." << std::endl;      
	MessageStreams::result() << "--scalenodebudget [n]: scale the default node budget by [n] percent (n integer)" << std::endl;      
	MessageStreams::result() << "--minworkbuffer [n]  : (unused) try to keep the work buffer above [n] work packages (to balance overhead and thread starving)." << std::endl;      
	MessageStreams::result() << "--maxworkbuffer [n]  : (unused) try to keep the work buffer below [n] work packages (to balance overhead and thread starving)." << std::endl;      
	MessageStreams::result() << std::endl;
	exit(0);
      }

      // output options:
      else if (strcmp(argv[i], "-i") == 0) {
	++i;
	if (argc >i) {
	  _input_file = argv[i];
	}
	FILE* f = freopen(_input_file, "r", stdin);

	MessageStreams::forced() << " -i                  : input read from " << _input_file << std::endl;
      }
      else if (strcmp(argv[i], "-v") == 0) {
	_verbose = true;

	MessageStreams::forced() << " -v                  : verbose output activated" << std::endl;
      }
      else if (strcmp(argv[i], "--reportfrequency") == 0) {
	++i;
	if (argc > i) {
	  _report_frequency = (size_type)atol(argv[i]);
	  _verbose = true;

	  MessageStreams::forced() << "--reportfrequency    : report every " << _report_frequency << "th new found object (implies '-v' = verbose)" << std::endl;
	}
      }
      else if (strcmp(argv[i], "-d") == 0) {
	MessageStreams::forced() << " -d                  : debug output activated" << std::endl;

	_debug = true;
      }
      else if (strcmp(argv[i], "--heights") == 0) {
	MessageStreams::forced() << "--heights            : output of defining heights activated" << std::endl;

	_output_heights = true;
	_check_sometimes = false;
	_check_regular = true;
	_lp_solver_needed = true;
      }

      else if (strcmp(argv[i], "--flips") == 0) {
	MessageStreams::forced() << "--flips              : output of flips activated" << std::endl;

	_output_flips = true;
      }
      else if (strcmp(argv[i], "--asy") == 0) {
	_output_asy = true;

	MessageStreams::forced() << "--asy                : write graphics output (in rank-3 triangulations, points are drawn as well)" << std::endl;
      }
      else if (strcmp(argv[i], "--asyfile") == 0) {
	++i;
	if (argc > i) {
	  _asy_file = argv[i];
	  _output_asy = true;

	  MessageStreams::forced() << "--asyfile            : graphics output to file " << _asy_file << std::endl;
	}
      }
      else if (strcmp(argv[i], "--stats") == 0) {
	_output_stats = true;

	MessageStreams::forced() << "--stats              : write statistics output" << std::endl;
      }
      else if (strcmp(argv[i], "--statsfile") == 0) {
	++i;
	if (argc > i) {
	  _stats_file = argv[i];
	  _output_stats = true;

	  MessageStreams::forced() << "--statsfile          : statistics output to file " << _stats_file << std::endl;
	}
      }

      // options for checking input:
      else if (strcmp(argv[i], "--checktriang") == 0) {
	MessageStreams::forced() << "--checktriangs       : check seed triangulation activated" << std::endl;

	_check = true;
      }

      // options for reporting properties of discovered triangulations:
      else if (strcmp(argv[i], "--flipdeficiency") == 0) {
	MessageStreams::forced() << "--flipdeficiency     : search for flip deficiency activated" << std::endl;

	_neighborcount = true;
      }
      else if (strcmp(argv[i], "--findregular") == 0) {
	if (_check_regular) {
	  MessageStreams::forced() << "--findregular cannot be used with --regular, ignoring --findregular." << std::endl;
	}
	else {
	  _check_regular = false;
	  _check_sometimes = true;
	  _lp_solver_needed = true;
	  ++i;
	  if (argc > i) {
	    _sometimes_frequency = (size_type)atol(argv[i]);
	  }

	  MessageStreams::forced() << "--findregular      : check regularity every " << _sometimes_frequency << "th triangulation and exit if regular activated" << std::endl;
	}
      }

      // options concerning which triangulations are output (no influence on exploration):
      else if (strcmp(argv[i], "--cardinality") == 0) {
	++i;
	if (argc > i) {
	  _no_of_simplices = (size_type)atol(argv[i]);
	}

	MessageStreams::forced() << "--cardinality        : restrict to triangulations with " << _no_of_simplices << " simplices" << std::endl;
      }

      else if (strcmp(argv[i], "--maxcardinality") == 0) {
	++i;
	if (argc > i) {
	  _max_no_of_simplices = (size_type)atol(argv[i]);
	}

	MessageStreams::forced() << "--maxcardinality     : restrict to triangulations with at most " << _max_no_of_simplices << " simplices" << std::endl;
      }

      else if (strcmp(argv[i], "--nonregular") == 0) {
	MessageStreams::forced() << "--nonregular         : search for non-regular triangulations activated" << std::endl;

	_check_nonregular = true;
	_lp_solver_needed = true;
      }

      else if (strcmp(argv[i], "--unimodular") == 0) {
	MessageStreams::forced() << "--unimodular         : restrict to unimodular triangulations (assumes isometric symmetries; correct only if there is a unimodular simplex)" << std::endl;

	_check_unimodular = true;
	_symmetries_are_isometric = true;
      }

      else if (strcmp(argv[i], "--requirepoint") == 0) {
	++i;
	if (argc > i) {
	  _require_point = true;
	  _required_point = (parameter_type)atol(argv[i]);
	}

	MessageStreams::forced() << "--requirepoint [k]   : allow only simplices containing point " << _required_point << std::endl;
      }

      // options concerning which triangulations are explored:
      else if (strcmp(argv[i], "--regular") == 0) {
	if (_check_sometimes) {
	  MessageStreams::forced() << "--regular cannot be used with --frequency, ignoring --regular." << std::endl;
	}
	else {
	  _check_sometimes = false;
	  _check_regular = true;
	  _lp_solver_needed = true;

	  MessageStreams::forced() << "--regular            : check for regular triangulations activated" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--regularearly") == 0) {
	_check_regular = true;
	_check_regular_early = true;
	_lp_solver_needed = true;

	MessageStreams::forced() << "--regularearly       : check for regular partial triangulations activated" << std::endl;
      }
      else if (strcmp(argv[i], "--reducepoints") == 0) {
	_reduce_points = true;

	MessageStreams::forced() << "--reducepoints       : reduce points heuristics activated" << std::endl;
      }
      else if (strcmp(argv[i], "--noinsertion") == 0) {
	_dont_add_points = true;

	MessageStreams::forced() << "--noinsertion        : never add points activated" << std::endl;
      }
      else if (strcmp(argv[i], "--keepcard") == 0) {
	_dont_change_card = true;

	MessageStreams::forced() << "--keepcard           : never change cardinality of triangulations by flipping activated" << std::endl;
      }

      // options concerning symmetries:
      else if (strcmp(argv[i], "--affinesymmetries") == 0) {
	_symmetries_are_affine = true;

	MessageStreams::forced() << "--affinesymmetries   : assumption that symmetries are affine activated" << std::endl;
      }
      else if (strcmp(argv[i], "--isometricsymmetries") == 0) {
	_symmetries_are_affine = true;
	_symmetries_are_isometric = true;

	MessageStreams::forced() << "--isometricsymmetries: assumption that symmetries are isometric activated" << std::endl;
      }
      else if (strcmp(argv[i], "--noorbitcount") == 0) {
	_skip_orbitcount = true;

	MessageStreams::forced() << "--noorbitcount       : skipping traversal of orbits activated" << std::endl;
      }
      else if (strcmp(argv[i], "--nosymmetries") == 0) {
	_ignore_symmetries = true;

	MessageStreams::forced() << "--nosymmetries       : ignoring symmetries activated" << std::endl;
      }
      else if (strcmp(argv[i], "--triangsymmetries") == 0) {
	_observe_required_symmetries = true;

	MessageStreams::forced() << "--triangsymmetries   : observing symmetries required for triangulations activated" << std::endl;
      }

      // options concerning internals:
      else if (strcmp(argv[i], "--preprocesspoints") == 0) {
	_preprocess_points = true;

	MessageStreams::forced() << "--preprocesspoints   : heuristics preprocessing of point matrix activated" << std::endl;
      }
      else if (strcmp(argv[i], "--preprocesschiro") == 0) {
	_preprocess_chiro = true;

	MessageStreams::forced() << "--preprocesschiro    : preprocessing of chirotope activated" << std::endl;
      }
      else if (strcmp(argv[i], "--simpidxsymmetries") == 0) {
	_simpidx_symmetries = true;

	MessageStreams::forced() << "--simpidxsymmetries  : preprocessing of a representation of the symmetry group on simplex indices activated" << std::endl;
      }
      else if (strcmp(argv[i], "--userandomorder") == 0) {
	_use_random_order = true;

	MessageStreams::forced() << "--userandomorder     : sort simplices in preprocessed index table randomly" << std::endl;
      }
      else if (strcmp(argv[i], "--usevolumeorder") == 0) {
	_use_volume_order = true;

	MessageStreams::forced() << "--usevolumeorder     : sort simplices in preprocessed index table by volume" << std::endl;
      }
      else if (strcmp(argv[i], "--usevolumes") == 0) {
	_use_volumes = true;

	MessageStreams::forced() << "--usevolumes         : use volumes to check extendability of partial triangulations" << std::endl;
      }
      else if (strcmp(argv[i], "--fullextensioncheck") == 0) {
	_full_extension_check = true;

	MessageStreams::forced() << "--fullextensioncheck : full extension check for partial triangulations activated" << std::endl;
      }
      else if (strcmp(argv[i], "--noextensioncheck") == 0) {
	_no_extension_check = true;

	MessageStreams::forced() << "--noextensioncheck   : skip extension check for partial triangulations activated" << std::endl;
      }
      else if (strcmp(argv[i], "--extensioncheckfirst") == 0) {
	_extension_check_first = true;

	MessageStreams::forced() << "--extensioncheckfirst: extension check prior to symmetry check activated" << std::endl;
      }

      else if (strcmp(argv[i], "--memopt") == 0) {
	_memopt = true;

	MessageStreams::forced() << "--memopt             : higher memory efficiency activated" << std::endl;
      }
      else if (strcmp(argv[i], "--parallelenumeration") == 0) {
	_parallel_enumeration = true;
	_no_of_threads = std::max<int>(std::thread::hardware_concurrency() - 1, 1);

	MessageStreams::forced() << "--parallelenumeration: multi-threading for enumeration activated" << std::endl;
      }
      else if (strcmp(argv[i], "--workbuffercontrol") == 0) {
	_workbuffercontrol = true;

	MessageStreams::forced() << "--workbuffercontrol  : control of worker interrupt by work buffer activated" << std::endl;
      }
      else if (strcmp(argv[i], "--nodebudgeting") == 0) {
	_workbuffercontrol = false;

	MessageStreams::forced() << "--nodebudgeting      : control of worker interrupt by node budget" << std::endl;
      }
      else if (strcmp(argv[i], "--parallelsymmetries") == 0) {
	if (!_ignore_symmetries) {
	  _parallel_symmetries = true;
	  _no_of_threads = std::max<int>(std::thread::hardware_concurrency() - 1, 1);

	  MessageStreams::forced() << "--parallelsymmetries : multi-threading for symmetry checks activated" << std::endl;
	}
	else {
	  MessageStreams::forced() << "--parallelsymmetries : multi-threading for symmetry checks ingnored because of --nosymmetries" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--threads") == 0) {
	++i;
	if (argc > i) {
	  _user_no_of_threads = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--threads            : no of threads set to " << _user_no_of_threads << " threads" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--minnodebudget") == 0) {
	++i;
	if (argc > i) {
	  _min_nodebudget = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--minnodebudget      : min node budget set to " << _min_nodebudget << " nodes" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--maxnodebudget") == 0) {
	++i;
	if (argc > i) {
	  _max_nodebudget = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--maxnodebudget      : max node budget set to " << _max_nodebudget << " nodes" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--scalenodebudget") == 0) {
	++i;
	if (argc > i) {
	  _scale_nodebudget = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--scalenodebudget    : scaling factor of node budget set to " << _scale_nodebudget << " percent" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--minworkbuffer") == 0) {
	++i;
	if (argc > i) {
	  _min_workbuffersize = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--minworkbuffer      : min work buffer size set to " << _min_workbuffersize << " work packages" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--maxworkbuffer") == 0) {
	++i;
	if (argc > i) {
	  _max_workbuffersize = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--maxworkbuffer      : max work buffer size set to " << _max_workbuffersize << " work packages" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--usegkz") == 0) {
	_use_gkz = true;

	MessageStreams::forced() << "--usegkz             : use GKZ vectors as a finger print in symmetry handling (only for points with isometric symmetries)." << std::endl;
      }
      else if (strcmp(argv[i], "--usenaivesymmetries") == 0) {
	_use_naive_symmetries = true;

	MessageStreams::forced() << "--usenaivesymmeries  : use of naive full scan of all symmetries for symmetry handling activated" << std::endl;
      }
      else if (strcmp(argv[i], "--useswitchtables") == 0) {
	_use_switch_tables = true;

	MessageStreams::forced() << "--useswitchtables    : use of Jordan-Joswig-Kastner switch tables activated" << std::endl;
      }
      else if (strcmp(argv[i], "--usesymmetrytables") == 0) {
	_use_switch_tables = false;
	_use_classified_symmetries = true;

	MessageStreams::forced() << "--usesymmetrytables  : use of tables of classified symmetries for symmetry handling activated" << std::endl;
      }
      else if (strcmp(argv[i], "--symtables") == 0) {
	++i;
	if (argc > i) {
	  _no_of_symtables = std::max<int>(1, (size_type)atol(argv[i]));

	  MessageStreams::forced() << "--symtables          : no of symmetry tables set to " << _no_of_symtables << " entries" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--chirocache") == 0) {
	++i;
	if (argc > i) {
	  _chirocache = (size_type)atol(argv[i]);

	  MessageStreams::forced() << "--chirocache         : cache for lazy chirotope set to " << _chirocache << " elements" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--localcache") == 0) {
	++i;
	if (argc > i) {
	  _localcache = (size_type)atol(argv[i]);

	  MessageStreams::forced() << "--localcache         : cache for local data set to " << _localcache << " elements" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--dumpfrequency") == 0) {
	++i;
	if (argc > i) {
	  _dump_frequency = (size_type)atol(argv[i]);
	  _dump_status = true;

	  MessageStreams::forced() << "--dumpfrequency      : dump every " << _dump_frequency << "th processed object" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--dumprotations") == 0) {
	++i;
	if (argc > i) {
	  _dump_rotations = (size_type)atol(argv[i]);
	  _dump_status    = true;

	  MessageStreams::forced() << "--dumprotations      : rotate dump into " << _dump_rotations << " many dump files" << std::endl;
	}
      }
      else if (strcmp(argv[i], "--dumpfile") == 0) {
	++i;
	if (argc > i) {
	  _dump_file = argv[i];
	  _dump_status = true;

	  MessageStreams::forced() << "--dumpfile           : dump to file " << _dump_file << std::endl;
	}
      }
      else if (strcmp(argv[i], "--dump") == 0) {
	_dump_status = true;

	MessageStreams::forced() << "--dump               : dump status of computation into file activated" << std::endl;
      }
      else if (strcmp(argv[i], "--readfile") == 0) {
	++i;
	if (argc > i) {
	  _read_file = argv[i];
	  _read_status = true;

	  MessageStreams::forced() << "--readfile           : read from file " << _read_file << std::endl;
	}
      }
      else if (strcmp(argv[i], "--read") == 0) {
	_read_status = true;

	MessageStreams::forced() << "--read               : read status from file" << std::endl;
      }
      else if (strcmp(argv[i], "--soplex") == 0) {
#ifdef HAVE_LIBSOPLEX      
	_use_soplex = true;

	MessageStreams::forced() << "--soplex             : soplex activated" << std::endl;
#else
	MessageStreams::forced() << "--soplex             : ignored (soplex support was not configured for this binary)" << std::endl;
#endif
      }
      else if (strcmp(argv[i], "--qsoptex") == 0) {
#ifdef HAVE_LIBQSOPTEX     
	_use_qsopt_ex = true;

	MessageStreams::forced() << "--qsoptex            : QSopt_ex activated" << std::endl;
#else
	MessageStreams::forced() << "--qsoptex            : ignored (QSOpt_ex support was not configured for this binary)" << std::endl;
#endif
      }

      // some options that are not documented:
      else if (strcmp(argv[i], "-A") == 0) {
	_compute_all = true;
      }
      else if (strcmp(argv[i], "-C") == 0) {
	_input_chiro = true;
      }
      else if (strcmp(argv[i], "-F") == 0) {
	_fine_only = true;
      }
      else if (strcmp(argv[i], "-O") == 0) {
	_output_triangs = true;
      }
      else if (strcmp(argv[i], "-E") == 0) {
	_output_flips = true;
      }
      else {
	MessageStreams::forced() << "unknown option " << argv[i] << " - exiting" << std::endl;
	exit(1);
      }
    }

    // collect information that should not depend on order of options:
    if (_user_no_of_threads > 0) {
      _no_of_threads = _user_no_of_threads;
    }
    _min_workbuffersize = _no_of_threads;

    if ((_no_of_simplices > 0) && (_max_no_of_simplices > 0)) {
      _max_no_of_simplices = 0;
      MessageStreams::forced() << "--maxcardinality [n] : ignored because it conflicts with --cardinality [n]" << std::endl;
    }

    // sanity checks:

    if (_read_status) {
      if (!std::filesystem::exists(_read_file)) {
	MessageStreams::forced() << "--read[file]         : ignored because file " << _read_file << " not found" << std::endl;
	_read_status = false;
      }
    }

    if (_require_point) {
      if ((strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)
	  &&
	  (strstr(argv[0], "points2triangs") == 0)
	  &&
	  (strstr(argv[0], "points2ntriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2mintriang") == 0)
	  &&
	  (strstr(argv[0], "chiro2triangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2ntriangs") == 0)) {
	MessageStreams::forced() << "--requirepoint [k]   : ignored because unsupported by " << argv[0] << std::endl;
	_require_point = false;
	_required_point = 0;
      }

    }
    
    if (_parallel_symmetries && _ignore_symmetries) {

      // if symmetries are ignored, there is no point in parallel processing symmetries:
      _parallel_symmetries = false;
      MessageStreams::forced() << "--parallelsymmetries : ignored because of --nosymmetries" << std::endl;
    }

    if (_use_gkz && !_symmetries_are_isometric) {
      
      // gkz is not invariant w.r.t. non-isometric symmetries:
      MessageStreams::forced() << "--usegkz             : ignored because it requires --isometricsymmetries" << std::endl;
      _use_gkz = false;
    }
    
    if (_use_volumes && !_symmetries_are_isometric) {

      // volume is not invariant w.r.t. non-isometric symmetries:
      MessageStreams::forced() << "--usevolumes         : ignored because it requires --isometricsymmetries" << std::endl;
      _use_volumes = false;
    }

    if (_use_volume_order && !_symmetries_are_isometric) {

      // volume is not invariant w.r.t. non-isometric symmetries:
      MessageStreams::forced() << "--usevolumeorder     : ignored because it requires --isometricsymmetries" << std::endl;
      _use_volume_order = false;
    }

    if (_simpidx_symmetries && _memopt) {
      MessageStreams::forced() << "--simpidxsymmetries  : ignored because it conflicts with --memopt" << std::endl;
      _simpidx_symmetries = false;
    }
    if (_use_switch_tables) {
      if ((strstr(argv[0], "check") == 0)
	  &&
	  (strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)
	  &&
	  (strstr(argv[0], "points2ncircuits") == 0)
	  &&
	  (strstr(argv[0], "points2ncocircuits") == 0)
	  &&
	  (strstr(argv[0], "points2circuits") == 0)
	  &&
	  (strstr(argv[0], "points2cocircuits") == 0)
	  &&
	  (strstr(argv[0], "chiro2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2mintriang") == 0)
	  &&
	  (strstr(argv[0], "chiro2ncircuits") == 0)
	  &&
	  (strstr(argv[0], "chiro2ncocircuits") == 0)
	  &&
	  (strstr(argv[0], "chiro2circuits") == 0)
	  &&
	  (strstr(argv[0], "chiro2cocircuits") == 0)) {
	MessageStreams::forced() << "--useswitchtables    : ignored because unsupported by " << argv[0] << std::endl;
	_use_switch_tables = false;
      }
            
      else if (!_simpidx_symmetries) {
	if ((strstr(argv[0], "check") == 0)
	    &&
	    (strstr(argv[0], "points2ncircuits") == 0)
	    &&
	    (strstr(argv[0], "points2ncocircuits") == 0)
	    &&
	    (strstr(argv[0], "points2circuits") == 0)
	    &&
	    (strstr(argv[0], "points2cocircuits") == 0)
	    &&
	    (strstr(argv[0], "chiro2ncircuits") == 0)
	    &&
	    (strstr(argv[0], "chiro2ncocircuits") == 0)
	    &&
	    (strstr(argv[0], "chiro2circuits") == 0)
	    &&
	    (strstr(argv[0], "chiro2cocircuits") == 0)) {
	  MessageStreams::forced() << "--useswitchtables    : ignored because it requires --simpidxsymmetries for " << argv[0] << std::endl;
	  _use_switch_tables = false;
	}
      }

      else if (_parallel_symmetries) {
	
	// switch tables do not support parallel symmetry processing:
	_parallel_symmetries = false;
	MessageStreams::forced() << "--parallelsymmetries : ignored because it conflicts with --useswitchtables" << std::endl;
      }
    }
    
    if (_output_asy) {
      if ((strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)
	  &&
	  (strstr(argv[0], "points2ncircuits") == 0)
	  &&
	  (strstr(argv[0], "points2ncocircuits") == 0)
	  &&
	  (strstr(argv[0], "points2circuits") == 0)
	  &&
	  (strstr(argv[0], "points2cocircuits") == 0)) {
	MessageStreams::forced() << "--asy                : ignored because unsupported by " << argv[0] << std::endl;
	_output_asy = false;
      }
    }

    if (_dump_status) {
      if ((strstr(argv[0], "points2ntriangs") == 0)
	  &&
	  (strstr(argv[0], "points2triangs") == 0)
	  &&
	  (strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)
	  &&
	  (strstr(argv[0], "chiro2ntriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2triangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2mintriang") == 0)
	  &&
	  (strstr(argv[0], "points2ncircuits") == 0)
	  &&
	  (strstr(argv[0], "points2ncocircuits") == 0)
	  &&
	  (strstr(argv[0], "points2circuits") == 0)
	  &&
	  (strstr(argv[0], "points2cocircuits") == 0)) {
	MessageStreams::forced() << "--dump               : ignored because unsupported by " << argv[0] << std::endl;
	_dump_status = false;
      }
    }
    
    if (_observe_required_symmetries) {
      if ((strstr(argv[0], "points2ntriangs") == 0)
	  &&
	  (strstr(argv[0], "points2triangs") == 0)
	  &&
	  (strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)
	  &&
	  (strstr(argv[0], "chiro2ntriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2triangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2mintriang") == 0)) {
	MessageStreams::forced() << "--triangsymmetries   : ignored because unsupported by " << argv[0] << std::endl;
	_observe_required_symmetries = false;
      }
    }
    
    if (_parallel_enumeration) {
      if ((strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)
	  &&
	  (strstr(argv[0], "chiro2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "chiro2mintriang") == 0)
	  &&
	  (strstr(argv[0], "points2circuits") == 0)
	  &&
	  (strstr(argv[0], "points2cocircuits") == 0)
	  &&
	  (strstr(argv[0], "points2ncircuits") == 0)
	  &&
	  (strstr(argv[0], "points2ncocircuits") == 0)) {
	MessageStreams::forced() << "--parallelenumeration: ignored because unsupported by " << argv[0] << std::endl;
	_parallel_enumeration = false;
      }
    }

    if (_check_regular_early) {
      if ((strstr(argv[0], "points2alltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2allfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nalltriangs") == 0)
	  &&
	  (strstr(argv[0], "points2nallfinetriangs") == 0)
	  &&
	  (strstr(argv[0], "points2mintriang") == 0)) {
	MessageStreams::forced() << "--regularearly       : ignored because unsupported by " << argv[0] << std::endl;
	_check_regular_early = false;
      }
    }

    if (_check_regular_early && !_symmetries_are_affine) {
      MessageStreams::forced() << "--regularearly       : ignored because it requires --affinesymmetries" << std::endl;
      _check_regular_early = false;
    }
    
    if (_use_qsopt_ex && _parallel_enumeration) {
      MessageStreams::forced() << "--parallelenumeration: ignored because qsopt_ex is not thread-safe" << std::endl;
      _parallel_enumeration = false;
    }

    _client = argv[0];
    MessageStreams::forced() << "... done." << std::endl;

    // finally, initialize the verbose and debug message handlers according to options:
    if (CommandlineOptions::verbose()) {
      MessageStreams::verbose().activate(std::cerr);
    }
    if (CommandlineOptions::debug()) {
      MessageStreams::verbose().activate(std::cerr);
      MessageStreams::debug().activate(std::cerr);
    }

  }

}; // namespace topcom

// eof CommandlineOptions.cc
