//@copyright_begin
// ================================================================
// Copyright Notice
// Copyright (C) 1998-2004 by Joe Linoff
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// 
// Comments and suggestions are always welcome.
// Please report bugs to http://ccdoc.sourceforge.net/ccdoc
// ================================================================
//@copyright_end

// MULTIPLE INCLUSION GUARD
#ifndef ccdoc_phase3_html_h
#define ccdoc_phase3_html_h

/**
 * This variable allows the header version
 * to be queried at runtime.
 */
namespace {
   char ccdoc_phase3_html_h_rcsid[] = "$Id: phase3_html.h,v 1.8 2004/09/30 04:16:07 jlinoff Exp $";
}

#include "switches.h"
#include "database.h"
#include "exceptions.h"
#include <fstream>
#include <set>

namespace ccdoc {
  namespace phase3 {
    /**
     * Generate the HTML output.
     * @author Joe Linoff
     * @version $Id: phase3_html.h,v 1.8 2004/09/30 04:16:07 jlinoff Exp $
     */
    class html {
    public:
      /**
       * Generate a checksum for a string.
       * @author Joe Linoff
       * @version $Id: phase3_html.h,v 1.8 2004/09/30 04:16:07 jlinoff Exp $
       */
      class checksum {
      public:
	/**
	 * Constructor.
	 */
	checksum() {clear();}
	/**
	 * Clear out the check sum.
	 */
	void clear(unsigned val = 0xffffffff) {m_checksum = val;}
	/**
	 * Add a string.
	 */
	void set(const char* str)
	{
	  for(;*str;++str) {
	    unsigned ch = *str;
	    m_checksum ^= ch;
	    ch = m_checksum & 0xff;
	    m_checksum = (m_checksum>>8) ^ m_crc_table[ch];
	  }
	  m_checksum ^= 0xFFFFFFFF;
	}
	/**
	 * Get the checksum.
	 * @returns The checksum.
	 */
	unsigned get() const {return m_checksum;}
      private:
	unsigned m_checksum;
	static unsigned m_crc_table[256];
      };
    public:
      /**
       * Constructor.
       * @param sw The command line switches.
       * @param db The database interface.
       */
      html(switches& sw,database& db);
      /**
       * Destructor.
       */
      ~html();
    public:
      /**
       * Was this phase completed correctly?
       * @returns True if it was or false if it wasn't.
       */
      bool ok() const {return m_ok;}
    public:
      /**
       * Run phase 3 processing to generate the HTML output.
       */
      bool run();
    public:
      bool get_debug() const {return m_debug;}
      void set_debug(bool f) {m_debug=f;}
    private:
      void write_indent(ostream& os) const;
      void write_unindent(ostream& os) const;
      void write_section_header(ostream& os,
				const char*,
				bool,
				const char* prev=0,
				const char* next=0);
      void write_section_header(ostream& os,
				statement::base*,
				bool,
				const char* prev=0,
				const char* next=0);
      void write_contents(ostream& os,statement::base*,bool=true);
      void write_ccdoc_src_info(ostream& os,statement::base*,statement::base*);
      bool write_ccdoc_src_info(string& path,statement::base*);
      void write_extends_clause(ostream& os,statement::base*);
      void write_class_details(ostream& os,statement::base*,bool=true);
      void write_friends_info(ostream& os,statement::base*);
      void write_friends_link(ostream& os,statement::base*,statement::base*);
      void write_code_section(ostream& os,statement::base*);
      void write_code_subsection_var(ostream& os,
				     statement::base*,
				     statement::base::strs_t&);
      void write_code_subsection_fct(ostream& os,
				     statement::base*,
				     statement::base::strs_t&);
      void write_code_subsection_opr(ostream& os,
				     statement::base*,
				     statement::base::strs_t&);
      void write_code_subsection_enum(ostream& os,
				      statement::base*,
				      statement::base::strs_t&);
      void write_code_subsection_token(ostream& os,
				       statement::base*,
				       const string&);
      bool write_code_subsection_token(ostream& os,
				       statement::base::stmts_t&,
				       const string&);
      void write_code_subsection_token(statement::base::stmts_t& vec,
                                       statement::base* stmt,
                                       const vector<string>& tokens,
                                       size_t idx) const;
      bool is_cxx_keyword(const string&);
      const char* format_string_for_html(const char*) const;
      const char* format_string_for_html(const string&) const;
      void write_html_formatted_string(ostream& os,const char*) const;
      void write_html_formatted_string(ostream& os,const string&) const;
    private:
      /**
       * Begin an indented code section.
       * @param os Output stream.
       */
      void code_begin(ostream& os);
      /**
       * End an indented code section.
       * @param os Output stream.
       */
      void code_end(ostream& os);
      /**
       * Load file.
       * @param fn The file name.
       * @param contents The string to load the file contents into.
       */
      void load(const string& fn,string& contents);
    private:
      /**
       * Write out the HTML files for the packages.
       * @throws ccdoc::exceptions::unwriteable_output_file
       *   If the output file cannot be written.
       */
      void write_ccdoc_pkgs_html();
      /**
       * Write out the HTML files for the namespaces.
       * @throws ccdoc::exceptions::unwriteable_output_file
       *   If the output file cannot be written.
       */
      void write_ccdoc_namespaces_html();
      /**
       * Write out the HTML files for the class, structs and unions.
       * @throws ccdoc::exceptions::unwriteable_output_file
       *   If the output file cannot be written.
       */
      void write_ccdoc_classes_html();
      /**
       * Write out class summary file.
       * @throws ccdoc::exceptions::unwriteable_output_file
       *   If the output file cannot be written.
       */
      void write_ccdoc_class_summary_html();
      /**
       * Write out class summary file.
       * @throws ccdoc::exceptions::unwriteable_output_file
       *   If the output file cannot be written.
       */
      void write_ccdoc_class_summary_html(ostream& os,
					  statement::base::stmts_t&,
					  bool rpthpc=false);
      /**
       * Write out class summary file.
       * @throws ccdoc::exceptions::unwriteable_output_file
       *   If the output file cannot be written.
       */
      void write_summary_tree(ostream& os,
			      statement::base::stmts_t&,
			      bool rpthpc=false,
			      statement::base* start = 0,
			      const char* indent = "",
			      bool sort_flag=true);
      /**
       * Write out class summary file.
       */
      void write_summary_tree_entry(ostream& os,
				    statement::base* stmt,
				    const char* indent = 0,
				    bool rpthpc=false);
      /**
       * Write out the short description for the contents
       * and summary.
       */
      void write_short_desc(ostream& os,
			    statement::base* stmt);
      /**
       * Write out the HTML files for functions.
       */
      void write_ccdoc_functions_html();
      /**
       * Write out the HTML files for variables.
       */
      void write_ccdoc_variables_html();
      /**
       * Write out the HTML files for enums.
       */
      void write_ccdoc_enums_html();
      /**
       * Write out the HTML files for typedefs.
       */
      void write_ccdoc_typedefs_html();
      /**
       * Write out the HTML files for macros.
       */
      void write_ccdoc_macros_html();
    private:
      /**
       * Write out the common header information.
       * @param os Output stream.
       * @param fn The file name.
       * @param stmt The statement.
       */
      void write_common_header_info(ostream& os,
				    const string& fn,
				    statement::base* stmt);
      /**
       * Write out the common header information.
       * @param os Output stream.
       * @param fn The file name.
       * @param title The title.
       */
      void write_common_header_info(ostream& os,
				    const string& fn,
				    const char* title);
    private:
      /**
       * Write out a link.
       * @param os Output stream.
       * @param stmt The statement.
       * @param name The optional link name.
       */
      void write_link(ostream& os,
		      const statement::base* stmt,
		      const char* name=0);
    private:
      /**
       * Extract and write links.
       * @param os Output stream.
       * @param link The name to look up in the database.
       * @param linkid The link identifier.
       * @param scope The scope for handling '#' operators in @link directives.
       * @returns The number of items written.
       */
      unsigned find_and_write_links(ostream&,
				    const char* link,
				    const char* linkid,
				    statement::base* scope);
    private:
      /**
       * Write out multiple links by creating an alternate page (issue 0082).
       * @param os Output stream.
       * @param stmt The statement.
       * @param name The optional link name.
       */
      void write_links(ostream& os,
		       const statement::base::stmts_t& stmt,
		       const char* name);
    private:
      /**
       * Write out the common trailer information.
       * @param os Output stream.
       */
      void write_common_trailer_info(ostream& os);
    private:
      /**
       * Write out the ccdoc information.
       * @param os Output stream.
       * @param stmt The statement.
       * @param author_required If true, the author field is required.
       * If the author is required and not specified, the string
       * "unascribed" is substituted.
       * @param version_required If true, the version field is required.
       * If the version is required and not specified, the string
       * "unknown" is substituted.
       * @param inherited If true, write out the hier_path of the
       * parent. This is used when writing class details for a child
       * that was defined in an inherited class.
       */
      void write_ccdoc_info(ostream& os,
			    statement::base* stmt,
			    bool author_required=false,
			    bool version_required=false,
			    bool inherited=false);
    private:
      /**
       * Write out a ccdoc description.
       */
      void write_ccdoc_desc_info(ostream& os,
				 const statement::base::strs_t& vec,
				 statement::base* scope,
                                 statement::base* stmt);
    private:
      /**
       * Write out a ccdoc @param directive.
       */
      void write_ccdoc_param_directive_info(ostream& os,
					    const statement::base::strss_t& vec,
					    statement::base* scope,
                                            statement::base* stmt);
    private:
      /**
       * Write out a ccdoc @exception directive.
       * @param os The output stream.
       * @param vec The exception data.
       * @param scope The scope.
       * @param stmt The statement for error reporting.
       */
      void write_ccdoc_exception_directive_info(ostream& os,
						const statement::base::strss_t& vec,
						statement::base* scope,
                                                statement::base* stmt);
    private:
      /**
       * Write out a ccdoc @see directive.
       */
      void write_ccdoc_see_directive_info(ostream& os,
					  const statement::base::strss_t& vecvec,
					  statement::base* stmt);
    private:
      /**
       * Write out the Inherited From: clause.
       */
      void write_inherited_from_info(ostream& os,
				     statement::base* stmt);
    private:
      /**
       * Write out a ccdoc directive.
       */
      void write_ccdoc_directive_info(ostream& os,
				      const char* name,
				      const statement::base::strs_t& vec,
				      const char* default_field,
				      statement::base* scope,
				      statement::base* stmt,
                                      bool commas);
    private:
      /**
       * Write out a ccdoc directive.
       */
      void write_ccdoc_directive_info(ostream& os,
				      const char* name,
				      const string& val,
				      const char* default_field,
				      statement::base* scope,
                                      statement::base* stmt);
      void write_ccdoc_line_info(ostream& os,
				 statement::base::strs_citr_t& i,
				 statement::base::strs_citr_t e,
				 statement::base* scope,
                                 statement::base* stmt);
    private:
      void write_meta(ostream& os,
		      const char* name,
		      const char* content);
    private:
      void make_class_contents(statement::base*,
			       statement::base::stmts_t&);
      unsigned load_extend_classes(const string& id,
				   statement::base::stmts_t& out,
				   statement::base*);
      void load_inheritance_classes(statement::base*,
				    statement::base::stmts_t&);
      void make_class_contents(statement::base::stmts_t&,
			       statement::base::stmts_t&,
			       statement::base::stmts_t&,
			       set<string>& used_method_ids);
      void get_fully_scoped_name(string& out_id,
				 const string& in_id,
				 statement::base::stmts_t parents) const;
    private:
      void make_contents(statement::base*,
			 statement::base::stmts_t&,
			 bool sort_flag=true);
      bool ignore_contents_stmt(statement::base*) const;
      void make_pkg_index_children(statement::base* stmt,
				   statement::base::stmts_t& outvec);
    private:
      void make_abs_path(statement::base* stmt,string& id) const;
      void make_rel_path(statement::base* top,statement::base* stmt,string& id) const;
    private:
      void make_tag_id(const statement::base* stmt,string& id) const;
    private:
      const statement::base* get_file_stmt(const statement::base* stmt) const;
    private:
      void make_file_url(string& url,string& fn) const;
      bool make_file_url(string& url,const statement::base* stmt);
    private:
      void make_unique_file_name(string& fn,
				 const statement::base* stmt);
    private:
      const char* format_name(const char*) const;
    private:
      /**
       * Get the current date and time.
       * @returns The date and time in a const char* buffer.
       */
      const char* date_time() const;
    private:
      bool m_debug;
      bool m_ok;
      database& m_db;
      set<string> m_keywords;
      string m_meta;
      string m_header;
      string m_trailer;
      string m_rptcsi; // Issue 0044
      switches& m_sw;
      unsigned m_multiple_ref_index;
    };
  }
}

#endif
