#open "windows";;
#open "camlwin";;

let IntMin = -10000;;
let IntMax = 10000;;



(* the parameters of us_parm are:
      0 -> left
      1 -> top
      2 -> width
      3 -> height
      4 -> graduate axes
      5 -> nb courbe
        -> color
        -> nb point
        -> x point
        -> y point
*)

let draw_graduation_param = 4;;
let nb_courb_param = 5;;
let fst_courb_param = 6;;


let range usr =
  let nb_graph = gr_int_of_melted usr.us_param.(nb_courb_param) 
  and pos = ref fst_courb_param 
  and Dx = ref (IntMax,IntMin) 
  and Dy = ref (IntMax,IntMin) in
    if vect_length usr.us_param <= fst_courb_param
    then ((0,0),(0,0))
    else
    (
      for i = 0 to nb_graph-1 do
          pos := !pos+1;
          let nb_points = gr_int_of_melted usr.us_param.(!pos) in
            pos := !pos+1;
          for j = 0 to nb_points-1 do
            let x = gr_int_of_melted usr.us_param.(!pos)
            and y = gr_int_of_melted usr.us_param.(!pos+1) in
              Dx := (min x (fst !Dx), max x (snd !Dx));
              Dy := (min y (fst !Dy), max y (snd !Dy));
              pos := !pos+2
          done
        done;
       (!Dx,!Dy)
     )
;;
      


let draw_graph usr =
    (* get the object size *)
  let left   = gr_to_real_coord (gr_int_of_melted usr.us_param.(0))
  and top    = gr_to_real_coord (gr_int_of_melted usr.us_param.(1))
  and width  = gr_to_real_coord (gr_int_of_melted usr.us_param.(2))
  and height = gr_to_real_coord (gr_int_of_melted usr.us_param.(3)) in
      (* erase the old object *)
    set_color (gr_backcolor ());
    fill_rect left (top-height) width height;
    set_color black;

    let rg = range usr 
    and size = text_size "00" in
      let xmax = snd (fst rg)
      and xmin = fst (fst rg)
      and ymax = snd (snd rg)
      and ymin = fst (snd rg) in

          let dx = xmax - xmin 
          and dy = ymax - ymin 
            and leftr = match (xmin < 0, xmax >= 0) with
                       (true, true)  -> left 
                     | (false, true) -> left + (fst size)
                     | (true, false) -> left 
                     | (false, false) -> raise (Failure "Error of range")
            and topr = match (ymin < 0, ymax >= 0) with
                       (true, true)  -> top
                     | (false, true) -> top
                     | (true, false) -> top - (snd size)
                     | (false, false) -> raise (Failure "Error of range")
            and widthr = match (xmin < 0, xmax >= 0) with
                       (true, true)  -> width
                     | (false, true) -> width - (fst size)
                     | (true, false) -> width - (fst size)
                     | (false, false) -> raise (Failure "Error of range") 
            and heightr = match (ymin < 0, ymax >= 0) with
                       (true, true)  -> height
                     | (false, true) -> height - (snd size)
                     | (true, false) -> height - (snd size)
                     | (false, false) -> raise (Failure "Error of range") in

            let yaxe = match (xmin < 0, xmax >= 0) with
                       (true, true)  -> leftr - widthr * xmin / dx
                     | (false, true) -> leftr + (fst size)
                     | (true, false) -> leftr + widthr - (fst size)
                     | (false, false) -> raise (Failure "Error of range")
            and xaxe = match (ymin < 0, ymax >= 0) with
                       (true, true)  -> topr - heightr - heightr * ymin / dy
                     | (false, true) -> topr - heightr + (snd size)
                     | (true, false) -> topr - (snd size)
                     | (false, false) -> raise (Failure "Error of range") in

                  (* draw the vertical axe *)
              moveto yaxe top;
              lineto yaxe (top-height);
              moveto (yaxe - 3) (top - 3);
              lineto yaxe top;
              lineto (yaxe+ 3) (top - 3);
              moveto (yaxe-(fst size)) (top-height);
              draw_string (string_of_int ymin);
              if not ymin = ymax
              then
              (
                moveto (yaxe-(fst size)) (top-(snd size));
                draw_string (string_of_int ymax)
              );



                  (* draw the horizontal axe *)
              moveto left xaxe;
              lineto (left+width) xaxe;
              moveto (left+width-3) (xaxe-3);
              lineto (left+width) xaxe;
              lineto (left+width-3) (xaxe+3);
              moveto left (xaxe-(snd size));
              draw_string (string_of_int xmin);
              if not xmin = xmax
              then
              (
                moveto (left+width-(fst size)) (xaxe-(snd size));
                draw_string (string_of_int xmax)
              );

    let nb_graph = gr_int_of_melted usr.us_param.(nb_courb_param) 
    and pos = ref fst_courb_param in
      for i = 0 to nb_graph-1 do
        set_color (gr_int_of_melted usr.us_param.(!pos));
        pos := !pos+1;
        let nb_points = gr_int_of_melted usr.us_param.(!pos) in
          pos := !pos+1;
          let x = gr_int_of_melted usr.us_param.(!pos)
          and y = gr_int_of_melted usr.us_param.(!pos+1) in
          moveto ( ( widthr * ( x - xmin ) / dx ) + leftr ) 
                 ( ( heightr * ( y - ymin ) / dy ) + topr-heightr);
          pos := !pos+2;
          for j = 1 to nb_points-1 do
            let x = gr_int_of_melted usr.us_param.(!pos)
            and y = gr_int_of_melted usr.us_param.(!pos+1) in
            lineto ( ( widthr * ( x - xmin ) / dx ) + leftr )
                   ( ( heightr * ( y - ymin) / dy ) + topr-heightr);
            pos := !pos+2
          done
      done
;;


  
let make_graph Window left top width height =
  {
     us_window = Window;
     us_param = [| int_type left; int_type top; 
                   int_type width; int_type height; bool_type false; int_type 0 |];
     us_draw = draw_graph;
     us_callback = gr_do_nothing
  }
;;


let rec vect_of_coordlist coords =
  match coords with
    [] -> [| |]
  | x::y -> concat_vect [|int_type (fst x); int_type (snd x) |] (vect_of_coordlist y)
;;

let add_func Graph Points Color =
  let len = list_length Points in
  if len > 0
  then
  (
    Graph.us_param.(nb_courb_param) <- int_type ((gr_int_of_melted Graph.us_param.(nb_courb_param)) + 1);
    Graph.us_param <- concat_vect Graph.us_param [| int_type Color |];
    Graph.us_param <- concat_vect Graph.us_param [| int_type len |];
    Graph.us_param <- concat_vect Graph.us_param (vect_of_coordlist Points)
  )
;;

let draw_graduation Graph val =
  Graph.us_param.(draw_graduation_param) <- int_type val
;;

let clear_graph Graph =
    Graph.us_param <- sub_vect Graph.us_param 0 6
;;

