/*

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 CLAUSECOPYCACHE_HPP
#define CLAUSECOPYCACHE_HPP

#include<iostream>
#include<string>
#include<vector>

#include "Matrix.hpp"

using std::vector;
using std::string;
using std::ostream;
using std::endl;
using std::cout;

class ClauseCopyCache {
private:
    /**
    * \brief Cache containing some number of copies 
    *        (with unique variables, not used anywhere 
    *        else) of clauses from the matrix.
    */
    vector<vector<Clause>> cache;
    /**
    * \brief Keep track of how many clauses there are in 
    *        the matrix.
    */
    size_t size;
    /**
    * \brief How many copies of each clause, in total, 
    *        are currently available? At any given time 
    *        some may be available immediately. 
    *        Anything beyond this requires an actual 
    *        new copy to be made.
    */
    vector<size_t> number_of_copies_available;
    /**
    * \brief Index of the next available copy of each clause.
    */
    vector<size_t> next_copy_index;
    /**
    * \brief Each time you supply a copy, remember the 
    * action so that you can backtrack.
    */
    vector<size_t> stack;
public:
    /**
    * \brief You probably don't know the size at the point 
    *        when this needs to be constructed.
    */
    ClauseCopyCache()
    : size(0)
    , cache()
    , number_of_copies_available()
    , next_copy_index()
    , stack()
    {}
    /**
    * \brief Set the number of clauses we need cached copies for.
    */
    inline void set_size(size_t _s) { size = _s; }
    /**
    * \brief This is for any actual initialisation, when 
    *        you either (1) intially know what you're dealing 
    *        with, or (2) need to restart after something like 
    *        a re-ordering of the matrix.
    *
    * @param _m  Reference to the actual matrix.
    * @param _vi Reference to variable index.
    * @param _ti Reference to term index.
    */
    void reset(const Matrix&, VariableIndex&, TermIndex&);
    /**
    * \brief If there is a copy cached, replace the parameter 
    *        with it. Otherwise, use the parameter to actually 
    *        make a copy, then add it to the cache and return it 
    *        in the same way.
    *
    * @param _index  Index of the clause in the matrix.
    * @param _clause Clause you want a copy of.
    * @param _m      Reference to the actual matrix.
    * @param _vi     Reference to the variable index.
    * @param _ti     Reference to the term index.
    */
    void make_copy_with_new_variables(size_t, Clause&, const Matrix&, VariableIndex&, TermIndex&);
    /**
    * \brief Backtracking is just looking at the last copy 
    *        supplied and undoing that action.
    */
    void backtrack();
    /**
    * \brief Mostly for development. See how many copies you actually 
    *        ended up with.
    */
    void show_counts() const;

    friend ostream& operator<<(ostream&, const ClauseCopyCache&);
};

#endif
