/**
 * @brief if the Tuple passed as the second parameter is present in the AnswerSets passed as first parameter
 */
bool ActionPluginFinalCallback::thisAnswerSetContainsThisAction(
		const AnswerSetPtr& answerSetPtr, const Tuple& action_tuple) {

	// used to have only the Action Atoms
	InterpretationPtr intr = InterpretationPtr(new Interpretation(registryPtr));
	intr->getStorage() |= ctxData.myAuxiliaryPredicateMask.mask()->getStorage();
	intr->getStorage() &= answerSetPtr->interpretation->getStorage();

	Interpretation::TrueBitIterator bit, bit_end;
	for (boost::tie(bit, bit_end) = intr->trueBits(); bit != bit_end; ++bit) {

		const Tuple & tuple = registryPtr->ogatoms.getByAddress(*bit).tuple;

		if (tuple.size() - 5 == action_tuple.size()) {

			bool different = false;

			for (int i = 0; i < action_tuple.size() && !different; i++)
				if (tuple[i + 1] != action_tuple[i])
					different = true;

			if (!different)
				return true;

		}

	}

	return false;

}
InterpretationPtr GuessAndCheckModelGenerator::generateNextModel()
{
    RegistryPtr reg = factory.reg;

    // now we have postprocessed input in postprocessedInput
    DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidgcsolve, "guess and check loop");

    InterpretationPtr modelCandidate;
    do {
        AnswerSetPtr guessas = guessres->getNextAnswerSet();
        if( !guessas )
            return InterpretationPtr();
        modelCandidate = guessas->interpretation;

        DBGLOG_SCOPE(DBG,"gM", false);
        DBGLOG(DBG,"= got guess model " << *modelCandidate);

        DBGLOG(DBG, "doing compatibility check for model candidate " << *modelCandidate);
        assert(!factory.ctx.config.getOption("ExternalLearning") &&
            "cannot use external learning in (non-genuine) GuessAndCheckModelGenerator");
        bool compatible = isCompatibleSet(
            modelCandidate, postprocessedInput, factory.ctx,
            SimpleNogoodContainerPtr());
        DBGLOG(DBG, "Compatible: " << compatible);
        if (!compatible) continue;

        // FLP check
        if (factory.ctx.config.getOption("FLPCheck")) {
            DBGLOG(DBG, "FLP Check");
            if( !isSubsetMinimalFLPModel<ASMOrdinaryASPSolver>(
                modelCandidate, postprocessedInput, factory.ctx) )
                continue;
        }
        else {
            DBGLOG(DBG, "Skipping FLP Check");
        }

        // remove edb and the guess (from here we don't need the guess anymore)
        modelCandidate->getStorage() -= factory.gpMask.mask()->getStorage();
        modelCandidate->getStorage() -= factory.gnMask.mask()->getStorage();

        modelCandidate->getStorage() -= mask->getStorage();

        DBGLOG(DBG,"= final model candidate " << *modelCandidate);
        return modelCandidate;
    }
    while(true);
}
/**
 * @brief function that fill the multimap (passed as parameter) with Precedence attribute and Action Tuple checking the Action Option attribute
 */
void ActionPluginFinalCallback::executionModeController(
		std::multimap<int, Tuple>& multimapOfExecution) {

	const AnswerSetPtr& bestModel = (*(ctxData.iteratorBestModel));

	// used to have only the Action Atoms
	InterpretationPtr intr = InterpretationPtr(new Interpretation(registryPtr));
	intr->getStorage() |= ctxData.myAuxiliaryPredicateMask.mask()->getStorage();
	intr->getStorage() &= bestModel->interpretation->getStorage();

	Interpretation::TrueBitIterator bit, bit_end;
	for (boost::tie(bit, bit_end) = intr->trueBits(); bit != bit_end; ++bit) {

		const OrdinaryAtom& oatom = registryPtr->ogatoms.getByAddress(*bit);
		const Tuple & tuple = oatom.tuple;

		int precedence, precedence_position = tuple.size() - 3;
		dlvhex::ID id_actionOption = tuple[tuple.size() - 4];

		Tuple action_tuple;

		for (int i = 1; i < tuple.size() - 4; i++)
			action_tuple.push_back(tuple[i]);

		if (tuple[precedence_position].isIntegerTerm()
				&& id_actionOption.isConstantTerm()) {

			precedence = tuple[precedence_position].address;

			DBGLOG(DBG,
					"actionOption: "
							<< registryPtr->getTermStringByID(id_actionOption));
			DBGLOG(DBG, "Precedence: " << precedence);

			if (id_actionOption == ctxData.getIDBrave())
				;
			else if (id_actionOption == ctxData.getIDCautious())
				if (!isPresentInAllAnswerSets(action_tuple)) {
					std::stringstream ss;
					printTuple(ss, action_tuple, registryPtr);
					DBGLOG(DBG,
							"This action atom isn't present in all AnswerSet: "
									<< ss.str());
					continue;
				} else if (id_actionOption == ctxData.getIDPreferredCautious())
					if (!isPresentInAllTheBestModelsAnswerSets(action_tuple)) {
						std::stringstream ss;
						printTuple(ss, action_tuple, registryPtr);
						DBGLOG(DBG,
								"This action atom isn't present in all BestModels AnswerSet: "
										<< ss.str());
						continue;
					} else
						throw PluginError(
								"Error in the selection of brave, cautious or preferred_cautious");

			multimapOfExecution.insert(
					std::pair<int, Tuple>(precedence, action_tuple));

		} else
			throw PluginError(
					"Precedence isn't Integer term or actionOption haven't a valid value");

	}

}
PlainModelGenerator::InterpretationPtr
PlainModelGenerator::generateNextModel()
{
  RegistryPtr reg = factory.ctx.registry();
  if( currentResults == 0 )
  {
    do // breakout possibility
    {
      // we need to create currentResults

      // create new interpretation as copy
      Interpretation::Ptr newint;
      if( input == 0 )
      {
        // empty construction
        newint.reset(new Interpretation(reg));
      }
      else
      {
        // copy construction
        newint.reset(new Interpretation(*input));
      }

      // augment input with edb
      newint->add(*factory.ctx.edb);

      // remember facts so far (we have to remove these from any output)
      InterpretationConstPtr mask(new Interpretation(*newint));

      // manage outer external atoms
      if( !factory.eatoms.empty() )
      {
        // augment input with result of external atom evaluation
        // use newint as input and as output interpretation
        IntegrateExternalAnswerIntoInterpretationCB cb(newint);
        evaluateExternalAtoms(factory.ctx, factory.eatoms, newint, cb);
        DLVHEX_BENCHMARK_REGISTER(sidcountexternalanswersets,
            "outer eatom computations");
        DLVHEX_BENCHMARK_COUNT(sidcountexternalanswersets,1);

        if( factory.xidb.empty() )
        {
          // we only have eatoms -> return singular result

          // remove EDB and direct input from newint
          // (keep local models as small as possible)
          newint->getStorage() -= mask->getStorage();

          PreparedResults* pr = new PreparedResults;
          currentResults.reset(pr);
          pr->add(AnswerSetPtr(new AnswerSet(newint)));
          break;
        }
      }

      // store in model generator and store as const
      postprocessedInput = newint;

      DLVHEX_BENCHMARK_REGISTER_AND_START(sidaspsolve,
          "initiating external solver");
      OrdinaryASPProgram program(reg,
          factory.xidb, postprocessedInput, factory.ctx.maxint, mask);
      ASPSolverManager mgr;
      currentResults = mgr.solve(*factory.externalEvalConfig, program);
      DLVHEX_BENCHMARK_STOP(sidaspsolve);
    }
    while(false); // end of breakout possibility
  }

  assert(currentResults != 0);
  AnswerSet::Ptr ret = currentResults->getNextAnswerSet();
  if( ret == 0 )
  {
    currentResults.reset();
    // the following is just for freeing memory early
    postprocessedInput.reset();
    return InterpretationPtr();
  }
  DLVHEX_BENCHMARK_REGISTER(sidcountplainanswersets, "PlainMG answer sets");
  DLVHEX_BENCHMARK_COUNT(sidcountplainanswersets,1);

  return ret->interpretation;
}