let main () =
  let posargs = OptParse.OptParser.parse_argv Options.options in
  let input_format = Input.guess_format [posargs] in
  let options = Options.set_options input_format in

  Boilerplate.enable_debug(OptParse.Opt.get Options.verbose);
  Boilerplate.all_quiet (OptParse.Opt.get Options.quiet);

  let global_constraints = not(OptParse.Opt.get Options.deb_ignore_essential) in

  if OptParse.Opt.get Options.out_type = "sqlite" then
    output_to_sqlite posargs
  else
  let (preamble,universe,from_cudf,to_cudf) = Boilerplate.load_universe ~options posargs in
  let get_cudfpkg ((n,a),c) = 
    let (name,filter) = Boilerplate.debvpkg to_cudf ((n,a),c) in
    try List.hd(Cudf.lookup_packages ~filter universe name)
    with ExtList.List.Empty_list -> fatal "package %s not found" n
  in

  let pkg_src () = List.map get_cudfpkg (OptParse.Opt.get Options.src) in
  let pkg_dst () =
    (* all packages q in R s.t. q is in the dependency closure of p *)
    let (p,v) = OptParse.Opt.get Options.dst in
    let pid = get_cudfpkg (p,v) in
    List.filter_map (fun pkg ->
      if List.mem pid (Depsolver.dependency_closure universe [pkg]) then
        Some(pkg)
      else None
    ) (Cudf.get_packages universe) 
  in
  let pkg_cone () =
    List.unique (List.fold_left (fun acc (p,v) ->
      let pid = get_cudfpkg (p,v) in
      if OptParse.Opt.is_set Options.cone_maxdepth then
        let md = OptParse.Opt.get Options.cone_maxdepth in
        (Depsolver.dependency_closure ~maxdepth:md universe [pid]) @ acc
      else
        (Depsolver.dependency_closure universe [pid]) @ acc
    ) [] (OptParse.Opt.get Options.cone))
  in
  let pkg_reverse_cone () =
    List.unique (List.fold_left (fun acc (p,v) ->
      let pid = get_cudfpkg (p,v) in
      if OptParse.Opt.is_set Options.cone_maxdepth then
        let md = OptParse.Opt.get Options.cone_maxdepth in
        (Depsolver.reverse_dependency_closure ~maxdepth:md universe [pid]) @ acc
      else
        (Depsolver.reverse_dependency_closure universe [pid]) @ acc
    ) [] (OptParse.Opt.get Options.reverse_cone))
  in

  let pkg_src_list = ref [] in
  let pkg_dst_list = ref [] in
  let plist =
    if OptParse.Opt.is_set Options.src && OptParse.Opt.is_set Options.dst then begin
      let (p,v) = OptParse.Opt.get Options.dst in
      let pid = get_cudfpkg (p,v) in
      pkg_src_list := pkg_src ();
      pkg_dst_list := [pid];
      (pid::!pkg_src_list)
    end
    else if OptParse.Opt.is_set Options.src then begin
      pkg_src_list := pkg_src ();
      !pkg_src_list
    end
    else if OptParse.Opt.is_set Options.dst then begin
      pkg_dst_list := pkg_dst ();
      !pkg_dst_list
    end
    else if OptParse.Opt.is_set Options.cone then 
      pkg_cone ()
    else if OptParse.Opt.is_set Options.reverse_cone then
      pkg_reverse_cone ()
    else Cudf.get_packages universe
  in

  let output ll =
    List.iter (fun l ->
      let u = Cudf.load_universe l in
      let oc =
        if OptParse.Opt.is_set Options.out_file then 
          open_out (OptParse.Opt.get Options.out_file)
        else stdout
      in
      begin match OptParse.Opt.get Options.out_type with
      |"dot" -> 
IFDEF HASOCAMLGRAPH THEN
          DGraph.D.output_graph oc (DGraph.dependency_graph u)
ELSE
        failwith ("dot not supported: needs ocamlgraph")
END
      |"cnf" -> Printf.fprintf oc "%s" (Depsolver.output_clauses ~global_constraints ~enc:Depsolver.Cnf u)
      |"dimacs" -> Printf.fprintf oc "%s" (Depsolver.output_clauses ~global_constraints ~enc:Depsolver.Dimacs u)
      |"cudf" -> output_cudf oc preamble u
      |"table" ->
IFDEF HASOCAMLGRAPH THEN
        Printf.fprintf oc "%d\t%d\t%d\n"
        (Cudf.universe_size u) (DGraph.G.nb_edges (DGraph.dependency_graph u))
        (nr_conflicts u)
ELSE
        failwith ("table not supported: needs ocamlgraph")
END
      |-> assert false
      end ;
      close_out oc;
    ) ll
  in output [plist]