-----------------------------------------------------------
--                   Eiffel/S libraries                  --
-----------------------------------------------------------
--               Copyright (C) 1991 - 1993               --
--                           by                          --
--                   SiG Computer GmbH                   --
--                  All rights reserved                  --
-----------------------------------------------------------
-- Release : 1.3 - October 1993                          --
-----------------------------------------------------------
-- Authors : Lambert Strether & Michael Schweitzer       --
-----------------------------------------------------------
  
class   TEXTFILE 
                    -- ASCII textfiles

-----------------------------------------------------------
creation {ANY}
    connect_to
-----------------------------------------------------------
feature {ANY}
-----------------------------------------------------------

    count        : INTEGER
    is_connected : BOOLEAN

-----------------------------------------------------------

    connect_to (hook : INTEGER) is

        local
            i : INTEGER
        do
            !!buffer.make (0, Buffer_size - 1)

            !!fs.make
            !!orig_file.connect_to (hook)

            open_temp_file
            load ($rt_read_range, $rt_put_strings, orig_file.count, buffer)
            count := max_line

            orig_path := fs.absolute_path (fs.identify (hook))
            orig_file.disconnect

            from
                if count < Min_size then
                    !!lines.make (1, Min_size)
                else
                    !!lines.make (1, count)
                end

                i := 1
            until
                i > count
            loop
                lines.put (i - 1, i)
                i := i + 1
            end

            free     := count
            crnt_buf := -1

            is_connected := true
        end
-----------------------------------------------------------

    disconnect is

        require
            connected : is_connected

        local
            hook : INTEGER
        do
            if is_dirty then
                hook := fs.access_file (orig_path, "rw", true) 
                !!orig_file.connect_to (hook)
                put_buffer
                store ($rt_write_range, $get_buffer, $buf_adr, 
                                                lines, count, out_buf)
                orig_file.disconnect
            end

            temp_file.disconnect
            fs.remove_file (temp_path)
            is_connected := false
        end
-----------------------------------------------------------
 
    abort is
            -- forget all changes made to original file

        require
            connected : is_connected
        do
            temp_file.disconnect
            fs.remove_file (temp_path)
            is_connected := false
        end
-----------------------------------------------------------
 
    item (index : INTEGER) : STRING is

        require
            connected  : is_connected
            good_index : 1 <= index and then index <= count

        local
            l_no : INTEGER
        do
            l_no := lines.item (index)

            if l_no // Buffer_size /= crnt_buf then
                get_buffer (l_no // Buffer_size)
            end

            result := buffer.item (l_no \\ Buffer_size)
        end
-----------------------------------------------------------

    put (s : STRING, index : INTEGER) is

        require
            connected  : is_connected
            good_index : 1 <= index and then index <= count

        local
            l_no : INTEGER

        do
            l_no := lines.item (index)

            if l_no // Buffer_size /= crnt_buf then
                get_buffer (l_no // Buffer_size)
            end

            buffer.put (s, l_no \\ Buffer_size)  
            buf_dirty := true
            is_dirty  := true 
        end
-----------------------------------------------------------

    insert (s : STRING, index : INTEGER) is
                -- insert line s AFTER index

        require
            connected  : is_connected
            good_index : 0 <= index and then index <= count

        do
            count := count + 1

            if count >= lines.size then
                lines.resize (1, lines.size + Min_size)
            end

            if free // Buffer_size /= crnt_buf then
                get_buffer (free // Buffer_size)
            end

            buffer.put (s, free \\ Buffer_size) 
            buf_dirty := true

            if index = count - 1 then
                lines.put (free, count)
            else
                lines.insert (free, index)
            end

            free := free + 1

            is_dirty := true
        end
-----------------------------------------------------------

    remove (index : INTEGER) is
                -- remove line at index

        require
            connected  : is_connected
            good_index : 1 <= index and then index <= count

        do
            count := count - 1
            lines.remove (index)
            is_dirty := true
        end
-----------------------------------------------------------
feature {NONE}
-----------------------------------------------------------

    Min_size    : INTEGER is 16
    Buffer_size : INTEGER is 1024
    Out_size    : INTEGER is 1024
    is_dirty    : BOOLEAN
    buf_dirty   : BOOLEAN
    orig_path   : STRING
    temp_path   : STRING
    temp_file   : FILE [ARRAY [STRING]] -- temporary file for dirty lines
    orig_file   : FILE [CHARACTER]      -- original file
    lines       : ARRAY [INTEGER]
    buffer      : ARRAY [STRING]
    fs          : FILE_SYSTEM
    free        : INTEGER               -- next free index in temp_file
    crnt_buf    : INTEGER               -- number of current buffer
 
-----------------------------------------------------------

    get_buffer (b_no : INTEGER) is

        do
            if b_no /= crnt_buf then
                if buf_dirty then
                    put_buffer
                end

                if b_no < temp_file.count then
                    buffer := temp_file.item (b_no + 1)
                else
                    !!buffer.make (0, Buffer_size - 1)
                end

                crnt_buf := b_no
            end
        end
-----------------------------------------------------------

    put_buffer is

        do
            temp_file.put (buffer, crnt_buf + 1)
            buf_dirty := false
        end
-----------------------------------------------------------

    load (p1, p2 : POINTER, size : INTEGER, buf : ARRAY [STRING]) is

        external "CWC" -- changed by x_c_cwc
        alias "ETF_load"
        end
-----------------------------------------------------------

    store (p1, p2, p3 : POINTER, lin : ARRAY [INTEGER], 
                        cnt : INTEGER, obuf: ARRAY [CHARACTER]) is

        external "CWC" -- changed by x_c_cwc
        alias "ETF_store"
        end
-----------------------------------------------------------
 
    open_temp_file is

        do
            temp_path := fs.absolute_path (fs.temp_file)

            if not fs.file_exists (temp_path) then
                fs.add_file (temp_path, "rw.rw.rw")
            end

            !!temp_file.connect_to (fs.access_file (temp_path, "rw", true))
        end
-----------------------------------------------------------

    buf_adr : ARRAY [STRING] is

        do
            Result := buffer
        end
-----------------------------------------------------------

    out_buf : ARRAY [CHARACTER] is

        once                    -- files use the same one
            !!result.make (0, Out_size - 1)
        end
-----------------------------------------------------------

    max_line : INTEGER is

        external "CWC" -- changed by x_c_cwc
        alias "ETF_max_line"
        end
-----------------------------------------------------------
-----------------------------------------------------------

    rt_read_range (from_idx, to_idx : INTEGER) : ARRAY [CHARACTER] is

        do
            Result := orig_file.item_range (from_idx, to_idx)
        end
-----------------------------------------------------------

    rt_write_range (b : ARRAY [CHARACTER], from_idx, to_idx : INTEGER) is

        do
            orig_file.put_range (b, from_idx, to_idx)
        end
-----------------------------------------------------------

    rt_put_strings (b : ARRAY [STRING], idx : INTEGER) is

        do
            temp_file.put (b, idx)
        end
-----------------------------------------------------------

end -- class TEXTFILE 

