////////////////////////////////////////////////////////////////////////////////
// 
// Cocircuits.cc
//
//    produced: 12/09/2006 jr
// 
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <ctype.h>
#include <string.h>
#include <assert.h>

#include "Cocircuits.hh"

namespace topcom {

  // Cocircuit:
  const std::string Cocircuit::_type_name = "cocircuit";

  Cocircuit::Cocircuit(const Chirotope& chiro, const dependent_set_type& coplanar_set) {
    assert(coplanar_set.card() == chiro.rank() - 1);
    basis_type basis(coplanar_set);
    int pm(0);
    bool found_nonzero(false);
    LabelSet universe(0, chiro.no());
    for (LabelSet::iterator iter = universe.begin();
	 iter != universe.end();
	 ++iter) {
      if (coplanar_set.contains(*iter)) {
	pm = -pm;
      }
      else {
	basis += *iter;
	MessageStreams::debug() << message::lock
				<< "chiro(" << basis << ") = " << std::endl
				<< message::unlock;
	int chiro_on_basis = chiro(basis);
	MessageStreams::debug() << message::lock
				<< chiro_on_basis << std::endl
				<< message::unlock;
	if (!found_nonzero && (chiro_on_basis != 0)) {
	  found_nonzero = true;
	  pm = chiro_on_basis;
	  first += *iter;
	}
	else {
	  if (chiro_on_basis * pm > 0) {
	    first += *iter;
	  }
	  else if (chiro_on_basis * pm < 0) {
	    second += *iter;
	  }
	}
	basis -= *iter;
      }
    }
  }

  // Cocircuits:
  Cocircuits::Cocircuits(const Chirotope& chiro, const bool only_positive) : 
    cocircuits_data(), _no(chiro.no()), _rank(chiro.rank()) {
    size_type count(0);
    // if (_no == _rank) {
    //   return;
    // }
    Permutation coplanar_perm(_no, _rank - 1);
    do {
      dependent_set_type coplanar_set(coplanar_perm);
      if (CommandlineOptions::debug()) {
	MessageStreams::debug() << message::lock
				<< "computing";
	if (only_positive) {
	  MessageStreams::debug() << " positive ";
	}
	MessageStreams::debug() << " sign vectors from spanning " 
				<< _rank - 1 << "-subset " 
				<< coplanar_set
				<< " ..."
				<< std::endl
				<< message::unlock;
      }
      Cocircuit cocircuit(chiro, coplanar_set);
      MessageStreams::debug() << message::lock
			      << "... done." << '\n'
			      << "result: " << cocircuit << std::endl
			      << message::unlock;
      if ((only_positive) && !cocircuit.first.empty() && !cocircuit.second.empty()) {
	continue;
      }
      if (!cocircuit.first.empty() || !cocircuit.second.empty()) {
	(*this)[cocircuit.first + cocircuit.second] = cocircuit;
	if (++count % 10000 == 0) {
	  MessageStreams::verbose() << message::lock
				    << size();
	  if (only_positive) {
	    MessageStreams::verbose() << " positive";
	  }
	  MessageStreams::verbose() << " cocircuits computed so far." << std::endl
				    << message::unlock;
	}
      }
    } while (coplanar_perm.lexnext());
    MessageStreams::verbose() << message::lock
			      << size();
    if (only_positive) {
      MessageStreams::verbose() << " positive";
    }
    MessageStreams::verbose() << " cocircuits in total." << std::endl
			      << message::unlock;
  }

  // stream output/input:
  std::ostream& Cocircuits::print_string(std::ostream& ost) const {
    ost << message::lock;
    ost << _no << ',' << _rank << ':' << std::endl;
    ost << '{' << std::endl;
    for (const_iterator iter = begin(); iter != end(); ++iter) {
#ifdef TOPCOM_CONTAINERS
      ost << '[' << iter->dataptr()->first << ',' << iter->dataptr()->second << ']' << '\n';
#else
      ost << '[' << iter->second.first << ',' << iter->second.second << ']' << '\n';
#endif
    }
    ost << '}' << std::endl;
    ost << message::unlock;
    return ost;
  }
  std::istream& Cocircuits::read_string(std::istream& ist) {
    char     c;
    Cocircuit  cocircuit;

    clear();
    if (!(ist >> std::ws >> _no)) {
#ifdef READ_DEBUG
      MessageStreams::forced() << message::lock
			       << "Cocircuits::read_string(std::istream&): "
			       << "number of points not found." << std::endl
			       << message::unlock;
#endif
      ist.clear(std::ios::failbit);
      return ist;
    }
    if (!(ist >> std::ws >> c)) {
#ifdef READ_DEBUG
      MessageStreams::forced() << message::lock
			       << "Cocircuits::read_string(std::istream&): "
			       << "separator not found." << std::endl
			       << message::unlock;
#endif
      ist.clear(std::ios::failbit);
      return ist;
    }
    if (!(ist >> std::ws >> _rank)) {
#ifdef READ_DEBUG
      MessageStreams::forced() << message::lock
			       << "Cocircuits::read_string(std::istream&): "
			       << "rank not found." << std::endl
			       << message::unlock;
#endif
      ist.clear(std::ios::failbit);
      return ist;
    }
    if (!(ist >> std::ws >> c)) {
#ifdef READ_DEBUG
      MessageStreams::forced() << message::lock
			       << "Cocircuits::read_string(std::istream&): "
			       << "separator not found." << std::endl
			       << message::unlock;
#endif
      ist.clear(std::ios::failbit);
      return ist;
    }
    while (ist >> std::ws >> c) {
      if (c == '{') {
	continue;
      }
      else if (c == '}') {
	break;
      }
      else {
	ist.putback(c);
	if (ist >> cocircuit) {
	  (*this)[cocircuit.first + cocircuit.second] = cocircuit;
	}
	else {
#ifdef READ_DEBUG
	  MessageStreams::forced() << message::lock
				   << "Cocircuits::read_string(std::istream&): "
				   << "not of appropriate type." << std::endl
				   << message::unlock;
#endif
	  ist.clear(std::ios::failbit);
	  return ist;		
	}
      }
    }
    return ist;
  }

}; // namespace topcom

// eof Cocircuits.cc
