# Normal.pm - The Normal Class derived from the Base HTML object.
# Created by James Pattie, 04/28/2000.

# Copyright (c) 2000 PC & Web Xperience, Inc. http://www.pcxperience.com/
# All rights reserved.  This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.

# updated 02/24/2001 - naming scheme change.

package HTMLObject::Normal;
use HTMLObject::Base;
use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

require Exporter;

@ISA = qw(HTMLObject::Base Exporter AutoLoader);
@EXPORT = qw(
);

$VERSION = '1.09';

# new
sub new
{
  my $class = shift;
  my $self = $class->SUPER::new(@_);

  $self->setErrorMessage(code => '3000', message => 'Parameters and Options are both required if they are to be used');
  $self->setErrorMessage(code => '3001', message => 'Invalid Decoration type specified');
  $self->setErrorMessage(code => '3002', message => 'Value must be specified');

  $self->setTitle("HTMLObject::Normal");

  $self->{javascriptBody} = "";
  $self->{javascriptOnload} = "";
  $self->{javascriptOnloadParameters} = "";
  $self->{javascriptOnloadOptions} = "";
  $self->{javascriptOnunload} = "";
  $self->{javascriptOnunloadParameters} = "";
  $self->{javascriptOnunloadOptions} = "";
  $self->{javascriptVersion} = "1.1";
  $self->{javascriptIncludes} = [];
  $self->{javascriptRequiredMessage} = "";
  $self->{javascriptRequiredVersion} = "";
  $self->{javascriptErrorHandler} = 1;
  $self->{javascriptErrorHandlerEmail} = "nobody\@not-a-valid-address.com";
  $self->{javascriptErrorHandlerCode} = "";
  $self->{javascriptErrorHandlerBaseWindowName} = "";
  $self->{linkTag} = [];
  $self->{baseHrefString} = "";
  $self->{baseTargetString} = "";
  $self->{linkStyleSheet} = "";

  return $self;
}

#reset
sub reset
{
  my $self = shift;

  $self->SUPER::reset(@_);
  $self->setErrorMessage(code => '3000', message => 'Parameters and Options are both required if they are to be used');
  $self->setErrorMessage(code => '3001', message => 'Invalid Decoration type specified');
  $self->setErrorMessage(code => '3002', message => 'Value must be specified');

  $self->setTitle("HTMLObject::Normal");

  $self->{javascriptBody} = "";
  $self->{javascriptOnload} = "";
  $self->{javascriptOnloadParameters} = "";
  $self->{javascriptOnloadOptions} = "";
  $self->{javascriptOnunload} = "";
  $self->{javascriptOnunloadParameters} = "";
  $self->{javascriptOnunloadOptions} = "";
  $self->{javascriptVersion} = "1.1";
  $self->{javascriptIncludes} = [];
  $self->{javascriptRequiredMessage} = "";
  $self->{javascriptRequiredVersion} = "";
  $self->{javascriptErrorHandler} = 1;
  $self->{javascriptErrorHandlerEmail} = "nobody\@not-a-valid-address.com";
  $self->{javascriptErrorHandlerCode} = "";
  $self->{javascriptErrorHandlerBaseWindowName} = "";
  $self->{linkTag} = [];
  $self->{baseHrefString} = "";
  $self->{baseTargetString} = "";
  $self->{linkStyleSheet} = "";
}

# displayError - Displays the specified error document and then exits.
sub displayError
{
  my $self = shift;
  my %args = (  title => 'Error: HTMLObject::Normal',
  		message => 'An Error Occurred!',
  		@_	# arguments passed in go here.
  	     );
  	
  my $doc = HTMLObject::Base->new();

  $doc->setTitle($args{'title'});
  $doc->setFocus("body");
  $doc->print("<h1>Error: &nbsp;<b>" . $self->getErrorCode() . "</b> Occurred!</h1>\n");
  $doc->print("Message: &nbsp;" . $self->getErrorMessage() . "\n<br>\n");
  $doc->print("<br>\n<br>\n$args{'message'}\n<br>\n");

  $doc->display();

  exit 0;
}

# displayLinks
sub displayLinks
{
  my $self = shift;

  my $output = "";

  if (scalar @{$self->{linkTag}} > 0)
  {
    foreach my $link (@{$self->{linkTag}})
    {
      $output .= "    $link\n";
    }
  }

  return $output;
}

# displayJavaScriptRequirements
sub displayJavaScriptRequirements
{
  my $self = shift;

  my $output = "";

  if (length $self->{javascriptRequiredMessage} > 0)
  {
    my $requiredVersion = '1.0';
    $output = "<script language=\"JavaScript\">\n  <!--\n  var _version = 1.0;\n  // -->\n</script>\n";
    if (length $self->{javascriptRequiredVersion} > 0)
    {
      $requiredVersion = $self->{javascriptRequiredVersion};
      $output .= "<script language=\"JavaScript$requiredVersion\">\n  <!--\n  _version = $requiredVersion;\n  // -->\n</script>\n";
    }
    $output .= "<script language=\"JavaScript\">\n";
    $output .= "  <!--\n";
    $output .= "  if (_version < $requiredVersion)\n";
    $output .= "  {\n";
    $output .= "    document.write('$self->{javascriptRequiredMessage}');\n";
    $output .= "    document.write('<br>');\n";
    $output .= "    document.write('<br>');\n";
    $output .= "    document.write('JavaScript Version $requiredVersion was not found!');\n";
    $output .= "  }\n";
    $output .= "  // -->\n";
    $output .= "</script>\n";
    $output .= "<noscript>\n$self->{javascriptRequiredMessage}\n</noscript>\n";

    $output =~ s/^(.*)$/    $1/mg;  # do the indentation.
  }

  return $output;
}

# displayJavaScriptIncludes
sub displayJavaScriptIncludes
{
  my $self = shift;

  my $output = "";

  if (scalar @{$self->{javascriptIncludes}} > 0)
  {
    foreach my $include (@{$self->{javascriptIncludes}})
    {
      $output .= "    $include\n";
    }
  }

  return $output;
}

# displayJavaScriptErrorHandler
sub displayJavaScriptErrorHandler
{
  my $self = shift;

  my $output = "";

  if ($self->{javascriptErrorHandler})
  {
    $output .= <<"END_OF_CODE";
  <script language="JavaScript1.1">
  <!--

  // This code taken and modified from the book "JavaScript the Definitive Guide 3rd Edition" by David Flanagan.  An O'Reilly Publication.

  // This ensures a unique window for each error.
  var errorCount = 0;

  // email address to mail this error report to.
  var email = "$self->{javascriptErrorHandlerEmail}";

  // Define the error handler.
  function reportError(msg, url, line)
  {
END_OF_CODE
  if (length $self->{javascriptErrorHandlerCode} == 0)
  {
    my $baseName = $self->{javascriptErrorHandlerBaseWindowName} . "Error";
    my $language = $self->getLanguage();
    my $charEncoding = $self->getCharEncoding();
    
    $output .= <<"END_OF_CODE";
    var w = window.open("", "$baseName"+errorCount++, "resizable,status,width=625,height=475");
    var d = w.document;

    d.open();
    d.writeln('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">');
    d.writeln('<html lang="$language">');
    d.writeln('<head>');
    d.writeln('<meta http-equiv="Content-Type" content="text/html; charset=$charEncoding">');
    d.writeln('</head>');
    d.writeln('<body bgcolor="white">');
    d.writeln('<div align=center>');
    d.writeln('<font size=7 face="helvetica"><b>');
    d.writeln('OOPS.... A JavaScript Error Has Occurred!');
    d.writeln('</b></font><br><hr size=4 width="80%">');
    d.writeln('<form action="mailto:'+email+'" method=post enctype="text/plain">');
    d.writeln('<font size=3>');
    d.writeln('<i>Click the "Report Error" button to send a bug report to <b>'+email+'</b>.</i><br>');
    d.writeln('<input type="submit" value="Report Error">&nbsp;&nbsp;');
    d.writeln('<input type="button" value="Dismiss" onClick="self.close()">');
    d.writeln('</div><div align=right>');
    d.writeln('<br>Your name <i>(optional)</i>: <input size=42 name="name" value="">');
    d.writeln('<br>Error Message: <input size=42 name="message" value="'+msg+'">');
    d.writeln('<br>Document: <input size=42 name="url" value="'+url+'">');
    d.writeln('<br>Line Number: <input size=42 name="line" value="'+line+'">');
    d.writeln('<br>Browser Version: <input size=42 name="version" value="'+navigator.userAgent+'">');
    d.writeln('<br>Program Version: <input size=12 name="prgVersion" value="1.0">');
    d.writeln('<br>Other Notes: <input size=42 name="notes" value="">');
    d.writeln('<br>HTMLObject Version <b>$VERSION</b>. <input type=hidden name="htmlobjectVersion" value="$VERSION">');
    d.writeln('</form>');
    d.writeln('</div></font>');
    d.writeln('</body>');
    d.write('</html>');
    d.close();

    return true;  // This stops JavaScript from displaying its own error dialog.
END_OF_CODE
  }
  else
  {
    $output .= $self->{javascriptErrorHandlerCode};
  }
  $output .= <<"END_OF_CODE";
  }

  // Now register the Error Handler for this window.
  self.onerror = reportError;
  // -->

  </script>
END_OF_CODE
  }

  return $output;
}

# displayLinkAttributes
sub displayLinkAttributes
{
  my $self = shift;

  my $output = "";

  if (length $self->{linkStyleSheet} > 0)
  {
    my $tempLinkStyleSheet = $self->{linkStyleSheet};
    $tempLinkStyleSheet =~ s/^(.*)$/    $1/mg;
    $output .= "$tempLinkStyleSheet\n";
  }

  return $output;
}

# displayBase
sub displayBase
{
  my $self = shift;

  my $output = "";

  if (length $self->{baseHrefString} > 0 || length $self->{baseTargetString} > 0)
  {
    $output = "<base";
    if (length $self->{baseHrefString} > 0)
    {
      $output .= " href=\"$self->{baseHrefString}\"";
    }
    if (length $self->{baseTargetString} > 0)
    {
      $output .= " target=\"$self->{baseTargetString}\"";
    }
    $output .= ">\n";
  }

  return $output;
}

# display
sub display
{
  my $self = shift;
  my $output = "";

  my ($tempHeadString, $tempBodyString, $tempJavascriptBody);
  my $headString = $self->getHeadString();
  my $contentTypeString = $self->getContentType();
  my $titleString = $self->getTitle();
  my $bodyString = $self->getBodyString();
  my $language = $self->getLanguage();

  if ($contentTypeString =~ /text\/html/i)
  {
    #make sure that all output is properly indented, this way the user doesn't have to do any indentation to fit our output indentation.
    ($tempHeadString = $headString) =~ s/^(.*)$/    $1/mg;  # currently 4 spaces.
    ($tempJavascriptBody = $self->{javascriptBody}) =~ s/^(.*)$/    $1/mg;
    ($tempBodyString = $bodyString) =~ s/^(.*)$/    $1/mg;

    # display Cookies if needed (They apparently must come before the Content-Type: header.)
    my $tempStr = $self->displayCookies();
    $output .= $tempStr if (length $tempStr > 0);

    $output .= "Content-Type: $contentTypeString\n\n"; # Display the Content-Type block.

    # output the Document Type header.
    $output .= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n";
    $output .= "<html lang=\"$language\">\n";
    $output .= "  <head>\n";

    # display Meta Tags if needed.
    $tempStr = $self->displayMetaTags();
    $output .= "$tempStr\n" if (length $tempStr > 0);

    # display Base if needed.
    $tempStr = $self->displayBase();
    $output .= "    $tempStr\n" if (length $tempStr > 0);

    $output .= "    <title>$titleString</title>\n\n";

    # display Links if needed.
    $tempStr = $self->displayLinks();
    $output .= $tempStr if (length $tempStr > 0);

    # display Link Attributes if needed.
    $tempStr = $self->displayLinkAttributes();
    $output .= "$tempStr\n" if (length $tempStr > 0);

    $output .= "$tempHeadString\n\n" if (length $headString > 0);

    # display JavaScript error handler.
    $tempStr = $self->displayJavaScriptErrorHandler();
    $output .= "$tempStr\n" if (length $tempStr > 0);

    # display Javascript Requirements if needed.
    $tempStr = $self->displayJavaScriptRequirements();
    $output .= "$tempStr\n" if (length $tempStr > 0);

    # display Javascript Includes if defined.
    $tempStr = $self->displayJavaScriptIncludes();
    $output .= "$tempStr\n" if (length $tempStr > 0);

    # display Javascript Block if needed.
    if (length $self->{javascriptOnload} > 0 || length $self->{javascriptOnunload} > 0 || length $self->{javascriptBody} > 0)
    {
      $output .= "    <script language=\"JavaScript$self->{javascriptVersion}\">\n";
      $output .= "      <!--\n";
      if (length $self->{javascriptOnload} > 0)
      {
        my $tempJavascriptOnload = $self->{javascriptOnload};
        $tempJavascriptOnload =~ s/^(.*)$/        $1/mg;  # 8 spaces.
        $output .= "      function doOnLoad($self->{javascriptOnloadParameters})\n";
        $output .= "      {\n";
        $output .= $tempJavascriptOnload . "\n";
        $output .= "      }\n";
      }
      if (length $self->{javascriptOnunload} > 0)
      {
        my $tempJavascriptOnunload = $self->{javascriptOnunload};
        $tempJavascriptOnunload =~ s/^(.*)$/        $1/mg;  # 8 spaces.
        $output .= "      function doOnUnLoad($self->{javascriptOnunloadParameters})\n";
        $output .= "      {\n";
        $output .= $tempJavascriptOnunload . "\n";
        $output .= "      }\n";
      }
      if (length $self->{javascriptBody} > 0)
      {
        my $tempJavascriptBody = $self->{javascriptBody};
        $tempJavascriptBody =~ s/^(.*)$/      $1/mg;  # 6 spaces.
        $output .= $tempJavascriptBody . "\n";
      }
      $output .= "      // -->\n";
      $output .= "    </script>\n\n";
    }

    $output .= "  </head>\n\n";
    $output .= "  <body bgcolor=\"$self->{bodyBgcolor}\" text=\"$self->{bodyFgcolor}\" link=\"$self->{bodyLinkColor}\" vlink=\"$self->{bodyVlinkColor}\" alink=\"$self->{bodyAlinkColor}\"";
    $output .= " background=\"$self->{bodyImage}\"" if (length $self->{bodyImage} > 0);
    $output .= " onLoad=\"doOnLoad($self->{javascriptOnloadOptions});\"" if (length $self->{javascriptOnload} > 0);
    $output .= " onUnLoad=\"doOnUnLoad($self->{javascriptOnunloadOptions});\"" if (length $self->{javascriptOnunload} > 0);
    $output .= ">\n\n";
    $output .= "$tempBodyString\n\n" if (length $bodyString > 0);
    $output .= "  </body>\n";
    $output .= "</html>\n";
  }
  else
  {
    $output .= "Content-Type: $contentTypeString\n\n";
    $output .= $bodyString;  # don't want to possibly corrupt anything so we put the original out.
  }

  print $output;
}

# set_focus
sub set_focus
{
  my $self = shift;

  if (!defined $_[0])
  {
    $self->doRequiredParameterError('Normal::set_focus', 'Section Name');
  }

  my $focus = shift;

  if ($focus ne "javascript")
  {
    # send it to the parent class to deal with
    $self->SUPER::setFocus($focus);
  }

  if ($self->{contentTypeString} !~ /text\/html/i)
  {
    $self->setError(code => '1006');
    $self->displayError(title => 'Error:  set_focus', message => 'Focus = "$focus" is invalid when Content-Type = "$self->{contentTypeString}" is used!');
  }

  $self->{currentSection} = $focus;
}

# setFocus
sub setFocus
{
  my $self = shift;

  if (!defined $_[0])
  {
    $self->doRequiredParameterError('Normal::setFocus', 'Section Name');
  }

  my $focus = shift;

  if ($focus ne "javascript")
  {
    # send it to the parent class to deal with
    $self->SUPER::setFocus($focus);
  }

  if ($self->{contentTypeString} !~ /text\/html/i)
  {
    $self->setError(code => '1006');
    $self->displayError(title => 'Error:  setFocus', message => 'Focus = "$focus" is invalid when Content-Type = "$self->{contentTypeString}" is used!');
  }

  $self->{currentSection} = $focus;
}

# print
sub print
{
  my $self = shift;

  if (!defined $_[0])
  {
    $self->doRequiredParameterError('print', 'Text');
  }

  my $text = shift;

  if ($self->{currentSection} eq "javascript")
  {
    $self->{javascriptBody} .= $text;
  }
  else
  {
    $self->SUPER::print($text);
  }
}

# read
sub read
{
  my $self = shift;
  my $text = "";

  if ($self->{currentSection} eq "javascript")
  {
    $text = $self->{javascriptBody};
  }
  else
  {
    $text = $self->SUPER::read();
  }

  return $text;
}

# delete
sub delete
{
  my $self = shift;

  if ($self->{currentSection} eq "javascript")
  {
    $self->{javascriptBody} = "";
  }
  else
  {
    $self->SUPER::delete();
  }
}

# set_javascript_include
# parameters: version, file
sub set_javascript_include
{
  my $self = shift;
  my %args = ( @_, );

  if (!exists $args{'file'})
  {
    $self->doRequiredParameterError('set_javascript_include', 'file');
  }

  my $version = $args{'version'};

  if (!exists $args{'version'})
  { # use the default version currently set.
    $version = $self->{javascriptVersion};
  }

  my $file = $args{'file'};

  my $include = "<script language=\"JavaScript$version\" src=\"$file\"></script>";
  my $num = scalar @{$self->{javascriptIncludes}};
  $self->{javascriptIncludes}[$num] = $include;
}

# setJavascriptInclude
# parameters: version, file
sub setJavascriptInclude
{
  my $self = shift;
  my %args = ( @_, );

  if (!exists $args{'file'})
  {
    $self->doRequiredParameterError('setJavascriptInclude', 'file');
  }

  my $version = $args{'version'};

  if (!exists $args{'version'})
  { # use the default version currently set.
    $version = $self->{javascriptVersion};
  }

  my $file = $args{'file'};

  my $include = "<script language=\"JavaScript$version\" src=\"$file\"></script>";
  my $num = scalar @{$self->{javascriptIncludes}};
  $self->{javascriptIncludes}[$num] = $include;
}

# set_javascript_version
# takes the string for the version
sub set_javascript_version
{
  my $self = shift;

  if (!defined $_[0])
  {
    $self->doRequiredParameterError('set_javascript_version', 'version');
  }

  my $version = shift;

  $self->{javascriptVersion} = $version;
}

# setJavascriptVersion
# takes the string for the version
sub setJavascriptVersion
{
  my $self = shift;

  if (!defined $_[0])
  {
    $self->doRequiredParameterError('setJavascriptVersion', 'version');
  }

  my $version = shift;

  $self->{javascriptVersion} = $version;
}

# get_javascript_version
sub get_javascript_version
{
  my $self = shift;

  return $self->{javascriptVersion};
}

# getJavascriptVersion
sub getJavascriptVersion
{
  my $self = shift;

  return $self->{javascriptVersion};
}

# print_javascript_required
# parameters: version, message
sub print_javascript_required
{
  my $self = shift;
  my %args = ( message => 'JavaScript is Required to properly view this content!', @_, );

  my $version = $args{'version'};
  my $message = $args{'message'};

  if (!exists $args{'version'})
  { # use the default version currently set.
    $version = $self->{javascriptVersion};
  }

  $self->{javascriptRequiredVersion} = $version;
  $self->{javascriptRequiredMessage} = $message;
}

# printJavascriptRequired
# parameters: version, message
sub printJavascriptRequired
{
  my $self = shift;
  my %args = ( message => 'JavaScript is Required to properly view this content!', @_, );

  my $version = $args{'version'};
  my $message = $args{'message'};

  if (!exists $args{'version'})
  { # use the default version currently set.
    $version = $self->{javascriptVersion};
  }

  $self->{javascriptRequiredVersion} = $version;
  $self->{javascriptRequiredMessage} = $message;
}

# disable_javascript_error_handler
# takes nothing
sub disable_javascript_error_handler
{
  my $self = shift;

  $self->{javascriptErrorHandler} = 0;
}

# disableJavascriptErrorHandler
# takes nothing
sub disableJavascriptErrorHandler
{
  my $self = shift;

  $self->{javascriptErrorHandler} = 0;
}

# is_javascript_error_handler_enabled
# returns the state of the disable flag.
sub is_javascript_error_handler_enabled
{
  my $self = shift;
  
  return $self->{javascriptErrorHandler};
}

# isJavascriptErrorHandlerEnabled
# returns the state of the disable flag.
sub isJavascriptErrorHandlerEnabled
{
  my $self = shift;
  
  return $self->{javascriptErrorHandler};
}

# set_javascript_error_handler_email
# parameters: email
sub set_javascript_error_handler_email
{
  my $self = shift;
  my %args = ( @_, );

  my $email = $args{'email'};

  if (length $email == 0)
  {
    $self->doRequiredParameterError('set_javascript_error_handler_email', 'email');
  }

  $self->{javascriptErrorHandlerEmail} = $email;
}

# setJavascriptErrorHandlerEmail
# parameters: email
sub setJavascriptErrorHandlerEmail
{
  my $self = shift;
  my %args = ( @_, );

  my $email = $args{'email'};

  if (length $email == 0)
  {
    $self->doRequiredParameterError('setJavascriptErrorHandlerEmail', 'email');
  }

  $self->{javascriptErrorHandlerEmail} = $email;
}

# get_javascript_error_handler_email
sub get_javascript_error_handler_email
{
  my $self = shift;
  
  return $self->{javascriptErrorHandlerEmail};
}

# getJavascriptErrorHandlerEmail
sub getJavascriptErrorHandlerEmail
{
  my $self = shift;
  
  return $self->{javascriptErrorHandlerEmail};
}

# set_javascript_error_handler_window
# parameters: name
sub set_javascript_error_handler_window
{
  my $self = shift;
  my %args = ( @_, );
  
  my $name = $args{'name'};
  
  if (! exists $args{'name'})
  {
    $self->doRequiredParameterError('set_javascript_error_handler_window', 'name');
  }
  
  $self->{javascriptErrorHandlerBaseWindowName} = $name;
}

# setJavascriptErrorHandlerWindow
# parameters: name
sub setJavascriptErrorHandlerWindow
{
  my $self = shift;
  my %args = ( @_, );
  
  my $name = $args{'name'};
  
  if (! exists $args{'name'})
  {
    $self->doRequiredParameterError('setJavascriptErrorHandlerWindow', 'name');
  }
  
  $self->{javascriptErrorHandlerBaseWindowName} = $name;
}

# get_javascript_error_handler_window
sub get_javascript_error_handler_window
{
  my $self = shift;
  
  return $self->{javascriptErrorHandlerBaseWindowName};
}

# getJavascriptErrorHandlerWindow
sub getJavascriptErrorHandlerWindow
{
  my $self = shift;
  
  return $self->{javascriptErrorHandlerBaseWindowName};
}

# set_javascript_error_handler
# parameters: code
sub set_javascript_error_handler
{
  my $self = shift;
  my %args = ( @_, );

  my $code = $args{'code'};

  if (length $code == 0)
  {
    $self->doRequiredParameterError('set_javascript_error_handler', 'code');
  }

  $self->{javascriptErrorHandlerCode} = $code;
}

# setJavascriptErrorHandler
# parameters: code
sub setJavascriptErrorHandler
{
  my $self = shift;
  my %args = ( @_, );

  my $code = $args{'code'};

  if (length $code == 0)
  {
    $self->doRequiredParameterError('setJavascriptErrorHandler', 'code');
  }

  $self->{javascriptErrorHandlerCode} = $code;
}

# set_onload
# parameters: parameters, options, code
sub set_onload
{
  my $self = shift;
  my %args = ( parameters => '', options => '', code => '', @_, );

  my $parameters = $args{'parameters'};
  my $options = $args{'options'};
  my $code = $args{'code'};

  if (length $code == 0)
  {
    $self->doRequiredParameterError('set_onload', 'code');
  }
  if ((length $parameters > 0 && length $options == 0) || (length $parameters == 0 && length $options > 0))
  {
    $self->setError(code => '3000');
    $self->displayError(title => 'set_onload', message => 'parameters and options are both required!');
  }

  $self->{javascriptOnload} = $code;
  $self->{javascriptOnloadParameters} = $parameters;
  $self->{javascriptOnloadOptions} = $options;
}

# setOnload
# parameters: parameters, options, code
sub setOnload
{
  my $self = shift;
  my %args = ( parameters => '', options => '', code => '', @_, );

  my $parameters = $args{'parameters'};
  my $options = $args{'options'};
  my $code = $args{'code'};

  if (length $code == 0)
  {
    $self->doRequiredParameterError('setOnload', 'code');
  }
  if ((length $parameters > 0 && length $options == 0) || (length $parameters == 0 && length $options > 0))
  {
    $self->setError(code => '3000');
    $self->displayError(title => 'setOnload', message => 'parameters and options are both required!');
  }

  $self->{javascriptOnload} = $code;
  $self->{javascriptOnloadParameters} = $parameters;
  $self->{javascriptOnloadOptions} = $options;
}

# set_onunload
# parameters: parameters, options, code
sub set_onunload
{
  my $self = shift;
  my %args = ( parameters => '', options => '', code => '', @_, );

  my $parameters = $args{'parameters'};
  my $options = $args{'options'};
  my $code = $args{'code'};

  if (length $code == 0)
  {
    $self->doRequiredParameterError('set_onunload', 'code');
  }
  if ((length $parameters > 0 && length $options == 0) || (length $parameters == 0 && length $options > 0))
  {
    $self->setError(code => '3000');
    $self->displayError(title => 'set_onunload', message => 'parameters and options are both required!');
  }

  $self->{javascriptOnunload} = $code;
  $self->{javascriptOnunloadParameters} = $parameters;
  $self->{javascriptOnunloadOptions} = $options;
}

# setOnunload
# parameters: parameters, options, code
sub setOnunload
{
  my $self = shift;
  my %args = ( parameters => '', options => '', code => '', @_, );

  my $parameters = $args{'parameters'};
  my $options = $args{'options'};
  my $code = $args{'code'};

  if (length $code == 0)
  {
    $self->doRequiredParameterError('setOnunload', 'code');
  }
  if ((length $parameters > 0 && length $options == 0) || (length $parameters == 0 && length $options > 0))
  {
    $self->setError(code => '3000');
    $self->displayError(title => 'setOnunload', message => 'parameters and options are both required!');
  }

  $self->{javascriptOnunload} = $code;
  $self->{javascriptOnunloadParameters} = $parameters;
  $self->{javascriptOnunloadOptions} = $options;
}

# set_base
# parameters: href, target
sub set_base
{
  my $self = shift;
  my %args = ( href => '', target => '', @_, );

  my $href = $args{'href'};
  my $target = $args{'target'};

  if (length $href == 0 && length $target == 0)
  {
    $self->doRequiredParameterError('set_base', 'href and/or target');
  }

  $self->{baseHrefString} = $href;
  $self->{baseTargetString} = $target;
}

# setBase
# parameters: href, target
sub setBase
{
  my $self = shift;
  my %args = ( href => '', target => '', @_, );

  my $href = $args{'href'};
  my $target = $args{'target'};

  if (length $href == 0 && length $target == 0)
  {
    $self->doRequiredParameterError('setBase', 'href and/or target');
  }

  $self->{baseHrefString} = $href;
  $self->{baseTargetString} = $target;
}

# set_link
# parameters: href, name, rel, rev, target, title, type
sub set_link
{
  my $self = shift;
  my %args = ( @_, );

  my $href = $args{'href'};
  my $name = $args{'name'};
  my $rel  = $args{'rel'};
  my $rev  = $args{'rev'};
  my $type = $args{'type'};
  my $title = $args{'title'};
  my $target = $args{'target'};

  if (!exists $args{'href'})
  {
    $self->doRequiredParameterError('set_link', 'href');
  }
  if (!exists $args{'title'})
  {
    $self->doRequiredParameterError('set_link', 'title');
  }
  if (!exists $args{'rel'})
  {
    $self->doRequiredParameterError('set_link', 'rel');
  }
  if (!exists $args{'type'})
  {
    $self->doRequiredParameterError('set_link', 'type');
  }

  my $link = "<link href=\"$href\" rel=\"$rel\" type=\"$type\" title=\"$title\"";
  if (length $rev > 0)
  {
    $link .= " rev=\"$rev\"";
  }
  if (length $name > 0)
  {
    $link .= " name=\"$name\"";
  }
  if (length $target > 0)
  {
    $link .= " target=\"$target\"";
  }
  $link .= ">\n";

  my $num = scalar @{$self->{linkTag}};
  $self->{linkTag}[$num] = $link;
}

# setLink
# parameters: href, name, rel, rev, target, title, type
sub setLink
{
  my $self = shift;
  my %args = ( @_, );

  my $href = $args{'href'};
  my $name = $args{'name'};
  my $rel  = $args{'rel'};
  my $rev  = $args{'rev'};
  my $type = $args{'type'};
  my $title = $args{'title'};
  my $target = $args{'target'};

  if (!exists $args{'href'})
  {
    $self->doRequiredParameterError('setLink', 'href');
  }
  if (!exists $args{'title'})
  {
    $self->doRequiredParameterError('setLink', 'title');
  }
  if (!exists $args{'rel'})
  {
    $self->doRequiredParameterError('setLink', 'rel');
  }
  if (!exists $args{'type'})
  {
    $self->doRequiredParameterError('setLink', 'type');
  }

  my $link = "<link href=\"$href\" rel=\"$rel\" type=\"$type\" title=\"$title\"";
  if (length $rev > 0)
  {
    $link .= " rev=\"$rev\"";
  }
  if (length $name > 0)
  {
    $link .= " name=\"$name\"";
  }
  if (length $target > 0)
  {
    $link .= " target=\"$target\"";
  }
  $link .= ">\n";

  my $num = scalar @{$self->{linkTag}};
  $self->{linkTag}[$num] = $link;
}

# set_link_decorations
# parameters: link, alink, vlink, hover
sub set_link_decorations
{
  my $self = shift;
  my %args = ( link => 'none', alink => 'none', vlink => 'none', hover => 'blue', @_, );

  my $link  = $args{'link'};
  my $alink = $args{'alink'};
  my $vlink = $args{'vlink'};
  my $hover = $args{'hover'};

  # make sure that the specified decorations are one of (none, underline, overline, line-through, blink)
  if ($link !~ /none|underline|overline|line-through|blink/i)
  {
    $self->setError(code => '3001');
    $self->displayError(title => 'set_link_decorations', message => "'$link' is invalid decoration for <b>link</b>!");
  }
  if ($alink !~ /none|underline|overline|line-through|blink/i)
  {
    $self->setError(code => '3001');
    $self->displayError(title => 'set_link_decorations', message => "'$alink' is invalid decoration for <b>alink</b>!");
  }
  if ($vlink !~ /none|underline|overline|line-through|blink/i)
  {
    $self->setError(code => '3001');
    $self->displayError(title => 'set_link_decorations', message => "'$vlink' is invalid decoration for <b>vlink</b>!");
  }
  if (length $hover == 0)
  {
    $self->setError(code => '3002');
    $self->displayError(title => 'set_link_decorations', message => "<b>hover</b> must have a color!");
  }

  # create the style sheet that defines our text decorations.
  my $decorations = "<style type=\"text/css\">\n";
  $decorations .= "<!--\n";
  $decorations .= "  a:hover   { color: $hover }\n";
  $decorations .= "  a:link    { text-decoration: $link }\n";
  $decorations .= "  a:visited { text-decoration: $vlink }\n";
  $decorations .= "  a:active  { text-decoration: $alink }\n";
  $decorations .= "-->\n";
  $decorations .= "</style>\n";

  $self->{linkStyleSheet} = $decorations;
}

# setLinkDecorations
# parameters: link, alink, vlink, hover
sub setLinkDecorations
{
  my $self = shift;
  my %args = ( link => 'none', alink => 'none', vlink => 'none', hover => 'blue', @_, );

  my $link  = $args{'link'};
  my $alink = $args{'alink'};
  my $vlink = $args{'vlink'};
  my $hover = $args{'hover'};

  # make sure that the specified decorations are one of (none, underline, overline, line-through, blink)
  if ($link !~ /none|underline|overline|line-through|blink/i)
  {
    $self->setError(code => '3001');
    $self->displayError(title => 'setLinkDecorations', message => "'$link' is invalid decoration for <b>link</b>!");
  }
  if ($alink !~ /none|underline|overline|line-through|blink/i)
  {
    $self->setError(code => '3001');
    $self->displayError(title => 'setLinkDecorations', message => "'$alink' is invalid decoration for <b>alink</b>!");
  }
  if ($vlink !~ /none|underline|overline|line-through|blink/i)
  {
    $self->setError(code => '3001');
    $self->displayError(title => 'setLinkDecorations', message => "'$vlink' is invalid decoration for <b>vlink</b>!");
  }
  if (length $hover == 0)
  {
    $self->setError(code => '3002');
    $self->displayError(title => 'setLinkDecorations', message => "<b>hover</b> must have a color!");
  }

  # create the style sheet that defines our text decorations.
  my $decorations = "<style type=\"text/css\">\n";
  $decorations .= "<!--\n";
  $decorations .= "  a:hover   { color: $hover }\n";
  $decorations .= "  a:link    { text-decoration: $link }\n";
  $decorations .= "  a:visited { text-decoration: $vlink }\n";
  $decorations .= "  a:active  { text-decoration: $alink }\n";
  $decorations .= "-->\n";
  $decorations .= "</style>\n";

  $self->{linkStyleSheet} = $decorations;
}

1;
__END__

=head1 NAME

HTMLObject::Normal - Perl extension for HTMLObject.

=head1 SYNOPSIS

  use HTMLObject::Normal;
  my $doc = HTMLObject::Normal->new();

  $doc->setTitle("Test of HTMLObject::Normal");
  $doc->setFocus("body");
  $doc->print(<<"END_OF_BODY");
  <center>
  <h1>HTMLObject::Normal</h1>
  <br>
  This is cool!
  END_OF_BODY

  $doc->setCookie(name => 'cookie name', value => 'This rocks!');

  $doc->setFocus("javascript");
  $doc->print(<<"END_OF_JAVASCRIPT");
    function helloWorld()
    {
      document.write("Hello World");
    }
  END_OF_JAVASCRIPT  # This must be left aligned all the way.

  # cause the helloWorld function to be called when the page has been
  # loaded!
  $doc->setOnload(code => "helloWorld();");

  # Actually generate the entire document, cookie and all!
  $doc->display();

=head1 DESCRIPTION

HTMLObject::Normal builds on the HTMLObject::Base object and provides JavaScript
support that facilitates making Dynamic HTML documents much easier than before.
See the documentation.html file for more details.

=head1 Exported FUNCTIONS

  scalar new()
    Creates a new instance of the HTMLObject::Normal document type.

  void reset()
    Resets the HTMLObject::Normal document back to the defaults.

  void display()
    This function generates the Normal Document displaying any cookies,
    JavaScript, Base, Links, etc. that were specified by the user plus
    the contents of the Body that the user created.  This function prints
    the generated document to standard out which is then hopefully being
    sent to a web server to process.

  void displayError(title => '', message => '')
    Creates a HTML document that displays the user specified error
    message along with the error message generated by the program. The
    user specified title is used also. The program is exited after the
    document is displayed. Uses display() to generate the actual document.

  void set_focus(section) (scalar value)
    Validates the section name specified and then sets the internal
    pointer to the specified section. The output of any following print,
    read, or delete commands will work with the specified section.
    Modifies $currentSection.  This version handles "javascript" and
    passes everything else to the HTMLObject::Base class to handle.

  void setFocus(section) (scalar value)
    Validates the section name specified and then sets the internal
    pointer to the specified section. The output of any following print,
    read, or delete commands will work with the specified section.
    Modifies $currentSection.  This version handles "javascript" and
    passes everything else to the HTMLObject::Base class to handle.

  void print(string) (scalar value)
    Appends the contents of string to the currently specified section.
    This could modify $headString, $bodyString, $javascriptBody.

  scalar read()
    Returns the contents of the currently specified section. This could
    be $headString, $bodyString, $javascriptBody.

  void delete()
    Deletes the contents of the currently specified section. You should
    call read() before doing this so you can restore if this was an
    accident. This could modify $headString, $bodyString,
    $javascriptBody.

  void set_javascript_include(version => '', file => '')
    This function creates an entry in the @javascriptIncludes array that
    will create the code to include the specified javascript file and run
    it at the specified language version. If the version is not
    specified, then "JavaScript" is the default language and version.
    Modifies @javascriptIncludes.

  void setJavascriptInclude(version => '', file => '')
    This function creates an entry in the @javascriptIncludes array that
    will create the code to include the specified javascript file and run
    it at the specified language version. If the version is not
    specified, then "JavaScript" is the default language and version.
    Modifies @javascriptIncludes.

  void set_javascript_version(version) (scalar value)
    This function sets what the Javascript version should be for the
    JavaScript body section. If not specified before the user calls
    display(), then the version will be JavaScript1.1. Modifies
    $javascriptVersion.

  void setJavascriptVersion(version) (scalar value)
    This function sets what the Javascript version should be for the
    JavaScript body section. If not specified before the user calls
    display(), then the version will be JavaScript1.1. Modifies
    $javascriptVersion.

  scalar get_javascript_version()
    This function returns the current JavaScript version that is set in
    javascriptVersion.

  scalar getJavascriptVersion()
    This function returns the current JavaScript version that is set in
    javascriptVersion.

  void print_javascript_required(version => '', message => '')
    This function will create the <noscript>$message</noscript> tags in
    the head that will be run if the browser does not support scripting
    at all and will also generate the code to display the message if the
    specified version of scripting is not supported. Modifies
    $javascriptRequiredMessage, $javascriptRequiredVersion.

  void printJavascriptRequired(version => '', message => '')
    This function will create the <noscript>$message</noscript> tags in
    the head that will be run if the browser does not support scripting
    at all and will also generate the code to display the message if the
    specified version of scripting is not supported. Modifies
    $javascriptRequiredMessage, $javascriptRequiredVersion.

  void disable_javascript_error_handler()
    This function sets the variable $javascriptErrorHandler to 0 so
    that I know not to generate that block of code when displaying the
    document.
    
  void disableJavascriptErrorHandler()
    This function sets the variable $javascriptErrorHandler to 0 so
    that I know not to generate that block of code when displaying the
    document.
    
  scalar is_javascript_error_handler_enabled()
    This function returns the value of the javascriptErrorHandler to
    see if it is enabled or disabled.

  scalar isJavascriptErrorHandlerEnabled()
    This function returns the value of the javascriptErrorHandler to
    see if it is enabled or disabled.

  void set_javascript_error_handler_email(email => '')
    This function will set the value of $javascriptErrorHandlerEmail
    to the value specified.  This is used in the generic JavaScript error
    handler.
    
  void setJavascriptErrorHandlerEmail(email => '')
    This function will set the value of $javascriptErrorHandlerEmail
    to the value specified.  This is used in the generic JavaScript error
    handler.
    
  scalar get_javascript_error_handler_email()
    This function returns the email address that will be used by the
    builtin error handling code.

  scalar getJavascriptErrorHandlerEmail()
    This function returns the email address that will be used by the
    builtin error handling code.

  void set_javascript_error_handler(code => '')
    This function will set the code to use for the JavaScript error
    handler and will assign it to $javascriptErrorHandlerCode.  It is
    up to the user to properly set the return value so that JavaScript
    does not continue to process the error message.  The user must also
    create their own JavaScript window, etc.
    
  void setJavascriptErrorHandler(code => '')
    This function will set the code to use for the JavaScript error
    handler and will assign it to $javascriptErrorHandlerCode.  It is
    up to the user to properly set the return value so that JavaScript
    does not continue to process the error message.  The user must also
    create their own JavaScript window, etc.
    
  void set_javascript_error_handler_window(name => '')
    This function will set the base window name to prepend to the
    window creation code used by the builtin error handler.
    
  void setJavascriptErrorHandlerWindow(name => '')
    This function will set the base window name to prepend to the
    window creation code used by the builtin error handler.
    
  scalar get_javascript_error_handler_window()
    This function returns the window name that will be used by the
    builtin error handler.

  scalar getJavascriptErrorHandlerWindow()
    This function returns the window name that will be used by the
    builtin error handler.

  void set_onload(parameters => '', options => '', code => '')
    This function stores the parameters needed by the code, the options
    to pass into the function and the code to be run and then generates
    the doOnLoad JavaScript function in the JavaScript block of code when
    the user calls display(). The onLoad="doOnLoad($options);" code is
    added to the <body> tag when the page is displayed. Modifies
    $javascriptOnloadParameters, $javascriptOnloadOptions,
    $javascriptOnload.

  void setOnload(parameters => '', options => '', code => '')
    This function stores the parameters needed by the code, the options
    to pass into the function and the code to be run and then generates
    the doOnLoad JavaScript function in the JavaScript block of code when
    the user calls display(). The onLoad="doOnLoad($options);" code is
    added to the <body> tag when the page is displayed. Modifies
    $javascriptOnloadParameters, $javascriptOnloadOptions,
    $javascriptOnload.

  void set_onunload(parameters => '', options => '', code => '')
    This function stores the parameters needed by the code, the options
    to pass into the function and the code to be run and then generates
    the doOnUnLoad JavaScript function in the JavaScript block of code
    when the user calls display(). The onUnLoad="doOnUnLoad($options);"
    code is added to the <body> tag when the page is displayed. Modifies
    $javascriptOnunloadParameters, $javascriptOnunloadOptions,
    $javascriptOnunload.

  void setOnunload(parameters => '', options => '', code => '')
    This function stores the parameters needed by the code, the options
    to pass into the function and the code to be run and then generates
    the doOnUnLoad JavaScript function in the JavaScript block of code
    when the user calls display(). The onUnLoad="doOnUnLoad($options);"
    code is added to the <body> tag when the page is displayed. Modifies
    $javascriptOnunloadParameters, $javascriptOnunloadOptions,
    $javascriptOnunload.

  void set_base(href => '', target => '')
    This function allows the user to specify the base url of the webpage
    or more importantly the default target that all links should point to
    if not explicitly specified. This is mainly used in web pages that
    are in a frameset. Modifies $baseHrefString, $baseTargetString.

  void setBase(href => '', target => '')
    This function allows the user to specify the base url of the webpage
    or more importantly the default target that all links should point to
    if not explicitly specified. This is mainly used in web pages that
    are in a frameset. Modifies $baseHrefString, $baseTargetString.

  void set_link(href => '', name => '', rel => '', rev => '',
                target => '', title => '')
    This function allows the user to specify a <link> tag item that is
    stored in the @linkTag array to be displayed in the <head> when the
    document is created. Modifies @linkTag.

  void setLink(href => '', name => '', rel => '', rev => '',
               target => '', title => '')
    This function allows the user to specify a <link> tag item that is
    stored in the @linkTag array to be displayed in the <head> when the
    document is created. Modifies @linkTag.

  void set_link_decorations(link => 'none', alink => 'none',
                            vlink => 'none', hover => '')
    This function allows the user to specify the decorations that the link,
    visited link, active link and hover link have.  If you specify nothing,
    then by default it turns off all decorations (no underline).  This 
    generates a CSS section to specify the link decorations you desire.

  void setLinkDecorations(link => 'none', alink => 'none',
                          vlink => 'none', hover => '')
    This function allows the user to specify the decorations that the link,
    visited link, active link and hover link have.  If you specify nothing,
    then by default it turns off all decorations (no underline).  This 
    generates a CSS section to specify the link decorations you desire.

=head1 AUTHOR

James A. Pattie, htmlobject@pcxperience.com

=head1 SEE ALSO

perl(1), HTMLObject::Base(3), HTMLObject::FrameSet(3), HTMLObject::ReadCookie(3).

=cut
