-- Reads in strings, counts the number of distinct vowels
-- For strings with 0..3 vowels, stores the head (2 chars)
-- For strings with 4..6 vowels, stores the tail (3 chars)
-- Prints all heads, followed by all tails
-- Example input:
--  abcde
--  aeiou
--  bbb
-- Example output:
--  ab
--  bb
--  iou

pragma Assertion_Policy (Check);  -- Turn on Dynamic_Predicate checking

procedure vowels_variations  is
type Distinct_Vowel_Count is range 0 .. 6;

-- Count number of distinct vowels in s
-- A second version to consider
function number_distinct_vowels(s: String) return Distinct_Vowel_Count is
check: array(Character) of Boolean := (others => false);
begin
for c of s loop
check(c) := true;
end loop;

return (if check('a') then 1 else 0)
+ (if check('e') then 1 else 0)
+ (if check('i') then 1 else 0)
+ (if check('o') then 1 else 0)
+ (if check('u') then 1 else 0)
+ (if check('y') then 1 else 0);

--  Another way to calculate the answer
--  for b of check loop
--     if b then
--        ans := ans + 1;
--     end if;
--  end loop;
--  return ans;

--  Yet Another way to calculate the answer
--  subtype vowels is Character
--  with static_predicate => vowels in 'a'|'e'|'i'|'o'|'u'|'y';
--  for v in vowels loop
--     if check(v) then
--        ans := ans + 1;
--     end if;
--  end loop;
--  return ans;
end number_distinct_vowels;

-- Count number of distinct vowels in s
-- A third version to consider
function number_distinct_vowels2(s: String) return Distinct_Vowel_Count is
type vowels is (a, e, i, o, u, y, not_a_vowel);

function char2vowel(c: Character) return vowels is
(case c is when 'a' => a, when 'e' => e, when 'i' => i, when 'o' => o,
when 'u' => u, when 'y' => y, when others => not_a_vowel);

subtype Binary_Distinct_Vowel_COunt is Distinct_Vowel_Count range 0 .. 1;
function bool2BDVC(b: Boolean) return Binary_Distinct_Vowel_COunt is
(if b then 1 else 0);

check: array(vowels) of Boolean;
ans: Distinct_Vowel_Count := 0;

begin
for c of s loop
check(char2vowel(c)) := true;
end loop;
for v in vowels loop
ans := ans + bool2BDVC(check(v));
--  ans := ans + Boolean'Pos(check(v));
--  The above works since False is at position 0, True at position 1!
--  Not necessarily a good idea!
end loop;
return ans;
end number_distinct_vowels2;

subtype Long_String is String with
Dynamic_Predicate => Long_String'length >= 3;
-- Predicate_Failure => raise Constraint_Error with "String too short!";
-- Unfortunately Predicate_Failure is not yet implemented

TAIL_LENGTH: COnstant := 3;

MAX_NUM_STRINGS: Constant := 100;
type String_Count is range 0 .. MAX_NUM_STRINGS;
subtype String_Index is String_Count range 1 .. String_Count'last;

use String_Count_IO;

type Tails_Array is array(String_Index) of String(1 .. TAIL_LENGTH);

procedure process_one_string(
s: Long_String;
num_tails: in out String_Count;
tails: in out Tails_Array)
is
TAIL_START: Constant Natural := s'last - TAIL_LENGTH + s'first;

subtype Few_Vowels is Distinct_Vowel_Count range 0 .. 3;
begin
if number_distinct_vowels(s) in Few_Vowels then
else
num_tails := num_tails + 1;
tails(num_tails) := s(TAIL_START .. s'last);
end if;
end process_one_string;

-- Slightly shorter version
procedure get_and_process_all_strings(
num_tails: out String_Count;
tails: out Tails_Array)
is
begin
num_tails := 0;
while not end_of_file loop
end loop;
end get_and_process_all_strings;

is
begin
for i in 1 .. num_heads loop
end loop;

for i in 1 .. num_tails loop
put_line(tails(i));
end loop;
end put;