/*

Copyright © 2023-26 Sean Holden. All rights reserved.

*/
/*

This file is part of Connect++.

Connect++ 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 3 of the License, or (at your 
option) any later version.

Connect++ 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.

You should have received a copy of the GNU General Public License along 
with Connect++. If not, see <https://www.gnu.org/licenses/>. 

*/

#ifndef STACKITEM_HPP
#define STACKITEM_HPP

#include<iostream>

#include "SimplePath.hpp"
#include "Lemmata.hpp"
#include "Matrix.hpp"

using std::ostream;

/**
* \brief Enumeration for the different kinds of stack item.
*
* You need to be able to identify them in this way to correctly 
* control backtracking.
*/
enum class StackItemType {
  Start, Axiom, Reduction, LeftBranch, RightBranch, Lemmata
};

ostream& operator<<(ostream&, const StackItemType&);

/**
* \brief Stack items: each contains its own material for 
*        generating possible next inferences.
*
* Note: this is *really* performance critical.
*/
struct StackItem {
/**
* \brief What type of StackItem is this?
*/
StackItemType item_type;
/**
* \brief Each node in the proof tree is a tuple of clause, 
*        matrix, path, lemmata: this is the clause.
*/
Clause c;
/** 
* \brief First literal of clause c.
*/
Literal lit;
/**
* \brief Negation of lit.
*/
Literal neg_lit;
/**
* \brief Each node in the proof tree is a tuple of clause, 
*        matrix, path, lemmata: this is the path.
*/
SimplePath p;
/**
* \brief Length of current path.
*/
size_t path_length;
/**
* \brief Each node in the proof tree is a tuple of clause, 
*        matrix, path, lemmas: this is the lemmas.
*/
Lemmata l;
/**
* \brief Length of current lemmas.
*/
size_t lemma_size;
/**
* \brief Some nodes in the proof tree have an associated 
*        substitution.
*/
Substitution sub;
/**
* \brief How deep in the proof tree are we?
*/
uint32_t depth;
/**
* \brief Action that got you to this clause, path etc.
*/
InferenceItem this_action;
/**
* \brief Pointer that allows a right branch to know 
* where to delete alternatives for restricted backtracking.
*
* DO NOT try to do this by storing a pointer to the StackItem. 
* As the vector can have its storage reallocated in the 
* background, you end up with all manner of segfaultyness.
*/
size_t bt_restriction_index;
//----------------------------------------------------------------------
// Generation of lemmas.
//----------------------------------------------------------------------
/**
* \brief Which possible lemma will we consider next?
*/
size_t lemma_current_lemma_index;
/**
* \brief Setting this to true stops any further possibilities 
*        from being generated.
*/
bool lemma_backtrack_restricted;
/**
* \brief Make it easy to know when there are no more possibilities.
*/
bool lemma_no_more_results;
//----------------------------------------------------------------------
// Generation of reductions.
//----------------------------------------------------------------------
/**
* \brief Which possible reduction will we consider next?
*/
size_t reduction_current_path_index;
/**
* \brief Setting this to true stops any further possibilities 
*        from being generated.
*/
bool reduction_backtrack_restricted;
/**
* \brief Make it easy to know when there are no more possibilities.
*/
bool reduction_no_more_results;
//----------------------------------------------------------------------
// Generation of extensions.
//----------------------------------------------------------------------
/**
* \brief Index computed for neg_lit telling us where to find 
*        the information we need in the matrix index.
*/
size_t extension_i;
/**
* \brief Which possible extension will we consider next?
*/
size_t extension_current_index_entry;
/**
* \brief Setting this to true stops any further possibilities 
*        from being generated.
*/
bool extension_backtrack_restricted;
/**
* \brief Make it easy to know when there are no more possibilities.
*/
bool extension_no_more_results;
//----------------------------------------------------------------------
// Methods.
//----------------------------------------------------------------------
StackItem() {};

StackItem(StackItemType sit,
    const Clause& _c,
    const SimplePath& _p,
    const Lemmata& _l,
    uint32_t _d)
: item_type(sit)
, c(_c)
, p(_p)
, l(_l)
, sub()
, depth(_d)
, this_action()
, bt_restriction_index(0)
{ 
  stack_item_setup(); 
}
/**
* \brief Basic set method.
*/
inline void set_this_action(const InferenceItem& inf_i) {
  this_action = inf_i;
}
/**
* \brief Basic set method.
*/
inline void set_bt_restriction_index(size_t i) {
  bt_restriction_index = i;
}
/**
* \brief Basic setup collected in a method to avoid repeating it 
*        in the various constructors.
*/
void stack_item_setup(); 
/**
* \brief Call this *after* the constructor but *before* you 
*        want to use the enumeration of possible actions.
*/
void initialize(Matrix&);
/**
* \brief Generate the next lemma.
*
* This is slightly different to the others as you only ever 
* need one. 
*/
InferenceItem next_lemma(); 
/**
* \brief Find the next possible reduction or indicate there 
*        is none. The state of the object keeps track of 
*        where we are. 
*/
InferenceItem next_reduction(Unifier&);
/**
* \brief Find the next possible extension or indicate there 
*        is none. The state of the object keeps track of 
*        where we are. 
*/
InferenceItem next_extension(Matrix&, Unifier&);
/**
* \brief Adjust the collection of actions to limit backtracking.
*
* Of course, you might want to modify how this works if you 
* want to do something more sophisticated. At present you 
* have the leanCop style.
*/
void restrict_backtrack();
/**
* \brief Get the next inference to try.
*/
InferenceItem get_next_inference(Matrix&, Unifier&); 
/**
* \brief Make a string representation.
*/
string to_string_unsubbed() const;
};

ostream& operator<<(ostream&, const StackItem&);

#endif
