//
// Author: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Time: Jan 7, 2010
//

//
// list all the words with a given prefix; see the command [look]
//

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

#include "BUCASCS320.hats"

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

#define :: list0_cons
#define cons list0_cons
#define nil list0_nil

typedef charlst = list0 char

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

extern fun string_perm_test (s1: string, s2: string): bool

(*
** the time complexity of this function is O(n1 * (n1 + n2))
** where [n1] and [n2] are lengths of [s1] and [s2], respectively.
*)
implement string_perm_test (s1, s2) = let
  // count the number of occurrences of [c] in [cs]
  fun cnt (cs: charlst, c: char, res: int): int =
    case+ cs of
    | c1 :: cs1 => let
        val res = (if c = c1 then res + 1 else res): int
      in
        cnt (cs1, c, res)
      end // end of [::]
    | nil () => res
  // end of [cnt]

  // testing whether each character in [cs] has the same number
  // of occurrences in [cs1] as in [cs2]
  fun test (cs: charlst, cs1: charlst, cs2: charlst): bool =
    case+ cs of
    | c :: cs => let
        val n1 = cnt (cs1, c, 0) and n2 = cnt (cs2, c, 0)
      in
        if n1 = n2 then test (cs, cs1, cs2) else false
      end (* end of [::] *)
    | nil () => true
  // end of [test]
in
  if string_length s1 = string_length s2 then let
    val cs1 = string_explode (s1) and cs2 = string_explode (s2)
  in
    test (cs1, cs1, cs2)
  end else false
end (* end of [string_perm_test] *)

//

(*
fun string_test {n:nat}
  (word: string n): bool = let
  val n = string1_length word
in
  case+ 0 of
  | _ when n = 13 =>
      (word[0] = 'c' andalso word[n-1] = 'm')
  | _ => false
end // end of [string_test]
*)

//

fun mylook
  (inp: FILEref, prfx: string): void = let
  val word = input_line (inp)
in
  if stropt_is_some word then let
    val word = stropt_unsome (word)
    val word = string1_of_string word
    val word = string_tolower word
    val word = string1_of_strbuf (word)
    val ans = string_perm_test (prfx, word)
    val () = if ans then printf ("%s\n", @(word)) 
  in
    mylook (inp, prfx)
  end else begin
    // nothing
  end (* end of [if] *)
end // end of [mylook]

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

#define WORDS_FILE "/usr/share/dict/words"

implement main (argc, argv) = let
  val () = assert (argc >= 2)
  val prfx = argv.[1]
  val prfx = string1_of_string prfx
  val prfx = string_tolower prfx
  val prfx = string1_of_strbuf prfx
  val inp = open_file_exn (WORDS_FILE, file_mode_r)
  val () = mylook (inp, prfx)
  val () = close_file_exn (inp)
in
  // empty
end (* end of [main] *)

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

(* end of [mylook_scrabble.dats] *)