package helma.doc;

import java.io.*;
import java.util.*;

import helma.util.*;

public class DocHtmlWriter extends PrintWriter	{

	public static DocApplication app;

	public static final int APPLICATION	= 0;
	public static final int PROTOTYPE	= 1;
	public static final int INDEX		= 2;
	public static final int METHOD		= 3;

	public DocHtmlWriter(String filename) throws FileNotFoundException	{
		super(new FileOutputStream(filename));
	}

	public void printHeader( String title )	{		printHeader(title,false);	}
	
	/** print header, slightly different for frameset file	**/
	public void printHeader( String title, boolean frameset )	{
		if ( frameset==true )
			print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"http://www.w3.org/TR/REC-html40/frameset.dtd\">");
		else
			print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">");
		print("<HTML><HEAD>");
		print("<!-- Generated by helmadoc on " + (new Date()).toString() + " -->");
		println("<TITLE>" + title + "</TITLE>");
		if ( frameset==true )
			print("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"stylesheet.css\" TITLE=Style>");
		println("</HEAD>");
	}

	
	public void printFrameSet()	{
		println ("<FRAMESET cols=\"20%,80%\">");
		println ("<FRAME src=\"app-frame.html\" name=appFrame>");
		println ("<FRAME src=\"app.html\" name=prototypeFrame>");
		println ("</FRAMESET><NOFRAMES>sorry, your browser doesn't understand frames!</NOFRAMES></HTML>");
	}

	/**	print app title for left frame */
	public void printAppIndexTitle(String title)	{
		print("<table border=0 width=\"100%\"><tr><td nowrap>");
		print("<FONT size=+1 ID=FrameTitleFont><b>");
		print("Application " + title + "</b></font></td></tr></table>" );
	}

	/**	print prototype list for left frame */
	public void printAppIndexList(DocElement[] pt)	{
		print("<TABLE BORDER=0 WIDTH=\"100%\"><TR><TD NOWRAP>");
		print("<P><FONT size=+1 ID=FrameHeadingFont>Prototypes</FONT><BR><BR>");
		for ( int i=0; i<pt.length; i++ )	{
			print ("<FONT ID=FrameItemFont><A HREF=\"" + pt[i].getDocFileName() + "\" TARGET=prototypeFrame>" + pt[i].getName() + "</A></FONT><BR>");
		}
		print ("</TD></TR></TABLE>");
	}

	/**	navigation on top of the page	**/
	public void printNavBar(String name, DocPrototype pt, int page )	{
		String urlPrefix = ( page==METHOD )	? "../" : "";
		print("<!-- ========== START OF NAVBAR ========== -->");
		print("<A NAME=navbar_top><!-- --></A>");
		print("<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0>");
		print("<TR><TD COLSPAN=2 BGCOLOR=#EEEEFF ID=NavBarCell1>");
		print("<A NAME=navbar_top_firstrow><!-- --></A>");

		print("<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=3>");
		print("<TR ALIGN=center VALIGN=top>");
		if ( page==APPLICATION )
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev><FONT ID=NavBarFont1Rev><B>Application</B></FONT>&nbsp;</TD>");
		else
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1><A HREF=\"" + urlPrefix + "app.html\"><FONT ID=NavBarFont1><B>Application</B></FONT></A>&nbsp;</TD>");
		if ( page==PROTOTYPE )
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev>&nbsp;<FONT ID=NavBarFont1Rev><B>Prototype</B></FONT>&nbsp;</TD>");
		else if ( page==METHOD )
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1>&nbsp;<a href=\"" + urlPrefix + "prototype_" + pt.getName() + ".html\"><FONT ID=NavBarFont1><B>Prototype</B></A></FONT>&nbsp;</TD>");
		else
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1>&nbsp;<FONT ID=NavBarFont1><B>Prototype</B></FONT>&nbsp;</TD>");
		if ( page==INDEX )
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev><FONT ID=NavBarFont1><B>Index</B></FONT>&nbsp;</TD>");
		else
			print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1><A HREF=\"" + urlPrefix + "index-1.html\"><FONT ID=NavBarFont1><B>Index</B></FONT></A>&nbsp;</TD>");
		print("</TR></TABLE>");

		print("</TD><TD ALIGN=right VALIGN=top ROWSPAN=3><EM><b>Application " + name + "</b><br><font size=-1></font></EM>");
		print("</TD></TR>");
		if ( pt!=null && page!=METHOD )	{
			print("<TR><TD VALIGN=top ID=NavBarCell3><FONT SIZE=-2>");
			print("<a href=\"#Actions\">ACTIONS</a>&nbsp;|&nbsp;");
			print("<a href=\"#Templates\">TEMPLATES</a>&nbsp;|&nbsp;");
			print("<a href=\"#Functions\">FUNCTIONS</a>&nbsp;|&nbsp;");
			print("<a href=\"#Macros\">MACROS</a>&nbsp;|&nbsp;");
			print("<a href=\"#Skins\">SKINS</a>&nbsp;");
			print("</TD></TR>");
		}

		print("</TABLE>");
		print("<!-- =========== END OF NAVBAR =========== -->");
	}

	public void printElementTitle(DocElement docEl)	{
		print("<HR><H2>" + docEl.getName() + "<BR>");
		print(docEl.getFullName() + "</H2>");
		print("<HR>");
	}

	public void printComment(DocElement docEl)	{
		if( docEl.getComment().length()>0 || docEl.countTags()>0 )	{
			print("<DL><DT>" + docEl.getComment() + "</DT>");
			print("<DT>");
			for ( int i=0; i<DocTag.TYPE_COUNT; i++ )	{
				if ( docEl.countTags(i)>0 )	{
					print("<DT><b>" + DocTag.kindDesc[i] + "</b><DT>");
					DocTag[] dt = docEl.listTags(i);
					for ( int j=0; j<dt.length; j++ )	{
						print("<DD>" + renderTag(dt[j],j) + "</DD>");
					}
				}
			}
			print("</DL>");
		}
	}

	private String renderFunctionName(DocFunction func)	{
		StringBuffer buf = new StringBuffer ();
		buf.append("<CODE><B>");
		if ( DocRun.getOption("-f").equals("true") )
			buf.append("<a href=\"" + func.getPrototype().getName().toLowerCase()+"/"+func.getDocFileName() + "\">" );
		if ( func.isMacro() )	{
			buf.append( func.getPrototype().getName()+"."+func.getName().substring(0,func.getName().length()-6) );
		}	else	{
			buf.append(func.getName().trim());
			if( func.isTemplate() || func.isFunction() )	{
				buf.append("(");
				int ct = func.countTags(DocTag.ARG);
				for ( int i=0; i<ct; i++ )	{
					buf.append("arg"+i);
					if ( i<ct-1 )	
						buf.append(", ");
				}
				buf.append(")");
			}
		}
		buf.append("</a></B></CODE>");
		if ( func.isFunction() || func.isMacro() )
			buf.append(" <small><i>in " + (new File(func.getLocation())).getName() + "</i></small>" );
		return buf.toString();
	}

	private String renderTag(DocTag tag)	{
		return renderTag(tag,0);
	}

	private String renderTag(DocTag tag, int i)	{
		int kind = tag.getKind();
		String text = tag.getText();
		String name = tag.getName();
		switch (kind)	{
			case DocTag.ARG:
				return( "<b>arg" + i + ":</b> " + text );
			case DocTag.PARAM:
				return( "<b>" + name + "</b> " + text );
			case DocTag.RETURNS:
			case DocTag.AUTHOR:
			case DocTag.VERSION:
			case DocTag.RELEASE:
				return( text );
			case DocTag.SEE:
				if ( text.startsWith("http://") )	{
					StringTokenizer tok = new StringTokenizer (text.trim()," ");
					String url = (tok.countTokens()>1)?tok.nextToken():text;
					return( "<a href=\"" + url + "\">" + ((tok.countTokens()>0)?text.substring(url.length(),text.length()):text) + "</a>" );
				}	else	{
					StringBuffer buf = new StringBuffer();
					StringTokenizer tok = new StringTokenizer (text.trim(),".");
					if ( tok.countTokens()==0 )	return text;
					DocPrototype dp = app.getPrototype( tok.nextToken() );
					if ( dp==null )	return text;
					buf.append("<a href=\"" );
					DocFunction df = null;
					if ( tok.countTokens()>0 )
						df = dp.getFunction( tok.nextToken() );
					if ( df==null )
						buf.append( link(dp) + "\">" + dp.getName() );
					else
						buf.append( link(df) + "\">" + dp.getName() + "." + df.getName() );
					return(buf.toString()+"</a>");
				}
		}
		return text;
	}

	public void printListHeader(String title)	{
		print("<A NAME=\"" + title + "\"><!-- --></A>");
		print("<TABLE BORDER=1 CELLPADDING=3 CELLSPACING=0 WIDTH=100%>");
		print("<TR BGCOLOR=#CCCCFF ID=TableHeadingColor><TD COLSPAN=2><FONT SIZE=+2><B>" + title + "</B></FONT></TD></TR>");
	}

	public void printPrototypeList(DocPrototype[] dl, String title)	{
		if ( dl.length==0 )		return;
		printListHeader(title);
		for ( int i=0; i<dl.length; i++ )	{
			print("<TR BGCOLOR=white ID=TableRowColor><TD ALIGN=right VALIGN=top WIDTH=1%><FONT SIZE=-1>");
			print("<a name=\"" + dl[i].getName() + "\"><!-- --></a>");
			print("<CODE>&nbsp;" + dl[i].getTypeName() + "</CODE></FONT></TD>");
			print("<TD><CODE><B><A HREF=\"" + dl[i].getDocFileName() + "\">" + dl[i].getName() + "</A></B></CODE>");
			print("<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + dl[i].getComment() + "<br>" );
			print("</TD></TR>");
		}
		print("</TABLE><BR>");
	}

	public void printFunctionList(DocFunction[] dl, String title)	{
		if ( dl.length==0 )		return;
		printListHeader(title);
		for ( int i=0; i<dl.length; i++ )	{
			print("<TR BGCOLOR=white ID=TableRowColor>");
			print("<TD ALIGN=right VALIGN=top WIDTH=50><FONT SIZE=-1>");
			print("<a name=\"" + dl[i].getName() + "\"><!-- --></a>");
			print("<CODE>&nbsp;" + dl[i].getTypeName() + "</CODE></FONT></TD>");
			print("<TD><DL><DT>" + renderFunctionName(dl[i]) );
			print("<DT>");
			printComment(dl[i]);
			print("</DL></TD></TR>");
		}
		print("</TABLE><BR>");
	}

	public void printFunctionIndex(DocFunction[] dl)	{
		if ( dl.length==0 )	return;
		String curChar = " ";
		print("<DL>");
		for ( int i=0; i<dl.length; i++ )	{
			String name = dl[i].getName();
			if ( !name.toLowerCase().startsWith(curChar) )	{
				print ( "</DL><h2>" + name.substring(0,1).toUpperCase() + "</h2><dl>");
				curChar = name.substring(0,1).toLowerCase();
			}
			print("<DT><a href=\"" + link(dl[i]) + "\">" + dl[i].getName() + "</a> - " + dl[i].getTypeName() + " in <a href=\"" + link(dl[i].getPrototype()) + "\">" + dl[i].getPrototype().getName() + "</a>" );
		}
		print("</DL>");
	}

	public void printInheritance(DocPrototype pt)	{
		if ( pt.getName().equalsIgnoreCase("hopobject") )
			return;
		DocApplication app = pt.getApplication();
		DocPrototype hopobject = (DocPrototype)app.getPrototype("hopobject");
		if ( hopobject==null || hopobject.countFunctions()==0 )
			return;
		print("<TABLE BORDER=1 CELLPADDING=3 CELLSPACING=0 WIDTH=100%>");
		print("<TR BGCOLOR=\"#EEEEFF\" CLASS=TableSubHeadingColor>");
		print("<TD><B>Methods inherited from Prototype <a href=\"" + link(hopobject) + "\">hopobject</A></B></TD>");
		print("</TR>");
		print("<TR BGCOLOR=\"white\" CLASS=TableRowColor><TD><code>");
		DocFunction[] df = hopobject.listFunctions();

		int lastType = -1;
		StringBuffer buf1 = new StringBuffer();
		StringBuffer buf2 = new StringBuffer();

		for ( int i=0; i<df.length; i++ )	{
			if ( df[i].getType()!=lastType && i>0 && buf2.length()>0 )	{
				buf1.append("<b>" + DocElement.typeNames[lastType] + ":</b> <code>" );
				buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) );
				buf1.append("</code><br>");
				buf2 = new StringBuffer();
			}
			lastType = df[i].getType();
			buf2.append ( "<a href=\"" + link(df[i]) + "\">" + df[i].getName() + "</a>, " );
		}
		if ( buf2.length()>0 )	{
			buf1.append("<b>" + DocElement.typeNames[lastType] + ":</b> <code>" );
			buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) );
			buf1.append("</code><br>");
		}
		print ( buf1.toString() );
		print("</TR></TABLE>");
	}

	public void printFunction(DocFunction func)	{
		print( "<br><br><small><i>in " + func.getPrototype().getName() + "/" + (new File(func.getLocation())).getName() + ":</i></small>" );
		print( "<br><pre>");
		print( HtmlEncoder.encodeAll(func.getSource()) );
		print( "</pre>" );
	}

	public void printStyleSheet()	{
		println( "/* Javadoc style sheet */");
		println( "/* Define colors, fonts and other style attributes here to override the defaults  */");
		println( "* Page background color */");
		println( "body { background-color: #FFFFFF }");
		println( "/* Table colors */");
		println( "#TableHeadingColor     { background: #CCCCFF } /* Dark mauve */");
		println( "#TableSubHeadingColor  { background: #EEEEFF } /* Light mauve */");
		println( "#TableRowColor         { background: #FFFFFF } /* White */");
		println( "/* Font used in left-hand frame lists */");
		println( "#FrameTitleFont   { font-size: normal; font-family: normal }");
		println( "#FrameHeadingFont { font-size: normal; font-family: normal }");
		println( "#FrameItemFont    { font-size: normal; font-family: normal }");
		println( "/* Example of smaller, sans-serif font in frames */");
		println( "/* #FrameItemFont  { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */");
		println( "/* Navigation bar fonts and colors */");
		println( "#NavBarCell1    { background-color:#EEEEFF;}/* Light mauve */");
		println( "#NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */");
		println( "#NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;}");
		println( "#NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}");
		println( "#NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}");
		println( "#NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}");
	}

	public String link(DocElement docEl)	{
		if ( docEl.isPrototype() )	{
			return "prototype_" + docEl.getName() + ".html";
		}	else if ( docEl.isMethod() )	{
			DocFunction df = (DocFunction)docEl;
			return "prototype_" + df.getPrototype().getName() + ".html#" + df.getName();
		}	else	{
			return "";
		}
	}

}

