(* Opt *)
(* $Id$ *)

type style = [ `Bourbaki | `List | `Raw | `Table | `Count | `Ast | `Install | `Remove ]
and fields = All | These of (string * int option) list
;;

let initial_parse_fieldspec x =
  if x = "*" then
    All
  else
    These(List.map
    (fun w ->
      try
        let i = String.index w ':' in
        if i + 1 = String.length w then
          failwith "Width specifier invalid"
  else
    let n =
      try
        int_of_string
        (String.sub w (i + 1)
        (String.length w - i - 1))
      with
      _ -> raise (Arg.Bad "Width specifier invalid")
        in
        (String.sub w 0 i,Some n)
      with
      Not_found -> (w,None)) (Util.split_at ',' x))
;;

let parse_fieldspec = ref initial_parse_fieldspec;;

let user_specified_config_file = ref false
let config_file = ref "ara.config"
let create_config = ref true
let save_history = ref true
let ast = ref false
let interactive = ref false
let terse = ref false
let borders = ref true
let style : style ref = ref `Bourbaki
let fields = ref (These["Package",Some 20;"Version",Some 10;"Description",Some 45])
let queries : (style * fields * string) list ref = ref []
let use_pager = ref true
let columns = ref (try max 10 (int_of_string (Sys.getenv "COLUMNS") - 5) with _ -> 75)
let rows = ref (try max 1 (int_of_string (Sys.getenv "LINES")) with _ -> 25)
let coalesce = ref true
let progress = ref false
let user_set_progress = ref false
let wrap = ref true
let fast = ref true
let low_memory = ref 32768
let very_slow = ref (Util.proc_get_free_mem () < !low_memory);;
let raise_exceptions = ref false

let batch_specs = [
  "-examples", Arg.Unit(fun () -> print_string Help.examples; exit 0),
  " Display some documentation including examples exit.";

  "-interactive",Arg.Unit(fun () ->
                          interactive := true;
                          if not !user_set_progress then progress := true),
  " Interactive mode ; prompt for a query, display it.";
  "-i",Arg.Unit(fun () ->
         interactive := true;
         if not !user_set_progress then progress := true),
  " Same as -interactive.";

  "-noconfig",Arg.Clear(create_config),
    " Don't attempt to create a configuration file.";
  "-nohistory",Arg.Clear(save_history),
    " Don't save command history.";
  "-config",Arg.String(fun w -> config_file := w; user_specified_config_file := true),
    " Specify alternate config file (default ~/.ara/ara.config)";

  "-fast",Arg.Clear(very_slow),
    " Run faster but use more memory.";
  "-slow",Arg.Set(very_slow),
    " Use minimal amount of memory but run very slowly.";
  "-cache-strings",Arg.Clear(fast),
    " With -fast, try to conserve memory somewhat."
];;

let add_query w = queries := (`List,!fields,w)::!queries;;

let common_specs = [
  "-version", Arg.Unit(fun () ->
    Printf.printf "ara version %s released %s under the GNU GPL by Berke Durak.\n"
      Version.version Version.date;
    if not !interactive then exit 0),
  " Print version.";
  "-about", Arg.Unit(fun () ->
    print_string Help.about;
    if not !interactive then exit 0),
  " Display copyright, thanks and dedication.";

  "-progress",Arg.Tuple[Arg.Set(progress); Arg.Set(user_set_progress)],
    " Show progress indicator when loading database.";
  "-noprogress",Arg.Tuple[Arg.Clear(progress); Arg.Set(user_set_progress)],
    " Don't show progress indicator.";

  "-new",Arg.Set(coalesce), " Show only newest version of each package. (default)";
  "-old",Arg.Clear(coalesce), " List all versions of packages.";

  "-query", Arg.String(add_query), "<query> Query (eg. depends:xlibs & !package:xcalc).";
  "-q", Arg.String(add_query), "<query> Same as -query.";

  "-short",Arg.String(fun x -> queries := (`Bourbaki,!fields,x)::!queries),
  "<query> Display names of packages satisfying query between a pair of curly braces.";

  "-list",Arg.String(fun x -> queries := (`List,!fields,x)::!queries),
  "<query> Same, but display one package name per line, and no curly braces (default).";

  "-raw",Arg.String(fun x -> queries := (`Raw,!fields,x)::!queries),
  "<query> For each package satisfying the query, display all selected fields.";

  "-table",Arg.String(fun x -> queries := (`Table,!fields,x)::!queries),
  "<query> Display results as a table.";

  "-count",Arg.String(fun x -> queries := (`Table,!fields,x)::!queries),
  "<query> Display number of matching packages.";
  
  "-rows",Arg.Set_int(rows),
  "<height> Set height of terminal for interactive display (default 25)";

  "-columns",Arg.Set_int(columns),
  "<width> Set width of terminal for interactive display (default 75)";

  "-wrap",Arg.Set(wrap)," Do word wrapping.";
  "-nowrap",Arg.Clear(wrap)," Don't do word wrapping.";

  "-pager",Arg.Set(use_pager),
  " Use a pager for displaying long output in interactive mode";

  "-nopager",Arg.Clear(use_pager),
  " Don't use a pager for displaying long output in interactive mode";

  "-fields",Arg.String(fun x -> fields := !parse_fieldspec x),
  "<field_1[:width_1],...> \
   Limit output to specified fields for the -table \
   and -raw options.  The optional width specifiers \
   are used with the -table option, ignored otherwise. \
   Use * to display all fields (but remember to escape \
   the star character from your shell).";

  "-borders",Arg.Set(borders),
  " Draw ASCII borders for tabular output. (default)";

  "-noborders",Arg.Clear(borders),
  " Don't draw ASCII borders for tabular output.";

  "-ast",Arg.Set(ast),
  " Dump the abstract syntax tree of parsed queries to stderr.";

  "-debug",Arg.Set(Debug.enable),
  " Enable debugging information";

  "-debug-level",Arg.Set_int(Debug.level),
  " Set debugging level (higher is more verbose, max is 100, default is 10)";

  "-raise-exceptions",Arg.Set(raise_exceptions),
  " Don't catch exceptions.  Useful with OCAMLRUNPARAM=b=1 in bytecode."
];;

let specs = Arg.align (batch_specs@common_specs);;

let cli_specs = Arg.align common_specs;;
  (* List.map (fun (x,y,z) -> (String.sub x 1 (String.length x - 1), y, z)) common_specs;; *)
