(****************************************************************************)
(*  Copyright © 2012-2015 Mehdi Dogguy <mehdi@debian.org>                   *)
(*                                                                          *)
(*  This file is part of Dochelp.                                           *)
(*                                                                          *)
(*  Dochelp 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 3 of the License, or (at your  *)
(*  option) any later version.                                              *)
(*                                                                          *)
(*  Dochelp 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 Dochelp.  If not, see <http://www.gnu.org/licenses/>.        *)
(****************************************************************************)

open Utils

let version_txt = "0.1"

let version () =
  print_endline version_txt

let list doc_base_dir =
  iter_files
    doc_base_dir
    begin fun file filename ->
          let tag = if is_valid_doc_base_file filename
                    then "I"
                    else "E"
          in
          Printf.printf "%s: %s\n" tag file
    end;
  Printf.printf "%!"

let search doc_base_dir regexp =
  let rex = Pcre.regexp regexp in
  iter_files
    doc_base_dir
    begin fun file filename ->
          if regexp_match rex filename then
            Printf.printf "I: %s\n" file
    end;
  Printf.printf "%!"

let cat doc_base_dir docid =
  match docid with
  | Some docid ->
     let path =
       if Sys.file_exists docid then
         docid
       else
         doc_base_dir // docid
     in
     let code = Sys.command (Printf.sprintf "cat %s" path) in
     exit code
  | None -> ()

let infos doc_base_dir docid =
  match docid with
  | Some docid ->
     let path =
       if Sys.file_exists docid then
         docid
       else
         doc_base_dir // docid
     in
     let ic = open_in path in
     let lexbuf = Lexing.from_channel ic in
     Document.print (Document.read path lexbuf)
  | None -> ()

let update doc_base_dir target online =
  Html.process doc_base_dir target online

open Cmdliner

let copts_sect = "OPTIONS"

let doc_base_dir =
  let docs = copts_sect in
  let doc_base_dir =
    let doc = "Specify doc-base dir" in
    Arg.(value & opt string "/usr/share/doc-base" & info ["base-doc"] ~docs ~doc)
  in
  doc_base_dir

let list_cmd =
  let doc = "List known registered documents" in
  let man = [
    `S "DESCRIPTION";
    `P "Shows all doc-base registered  version number of dochelp"]
  in
  Term.(pure list $ doc_base_dir),
  Term.info "list" ~sdocs:copts_sect ~doc ~man

let search_cmd =
  let doc = " Look for a matching documents" in
  let man = [
    `S "DESCRIPTION";
    `P "Lists all documents matching a regular expression"]
  in
  let regex =
    let doc = "Regular expression" in
    Arg.(value & pos 0 string ".*" & info [] ~docv:"regex" ~doc)
  in
  Term.(pure search $ doc_base_dir $ regex),
  Term.info "search" ~sdocs:copts_sect ~doc ~man

let cat_cmd =
  let doc = " Dump the content of a document" in
  let man = [
    `S "DESCRIPTION";
    `P "Shows the raw content of some selected document"]
  in
  let docid =
    let doc = "Document ID" in
    Arg.(value & pos 0 (some string) None & info [] ~docv:"docid" ~doc)
  in
  Term.(pure cat $ doc_base_dir $ docid),
  Term.info "cat" ~sdocs:copts_sect ~doc ~man

let info_cmd =
  let doc = " Print available information for a document" in
  let man = [
    `S "DESCRIPTION";
    `P "Print available information for a document"]
  in
  let docid =
    let doc = "Document ID" in
    Arg.(value & pos 0 (some string) None & info [] ~docv:"docid" ~doc)
  in
  Term.(pure infos $ doc_base_dir $ docid),
  Term.info "info" ~sdocs:copts_sect ~doc ~man

let update_cmd =
  let doc = " Print available information for a document" in
  let man = [
    `S "DESCRIPTION";
    `P "Print available information for a document"]
  in
  let target =
    let doc = "Path of the generated HTML page" in
    Arg.(value & pos 0 string "/var/lib/dochelp/documents.html" & info [] ~docv:"target" ~doc)
  in
  let online =
    let doc = "Use relative paths in generated HTML page" in
    Arg.(value & flag & info ["online"] ~docs:copts_sect ~doc)
  in
  Term.(pure update $ doc_base_dir $ target $ online),
  Term.info "update" ~sdocs:copts_sect ~doc ~man

let cmds = [list_cmd; search_cmd; cat_cmd; info_cmd; update_cmd]

let () =
  let default_cmd =
    let doc = "Utility to browse system documentation" in
    let man = [
      `S copts_sect;
      `P "These options are common to all commands.";
      `S "MORE HELP";
      `P "Use `$(mname) $(i,COMMAND) --help' for help on a single command.";
      `S "BUGS";
      `P "Check bug reports at http://bugs.debian.org/src:dochelp.";
    ]
    in
    Term.(pure (fun () -> ignore (Sys.command "sensible-browser /var/lib/dochelp/documents.html")) $ pure ()),
    Term.info "dochelp" ~version:version_txt ~sdocs:copts_sect ~doc ~man
  in
  match Term.eval_choice default_cmd cmds with
  | `Error _ -> exit 1
  | _ -> exit 0
