def document_ca65_source_as_html(codebase_dir,codebase_title,output_dir)



Dir.mkdir(output_dir) unless File.exist?(output_dir)

symbol_attributes={}
html_filenames={}
file_overviews={}


puts "generating documentation for #{codebase_title}"

documentation_title="#{codebase_title} technical reference"
require 'find'

files_to_parse=[]
Find.find(codebase_dir) do |path|
  Find.prune if path[0]=='.'
  files_to_parse  <<path.sub(codebase_dir,"").sub(/^\//,"") if path=~/\.s$/
end
files_to_parse.each do |filename|	

  html_filename="#{filename.gsub(/[\/.]/,"_")}.html"
  puts "scanning #{filename} (#{html_filename})"
  html_filenames[filename]=html_filename
  last_comment=nil
  symbol=nil
  file_overviews[filename]=""
  found_non_comment_line=false
  full_filename="#{codebase_dir}/#{filename}"
	File.open(full_filename).each_line do |line|
    
    #skip to next line if this is nothing but white space
    next if line=~/^\s*$/
    
    last_symbol=symbol unless symbol.nil?
    symbol=nil
    if (line=~/^\s*;(.*)/) && !(found_non_comment_line) then
      file_overviews[filename]<<"#{$1}\n"
    else
      found_non_comment_line=true      
    end
    

		if line=~/\.export\s+(\w+)/ then
			symbol=$1
      symbol_attributes[symbol]={} if symbol_attributes[symbol].nil?
			symbol_attributes[symbol][:type]=:function
			symbol_attributes[symbol][:defined_in]=[] if symbol_attributes[symbol][:defined_in].nil?
      symbol_attributes[symbol][:defined_in]<<filename
      filename
		end

		if line=~/\.exportzp\s+(\w+)/ then
			symbol=$1
      symbol_attributes[symbol]={} if symbol_attributes[symbol].nil?
			symbol_attributes[symbol][:type]=:variable
      symbol_attributes[symbol][:zero_page]=true
			symbol_attributes[symbol][:defined_in]=[] if symbol_attributes[symbol][:defined_in].nil?
      symbol_attributes[symbol][:defined_in]<<filename
		end

		if line=~/(\w+):?.*\.res\s+(\S+)/ then
			symbol=$1
			size=$2
      if !symbol_attributes[symbol].nil? then
        symbol_attributes[symbol][:type]=:variable 
        symbol_attributes[symbol][:size]={} if symbol_attributes[symbol][:size].nil?
        symbol_attributes[symbol][:size][filename]=size
      end
		end

		if line=~/(\w*)(:)*\s*\.(byte|asciiz)\s+([^;]*)/ then
      symbol=$1      
      symbol=last_symbol if symbol.length<1
      value=$4
						
      if !symbol_attributes[symbol].nil? then
        symbol_attributes[symbol][:type]=:constant 
        symbol_attributes[symbol][:value]={} if symbol_attributes[symbol][:value].nil?
        if symbol_attributes[symbol][:value][filename].nil? then
          symbol_attributes[symbol][:value][filename]=value
        else
          symbol_attributes[symbol][:value][filename]+="\n#{value}"
        end
      end
		end


		if line=~/(\w+):?.*=/ then
			symbol=$1
        if !symbol_attributes[symbol].nil? then
        symbol_attributes[symbol][:type]=:variable if symbol_attributes[symbol][:type]==:function
      end
		end

		if line=~/(\w+).*=\s?([^;]*)/ then
			symbol=$1
			value=$2
      if !symbol_attributes[symbol].nil? then
        symbol_attributes[symbol][:type]=:constant 
        symbol_attributes[symbol][:value]={} if symbol_attributes[symbol][:value].nil?
        symbol_attributes[symbol][:value][filename]=value
      end
    end
    
    if (symbol.nil?) &&  line=~/^(\w+):/ then
			symbol=$1
		end
    
		comment=nil
		if (!(symbol.nil?) && line=~/;(.*)/) then
			comment=$1
		end
    
		if ((comment.nil?) && (!last_comment.nil?) && (!symbol.nil?)) then
			comment=last_comment
		end

    if !symbol_attributes[symbol].nil?  && !comment.nil? then
      symbol_attributes[symbol][:comment]={} if symbol_attributes[symbol][:comment].nil?
      symbol_attributes[symbol][:comment][filename]=comment      
    end

		if line=~/^;(.*)/ then
			if last_comment.nil? then
				last_comment=""
			else
        last_comment+="\n"				
			end
			last_comment+=$1
		else
			last_comment=nil
		end

	end

end

symbol_names=symbol_attributes.keys.sort
source_files=[]
require 'markaby'

[:function,:variable,:constant].each do |symbol_type|
  mab = Markaby::Builder.new
  mab.html do
    head do
      link(:rel=>"stylesheet", :href=>"ca65-doc-style.css",:type=>"text/css")
    end    
    body do    
      h2 "#{symbol_type}s"
      table  do
        tr do 
          th "#{symbol_type}"
          th "defined in"
        end
        symbol_names.each do |symbol|
          if symbol_attributes[symbol][:type]==symbol_type then
            tr do 
                td symbol 
                count=0
                td do
                  symbol_attributes[symbol][:defined_in].each do |filename|
                    count+=1
                    text ", " unless count==1
                    a(:href=>"#{html_filenames[filename]}##{symbol_type}s", :target=>"docwin"){filename}
                    source_files<<filename unless source_files.include?(filename)
                  end
                end
              end
          end
        end
      end
    end
  end
  File.open("#{output_dir}/#{symbol_type}_index.html","w") <<mab.to_s
end


mab = Markaby::Builder.new
mab.html do
  head do
    link(:rel=>"stylesheet", :href=>"ca65-doc-style.css",:type=>"text/css")
  end

  body do    
    h1 "#{documentation_title}"

    h2 "files"
    table  do
      tr do 
        th "file"
        th "symbols"
      end        
      source_files.sort.each do |filename|
        tr do
          td {a(:href=>"#{html_filenames[filename]}", :target=>"docwin"){filename}}
          symbols_in_file=(symbol_names.collect{|symbol| symbol_attributes[symbol][:defined_in].include?(filename) ? symbol:nil}).compact
          td symbols_in_file.join(", ")
        end
      end
    end
  end
end
File.open("#{output_dir}/ref_index.html","w") <<mab.to_s



source_files.sort.each do |filename|
  functions_in_file=[]
  variables_in_file=[]
  constants_in_file=[]
  
  symbol_names.each do |symbol|
    symbol_attribute=symbol_attributes[symbol]
    if symbol_attribute[:defined_in].include?(filename) then
      functions_in_file<<symbol if symbol_attribute[:type]==:function
      variables_in_file<<symbol if symbol_attribute[:type]==:variable
      constants_in_file<<symbol if symbol_attribute[:type]==:constant
    end
  end

  mab = Markaby::Builder.new
  mab.html do
    head do
        link(:rel=>"stylesheet", :href=>"ca65-doc-style.css",:type=>"text/css")
    end
    body do    
      a(:href=>"ref_index.html") { h1 documentation_title} 
      h1 "File : #{filename}"
      pre file_overviews[filename] if file_overviews[filename].length>1

      if functions_in_file.length>0 then
        h2(:id=>"functions") {"functions"}
        table do
          tr do 
            th{"function"} 
            th{"description"}
          end
          functions_in_file.each do |symbol|
            tr do
              td(:id=>symbol){symbol} 
              td{pre symbol_attributes[symbol][:comment][filename] unless  symbol_attributes[symbol][:comment].nil?}
            end
          end
        end
      end

      if variables_in_file.length>0 then
        h2(:id=>"variables"){"variables"}
          table do
          tr do 
            th{"variable"} 
            th{"description"}
            th{"size (bytes)"}
          end
          variables_in_file.each do |symbol|
            tr do
              td(:id=>symbol){symbol} 
              td{symbol_attributes[symbol][:comment][filename] unless  symbol_attributes[symbol][:comment].nil?}
              td{symbol_attributes[symbol][:size][filename] unless  symbol_attributes[symbol][:size].nil?}
            end
          end
        end

      end
      
      if constants_in_file.length>0 then
        h2(:id=>"constants") {"constants"}
          table do
          tr do 
            th{"constants"} 
            th{"description"}
            th{"value"}
          end
          constants_in_file.each do |symbol|
            tr do
              td(:id=>symbol){symbol} 
              td{symbol_attributes[symbol][:comment][filename] unless  symbol_attributes[symbol][:comment].nil?}
              td{symbol_attributes[symbol][:value][filename] unless  symbol_attributes[symbol][:value].nil?}
            end
          end
        end
        
      end
      h2{ "implementation"}
      pre(:id=>:code) {File.open("#{codebase_dir}/#{filename}").read.gsub("\t","  ")}
    end
  end
  
  File.open("#{output_dir}/#{html_filenames[filename]}","w") <<mab.to_s
end


#markaby doesn't like framesets so do the index.html frameset the 'old fashioned' way
File.open("#{output_dir}/ref_frames.html","w") << <<EOF
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> 
  <title>#{documentation_title}</title>
</head>
<frameset rows="20%, 80%" border=1>
  <frameset cols="5,5,5" border=1>
    <frame src="function_index.html"  title="functions" name="functions" />
    <frame src="variable_index.html"   title="variables" name="variables"/>
    <frame src="constant_index.html"  title="constants" name="constants"/>
  </frameset>
  <frame name="docwin"  src="ref_index.html"   />

</frameset>    
EOF

end



if __FILE__ == $0 then
  #run from command line
  codebase_dir=Dir.pwd
  output_dir="doc"
  codebase_title=File.basename(codebase_dir) 
  document_ca65_source_as_html(codebase_dir,codebase_title,output_dir)
end