-- Reads a file and prints the lines in reverse and each line in reverse
-- ITEC 320 3/6/15
--  Uses an array of unbounded strings

-- Program terminates immediately if lines are too long
--    or there are too many lines

with Ada.Text_IO; use Ada.Text_IO; 
with Ada.Strings.Unbounded, Ada.Text_IO.Unbounded_IO;

procedure reverse_unbounded  is 
    Max_Line_Length: constant := 80;
    Max_Num_Lines:   constant := 100;

    -- These 2 types are for creating arrays of lines
    type Line_Count is range 0 .. Max_Num_Lines;
    subtype Line_Range is Line_Count range 1 .. Line_Count'Last;

    -- Type of an array of unbounded strings
    type U_Line_Array is array(Line_Range) of 
        Ada.Strings.Unbounded.Unbounded_String;

    Line_Too_Long, Too_Many_Lines: Exception;

    ---------------------------------------------------------------------------
    --  Fill an array of unbounded strings
    procedure fill_4
        (u_lines: out U_Line_Array; num: out Line_Count)
    is
        use Ada.Strings.Unbounded, Ada.Text_IO.Unbounded_IO;
        u: Unbounded_String;
    begin
        num := 0;
        while not end_of_file and num < Line_Count'Last loop
            num := num + 1;

            u := get_line; 

            if length(u) > Max_Line_Length then
                raise Line_Too_Long;
            end if;
            u_lines(num) := u;
        end loop;
        if not end_of_file then
            raise Too_Many_Lines;
        end if;
    end fill_4;

    ---------------------------------------------------------------------------
    -- Reverse output num elements of an array of unbounded strings
    procedure put_lines (lines: U_Line_Array; num: Line_Count) is
        -- Nested procedure for printing a string in reverse
        procedure put_reverse(S: String) is
        begin
            for i in reverse s'range loop
                put(s(i));
            end loop;
        end put_reverse;
        use Ada.Strings.Unbounded;
    begin
        for i in reverse 1 .. num loop
            put_reverse(to_string(lines(i)));
            new_line;
        end loop;
    end put_lines;

---------------------------------------------------------------------------
    unbounded_lines : U_Line_Array;
    num_lines   : Line_Count;
begin
    fill_4(unbounded_lines, num_lines);
    put_lines(unbounded_lines, num_lines);
end reverse_unbounded;