/* 
 * Kodkod -- Copyright (c) 2005-2011, Emina Torlak
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package kodkod.engine.fol2sat;

import java.util.Iterator;
import java.util.Set;

import kodkod.ast.Formula;
import kodkod.engine.Solver;
import kodkod.engine.config.Options;
import kodkod.instance.Bounds;

/**
 * A log of the translations of the descendants of a given formula that 
 * are either formulas or that desugar to formulas.
 * @specfield originalFormula: Formula // the {@linkplain Solver#solve(Formula, kodkod.instance.Bounds) original} formula, provided by the user
 * @specfield originalBounds: Bounds // the {@linkplain Solver#solve(Formula, kodkod.instance.Bounds) original} bounds, provided by the user
 * @specfield formula: Formula // desugaring of this.formula that was translated
 * @specfield bounds: Bounds // translation bounds
 * @specfield records: set TranslationRecord
 * @specfield replay: [0..#records) one->one records // replay order -- i.e. the order in the which records were added to the log
 * @invariant all r: records | r.node in formula.*children
 * @invariant Solver.solve(formula, bounds).instance() == null iff Solver.solve(originalFormula, originalBounds).instance() == null
 * @author Emina Torlak
 */
public abstract class TranslationLog {
	TranslationLog() {}
	
	/**
	 * Returns the roots of this.formula.  In other words, returns the subformulas, {f0, ..., fk}, 
     * of this.formula such that, for all 0<=i<=k, f<sub>i</sub>  [[f0 && ... && fk]] <=> [[formula]]. 
     * The granularity of the subdivision of this.formula into roots depends on the core granularity
     * specified in the {@linkplain Options} that were used when translating this.formula.
     * 
     * <p>Unless a given root translates to a constant, the highest magnitude  literal corresponding to 
     * each root (as given by this.records) is guaranteed to be present in the translation of this.formula
     * as a unit clause.  All the remaining clauses (except those comprising the symmetry 
     * breaking predicate, encoded with its own unit clause containing the maximum literal)
     * that are reachable from such a unit clause represent the translations
     * of the given root's descendants.  We define reachability over the clauses in a translation
     * as follows:  let l1 be the highest magnitude literal in the clause c1, and let l2 be the
     * highest magnitude literal in c2.  If l2 occurs in c1 (in any polarity), then there is 
     * an edge from c1 and c2. The unit clauses are always the last clauses to be added to a SAT solver
     * during translation. </p>
     * 
	 * @return roots of this.formula
	 */
	public abstract Set<Formula> roots();

	/**
	 * Returns this.bounds.
	 * @return this.bounds.
	 */
	public abstract Bounds bounds();
	
	/**
	 * Returns an iterator over the translation records in this log that are accepted
	 * by the given filter.  The iterator returns the records in the order in which
	 * they were generated.  This guarantees that records for the descendants of a 
	 * node are always returned before the record for the node itself.  
	 * 
	 * <p><b>Note:</b>The record objects returned by the iterator are not 
	 * required to be immutable.  In particular, the state of a record object
	 * returned by <tt>next()</tt> is guaranteed to remain the same only until the
	 * subsequent call to <tt>next()</tt>.</p>
	 * @return an iterator, in the proper replay sequence, over the translation records 
	 * in this log that are accepted by the given filter.
	 */
	public abstract Iterator<TranslationRecord> replay(RecordFilter filter);
	
	/**
	 * Returns an iterator over all translation records in this log.  The iterator returns 
	 * the records in the order in which they were generated.  This guarantees that records for 
	 * the descendants of a  node are always returned before the record for the node itself.  
	 * The effect of this method is the same as calling {@linkplain #replay(RecordFilter) replay(RecordFilter.ALL)}.
	 * 
	 * <p><b>Note:</b>The record objects returned by the iterator are not 
	 * required to be immutable.  In particular, the state of a record object
	 * returned by <tt>next()</tt> is guaranteed to remain the same only until the
	 * subsequent call to <tt>next()</tt>.</p>
	 * @return an iterator over all translation records in this.log, in the proper replay sequence.
	 * @see #replay(RecordFilter)
	 */
	public final Iterator<TranslationRecord> replay() {
		return replay(RecordFilter.ALL);
	}
	
//	/**
//	 * Compresses this translation log (optional operation) by eliminating
//	 * redundant records.
//	 * @ensures all r: this.records | one r': this.records' | r.node = r'.node && r.literal = r'.literal && r.env.equals(r'.env)
//	 * @throws UnsupportedOperationException  this log does not support compression
//	 */
//	public abstract void compress();
}
