ANY FILTER_OUTPUT_STREAM NONE
class interface HTML_OUTPUT_STREAM
   --
   -- Highly tailored filter that outputs well-formed HTML. Be aware that you cannot add any character as you
   -- want. You can filter this stream, but keep it available because it controls the tags.
   --

creation
   connect_to (a_stream: OUTPUT_STREAM)
      -- Connect the filter to some underlying stream.
      require
         not is_connected;
         a_stream.is_connected;
         not a_stream.is_filtered
      ensure
         is_connected

feature(s) from STREAM
   is_connected: BOOLEAN
      -- True if the filter is connected to some underlying stream.

   disconnect
      -- Disconnect from the underlying stream.
      require
         is_connected
      require else
         is_connected
      ensure
         not is_connected;
         stream = Void;
         filter = Void

   is_filtered: BOOLEAN

   detach
      ensure
         not is_filtered

feature(s) from STREAM
   set_filter (a_filter: FILTER_OUTPUT_STREAM)
      require
         a_filter /= Void
      ensure
         filter = a_filter

   filter: FILTER_OUTPUT_STREAM

feature(s) from OUTPUT_STREAM
   put_character (c: CHARACTER)
      require
         is_connected;
         not is_filtered and then can_put_character(c)

   flush
      -- Flushes the pipe. If is_filtered, calls the filter's
      -- flush instead.
      require
         is_connected

   can_put_character (c: CHARACTER): BOOLEAN

feature(s) from OUTPUT_STREAM
   filtered_put_character (c: CHARACTER)
      require
         is_connected;
         can_put_character(c)

   filtered_flush
      require
         is_connected

feature(s) from OUTPUT_STREAM
   put_string (s: STRING)
      -- Output s to current output device.
      require
         is_connected;
         not is_filtered;
         s /= Void

   put_unicode_string (unicode_string: UNICODE_STRING)
      -- Output the UTF-8 encoding of the unicode_string.
      require
         is_connected;
         not is_filtered;
         unicode_string /= Void

feature(s) from OUTPUT_STREAM
   -- To write a number:

   put_integer (i: INTEGER_64)
      -- Output i to current output device.
      require
         is_connected;
         not is_filtered

   put_integer_format (i: INTEGER_64; s: INTEGER)
      -- Output i to current output device using at most s character.
      require
         is_connected;
         not is_filtered

   put_real (r: REAL)
      -- Output r to current output device.
      require
         is_connected;
         not is_filtered

   put_real_format (r: REAL; f: INTEGER)
      -- Output r with only f digit for the fractionnal part.
      -- Examples:
      --    put_real(3.519,2) print "3.51".
      require
         is_connected;
         not is_filtered;
         f >= 0

   put_double (d: DOUBLE)
      -- Output d to current output device.
      require
         is_connected;
         not is_filtered

   put_double_format (d: DOUBLE; f: INTEGER)
      -- Output d with only f digit for the fractionnal part.
      -- Examples:
      --    put_double(3.519,2) print "3.51".
      require
         is_connected;
         not is_filtered;
         f >= 0

   put_number (number: NUMBER)
      -- Output the number.
      require
         is_connected;
         not is_filtered;
         number /= Void

feature(s) from OUTPUT_STREAM
   -- Other features:

   put_boolean (b: BOOLEAN)
      -- Output b to current output device according
      -- to the Eiffel format.
      require
         is_connected;
         not is_filtered

   put_pointer (p: POINTER)
      -- Output a viewable version of p.
      require
         is_connected;
         not is_filtered

   put_new_line
      -- Output a newline character.
      require
         is_connected;
         not is_filtered

   put_spaces (nb: INTEGER)
      -- Output nb spaces character.
      require
         is_connected;
         not is_filtered;
         nb >= 0

   append_file (file_name: STRING)
      require
         is_connected;
         not is_filtered;
         file_exists(file_name)

feature(s) from FILTER
   do_detach
      -- Used by the underlying stream to require not to be filtered anymore

feature(s) from HTML_OUTPUT_STREAM
   -- CGI extensions: written before the HTML itself is open

   put_cgi_header (key, value: STRING)
      require
         not started;
         key /= Void;
         value /= Void
      ensure
         has_cgi_header

feature(s) from HTML_OUTPUT_STREAM
   -- Main HTML structure

   header
      require
         not started
      ensure
         in_header

   body
      require
         in_header
      ensure
         in_body

   frames
      require
         in_header
      ensure
         in_frames

   close
      require
         in_body or else in_frames
      ensure
         finished

feature(s) from HTML_OUTPUT_STREAM
   last_tag: STRING
      require
         started and then not finished;
         has_open_tag
      ensure
         Result /= Void

   has_open_tag: BOOLEAN
      ensure
         Result implies started and then not finished

feature(s) from HTML_OUTPUT_STREAM
   -- Attributes management

   attributes: STRING
      -- Because there are so many attributes for each tag, we did not want features with scores
      -- of parameters. So, we decided to have a general-purpose with_attribute feature to be called
      -- before a tag creation.
      --
      -- Typical use:
      --
      -- html_out.with_attribute(once "width", once "80%%")
      -- html_out.with_attribute(once "align", once "center")
      -- html_out.with_attribute(once "valign", once "top")
      -- html_out.open_table_cell

   with_attribute (name, value: STRING)
      -- Call this feature before adding an opening tag; all the attributes will be added to the tag.

feature(s) from HTML_OUTPUT_STREAM
   -- Putting characters

   put_entity (entity: STRING)
      require
         started;
         not finished;
         not entity.has(';');
         not entity.has('&');
         not entity.has('<');
         not entity.has('>')

   put_comment (comment: STRING)

feature(s) from HTML_OUTPUT_STREAM
   indent
      require
         started;
         not finished

feature(s) from HTML_OUTPUT_STREAM
   -- Header tags

   put_base (base: STRING)
      require
         in_header

   put_meta (equiv, content: STRING)
      require
         in_header

   put_stylesheet (ref: STRING)
      require
         in_header

   open_title
      require
         in_header

   close_title
      require
         in_header;
         last_tag.same_as(os_title)

   put_script (language, source: STRING)
      require
         in_header;
         language /= Void;
         source /= Void

   open_script (language: STRING)
      require
         in_header;
         language /= Void

   close_script
      require
         in_script;
         last_tag.same_as(os_script)

feature(s) from HTML_OUTPUT_STREAM
   -- Frames

   open_frameset
      require
         in_frames or else in_frameset
      ensure
         in_frameset

   close_frameset
      require
         in_frameset
      ensure
         in_frames or else in_frameset

   put_frame (src, name: STRING)
      require
         in_frameset;
         src /= Void
      ensure
         in_frameset

   open_noframes
      require
         in_frames
      ensure
         in_noframes

   close_noframes
      require
         in_noframes
      ensure
         in_frames

feature(s) from HTML_OUTPUT_STREAM
   -- Body tags

   open_section
      require
         in_a_body

   close_section
      require
         in_a_body;
         last_tag.same_as(os_h1)

   open_subsection
      require
         in_a_body

   close_subsection
      require
         in_a_body;
         last_tag.same_as(os_h2)

   open_subsubsection
      require
         in_a_body

   close_subsubsection
      require
         in_a_body;
         last_tag.same_as(os_h3)

   put_break
      require
         in_a_body

   put_image (source: STRING)
      require
         in_a_body;
         source /= Void

   open_bold
      require
         in_a_body

   close_bold
      require
         in_a_body;
         last_tag.same_as(os_b)

   open_font (size: STRING)
      require
         in_a_body

   close_font
      require
         in_a_body;
         last_tag.same_as(os_font)

   open_italics
      require
         in_a_body

   close_italics
      require
         in_a_body;
         last_tag.same_as(os_i)

   open_typeset
      require
         in_a_body

   close_typeset
      require
         in_a_body;
         last_tag.same_as(os_tt)

   open_preformatted
      require
         in_a_body

   close_preformatted
      require
         in_a_body;
         last_tag.same_as(os_pre)

   open_anchor_address (ref, target: STRING)
      require
         in_a_body;
         ref /= Void

   open_anchor_name (ref: STRING)
      require
         in_a_body;
         ref /= Void

   close_anchor
      require
         in_a_body;
         last_tag.same_as(os_a)

   open_list
      require
         in_a_body
      ensure
         in_list

   open_numbered_list
      require
         in_a_body
      ensure
         in_list

   close_list
      require
         in_list;
         last_tag.same_as(os_ul) or else last_tag.same_as(os_ol)
      ensure
         in_a_body

   open_list_item
      require
         in_list
      ensure
         in_list_item

   close_list_item
      require
         in_list_item;
         last_tag.same_as(os_li)
      ensure
         in_list

   open_table
      require
         in_a_body
      ensure
         in_table

   close_table
      require
         in_table;
         last_tag.same_as(os_table)
      ensure
         in_a_body

   open_table_row
      require
         in_table
      ensure
         in_table_row

   close_table_row
      require
         in_table_row;
         last_tag.same_as(os_tr)
      ensure
         in_table

   open_table_cell
      require
         in_table_row
      ensure
         in_table_cell

   close_table_cell
      require
         in_table_cell;
         last_tag.same_as(os_td)
      ensure
         in_table_row

feature(s) from HTML_OUTPUT_STREAM
   -- Forms

   open_form (name, method, action: STRING)
      require
         in_a_body;
         name /= Void;
         action /= Void;
         method.same_as(os_method_get) or else method.same_as(os_method_post)
      ensure
         in_form

   close_form
      require
         in_form;
         last_tag.same_as(os_form)

   open_text_area (name: STRING; rows, cols: INTEGER)
      require
         in_a_form;
         name /= Void;
         rows > 0;
         cols > 0
      ensure
         in_text_area

   close_text_area
      require
         in_text_area

   put_validate_button (name, title: STRING)
      require
         in_a_form;
         name /= Void

   put_reset_button (name, title: STRING)
      require
         in_a_form;
         name /= Void

   put_hidden_field (name, value: STRING)
      require
         in_a_form;
         name /= Void

   put_text_field (name, value: STRING)
      require
         in_a_form;
         name /= Void

   put_radio_button (name, value: STRING; checked: BOOLEAN)
      require
         in_a_form;
         name /= Void;
         value /= Void

   put_check_box (name, value: STRING; checked: BOOLEAN)
      require
         in_a_form;
         name /= Void;
         value /= Void

   open_combo_select (name: STRING)
      require
         in_a_form;
         name /= Void
      ensure
         in_select

   open_multiple_select (name: STRING; size: INTEGER)
      require
         in_a_form;
         name /= Void;
         size > 0
      ensure
         in_select

   close_select
      require
         in_select;
         last_tag.same_as(os_select)
      ensure
         in_a_form

   open_option (value: STRING)
      require
         in_select
      ensure
         in_option

   close_option
      require
         in_option;
         last_tag.same_as(os_option)
      ensure
         in_select

   open_paragraph
      require
         in_a_body
      ensure
         in_paragraph

   close_paragraph
      require
         in_paragraph
      ensure
         in_a_body

feature(s) from HTML_OUTPUT_STREAM
   -- State queries

   started: BOOLEAN

   finished: BOOLEAN

   in_header: BOOLEAN

   in_script: BOOLEAN

   in_body: BOOLEAN

   in_list: BOOLEAN

   in_list_item: BOOLEAN

   in_table: BOOLEAN

   in_table_row: BOOLEAN

   in_table_cell: BOOLEAN

   in_form: BOOLEAN

   in_select: BOOLEAN

   in_option: BOOLEAN

   in_frames: BOOLEAN

   in_frameset: BOOLEAN

   in_noframes: BOOLEAN

   in_a_body: BOOLEAN

   in_a_form: BOOLEAN

   in_text_area: BOOLEAN

   in_paragraph: BOOLEAN


invariant

    stream /= Void implies stream.filter = Current;

end of HTML_OUTPUT_STREAM