open Printf

open Deck

let saved_newdeck = ref Deck.empty

let rec get_response () =
    match read_line () with
        | "y" | "Y" -> true
        | "n" | "N" -> false
        | _ -> 
              printf "Please input 'y' or 'n'\n";
              get_response ()
                  
let do_card card = 
    printf "%s\n> Press Enter" card.front;
    ignore (read_line ());
    printf "%s\n> Correct? (y/n) " card.back;
    let response = get_response () in printf "\n"; response
    

let rec main_rec
    ~level
    cards
    =
    let chosen_cards, nonchosen_cards = 
        List.partition (fun (card, clevel) -> level = level) cards
    in
    if chosen_cards = [] then
        if List.exists (fun (card, clevel) -> level > level) cards then
            main_rec ~level:(level+1) cards
        else if level > 0 then
            main_rec ~level:0 cards
        else 
            failwith "WTF? There are no cards with level 0 or greater... WTF."
    else (
        printf "Proceeding at level %i:\n" level;
        let new_chosen_cards =
            List.map
                (fun (card, level) -> 
                     let newcard, newlevel =
                         if do_card card 
                         then card, level + 1
                         else card, 0
                     in
                     saved_newdeck := Deck.add ~level:newlevel newcard !saved_newdeck;
                     newcard, newlevel)
                chosen_cards
        in
        Deck.of_list_with_levels (nonchosen_cards @ new_chosen_cards)
        (*main_rec ~level (nonchosen_cards @ new_chosen_cards)*)
        
    )

let min_level deck =
    let calculated_min =
        List.fold_right 
            (fun (_, clevel) min -> if clevel < min then clevel else min)
            deck
            max_int
    in
    if calculated_min = max_int then 0 else calculated_min
        
        
let main ?level deck =
    let cards = Deck.to_list deck in
    let level = match level with
        | Some 0 (* HACK, fix main.ml instead *)
        | None -> min_level cards
        | Some l -> l
    in

    let cards =
        List.filter (fun (card,clevel) -> clevel = level)
        cards
    in

    if (List.length cards) = 0 then (
        eprintf "Level %i is empty, quitting.\n%!" level;
        exit 0
    );

    (* Sigint is the normal way of quitting early *)
    ignore (
        Sys.signal Sys.sigint (Sys.Signal_handle
                                   (fun signal -> 
                                        Data.save_data !saved_newdeck; 
                                        exit signal)));
    
    printf "Proceeding at level %i:\n" level;
    saved_newdeck := Deck.empty;
    List.iter
        (fun (card, level) -> 
             let newcard, newlevel =
                 if do_card card 
                 then card, level + 1
                 else card, 0
             in
             saved_newdeck := 
                 Deck.add ~level:newlevel newcard !saved_newdeck)
        cards;
        
    Data.save_data !saved_newdeck;
    saved_newdeck := Deck.empty
