(*
This file is part of the first order theorem prover dpllt
Copyright (C) 2004  The University of Iowa
Cesare Tinelli
George Hagen
Michael Decoster

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.
*)

(* main.ml *)



(*** signal handling ***)

let handle_term_signal (signal_number: int) : unit =
  if signal_number = Sys.sigvtalrm then
    raise Dpllt.GlobalTimeout
      
  else
    failwith "Main.handle_term_signal: called for unregistered signal"

(* handles currently only cpu timeout *)
let init_signal_handlers () =
  Sys.set_signal Sys.sigvtalrm (Sys.Signal_handle handle_term_signal)


(* set user defined timeouts *)
let set_time_out (time_out: float) : unit =
  ignore (
    Unix.setitimer
      Unix.ITIMER_VIRTUAL
      {
   	Unix.it_interval = 0.0;
   	Unix.it_value  = time_out;
      }
      : Unix.interval_timer_status)




(** Command-line interface main file. *)

(* 'main' function *)
let () =
  init_signal_handlers ();

let print = Printf.printf in
let stime = Sys.time() in
let use_file = ref stdin in
let start filename =
if Global.pars.Global.verbose then begin
  print "Reading file %s...\n" filename;
  print "parsing...\n";
  flush stdout;
end;
  use_file := open_in filename

in
let usage_msg = "Usage: sammy [-max_lemmas n] [-active_lemmas n] [-activity_cycle n] [-t n] 
[-max_instances n] [-quiet] [-no_negate_queries] filename"
in
let speclist = [

                ("-activity_behavior",
                 Arg.Int (fun n -> Global.pars.Global.activity_behavior 
                   <- n),
                 "Modifications to predicate scoring method (see global.ml)"
                );
(*
                ("-max_lemmas",
                 Arg.Int (fun n -> Global.pars.Global.max_lemmas <- n),
                 "Maximum total number of learned lemmas [512]"
                );
*)
(*
                ("-active_lemmas",
                 Arg.Int (fun n -> Global.pars.Global.max_active_lemmas <- n),
                 "Number of active learned lemmas (=< max_lemmas) [128]"
                );
*)
                ("-activity_cycle",
                 Arg.Int (fun n -> Global.pars.Global.activity_cycle <- n),
                 "Length of activity cycle [60]"
                );
                ("-quiet",
                 Arg.Unit (fun () -> Global.pars.Global.verbose <- false),
                 "Quiet mode (minimal statistics) (off)"
                );
                ("-t",
                 Arg.Float (fun n -> Global.pars.Global.timeout <- n),
                 "Timeout duration, in seconds [3600]"
                );
                ("-gt",
                 Arg.Float (fun n ->
	           Arg.Float (fun n -> Global.pars.Global.timeout <- n); set_time_out n;),
(*                   Api_native.set_flag (Global.GLOBAL_TIMEOUT n); (*set_time_out n;*)),*)
                 "System timeout duration, in seconds [3600]"
                );
                ("-restart_cycle",
                 Arg.Int (fun n ->
                   Api_native.set_flag (Global.RESTART_CYCLE n)),
                 "Restart search after n conflicts [max_int]"
                );

                ("-max_instances",
                 Arg.Int (fun n -> Global.pars.Global.max_instances <- n;Parser_helper.skolemizer#set_max_instances_per_call n),
                 "Maximum number of instances generated at once [30]"
                );

                ("-no_negate_queries",
                 Arg.Unit (fun () -> Global.pars.Global.negate_queries <- false),
                 "Do not automatically negate input queries (off)"
                );

                ("-no_favor_watched",
                 Arg.Unit (fun () -> Global.pars.Global.nonwatched_lits_last <- false),
                 "Do not only choose watched literals first (off)"
                );

                ("-no_favor_polarity",
                 Arg.Unit (fun () -> Global.pars.Global.use_favored_polarity <- false),
                 "Do not default to favored polarity in (abstract) lits (off)"
                );
                ("-no_favor_guards",
                 Arg.Unit (fun () -> Global.pars.Global.favor_ite_guards <- false),
                 "Do not favor ite guard literals (off)"
                );
                ("-no_favor_depth",
                 Arg.Unit (fun () -> Global.pars.Global.favor_depth <- false),
                 "Do not favor lits with (min) subformula depth (off)"
                );
                ("-favor_max_depth",
                 Arg.Unit (fun () -> Global.pars.Global.favor_min_depth <- false),
                 "If favoring depth, favor max instead of min depth (off)"
                );
                ("-vsids_only",
                 Arg.Unit (fun () -> 
                   Global.pars.Global.nonwatched_lits_last <- false;
                   Global.pars.Global.use_favored_polarity <- false;
                   Global.pars.Global.favor_ite_guards <- false;
                   Global.pars.Global.favor_depth <- false),
                 "Only use VSIDS as decision heuristic (off)"
                );
                ("-rand_seed",
                 Arg.Int (fun n ->
                   Parser_helper.skolemizer#set_rand_seed(n)),
                 "set the random seed to the argument"
                );
                ("-stdin",
                 Arg.Unit (fun () -> use_file := stdin),
                 "use input from stdin"
                );
                ("-exhaustive",
                 Arg.Unit (fun () -> Global.pars.Global.exhaustive <- true),
                 "use our non random instantiation"
                )
               ]
in

  (try Arg.parse speclist start usage_msg;
       Api_native.start_solver ();
       let in_ch = !use_file in
       let lexbuf = Lexing.from_channel in_ch in
       Smt_parser.main Smt_lexer.token lexbuf
  with Theory.Incons -> 
      if Global.pars.Global.verbose then
        print "\nInconsistent Context\n";
      if Global.pars.Global.negate_queries then
        print "Unsatisfiable. (Query is Valid)\n"
      else
        print "Unsatisfiable.\n"
(*
  | Reduce.Incons -> 
      if Global.pars.Global.verbose then
        print "\nConflict in initial BCP\n";
      print "Unsatisfiable.\n";
*)
  | Satbox.SBI_Incons ->
      if Global.pars.Global.verbose then
        print "\nConflict in initial BCP\n";
      if Global.pars.Global.negate_queries then
        print "Unsatisfiable. (Query is Valid)\n"
      else
        print "Unsatisfiable.\n"
  | Dpllt.Timeout ->
      failwith "\nTimeout - but local one. shouldn't get here.\n"
      
  | Dpllt.GlobalTimeout ->
      print "\nTimeout.\n"
  | Dpllt.DontKnow -> (*print "unknown\n"*)
    print "Don't Know."
  );
if Global.pars.Global.verbose then
  print "\nElapsed time %f seconds\n" (Sys.time() -. stime);

  exit 0
