(*
 * This file is part of Bisect.
 * Copyright (C) 2008-2012 Xavier Clerc.
 *
 * Bisect 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.
 *
 * Bisect 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, see <http://www.gnu.org/licenses/>.
 *)

let url = "http://bisect.x9c.fr"

let (++) x y =
  if ((x > 0) && (y > 0) && (x > max_int - y)) then
    max_int
  else if ((x < 0) && (y < 0) && (x < min_int - y)) then
    min_int
  else
    x + y

let (--) x y =
  if y > min_int then
    (++) x (-y)
  else
    let res = (++) x max_int in
    if res < max_int then
      succ res
    else
      res

let rec zip op x y =
  let lx = Array.length x in
  let ly = Array.length y in
  if lx >= ly then begin
    let z = Array.copy x in
    for i = 0 to (pred ly) do
      z.(i) <- op x.(i) y.(i)
    done;
    z
  end else
    zip op y x

let (+|) x y = zip (++) x y

let (-|) x y = zip (--) x y

let mkdirs ?(perm=0o755) dir =
  let rec mk dir =
    if not (Sys.file_exists dir) then begin
      mk (Filename.dirname dir);
      Unix.mkdir dir perm
    end in
  mk dir

let split p l =
  let rec spl acc l =
    match l with
    | hd :: tl ->
        if (p hd) then
          spl (hd :: acc) tl
        else
          (List.rev acc), l
    | [] -> (List.rev acc), [] in
  spl [] l

let split_after n l =
  let rec spl n acc l =
    match l with
    | hd :: tl ->
        if n > 0 then
          spl (pred n) (hd :: acc) tl
        else
          (List.rev acc), l
    | [] -> (List.rev acc), [] in
  spl n [] l

let open_both in_file out_file =
  let in_channel = open_in in_file in
  try
    let out_channel = open_out out_file in
    (in_channel, out_channel)
  with e ->
    close_in_noerr in_channel;
    raise e

let output_strings lines mapping ch =
  let get x =
    try List.assoc x mapping with Not_found -> "" in
  List.iter
    (fun l ->
      let buff = Buffer.create (String.length l) in
      Buffer.add_substitute buff get l;
      output_string ch (Buffer.contents buff);
      output_char ch '\n')
    lines

let output_bytes data filename =
  Common.try_out_channel
    true
    filename
    (fun channel -> Array.iter (output_byte channel) data)

let current_time () =
  let now = Unix.localtime (Unix.time ()) in
  Printf.sprintf "%d-%02d-%02d %02d:%02d:%02d"
    (1900 + now.Unix.tm_year)
    (succ now.Unix.tm_mon)
    now.Unix.tm_mday
    now.Unix.tm_hour
    now.Unix.tm_min
    now.Unix.tm_sec
