/******************************************************************************
 JHTMLScanner.cc

	Base class for all objects that read HTML files.

	Information on HTML can be found at:

		http://home.netscape.com/assist/net_sites/index.html
		http://www.ncsa.uiuc.edu/General/Internet/WWW/HTMLPrimer.html
		http://home.netscape.com/assist/net_sites/html_extensions.html
		http://home.netscape.com/assist/net_sites/html_extensions_3.html

	BASE CLASS = JHTMLFlexLexer

	Copyright © 1998 by John Lindal. All rights reserved.

 ******************************************************************************/

#include <JHTMLScanner.h>
#include <jStreamUtil.h>
#include <jStrStreamUtil.h>
#include <jAssert.h>

/******************************************************************************
 Constructor (protected)

 ******************************************************************************/

JHTMLScanner::JHTMLScanner()
	:
	JHTMLFlexLexer()
{
	itsTagInfo = NULL;
}

/******************************************************************************
 Destructor

 ******************************************************************************/

JHTMLScanner::~JHTMLScanner()
{
}

/******************************************************************************
 LexHTML (protected)

 ******************************************************************************/

void
JHTMLScanner::LexHTML
	(
	const JCharacter* text
	)
{
	jistrstream(input, text, strlen(text));
	LexHTML(input);
}

void
JHTMLScanner::LexHTML
	(
	istream& input
	)
{
	TagInfo info;
	itsTagInfo     = &info;
	itsTagOpenFlag = kFalse;

	itsMatchRange.Set(JTellg(input)+1, JTellg(input));
	itsCommentRange.SetToNothing();

	FlexLexer::yylex(&input);

	if (itsTagOpenFlag)
		{
		TagFinished();
		HandleHTMLError(kUnclosedTag, "*** unclosed tag ***", JIndexRange());
		}

	(itsTagInfo->attr).DeleteAll();
	itsTagInfo = NULL;
}

/******************************************************************************
 NewTag (private)

 ******************************************************************************/

void
JHTMLScanner::NewTag()
{
	itsTagOpenFlag = kTrue;

	(itsTagInfo->name).Clear();
	(itsTagInfo->lastAttr).Clear();
	(itsTagInfo->valueBuffer).Clear();
	(itsTagInfo->attr).DeleteAll();
	itsTagInfo->range.first = itsMatchRange.first;
}

/******************************************************************************
 TagFinished (private)

 ******************************************************************************/

JBoolean
JHTMLScanner::TagFinished()
{
	assert( itsTagOpenFlag );

	JBoolean result = kTrue;

	(itsTagInfo->range).last = itsMatchRange.last;
	if ((itsTagInfo->name).IsEmpty())
		{
		result = HandleHTMLError(kEmptyTag, "*** empty tag ***", itsTagInfo->range);
		}
	else
		{
		result = HandleHTMLTag(itsTagInfo->name, itsTagInfo->attr, itsTagInfo->range);
		}

	itsTagOpenFlag = kFalse;
	return result;
}

/******************************************************************************
 SaveAttributeValue (private)

	Stores the contents of valueBuffer as the value of the latest
	attribute.

 ******************************************************************************/

void
JHTMLScanner::SaveAttributeValue()
{
	JString* value = new JString(itsTagInfo->valueBuffer);
	assert( value != NULL );
	const JBoolean ok = (itsTagInfo->attr).SetOldElement(itsTagInfo->lastAttr, value);
	assert( ok );

	(itsTagInfo->lastAttr).Clear();
	(itsTagInfo->valueBuffer).Clear();
}

/******************************************************************************
 HandleChar (private)

	If the character is part of an attribute value, we append it to the
	attribute value buffer.  Otherwise, we treat it like a normal word.

 ******************************************************************************/

JBoolean
JHTMLScanner::HandleChar
	(
	const JCharacter c
	)
{
	JBoolean result = kTrue;
	if (yy_top_state() == 0)
		{
		const JCharacter str[] = { c, '\0' };
		result = HandleHTMLWord(str, itsMatchRange);
		}
	else
		{
		(itsTagInfo->valueBuffer).AppendCharacter(c);
		}

	yy_pop_state();
	return result;
}

/******************************************************************************
 Handle something (virtual protected)

	These functions are not pure virtual because some derived classes
	may not need to implement all of them.

	Return kFalse to cancel lexing.

 ******************************************************************************/

JBoolean
JHTMLScanner::HandleHTMLWord
	(
	const JCharacter*	word,
	const JIndexRange&	range
	)
{
	return kTrue;
}

JBoolean
JHTMLScanner::HandleHTMLWhitespace
	(
	const JCharacter*	space,
	const JIndexRange&	range
	)
{
	return kTrue;
}

JBoolean
JHTMLScanner::HandleHTMLTag
	(
	const JString&					name,
	const JStringPtrMap<JString>&	attr,
	const JIndexRange&				range
	)
{
	return kTrue;
}

JBoolean
JHTMLScanner::HandleHTMLComment
	(
	const JIndexRange& range
	)
{
	return kTrue;
}

JBoolean
JHTMLScanner::HandleHTMLError
	(
	const HTMLError		err,
	const JCharacter*	errStr,
	const JIndexRange&	range
	)
{
	return kTrue;
}
