(*********************************************************************************)

(*                Cameleon                                                       *)
(*                                                                               *)
(*    Copyright (C) 2005,2006 Institut National de Recherche en Informatique     *)
(*    et en Automatique. All rights reserved.                                    *)
(*                                                                               *)
(*    This program is free software; you can redistribute it and/or modify       *)
(*    it under the terms of the GNU Library General Public License as            *)
(*    published by the Free Software Foundation; either version 2 of the         *)
(*    License, or  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 Library General Public License for more details.                       *)
(*                                                                               *)
(*    You should have received a copy of the GNU Library 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                                                            *)
(*                                                                               *)
(*    Contact: Maxence.Guesdon@inria.fr                                          *)
(*                                                                               *)
(*********************************************************************************)


(** Revision manipulation. *)


open Ocvs_types

let print_DEBUG s = () (*print_string s ; print_newline ()*)

let string_of_revision_number number =
  String.concat "." (List.map string_of_int number)

(** A string to display information about a revision. *)

let string_of_revision r =
  Ocvs_messages.revision^": "^
  (string_of_revision_number r.rev_number)^"\n"^
  Ocvs_messages.date^": "^r.rev_date^"\n"^
  Ocvs_messages.author^": "^r.rev_author^"\n"^
  r.rev_comment

(** Get the first revision of the given subbranch. *)

let first_subbranch_revision number revs =
  let len = List.length number in
  let res =
    List.fold_left
      (fun (id_rev_opt) -> fun r ->
        let (first, last) = Ocvs_misc.get_n_first_ele len r.rev_number in
        if len < List.length r.rev_number && first = number then
          match last with
            [id2] ->
              (
               match id_rev_opt with
                 Some (id, _) when id2 < id -> Some (id2, r)
              | Some (id, _) -> id_rev_opt
              | _ -> Some (id2, r)
              )
          | _ ->
              id_rev_opt
       else
          id_rev_opt
      )
      None
      revs
  in
  match res with
    None -> None
  | Some (_, r) -> Some r

(** Get the subranches numbers of a revision. *)

let subranches_numbers revs rev =
  let len = List.length rev.rev_number in
  let subbranches_rev =
    List.filter
      (fun r ->
        len < List.length r.rev_number &&
        (fst (Ocvs_misc.get_n_first_ele len r.rev_number)) = rev.rev_number
      )
      revs
  in
  let l =
    List.fold_left
      (fun acc -> fun r ->
        let (_, remain) = Ocvs_misc.get_n_first_ele len r.rev_number in
        match remain with
        | n :: _ when not (List.mem n acc)-> n :: acc
        | _ -> acc
      )
      []
      subbranches_rev
  in
  List.map (fun n -> rev.rev_number @ [n]) l

(** Return the list of revisions which are a child of a given revision. *)

let children_revisions (revs : cvs_revision list) rev =
  match rev.rev_number with
    [] -> []
  | _ ->
      let subbranch_numbers = subranches_numbers revs rev in
      let first_subs = List.fold_left
          (fun acc -> fun n ->
            match first_subbranch_revision n revs with
              None -> acc
            | Some r -> r :: acc
          )
          []
          subbranch_numbers
      in
      let len = List.length rev.rev_number in
      let s = string_of_revision_number rev.rev_number in
      let f rev2 =
        if rev2.rev_number = [] then
          false
        else
          let len2 = List.length rev2.rev_number in
          if len < len2 then
            len + 2 = len2 &&
            (fst (Ocvs_misc.get_n_first_ele len rev2.rev_number)) = rev.rev_number &&
            List.mem rev2 first_subs

          else if len = len2 then
            try
              let (before, after) = Ocvs_misc.get_n_first_ele (len - 1) rev.rev_number in
              let (before2, after2) = Ocvs_misc.get_n_first_ele (len - 1) rev2.rev_number in
              before = before2 &&
              (List.hd after) + 1 = List.hd (after2)
            with
              Not_found ->
                (List.hd (List.rev rev.rev_number)) + 1 = List.hd (List.rev rev2.rev_number)
            | Invalid_argument s ->
                prerr_endline ("Invalid argument "^s);
                false
          else
            false
      in
      let res = List.filter f revs in
      print_DEBUG (s^" ->");
      List.iter (fun r -> print_DEBUG (" "^(string_of_revision_number r.rev_number))) res ;
      res

(** Get the first revision of a list of revisions. *)

let first_revision revs =
(*  let order n1 n2 =
    match n1, n2 with
      [], (_::_) ->
    | _, [] -> false
    | (id1 :: q1), (id2 :: q2) ->
        (id1 < id2) or
        ((id1 = id2) && (order q1 q2))
  in
*)

  match List.sort (fun r1 -> fun r2 -> compare r1.rev_number r2.rev_number) revs
  with
    [] -> None
  | h :: _ -> Some h