(*
This file is part of the dpll(t) engine sammy
Copyright (C) 2004  The University of Iowa
Cesare Tinelli

This program 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 2
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*)

(* state.ml *)

type state = { lev: int }

type current = { mutable size: int;
     mutable level: int;
     mutable states: state array
         }

let (dummy_state:state) = { lev = max_int }
let (initial_state:state) = { lev = 0 } (* must have level 0 *)

let initial_size = 128

let (current:current) = 
{ size = initial_size;
      level = 0; (* must start with 0 *)
      states = Array.make initial_size dummy_state
          }

let initial_state_set = current.states.(0) <- initial_state


let current_state () = current.states.(current.level)

let empty_lev = ref 0

let empty_level () = !empty_lev

let current_level () = current.level

let level (state:state) = state.lev

let previous_state (n:int) = 
  if n > current.level || n < 0 then 
    failwith "Attempted to access invalid state";
  current.states.(n)

let next () = 
  let new_level = current.level + 1 in
  let new_state = { lev = new_level } in
    (try 
       current.states.(new_level) <- new_state
     with Invalid_argument _(*"Array.set"*) ->
       let new_size = 2 * current.size in
       let new_states = Array.make new_size dummy_state in
         Array.blit current.states 0 new_states 0 current.size;
   current.size <- new_size;
   current.states <- new_states;
   current.states.(new_level) <- new_state
    );
    current.level <- new_level;
    new_state


let is_valid (state: state) = 
  state.lev <= current.level &&
  current.states.(state.lev) == state



(* requires n >= 0 *)
let backtrack n = 
  current.level <- current.level - n
    (* if new current level is < current.size/4, say, then
       we might consider shrinking current.states here
    *)

(* requires that l <= current.level *)
let backtrack_to_level l =
  current.level <- l
    (* if new current level is < current.size/4, say, then
       we might consider shrinking current.states here
    *)

let advance_state () =
  backtrack_to_level (empty_level());
  next();
  empty_lev := current_level ()

let retract_state () =
  backtrack_to_level (empty_level());
  backtrack 1;
  empty_lev := current_level ()
