#!/usr/bin/perl

# before anything else, the script needs to find out its own name
#
# some servers (notably IIS on windows) don't set the cwd to the script's
# directory before executing it.  So we get that information
# from $0 (the full name & path of the script).
BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_}

$name = $0;
$name =~ s/.+\/?.+\///;  # for unix
$name =~ s/.+\\.+\\//;  # for windows
$path = $0;
$path =~ s/(.+\/).+/$1/g;  # for unix
$path =~ s/(.+\\).+/$1/g;  # for windows

# The "use Cwd" method would be nice, but it doesn't work with 
# some versions of IIS/ActivePerl
#use Cwd;
#$path = cwd;

if ($path ne "")
{
  chdir $path;
  push @INC,$path;
}
# finished discovering name


# some global variables (more further down)
local $plans_version = "6.5.4";        # version
local $debug_info;
local %options;
local $perl_version = (sprintf ("%vd",$^V));
local $options{data_storage_mode};
local $fatal_error = 0;          # fatal errors cause plans to abort and print an error message to the browser
local $error_info = "";        
local $html_output;
local $event_details_template;

local %calendars;
local %current_calendar;
local %latest_calendar;
local %latest_new_calendar;
local $max_cal_id = 0;
local $max_new_cal_id = 0;
local $max_series_id = 0;

local %events;
local %current_event;
local %latest_event;
local $max_event_id = 0;
local %text;

local $max_remote_event_id = 0;


local $options{default_template_path} = "";
local $theme_url = "";
local $options{choose_themes} = "";
local $graphics_url = "";
local $icons_url = "";
local $input_cal_id_valid = 0;
local $options{right_click_menus_enabled} = 0;
local %cal_options;

local $rightnow;
local @months;
local @months_abv;
local @day_names;
local $loaded_all_events;    # flag used to avoid calling load_events("all") twice
                             # not needed for calendars (we always load all calendars)


# check for required modules.

my $module_found=0;
foreach $temp_path (@INC)
{
  if (-e "$temp_path/plans_config.pl")
    {$module_found=1;}
}
if ($module_found == 0)
{
  $fatal_error=1;
  $error_info .= "Unable to locate <b>plans_config.pl</b>!  It should be in the same directory as plans.cgi!\n";
}
else {require "plans_config.pl";}



$module_found=0;
foreach $temp_path (@INC)
{
  if (-e "$temp_path/CGI")
    {$module_found=1;}
}

if ($module_found == 0)
{
  $fatal_error=1;
  $error_info .= "unable to locate required module <b>CGI</b>!\n";
}
else
  {use CGI;}


$module_found=0;
foreach $temp_path (@INC)
{
  if (-e "$temp_path/CGI/Carp.pm")
    {$module_found=1;}
}

if ($module_found == 0)
{
  $fatal_error=1;
  $error_info .= "unable to locate required module <b>CGI::Carp</b>!\n";
}
else
  {use CGI::Carp qw/fatalsToBrowser/;}

$module_found=0;
foreach $temp_path (@INC)
{
  if (-e "$temp_path/Time")
    {$module_found=1;}
}

if ($module_found == 0)
{
  $fatal_error=1;
  $error_info .= "unable to locate required module <b>Time.pm</b>!\n";
}
else
  {use Time::Local;}

$module_found=0;
foreach $temp_path (@INC)
{
  if (-e "$temp_path/IO.pm")
    {$module_found=1;}
}
if ($module_found == 0)
{
  $fatal_error=1;
  $error_info .= "unable to locate required module <b>IO.pm</b>!\n";
}
else
  {use IO::Socket;}

if ($fatal_error == 1)  # print error and bail out
{
  &fatal_error();
}


$module_found=0;
foreach $temp_path (@INC)
{
  if (-r "$temp_path/plans_lib.pl")
    {$module_found=1;}
}
if ($module_found == 0)
{
  $fatal_error=1;
  $error_info .= "Unable to locate <b>plans_lib.pl</b>!  It should be in the same directory as plans.cgi!\n";
}
else {require "plans_lib.pl";}

# get the language file, if one is defined

if (defined $options{language_file})
{
  $module_found=0;
  foreach $temp_path (@INC)
  {
    if (-r "$temp_path/$options{language_file}")
      {$module_found=1;}
  }
  if ($module_found == 0)
  {
    $fatal_error=1;
    $error_info .= "Unable to locate language file <b>$options{language_file}</b>!  It should be in the same directory as plans.cgi!\n";
  }
  else {require $options{language_file};}
}
else
{
  $fatal_error=1;
  $error_info .= "No language file defined in plans.config!\n";
}

# check for perl version
my $temp = substr($perl_version,0,3);
if ($temp < 5.6) {
  $fatal_error=1;
  $error_info .= "Your version of perl ($perl_version) is too old!  Plans requires perl version 5.6 or better.\n";
}

if ($fatal_error == 1)  # print error and bail out
{
  &fatal_error();
}


# init cgi stuff
$q = new CGI;
$script_url = $q->url(-path_info>=1);
$script_url =~ /(.*)\//;          # remove trailing / and all text after
$script_url = $1;                 # remove trailing / and all text after

# check if data files or tables are present
&check_data();                         

# fatal error?  Print error and bail out
if ($fatal_error == 1)                  
  {&fatal_error();}

if ($options{choose_themes})
{
  $theme_url=$q->param('theme_url');
  $theme_url=$theme_url;
} 

if ($theme_url eq "")
  {$theme_url = "$script_url/theme";}

$graphics_url ="$theme_url/graphics";                      # where misc. graphics are 
$icons_url = "$theme_url/icons";                           # where icons are
$css_path = "$theme_url/plans.css";                         # css file



# globals for http parameters
my $active_tab = $q->param('active_tab');
my $add_edit_cal_action = $q->param('add_edit_cal_action');
my $add_edit_event = $q->param('add_edit_event');
local $current_event_id = $q->param('evt_id');

local $cal_num_months = $q->param('cal_num_months');
local $cal_start_month = $q->param('cal_start_month');
local $cal_start_year = $q->param('cal_start_year');

my $special_action = $q->param('special_action');
local $display_type = $q->param('display_type');
$display_type = 0 if ($display_type eq "");


# other globals
my $event_start_date;
my $event_start_timestamp;
my $event_days;
my $start_mday;
my $start_mon;
my $start_year;
my @timestamp_array;
my $recur_end_timestamp;

# load calendar data
&load_calendars();


local $current_cal_id = $q->param('cal_id');

# if calendar id not supplied, but evt_id is supplied (like when viewing an event) use that event's calendar as the current calendar
#if ($current_event_id ne "")
#{
#  &load_event($current_event_id);
#  
#  my %temp_current_event = %{$events{$current_event_id}};
#  if ($current_cal_id eq "")
#  {
#    $current_cal_id = $temp_current_event{cal_ids}[0];
#  }
#}

foreach $cal_id (keys %calendars)
{
  if ($cal_id eq $current_cal_id)
    {$input_cal_id_valid = 1;}
}
    
if ($current_cal_id eq "")
  {$input_cal_id_valid = 0;}
  
if ($current_cal_id =~ /\D/)
  {$input_cal_id_valid = 0;}
  
$current_cal_id = 0 if ($current_event_id eq "" &&  !$input_cal_id_valid);

# make all calendars selectable by default
foreach $cal_id (keys %calendars)
  {$default_cal{selectable_calendars}{$cal_id} = 1;}

%current_calendar = %{$calendars{$current_cal_id}};

# time-related globals
$rightnow = time() + 3600 * $current_calendar{gmtime_diff};
@rightnow_array = gmtime $rightnow;
$rightnow_year = $rightnow_array[5]+1900;
$rightnow_month = $rightnow_array[4];
$rightnow_mday = $rightnow_array[3];
$next_year = $rightnow_year+1;
$rightnow_description = formatted_time($rightnow, "hh:mm:ss mn md yy");

@weekday_sequence = @day_names;

# custom stylesheet?
if ($current_calendar{custom_stylesheet} ne "")
{
  $css_path = "http://$current_calendar{custom_stylesheet}";
}

# if this is a custom calendar request, shoehorn the request parameters in
if ($q->param('custom_calendar') == 1)
{
  $current_cal_id = $q->param('custom_calendar_calendar');
  @custom_calendar_backgound_calendars = $q->param('custom_calendar_background_calendars');
  
  foreach $local_background_calendar (keys %{$calendars{$current_cal_id}{local_background_calendars}})
    {delete $calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar};}
    
  foreach $local_background_calendar (@custom_calendar_backgound_calendars)
    {$calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar} = 1;}
  
  %current_calendar = %{$calendars{$current_cal_id}};
}

# make sure we can select the current calendar
#$current_calendar{selectable_calendars}{$current_cal_id} = 1;


# set info window height & width
$current_calendar{info_window_size} ="400x400" if ($current_calendar{info_window_size} eq ""); # default
my ($info_window_width, $info_window_height) = split("x", $current_calendar{info_window_size});


# rotate weekday_sequence by the offset defined in the week start day.
for ($l1=0;$l1 < $current_calendar{week_start_day};$l1++)
  {push @weekday_sequence, (shift @weekday_sequence);}



# load background_colors
my @temp_lines = split ("\n", $event_background_colors);

foreach $temp_line (@temp_lines)
{
  if ($temp_line !~ /\w/) # skip any blank lines
    {next;}
    
  $temp_line =~ s/^\s+//;   
  my ($hex_color, $hex_color_title) = split (/,*\s+/, $temp_line, 2);
  if ($hex_color_title eq "")
    {$hex_color_title = "&nbsp;";}
    
  push @event_bgcolors, {color => $hex_color, title => $hex_color_title};
}

my $template_html;



#load template
my $custom_template_file_found=1;
my $local_template_file = 0; # tells whether the template was loaded via a filesystem open or through a http request.

if ($current_calendar{custom_template} ne "")  # custom template
{
  $template_html = &get_remote_file("$current_calendar{custom_template}");

  if ($template_html !~ /###/)
  {
    $custom_template_file_found=0;
    $lang{custom_template_fail} =~ s/###template###/$current_calendar{custom_template}/;
    $debug_info .= "$lang{custom_template_fail}\n";
  }
}


if ($current_calendar{custom_template} eq "" || $custom_template_file_found ==0)
{
  if (!(-e "$options{default_template_path}"))
  {
    $fatal_error=1;
    $lang{default_template_fail} =~ s/###template###/$options{default_template_path}/;
    $debug_info .= "$lang{default_template_fail}\n";
    &fatal_error();
  }
  else
  {
    open (FH, "$options{default_template_path}") || ($debug_info .="<br/>Unable to open default template file $options{default_template_path} for reading<br/>");
    flock FH,2;
    @template_lines=<FH>;
    close FH;
    $template_html = join "", @template_lines;
    $local_template_file = 1;
  }
}

# separate the main calendar template and the event details template
$event_details_template = $template_html;
$template_html =~ s/<\/html>.+/<\/html>/s;
$template_html =~ s/<event_details>.+<\/event_details>//s;  # needed in case the event details aren't at the bottom of the html. It happens.

if ($event_details_template =~ /<event_details>/ && $event_details_template =~ /<\/event_details>/)
{
  $event_details_template =~ s/.*<event_details>//s;
  $event_details_template =~ s/<\/event_details>.+//s;
}
else
{
  $debug_info .= "Warning!  No event details template found.  (The template file doesn't contain &lt;event_details&gt;...&lt;/event_details&gt;\n";
  $event_details_template = "";
}

# ssi-style includes in the template
if ($local_template_file)
{
  my $new_html = $template_html;
  
  $template_html =~ s/###include\s+(.+)###/&load_file($1)/ge;
  
  #while ($new_html =~ s/###include\s+(.+)###//g)
  if(0)
  {
    my $include_file=$1;
    if (-e $include_file)
    {
      open (FH, "$include_file") || ($debug_info .="<br/>unable to open include file $include_file for reading<br/>");
      flock FH,2;
      my @include_lines=<FH>;
      close FH;
      $include_html = join "", @include_lines;
    }
    $template_html =~ s/###include\s+(.+)###/$include_html/;
  }
}

sub load_file()
{
  my ($file)=@_;
  if (-e $file)
  {
    open (FH, "$file") || (return "unable to open include file $file for reading");
    flock FH,2;
    my @lines=<FH>;
    close FH;
    $text = join "", @lines;
    return $text;
  }
  else
  {
    return "file $file does not exist";
  }
}



if($options{choose_themes})
{
  my $theme_file="choose_theme.html";
  my $theme_html="";
  if (-e $theme_file)
  {
    open (FH, "$theme_file") || ($debug_info .="<br/>unable to open theme file $theme_file for reading<br/>");
    flock FH,2;
    my @theme_lines=<FH>;
    close FH;
    $theme_html = join "", @theme_lines;
  }
  $template_html =~ s/###choose theme###/$theme_html/;
}
else
{
  $template_html =~ s/###choose theme###//;
}

                            

#evaluate browser type and version
$_ = $ENV{HTTP_USER_AGENT};

if (/Mozilla/) {
  if (/Opera.([0-9\.]+)/) { $browser_type = 'Opera'; $browser_version=$1;}
  elsif (/MSIE.([0-9.]+)/) { $browser_type = 'IE'; $browser_version = $1;}
  elsif (/Mozilla\/([0-9\.]+)/) {$browser_type = 'Mozilla'; $browser_version=$1;
    if (($browser_version<5) || (/Netscape/)) {$browser_type = "Netscape";} }
  if (/\)[^0-9.]+[0-9]*[\/\ ]([0-9.]+)/) {$browser_version=$1;}
} elsif (/(\w+)\/([0-9\.]+)/) {$browser_type = $1; $browser_version = $2}

#evaluate, transform, tweak, adjust, modify input values
#$debug_info .= "browser type: $browser_type<br/>";


#if the input is greater than the number of tabs, things look goofy
if ($q->param('active_tab') >= scalar @tab_text || $q->param('active_tab') eq "")
{
  $active_tab = 0;
}

#if no month is selected, use the current month
if ($cal_start_month eq "")
{
  $cal_start_month = $rightnow_month;
  #$cal_start_month = 2;
}

#if the input year is out of range use the current year
if (($cal_start_year+0) < 1902 || ($cal_start_year+0)> 2037)
{
  $cal_start_year = $rightnow_year;
}

if ($cal_num_months eq "" || $cal_num_months > $current_calendar{max_number_of_months})
{
  $cal_num_months = "$current_calendar{default_number_of_months}";
}

if ($cal_num_months eq "" || $cal_num_months > $current_calendar{max_number_of_months})
{
  $cal_num_months = 1;
}

#calculate calendar end month and year
$cal_end_month = $cal_start_month;
$cal_end_year = $cal_start_year;
for ($l1=1;$l1<$cal_num_months;$l1++)
{
  $cal_end_month++;
  if ($cal_end_month == 12)
  {
    $cal_end_month=0;
    $cal_end_year++;
  }
}

#check to make sure num_months+cal_start_date doesn't go out of bounds
if ($cal_end_year < 1902 || $cal_end_year> 2037)
{
  $cal_end_year = $cal_start_year;
  $cal_end_month = $cal_start_month;
  $cal_num_months = 1;
}

# time window for loading events

my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year) - 2592000;
my $cal_end_timestamp = timegm(0,0,0,1,$cal_end_month,$cal_end_year) + 5184000;
if ($q->param('cal_start_timestamp') ne "" && $q->param('cal_start_timestamp') !~ /\D/)
  {$cal_start_timestamp = $q->param('cal_start_timestamp');}
if ($q->param('cal_end_timestamp') ne "" && $q->param('cal_end_timestamp') !~ /\D/)
  {$cal_end_timestamp = $q->param('cal_end_timestamp');}
  

#$debug_info .="start: $cal_start_timestamp\nend: $cal_end_timestamp\nrightnow: $rightnow\n";

# load event data, for main calendar and its background calendars
my @temp_calendars = ($current_cal_id);
foreach $local_background_calendar (keys %{$current_calendar{local_background_calendars}})
  {push @temp_calendars, $local_background_calendar;}

&load_events($cal_start_timestamp, $cal_end_timestamp, \@temp_calendars);
if ($current_event_id ne "")
{
  &load_event($current_event_id);
  %current_event = %{$events{$current_event_id}};
}


# load events from remote background calendars

if (scalar keys %{$current_calendar{remote_background_calendars}} > 0)
{
  $remote_calendars_status="";
  my $temp = scalar keys %{$current_calendar{remote_background_calendars}};
  foreach $remote_calendar_id (keys %{$current_calendar{remote_background_calendars}})
  {
    # pull in remote calendar name
    my $remote_calendar_url = $current_calendar{remote_background_calendars}{$remote_calendar_id}{url};
    $remote_calendar_complete_url = $remote_calendar_url;
    #$debug_info .= "remote calendar: $remote_calendar_complete_url\n";

    $remote_calendar_complete_url .= "?remote_calendar_request=1&cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}&cal_start_year=$cal_start_year&cal_start_month=$cal_start_month&num_months=$cal_num_months";
    #$debug_info .= "remote calendar url: $remote_calendar_complete_url\n";

    my $xml_results = &get_remote_file($remote_calendar_complete_url);
    
    if ($xml_results =~ /<error>/)
    {
      $xml_results =~ s/</&lt;/g;
      $xml_results =~ s/>/&gt;/g;
    
      $debug_info .= "Error fetching remote calendar: $xml_results\n";
    }
    else
    {
      my %remote_calendars = %{&xml2hash($xml_results)};

      my $remote_cal_title=$remote_calendars{'xml'}{calendar}{title};
    
      my $temp=$xml_results;
      $temp=~ s/>/&gt;/g;
      $temp=~ s/</&lt;/g;
      #$debug_info .= "xml results: $temp\n";
      
      &load_remote_events($xml_results, $current_calendar{remote_background_calendars}{$remote_calendar_id});
    }
  }
}

# calculate previous X months range.
my $previous_cal_start_month = $cal_start_month - $cal_num_months;
my $previous_cal_start_year = $cal_start_year;
if ($previous_cal_start_month < 0)
{
  $previous_cal_start_year = $cal_start_year - 1 - int(abs($cal_num_months - $cal_start_month) / 12);
  $previous_cal_start_month = 12 - abs($previous_cal_start_month) % 12;
}

# for the case when num_months = 12 and start_month=0
if ($previous_cal_start_month == 12)
{
  $previous_cal_start_month=0;
  $previous_cal_start_year++;
}


# singular or plural?
if ($cal_num_months > 1)
{
  $prev_string = $lang{previous_months};
  $prev_string =~ s/###num###/$cal_num_months/;
}
else
{
  $prev_string = $lang{previous_month};
}


# calculate next X months range.
my $next_cal_start_month = $cal_start_month + $cal_num_months;
my  $next_cal_start_year = $cal_start_year;
if ($next_cal_start_month > 11)
{
  $next_cal_start_year = $cal_start_year + int(abs($cal_num_months + $cal_start_month) / 12);
  $next_cal_start_month = abs($cal_start_month + $cal_num_months) % 12;
}


# singular or plural?
if ($cal_num_months > 1)
{
  $next_string = $lang{next_months};
  $next_string =~ s/###num###/$cal_num_months/;
}
else
{
  $next_string = $lang{next_month};
}



$consistent_parameter_string="";
&make_consistent ("cal_id");
&make_consistent ("cal_start_month");
&make_consistent ("cal_start_year");
&make_consistent ("cal_num_months");
&make_consistent ("display_type");
&make_consistent ("theme_url");

if ($q->param('diagnostic_mode') eq "1")
{
  &diagnostic_mode();
  exit(0);
}

if ($q->param('detect_remote_calendars') eq "1")
{
  &detect_remote_calendars();
  exit(0);
}

if ($q->param('remote_calendar_request') eq "1")
{
  &remote_calendar_request();
  exit(0);
}

if ($q->param('export_calendar') eq "1")
{
  &normalize_timezone();
  if ($q->param('export_type') eq "ascii_text")
  {
    &ascii_text_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
    exit(0);
  }
  elsif ($q->param('export_type') eq "csv_file")
  {
    &csv_file($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
    exit(0);
  }
  elsif ($q->param('export_type') eq "vcalendar")
  {
    &vcalendar_export_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
    exit(0);
  }
}

if ($q->param('export_event') eq "1")
{
  if ($q->param('export_type') eq "ascii_text")
  {
    &ascii_text_event();
    exit(0);
  }
  elsif ($q->param('export_type') eq "icalendar")
  {
    &icalendar_export_event();
    exit(0);
  }
  elsif ($q->param('export_type') eq "vcalendar")
  {
    &vcalendar_export_event();
    exit(0);
  }
}
elsif ($q->param('view_event') eq "1")
{
  &view_event();
  exit(0);
}
elsif ($q->param('email_reminder') eq "1")
{
  &email_reminder_prompt();
  exit(0);
}
elsif ($q->param('email_reminder_confirm') eq "1")
{
  &email_reminder_confirm();
  exit(0);
}
elsif ($special_action eq "preview_event")
{
  &preview_event();
  exit(0);
}
elsif ($special_action eq "preview_date")
{
  &preview_date();
  exit(0);
}



  $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n

$template_html
p1

  $html_output =~ s/###current calendar title###/$current_calendar{title}/g;

  $insert_text =<<p1;
<script type="text/javascript" ><!--
###common javascript###
###page-specific javascript###
###browser-specific javascript###
//-->
</script>
p1
  chomp $insert_text;
  $html_output =~ s/###javascript stuff###/$insert_text/;

#default page
&display_default();

exit(0);




sub display_default
{
  chomp $insert_text;
  $html_output =~ s/###css file###/$css_path/g;
  
  
  # tab menu stuff
 $menu_tabs[0] = {status => "inactive",
                  html => "<a href=\"$script_url/$name?active_tab=0$consistent_parameter_string\">$tab_text[0]</a>"};
 $menu_tabs[1] = {status => "inactive",
                  html => "<a href=\"$script_url/$name?active_tab=1$consistent_parameter_string\">$tab_text[1]</a>"};
 $menu_tabs[2] = {status => "inactive",
                  html => "<a href=\"$script_url/$name?active_tab=2$consistent_parameter_string\">$tab_text[2]</a>"};

 $menu_tabs[$active_tab]{status} ="active";
                  
 $menu_tabs[2]{html} = "<a href=\"$script_url/$name?active_tab=2$consistent_parameter_string\">$tab_text[2]</a>";

 $insert_text =<<p1;
<br/>
<div style="padding:0px;margin:0px;margin-left:20px;white-space:nowrap;">
p1

  # this kludge sucks!  
  if ($browser_type eq "IE")
    {$tab_vert_offset=4;}
  else
    {$tab_vert_offset=0;}
  
  #lay out the actual menu tabs
  for ($l1=0;$l1<scalar @tab_text;$l1++)
  {
    if ($tab_text[$l1] eq "") 
      {next;}
    $menu_tab = $menu_tabs[$l1];
    my $style="";
   
   #$tab_vert_offset=0;
    
   if ($$menu_tab{status} eq "active")
   {
     $style="top:".($tab_vert_offset-3)."px;padding-top:5px;padding-bottom:5px;margin-top:0;height:2em;";
   }
   else
   {
     $style="top:".($tab_vert_offset-3)."px;padding-top:3px;padding-bottom:4px;margin-top:1px;height:2em;";
   }
    $insert_text .=<<p1;
<span class="$$menu_tab{status}_tab" style="position:relative;border-bottom-width:0px;padding-top:5px;margin-bottom:0;margin-left:5px;margin-right:2px;white-space:nowrap;text-align:center;$style"> &nbsp; &nbsp; &nbsp; $$menu_tab{html} &nbsp; &nbsp; &nbsp; </span>
p1
   
    $noinsert_text .=<<p1;
<span class="$$menu_tab{status}_tab" style="position:relative;$style">$$menu_tab{html} &nbsp; &nbsp; &nbsp; </span>
p1
  }
  
  $insert_text .=<<p1;
</div>
p1
  chomp $insert_text;


    if ($q->param('custom_calendar') == 1)
    {
      $html_output =~ s/###tab menu stuff###//;
    }
    else
    {
      $html_output =~ s/###tab menu stuff###/$insert_text/;
    }
    
    
  $insert_text ="";

  #invisible html for context menu  
    $insert_text .=<<p1;
<div id="contextmenu" class="contextmenu" style="position:absolute;visibility:hidden;">
</div>
p1

  #main box stuff
  $insert_text .=<<p1;
p1

  #finished displaying tab menus, now time to display the appropriate stuff for
  #the selected tab

  if ($active_tab eq "0") #the first tab is the main calendar view
  {
    my $cal_controls_text =<<p1;
<div class="calendar_controls">
<form name="tab0_form" action="$script_url/$name" method="get">
<input type="hidden" name="theme_url" value="$theme_url"/>

<div style="float:right;margin:5px;padding:2px;vertical-align:middle;">
<input id="controls_submit_button" type="submit" value="$lang{controls_change}"/>
</div>

<div style="margin:5px;padding:2px;text-align:right;float:right;">
$lang{controls_start_month}: 
<select name="cal_start_month" onChange="blink('controls_submit_button', 3, 0);">
p1
    #list each month in the year
    $month_index=0;
    foreach $possible_month (@months)
    {
      if ($cal_start_month eq $month_index)
      {
        $cal_controls_text .=<<p1;
<option value="$month_index" selected>$possible_month
p1
      }
      else
      {
        $cal_controls_text .=<<p1;
<option value="$month_index">$possible_month
p1
      }
      $month_index++;
    }
    $cal_controls_text .=<<p1;
</select>
<input name="cal_start_year" value = "$cal_start_year" size=4 onChange="blink('controls_submit_button', 3, 0);"/><br/>
$lang{controls_num_months}
<input name="cal_num_months" value = "$cal_num_months" size=3 onChange="blink('controls_submit_button', 3, 0);"/>
</div>
p1
      $cal_controls_text .=<<p1;
<div class="calendar_select" style="margin:5px;padding:2px;float:left;text-align:left;">
$lang{controls_calendar_label}<br/>
p1

    my $num_selectable_calendars = scalar keys %{$current_calendar{selectable_calendars}};
    
    my @selectable_calendars;
    if ($options{all_calendars_selectable})
    {
      @selectable_calendars = keys %calendars;
    }
    else
    {
      @selectable_calendars = keys %{$current_calendar{selectable_calendars}};
    }
    
    
    if (scalar @selectable_calendars > 0)
    {
      $cal_controls_text .=<<p1;
<select name="cal_id" onChange="blink('controls_submit_button', 3, 0);">
p1
      #list each calendar for the user to select
      foreach $selectable_calendar_id (sort {$a <=> $b} @selectable_calendars)
      {
        my $selected ="";
        $selected =" selected" if ($selectable_calendar_id eq $current_calendar{id});
        $selectable_calendar_id=~ s/\D//g;
        #$debug_info .= "calendar id: -$selectable_calendar_id-\n ";
        
        $cal_controls_text .=<<p1;
<option value = "$selectable_calendar_id"$selected>$calendars{$selectable_calendar_id}{title}
p1
      }
  
      $cal_controls_text .=<<p1;
</select>
p1
    }
    else
    {
      $cal_controls_text .=<<p1;
<span style="font-weight:bold;">$current_calendar{title}</span>
<input type="hidden" name="cal_id" value="$current_calendar{id}"/>
p1
    }
      $cal_controls_text .=<<p1;
</div>
p1
    
    
    $cal_controls_text .=<<p1;
<div style="margin:5px;padding:2px;float:left;text-align:left;">
$lang{controls_display_label}<br/>
<select name="display_type" onChange="blink('controls_submit_button', 3, 0);">
p1
    #foreach $possible_display_type (@{$options{display_types}})
    for (my $l1=0;$l1<scalar @{$options{display_types}};$l1++)
    {
      if ($options{display_types}[$l1] ne "1")
        {next};
      my $selected="";
      
      if ($l1 eq $display_type) 
        {$selected = "selected";}
        
      $cal_controls_text .=<<p1;
<option value="$l1" $selected>$lang{controls_display_type}[$l1]
p1
    }
    $cal_controls_text .=<<p1;
</select>
</div>
p1



    $cal_controls_text .=<<p1;
<br style="clear:both;"/>
</form>
</div>
p1
    if ($q->param('custom_calendar') == 1)
    {
      $html_output =~ s/###calendar controls###//g;
    }
    else
    {
      $html_output =~ s/###calendar controls###/$cal_controls_text/g;
    }
    
    $insert_text .= &do_calendar_list_view();  
    
    #select event range
    
    $cal_month_start_date = timegm(0,0,0,1,$cal_start_month,$cal_start_year);
    @cal_month_start_date_array = gmtime $cal_month_start_date;
  
    $events_start_timestamp = $cal_month_start_date - 604800;                            # +7 day margin
    $events_end_timestamp = &find_end_of_month($cal_end_month, $cal_end_year) + 604800;  # +7 day margin
      
    #now that we have selected the appropriate events, we can 
    #generate the corresponding javascript and calendar view
    #and insert/add it to the html output.
    $common_javascript = &common_javascript();
    $page_javascript = &calendar_view_javascript($events_start_timestamp, $events_end_timestamp);
  
    #display browser-appropriate javascript
    if ($browser_type eq "IE" || $browser_type eq "Opera")
      {$browser_javascript = &IE_javascript();}
    else
      {$browser_javascript = &NS6_javascript();}
    
    #replace javascript placeholders with actual html/javascript code

    $html_output =~ s/###common javascript###/$common_javascript/;
    $html_output =~ s/###page-specific javascript###/$page_javascript/;
    $html_output =~ s/###browser-specific javascript###/$browser_javascript/;
    
    my $temp1 .=<<p1;
<a href="$script_url/$name?cal_id=$current_cal_id&amp;display_type=$display_type&amp;cal_start_month=$previous_cal_start_month&amp;cal_start_year=$previous_cal_start_year&amp;cal_num_months=$cal_num_months ">$prev_string</a>
p1
    my $temp2 .=<<p1;
<a href="$script_url/$name?cal_id=$current_cal_id&amp;display_type=$display_type&amp;cal_start_month=$next_cal_start_month&amp;cal_start_year=$next_cal_start_year&amp;cal_num_months=$cal_num_months">$next_string</a>
p1
    $html_output =~ s/###previous month link###/$temp1/g;
    $html_output =~ s/###next month link###/$temp2/g;
    
  }
  elsif ($active_tab eq "1") #the second tab is the add/edit events view
  {
    $html_output =~ s/###calendar controls###//;

    $insert_text .=<<p1;
<form id="add_event_form" name="add_event_form" action="$script_url/$name" method="POST">
<input type="hidden" name="active_tab" value="1"/>
<input type="hidden" name="special_action" value=""/>
<input type="hidden" name="add_edit_event" value="$add_edit_event"/>
<input type="hidden" name="evt_id" value="$current_event_id"/>
<input type="hidden" name="cal_id" value="$current_cal_id"/>
<input type="hidden" name="cal_start_month" value="$cal_start_month"/>
<input type="hidden" name="cal_start_year" value="$cal_start_year"/>
<input type="hidden" name="cal_num_months" value="$cal_num_months"/>
<input type="hidden" name="display_type" value="$display_type"/>
<input type="hidden" name="theme_url" value="$theme_url"/>
p1
    
    $insert_text .= &add_edit_events();
    $insert_text .=<<p1;
</form>
p1
   
    #generate javascript for add/edit events page
    $common_javascript = &common_javascript();
    $page_javascript = &add_edit_events_javascript();
  
    #display browser-appropriate javascript
    if ($browser_type eq "IE" || $browser_type eq "Opera")
    {$browser_javascript = &IE_javascript();}
    else
    {$browser_javascript = &NS6_javascript();}
    
    #replace javascript placeholders with actual html/javascript code
    $html_output =~ s/###common javascript###/$common_javascript/;
    $html_output =~ s/###page-specific javascript###/$page_javascript/;
    $html_output =~ s/###browser-specific javascript###/$browser_javascript/;
    
    # sneak in the color select javascript before all other javascript.
    my $temp =<<p1; 
<script  type="text/javascript" src="$theme_url/color_select.js"></script>
p1
    $html_output =~ s/(<script)/$temp$1/;
  }
  elsif ($active_tab eq "2") #the third tab is for calendar information
  {
    &load_new_calendars();
    $html_output =~ s/###calendar controls###//;
    if ($add_edit_cal_action eq "")  # calendar management view
    {
      $num_new_calendars = scalar keys %new_calendars;
    
      if ($num_new_calendars == 0)
        {$new_calendars_info = $lang{tab2_no_new_calendars};}
      else
      {
        $new_calendars_info = $lang{tab2_some_new_calendars};
        $new_calendars_info =~ s/###num###/$num_new_calendars/;
      }
    
      $insert_text .=<<p1;
<div>
<div class="info_box" style="margin-top:20px;float:left;padding-left:20px;padding-right:20px;text-align:left;">

<form name="view_cal_form" action="$script_url/$name" method="POST">
<input type="hidden" name = "active_tab" value="2"/>
<input type="hidden" name = "cal_start_month" value="$cal_start_month"/>
<input type="hidden" name = "cal_start_year" value="$cal_start_year"/>
<input type="hidden" name = "cal_num_months" value="$cal_num_months"/>
<input type="hidden" name = "display_type" value="$display_type"/>
<input type="hidden" name = "special_action" value="$special_action"/>
<input type="hidden" name = "add_edit_cal_action" value="edit"/>
<input type="hidden" name="theme_url" value="$theme_url"/>

$lang{tab2_select_a_calendar}
<select name="cal_id">
p1
      foreach $cal_id (sort {$a <=> $b} keys %calendars)
      {
        my $selected="";
        if ($cal_id eq $current_cal_id)
        {
          #$debug_info .= "$cal_id<br/>";
          $selected=" selected";
        }
        $insert_text .=<<p1;
<option value = "$cal_id"$selected>$calendars{$cal_id}{title}
p1
      }

    $insert_text .=<<p1;
</select>
</form>
<ul>
<li><a href="javascript:display_cal_info(document.view_cal_form.cal_id.options[document.view_cal_form.cal_id.selectedIndex].value)">$lang{tab2_view_calendar_details}</a></li>
p1

    $writable{calendars_file} and $insert_text .=<<p1;
<li><a href="javascript:document.view_cal_form.submit();">$lang{tab2_edit_delete}</a></li>
p1

  $writable{new_calendars_file} and $insert_text .=<<p1;
</ul>
</div>

<div class="info_box" style="float:left;clear:left;width:90%;margin-top:20px;padding-left:20px;padding-right:20px;text-align:left;">
<ul>

<li><a href="$script_url/$name?active_tab=2&amp;add_edit_cal_action=add$consistent_parameter_string">$lang{tab2_add_new_calendar}</a></li>
<li><a href="$script_url/$name?active_tab=2&amp;add_edit_cal_action=view_pending$consistent_parameter_string">$lang{tab2_view_new_calendars}</a> $new_calendars_info</li>

</ul>
</div>

<br style="clear:both;"/>
</div>

p1
    }
    elsif($add_edit_cal_action eq "add" || $add_edit_cal_action eq "edit")  #add/edit calendars
    {    
      $insert_text .=<<p1;
<form id="update_cal_form" name="update_cal_form" action="$script_url/$name" method="POST">
p1
      $insert_text .=  &add_edit_calendars();
      $insert_text .=<<p1;
</form>
p1
    }
    elsif ($add_edit_cal_action eq "view_pending")  #view/approve/reject new pending calendars
    {
      $insert_text .=  &view_pending_calendars();
    }
    
    
    #generate javascript for calendar info page
    $common_javascript = &common_javascript();
    $page_javascript = &cal_info_view_javascript();
    $page_javascript.= &add_edit_calendars_javascript();

    #display browser-appropriate javascript   
    if ($browser_type eq "IE" || $browser_type eq "Opera")
    {$browser_javascript = &IE_javascript();}
    else
    {$browser_javascript = &NS6_javascript();}
    
    #replace javascript placeholders with actual html/javascript code
    $html_output =~ s/###common javascript###/$common_javascript/;
    $html_output =~ s/###page-specific javascript###/$page_javascript/;
    $html_output =~ s/###browser-specific javascript###/$browser_javascript/;
    
    # sneak in the color select javascript before all other javascript.
    my $temp =<<p1; 
<script  type="text/javascript" src="$theme_url/color_select.js"></script>
p1
    $html_output =~ s/(<script)/$temp$1/;
    
  }
  
  #done with main active tab stuff (the stuff that's different depending
  #on which tab is active.  The following stuff is the same regardless
  #of which tab is active.
  
  $html_output =~ s/###calendar area###/$insert_text/g;
  $html_output =~ s/###version###/$plans_version/g;
  
  
  my $add_event_to_current_cal_text =<<p1;
<a target = "_self" href="$script_url/$name?active_tab=1&amp;cal_id=$current_cal_id">$lang{add_event_to_this_calendar}</a>
p1
  chomp $add_event_to_current_cal_text;
  
  my $current_calendar_options_text =<<p1;
<a target="_self" href="$script_url/$name?active_tab=2&amp;cal_id=$current_cal_id&amp;add_edit_cal_action=edit">$lang{edit_calendar_options}</a>
p1
  chomp $current_calendar_options_text;
  
  if ($active_tab eq "0")
  {
    $html_output =~ s/###add event to current calendar link###/$add_event_to_current_cal_text/;
    $html_output =~ s/###edit calendar options link###/$current_calendar_options_text/;
    
    my $temp = &export_calendar_link();
    $html_output =~ s/###export calendar link###/$temp/;
    
    my $custom_calendar_link =<<p1;
<a href="javascript:custom_calendar()">$lang{make_custom_calendar}</a>
p1
    chomp $custom_calendar_link;
    $html_output =~ s/###custom calendar link###/$custom_calendar_link/;

    #$debug_info .= "custom calendar link: $custom_calendar_link\n";
  }
  else
  {
    $html_output =~ s/###add event to current calendar link###//;
    $html_output =~ s/###edit calendar options link###//;
    $html_output =~ s/###custom calendar link###//;
    $html_output =~ s/###export calendar link###//;
  }
  
  $debug_info = "$error_info$debug_info";
  
  if ($debug_info =~ /\S/)
  {
    $debug_info =~ s/\n/<br\/>\n/g;
    $debug_info = <<p1;
<div style="width:100%;padding:10px;margin:10px;border:solid 1px #000;background-color:#fff;">
<b>Error, Warnings, & Debug Messages:</b><br/>
$debug_info
<\/div>
p1
  }
  $html_output =~ s/###debug stuff###/$debug_info/g;

  print $html_output;

} #********************end default view code*****************************

sub add_edit_calendars
{

  my $temp="<link rel=\"stylesheet\" href=\"$theme_url/color_select.css\" type=\"text/css\">";
  $html_output =~ s/<head>/<head>\n$temp\n/;

  my $return_text = "";
  
  my $cal_start_month = $q->param('cal_start_month');
  my $cal_start_year = $q->param('cal_start_year');
  my $cal_num_months = $q->param('cal_num_months');

  if ($q->param('update_cal_button') eq "" && $q->param('del_cal_button') eq "")  #add/edit calendar main screen
  {
    $add_edit_string = $lang{add_new_calendar};
    #generate html for blank (default) calendar preview window
   
    $cal_details = $new_calendar_default_details;
    $shared_cal_select_size = scalar keys %calendars;
    $cal_link="http://";
    
    if ($add_edit_cal_action ne "edit")
      {%current_calendar = %default_cal;}
    
    $add_edit_string = "$lang{edit_calendar} ($current_calendar{title})" if ($add_edit_cal_action eq "edit");
    
    my %checked;
    $checked{list_background_calendars_together} = " checked" if ($current_calendar{list_background_calendars_together} eq "yes");
    $checked{background_events_display_style1} = " checked" if ($current_calendar{background_events_display_style} eq "normal");
    $checked{background_events_display_style2} = " checked" if ($current_calendar{background_events_display_style} eq "single_color");
    $checked{background_events_display_style3} = " checked" if ($current_calendar{background_events_display_style} eq "faded");
    
    $current_calendar{custom_stylesheet} = "http://$current_calendar{custom_stylesheet}";
    $current_calendar{custom_template} = "http://$current_calendar{custom_template}";
    
    $cal_details =~ s/</&lt;/g;     
    $cal_details =~ s/>/&gt;/g;     
      
    $return_text .=<<p1;
    
<!-- color_select_box 0-->
<div id="color_select_box0" class="color_select_box" style="display:none;">
<!-- cursors -->
<div id="sv_crosshair_horiz_cursor0" class="sv_crosshair_horiz_cursor" style="visibility:hidden;">
</div>
<div id="sv_crosshair_center_cursor0" class="sv_crosshair_center_cursor" style="visibility:hidden;">
</div>
<div id="sv_crosshair_vert_cursor0" class="sv_crosshair_vert_cursor" style="visibility:hidden;">
</div>
<!-- /cursors -->
<div id="sv_select_box_bg0" class="sv_select_box" style="background-color:#0000ff;">
<div id="sv_select_box0" onMouseDown="cs0.sv_select_box_focus=true;color_select_update();"
                      onMouseUp="cs0.sv_select_box_focus=false;color_select_update();"
 style="line-height:256px;height:256px;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true src='$graphics_url/sv_blend.png')">
<br/>
</div>
</div>
<div id="h_select_box0" class="h_select_box" style="margin-left:5px;background-image:url($graphics_url/hue_blend.png)" 
 onMouseDown="cs0.h_select_box_focus=true;color_select_update()" onMouseUp="cs0.h_select_box_focus=false;color_select_update();">
<div id="hue_cursor0" class="hue_cursor" style="visibility:hidden;">
</div>
</div>
<div id="color_box0" class="color_box">
<div id="color_value_box0" class="color_value_box">
</div>
</div>
</div> 
<!-- end color_select_box 0-->  
  
<!-- color_select_box 1-->
<div id="color_select_box1" class="color_select_box" style="display:none;">
<!-- cursors -->
<div id="sv_crosshair_horiz_cursor1" class="sv_crosshair_horiz_cursor" style="visibility:hidden;">
</div>
<div id="sv_crosshair_center_cursor1" class="sv_crosshair_center_cursor" style="visibility:hidden;">
</div>
<div id="sv_crosshair_vert_cursor1" class="sv_crosshair_vert_cursor" style="visibility:hidden;">
</div>
<!-- /cursors -->
<div id="sv_select_box_bg1" class="sv_select_box" style="background-color:#0000ff;">
<div id="sv_select_box1" onMouseDown="cs1.sv_select_box_focus=true;color_select_update();"
                      onMouseUp="cs1.sv_select_box_focus=false;color_select_update();"
 style="line-height:256px;height:256px;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true src='$graphics_url/sv_blend.png')">
<br/>
</div>
</div>
<div id="h_select_box1" class="h_select_box" style="margin-left:5px;background-image:url($graphics_url/hue_blend.png)" 
 onMouseDown="cs1.h_select_box_focus=true;color_select_update()" onMouseUp="cs1.h_select_box_focus=false;color_select_update();">
<div id="hue_cursor1" class="hue_cursor" style="visibility:hidden;">
</div>
</div>
<div id="color_box1" class="color_box">
<div id="color_value_box1" class="color_value_box">
</div>
</div>
</div> 
<!-- end color_select_box 1-->    
    
<input type="hidden" name="active_tab" value="2"/>
<input type="hidden" name="add_edit_cal_action" value="$add_edit_cal_action"/>
<input type="hidden" name="cal_id" value="$current_calendar{id}"/>
<input type="hidden" name="cal_start_month" value="$cal_start_month"/>
<input type="hidden" name="cal_start_year" value="$cal_start_year"/>
<input type="hidden" name="cal_num_months" value="$cal_num_months"/>
<input type="hidden" name="display_type" value="$display_type"/>
<input type="hidden" name="theme_url" value="$theme_url"/>
<input type="hidden" name="new_remote_calandars_xml" value=""/>

<p class="cal_title" style="text-align:center;">
$add_edit_string
</p>

<div class="info_box" style="text-align:center;margin-bottom:2em;float:left;">
<span class="optional_field">$lang{fields_text1} <span class="required_field">$lang{fields_text2}</span> $lang{fields_text3}</span>
</div>

<div style="width:90%;text-align:left;white-space:nowrap;clear:left;">
<a id="tab0" href="javascript:tab_show(0)" class="info_box_tab active">$lang{add_edit_calendars_tab0}</a>
<a id="tab1" href="javascript:tab_show(1)" class="info_box_tab">$lang{add_edit_calendars_tab1}</a>
<a id="tab2" href="javascript:tab_show(2)" class="info_box_tab">$lang{add_edit_calendars_tab2}</a>
<a id="tab3" href="javascript:tab_show(3)" class="info_box_tab">$lang{add_edit_calendars_tab3}</a>
</div>

<div id="tab_area0" class="info_box" style="width:100%;position:relative;z-index:101;padding-top:20px;">


<div class="leftcol" style="">
<label class="required_field" for="cal_title">$lang{calendar_title}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="cal_title" name="cal_title" style="width:50%;" value = "$current_calendar{title}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('cal_title','$lang{calendar_title}')">$lang{help_on_this}</a></span>
</div>

<div class="leftcol" style="">
<label class="optional_field" for="cal_link">$lang{calendar_link}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="cal_link" name="cal_link" style="width:50%;" value = "$current_calendar{link}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('cal_link','$lang{calendar_link}')">$lang{help_on_this}</a></span>
</div>

<div class="leftcol" style="">
<label class="optional_field" for="cal_details">$lang{calendar_details}</label>
<br/>
<span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('cal_details','$lang{calendar_details}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
</div>
<div class="rightcol" style="white-space:nowrap;">
<textarea name="cal_details" id="cal_details" rows=10 cols=0 style="width:100%;">
$current_calendar{details}
</textarea>
</div>


<div style="clear:both;text-align:center;padding-top:20px;padding-bottom:20px;">
<b><a href="javascript:preview_cal()">$lang{preview_calendar_details}</a></b>
</div>

<br style="clear:both;"/>&nbsp;
</div>

<div id="tab_area1" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;">
<div style="float:left;width:45%;text-align:left;">




<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">
p1
    if (scalar (keys %calendars) > 1 || $add_edit_cal_action ne "edit")
    {
  $return_text .=<<p1;
<label class="optional_field" style="float:left;" for="background_calendars">$lang{background_calendars1}<br/><span class="small_note">$lang{background_calendars2}</span>
<br/><span class="small_note" ><a href="javascript:display_help('cal_background_calendars','$lang{background_calendars1}')">$lang{help_on_this}</a></span>
<br/>
$lang{background_calendars3}
</label>
<select multiple size=8 style="display:block;clear:left;" name="background_calendars" id="background_calendars">
p1
#'
      foreach $cal_id (sort {$a <=> $b} keys %calendars)
      {
        #don't display a choice for the calendar currently being edited
        if ($cal_id eq $current_calendar{id})
          {next;}

        #$debug_info .= "$current_calendar{title} local_background_calendars{$cal_id} = $current_calendar{local_background_calendars}{$cal_id}\n";
        my $selected="";
        
        if ($current_calendar{local_background_calendars}{$cal_id} eq "1")
          {$selected = " selected";}
          
          $return_text .=<<p1;
<option value = "$cal_id"$selected>$calendars{$cal_id}{title}
p1
      }

      $return_text .=<<p1;
</select>
p1
    }

    $return_text .=<<p1;
</div>
<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">
<label class="optional_field" style="float:left;" for="remote_background_calendars">$lang{remote_background_calendars1}</label> 
&nbsp;<span class="small_note" ><a href="javascript:display_help('help_remote_background_calendars','$lang{remote_background_calendars1}')">$lang{help_on_this}</a></span>
p1
    my $remote_calendars_status = $lang{remote_background_calendars_none};

    if (scalar keys %{$current_calendar{remote_background_calendars}} > 0)
    {
      $remote_calendars_status="";
      my $temp = scalar keys %{$current_calendar{remote_background_calendars}};
      if ($temp>4) {$temp=4};
      $temp = ($temp * 20)."px";
          
      $return_text .=<<p1;
<div class="scroll_surround" style="height:$temp;white-space:nowrap;">
p1
      foreach $remote_calendar_id (keys %{$current_calendar{remote_background_calendars}})
      {
        # pull in remote calendar name
          my $remote_calendar_url = $current_calendar{remote_background_calendars}{$remote_calendar_id}{url};
          $remote_calendar_complete_url = $remote_calendar_url;

          $remote_calendar_complete_url .= "?remote_calendar_request=1&cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}&cal_start_year=1971&cal_start_month=0&num_months=1";
          my $xml_results = &get_remote_file($remote_calendar_complete_url);
          
          if ($xml_results =~ /<error>/)
          {
            $xml_results =~ s/</&lt;/g;
            $xml_results =~ s/>/&gt;/g;
          
            $debug_info .= "Error fetching remote calendar: $xml_results\n";
          }
          else
          {
            my %remote_calendars = %{&xml2hash($xml_results)};

            my $remote_cal_title=$remote_calendars{'xml'}{calendar}{title};
        
            $return_text .=<<p1;
<a target="_blank" href="$remote_calendar_url?cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}" style="font-size:small;">$remote_cal_title</a>
&nbsp;&nbsp;&nbsp;&nbsp;
(<input type="checkbox" name="delete_remote_calendar_$remote_calendar_id" style="margin-top:0;margin-bottom:0;padding:0;vertical-align:bottom;" value="y"/>$lang{get_remote_calendar3})
<br/>
p1
          }
          
      }
      $return_text .=<<p1;
</div>
p1
    }
      $return_text .=<<p1;
<div id="remote_background_calendars_status" class="small_note">$remote_calendars_status</div>
<div class="small_note"><a href="javascript:get_remote_calendars();">$lang{get_remote_calendars}</a></div>
p1
      $return_text .=<<p1;
</div> <!-- end border div -->
p1

    my $temp1="";
    my $temp2="";
    my $temp3="";
    if ($current_calendar{allow_remote_calendar_requests} =~ /y/)
      {$temp1=" checked";}
      
    if ($current_calendar{remote_calendar_requests_require_password} =~ /y/)
    {
      $temp2=" checked";
      $temp3="$current_calendar{remote_calendar_requests_password}";
    }
      
    $return_text .=<<p1;
<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">
<input type="checkbox" id="allow_remote_calendar_requests" name="allow_remote_calendar_requests" value="yes" $temp1 onclick="update_remote_calendar_requests()"/>
<label class="optional_field" for="allow_remote_calendar_requests">$lang{allow_remote_calendar_requests}</label>
<br/><span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('allow_remote_calendar_requests','$lang{allow_remote_calendar_requests}')">$lang{help_on_this}</a></span>
<br/>
<input type="checkbox" id="remote_calendar_requests_require_password" name="remote_calendar_requests_require_password" value="yes" $temp2  onclick="update_remote_calendar_requests()"/>
<label class="optional_field" for="remote_calendar_requests_password">$lang{remote_calendar_requests_password1}</label>
<input type="password" id="remote_calendar_requests_password" name="remote_calendar_requests_password" value="$temp3"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('remote_calendar_requests_password','$lang{remote_calendar_requests_password1}')">$lang{help_on_this}</a></span>
</div> 







</div>  <!-- end left column -->
<div style="float:left;width:45%;text-align:left;">

<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">
p1
    if (scalar (keys %calendars) > 1 || $add_edit_cal_action ne "edit")
    {
  $return_text .=<<p1;
<label class="optional_field" style="float:left;" for="selectable_calendars">$lang{selectable_calendars1}
<br/><span class="small_note">$lang{selectable_calendars2}</span> 
<span class="small_note" style="margin-left:1em;white-space:nowrap;"><a href="javascript:display_help('selectable_calendars','$lang{selectable_calendars1}')">$lang{help_on_this}</a></span>
</label>
<select multiple size=8 style="display:block;clear:left;" name="selectable_calendars" id="selectable_calendars">
p1
      foreach $cal_id (sort {$a <=> $b} keys %calendars)
      {
        #don't display a choice for the calendar currently being edited
        if ($cal_id eq $current_calendar{id})
          {next;}
        my $selected="";
    
        if ($current_calendar{selectable_calendars}{$cal_id} eq "1" || $add_edit_cal_action eq "add")
          {$selected = " selected";}
          
          $return_text .=<<p1;
<option value = "$cal_id"$selected>$calendars{$cal_id}{title}
p1
      }
      $return_text .=<<p1;
</select>
p1
    }
     
    if ($options{new_calendars_automatically_selectable} eq "1")
    {
      my $temp="";
      if ($current_calendar{new_calendars_automatically_selectable} =~ /y/)
        {$temp=" checked";}
      $return_text .=<<p1;
<div style="margin-top:2ex;">
<input type="checkbox" id="new_calendars_automatically_selectable" name="new_calendars_automatically_selectable" value="yes" $temp/>
<label class="optional_field" for="new_calendars_automatically_selectable">$lang{new_calendars_automatically_selectable}</label>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('new_calendars_automatically_selectable','$lang{new_calendars_automatically_selectable}')">$lang{help_on_this}</a></span>
</div>
p1
    }
      $return_text .=<<p1;
</div>

<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">
<input type="checkbox" id="list_background_calendars_together" name="list_background_calendars_together" value = "yes" $checked{list_background_calendars_together}/>
<label class="optional_field" for="list_background_calendars_together">$lang{bg_events_display_style8}</label>
<br/><span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('list_background_calendars_together','$lang{bg_events_display_style8}')">$lang{help_on_this}</a></span>
</div>
   
</div> <!--end right column-->
    
<br style="clear:both;"/>&nbsp;
</div>




<div id="tab_area2" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;">

<div style="float:left;width:45%;text-align:left;">
<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">

<div class="optional_field">
$lang{cal_events_display_style1}
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('calendar_events_display_style','$lang{bg_events_display_style1}')">$lang{help_on_this}</a></span>
</div>

<div style="clear:left;margin-top:2em;" onClick="cs_init();">
<label class="optional_field" for="cal_events_display_style2">$lang{cal_events_display_style2}</label>
<input name="dummy" value="" size=1 style="display:none;">
<select id="calendar_events_color" name="calendar_events_color" value = "" style="margin-left:27px;width:10ex;" onChange="update_cal_color_select_box();" onKeyPress="if (event.keyCode == 13){return false;}">
<option value="" style="background-color:#fff;">none</option>
p1
      my $custom_color=1;
      #update_bg_color_select_box()cs1.setrgb(this.value);


      foreach $temp (@event_bgcolors)
      {
        %possible_bgcolor = %{$temp};
        my $selected="";
        if ($possible_bgcolor{color} eq "$current_calendar{calendar_events_color}")  #default
        {
          $custom_color=0;
          $selected=" selected";
        }
        my $description = "";
        if ($options{show_event_background_color_descriptions})
          {$description = $possible_bgcolor{title}}
      
        $return_text .=<<p1;
<option value = "$possible_bgcolor{color}" style="background-color:$possible_bgcolor{color};"$selected>$description
p1
      }
    
      my $color_select_icon_style="visibility:hidden;";
      if ($custom_color == 1 && $current_calendar{calendar_events_color} ne "")
      {
        $color_select_icon_style="";
        $return_text .=<<p1;
<option id="custom_evt_color" value = "$current_calendar{calendar_events_color}" selected style="background-color:$current_calendar{calendar_events_color};">$lang{event_background_colorcustom}
p1
      }
      else
      {
        $return_text .=<<p1;
<option id="custom_evt_color" value="#ffffff" style="background-color:#fff;">$lang{event_background_colorcustom}
p1
      }

      $return_text .=<<p1;
</select>



<span id="color_select_icon1" class="color_select_icon" style="$color_select_icon_style vertical-align:top;background-image:url($graphics_url/color_select_icon.gif);" onClick="cs_init();cs1.toggle_color_select();">&nbsp;&nbsp;&nbsp;&nbsp;</span>
</div>

</div>
</div> <!-- end left column -->

<div style="float:left;width:45%;text-align:left;">



<div style="border:solid 1px #cccccc;margin:5px;padding:5px;">
<div class="optional_field">
$lang{bg_events_display_style1}
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('background_events_display_style','$lang{bg_events_display_style1}')">$lang{help_on_this}</a></span>
</div>

<div style="clear:left;margin-top:1em;" onClick="document.update_cal_form.background_events_display_style[0].checked=true;document.getElementById('bg_preview_e1').style.background = '#ffffcc';document.getElementById('bg_preview_e2').style.background = '#ccffff';document.update_cal_form.background_events_color.value = '';">
<input type="radio" id="background_events_display_style1" name="background_events_display_style" value = "normal" $checked{background_events_display_style1}/>
<label class="optional_field" for="background_events_display_style1">$lang{bg_events_display_style2}</label>
</div>

<div style="clear:left;margin-top:2em;" onClick="cs_init();document.update_cal_form.background_events_display_style[1].checked=true;">
<input type="radio" id="background_events_display_style2" name="background_events_display_style" value = "single_color" $checked{background_events_display_style2}/>
<label class="optional_field" for="background_events_display_style2">$lang{bg_events_display_style3}</label>
<input id="background_events_color" name="background_events_color" value = "" style="margin-left:27px;width:10ex;" onChange="cs0.setrgb(this.value);" onKeyPress="if (event.keyCode == 13){return false;}">
<span id="color_select_icon0" class="color_select_icon" style="vertical-align:top;background-image:url($graphics_url/color_select_icon.gif);" onClick="cs_init();cs0.toggle_color_select();">&nbsp;&nbsp;&nbsp;&nbsp;</span>
</div>

<div style="clear:left;margin-top:2em;" onClick="document.update_cal_form.background_events_display_style[2].checked=true;fade_preview();document.update_cal_form.background_events_color.value = ''">
<input type="radio" id="background_events_display_style3" name="background_events_display_style"  value = "faded" $checked{background_events_display_style3}/>
<label class="optional_field" for="background_events_display_style3">$lang{bg_events_display_style4}</label>
<select id="background_events_fade_factor" name="background_events_fade_factor" onChange="fade_preview();">
p1
    for ($i=1;$i<8;$i++)
    {
      my $selected="";
      $selected = " selected" if ($i eq $current_calendar{background_events_fade_factor});
        $return_text .=<<p1;
<option value="$i"$selected>$i\l0\% faded
p1
    }

    $return_text .=<<p1;
</select>
</div>

</div>


</div> <!-- end right column -->



<div style="clear:both;border:solid 1px #cccccc;margin:5px;padding:5px;">
<div style="text-align:center;margin-top:20px;" class="optional_field">$lang{bg_events_display_style5}</div>
<table class="calendar">
<tr><td class="day" style="border-bottom-width:0;">
<span class="this_month">1</span> 
</td><td class="day" style="border-bottom-width:0;">
<div>2</div> 
</td></tr>
<tr><td class="day" style="border-top-width:0;border-bottom-width:0;">
  <a id="preview_e1" class="event_box" href="" style="display:block;background-color:#ffffcc;">
  $lang{bg_events_display_style6}
  </a>
</td><td class="day" style="border-top-width:0;border-bottom-width:0;">
  <a id="bg_preview_e1" class="event_box background" style="display:block;background-color:#ffffcc;" href="">
  $lang{bg_events_display_style7}
  </a>
   <a id="preview_e2" class="event_box" href="" style="display:block;background-color:#ccffcc;">
  $lang{bg_events_display_style6}
  </a>
</td></tr>
<tr><td class="day" colspan=2 style="border-top-width:0;">
  <a id="bg_preview_e2" class="event_box background" style="display:block;background-color:#ccffff;text-align:center;">
  $lang{bg_events_display_style7}
  </a>
</td></tr>
</table>
</div>


<div style="clear:both;border:solid 1px #cccccc;margin:5px;padding:5px;">


<div class="leftcol" style="">
<label class="optional_field" for="custom_stylesheet">$lang{custom_stylesheet}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="custom_stylesheet" name="custom_stylesheet" style="width:80%;" value = "$current_calendar{custom_stylesheet}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('custom_stylesheet','$lang{custom_stylesheet}')">$lang{help_on_this}</a></span>
</div>

<div class="leftcol" style="margin-bottom:0;">
<label class="optional_field" for="custom_template">$lang{custom_template}</label>
</div>
<div class="rightcol" style="white-space:nowrap;margin-bottom:0;">
<input id="custom_template" name="custom_template" style="width:80%;" value = "$current_calendar{custom_template}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('custom_template','$lang{custom_template}')">$lang{help_on_this}</a></span>
</div>
<br style="clear:both;"/>&nbsp;

</div>


<br style="clear:both;"/>&nbsp;

</div> <!-- end tab_area2-->



<div id="tab_area3" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;">

<div class="leftcol" style="">
<label class="optional_field" for="number_of_months">$lang{default_number_of_months}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="number_of_months" name="number_of_months" value = "$current_calendar{default_number_of_months}" style="width:5ex;vertical-align:bottom;"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('number_of_months','$lang{default_number_of_months}')">$lang{help_on_this}</a></span>
</div>
<br style="line-height:0px;height:0px;clear:both;"/>

<div class="leftcol" style="margin-bottom:5ex;">
<label class="optional_field" for="max_months">$lang{max_months}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="max_months" name="max_months" style="width:5ex;" value = "$current_calendar{max_number_of_months}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('max_months','$lang{max_months}')">$lang{help_on_this}</a></span>
</div>
<br style="line-height:0px;height:0px;clear:both;"/>
p1

    if ($options{force_single_timezone} ne "1" || $current_calendar{id} eq "0")
    {
      $return_text .=<<p1;
<div class="leftcol" style="">
<label class="optional_field" for="gmtime_diff">$lang{timezone_offset}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="gmtime_diff" name="gmtime_diff" style="width:5ex;" value = "$current_calendar{gmtime_diff}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('gmtime_diff','$lang{timezone_offset}')">$lang{help_on_this}</a></span>
</div>
<br style="line-height:0px;height:0px;clear:both;"/>
p1
    }

    $return_text .=<<p1;

<div class="leftcol" style="">
<label class="optional_field" for="date_format">$lang{date_format}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="date_format" name="date_format" style="width:10ex" value = "$current_calendar{date_format}"/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('date_format','$lang{date_format}')">$lang{help_on_this}</a></span>
</div>
<br style="line-height:0px;height:0px;clear:both;"/>

<div class="leftcol" style="margin-bottom:5ex;">
<label class="optional_field" for="week_start_day">$lang{week_start_day}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<select id="week_start_day" name="week_start_day">
p1
    
    for ($i=0;$i<7;$i++)
    {
      my $selected="";
      $selected = " selected" if ($i eq $current_calendar{week_start_day});
        $return_text .=<<p1;
<option value="$i"$selected>$day_names[$i]
p1
    }
    
    my $temp1;
    if ($current_calendar{preload_event_details} =~ /y/)
    {$temp1=" checked";}
    
    $return_text .=<<p1;
</select>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('week_start_day','$lang{week_start_day}')">$lang{help_on_this}</a></span>
</div>
<br style="line-height:0px;height:0px;clear:both;"/>

<div class="leftcol" style="margin-bottom:0;">
<label class="optional_field" for="preload_event_details">$lang{preload_event_details}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="checkbox" id="preload_event_details" name="preload_event_details" value="yes" $temp1/>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('preload_event_details','$lang{preload_event_details}')">$lang{help_on_this}</a></span>
</div>

<div class="leftcol" style="margin-bottom:0;">
<label class="optional_field" for="popup_window_size">$lang{popup_window_size1}</label>
</div>
<div class="rightcol" style="white-space:nowrap;margin-bottom:0;">
<input id="popup_window_size" name="popup_window_size" style="width:12ex;" value="$current_calendar{info_window_size}"/>
<span class="small_note" style="vertical-align:top;">$lang{popup_window_size2}</span>
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('popup_window_size','$lang{popup_window_size1}')">$lang{help_on_this}</a></span>
</div>

<br style="line-height:0px;height:0px;clear:both;"/>

</div>



<div class="info_box" style="width:100%;margin-top:40px;">
<br style="clear:both;"/>
p1
    if ($add_edit_cal_action eq "edit")
    {
      if ($options{disable_passwords} ne "1")
      {
      $return_text .=<<p1;
<div class="leftcol" style="white-space:nowrap;clear:both;margin-bottom:3ex;">
<label class="required_field" for="cal_password">$lang{cal_password}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="password" name="cal_password" id="cal_password" size=12 />
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('current_cal_password','$lang{cal_password}')">$lang{help_on_this}</a></span>
</div>
<div class="leftcol" style="white-space:nowrap;">
<label class="optional_field" for="new_cal_password">$lang{change_password}</label>
<br/>
<span class="small_note" ><a href="javascript:display_help('change_cal_password','$lang{change_password}')">$lang{help_on_this}</a></span>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="password" name="new_cal_password" id="new_cal_password" size=12 />
<span class="small_note" style="vertical-align:top;">$lang{new_password} </span>
<br/>
<input type="password" name="repeat_new_cal_password" size=12 />
<span class="small_note" style="vertical-align:top;">$lang{repeat_new_password}</span>
</div>
p1

      }
      $return_text .=<<p1;

<div class="leftcol">
&nbsp;
</div>
<div class="rightcol" style="white-space:nowrap;">
<input name="update_cal_button" type=submit value = "$lang{update_cal_button}"/>
</div>

<div class="leftcol">
&nbsp;
</div>
<div class="rightcol" style="white-space:nowrap;">
<span class="info_box_text small_note" id="preview_warning">$lang{preview_warning}</span>
</div>

<br style="clear:both;"/>


<div style="float:left;text-align:left;">
<input name="del_cal_button" class="delete_button" type=submit value = "$lang{del_cal_button1}"
onclick="return confirm('$lang{del_cal_button2}');" />
<div id=delete_note>
<span class="small_note">
$lang{del_cal_button3} 
</span>
</div>
</div>

<br style="clear:both;">
<br style="clear:both;">

p1
    }
    elsif ($add_edit_cal_action eq "add")
    {
      $return_text .=<<p1;
<div class="leftcol" style="white-space:nowrap;">
<label class="required_field" for="new_cal_password">$lang{password}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="password" name="new_cal_password" id="new_cal_password" size=12 />
<span class="small_note" style="vertical-align:top;">$lang{choose_password} </span>&nbsp;
<span class="small_note" style="vertical-align:top;"><a href="javascript:display_help('new_cal_password','$lang{choose_password}')">$lang{help_on_this}</a></span>

<br/>
<input type="password" name="repeat_new_cal_password" size=12 />
<span class="small_note" style="vertical-align:top;">$lang{repeat_password} </span>
</div>

<div class="leftcol">
&nbsp;
</div>
<div class="rightcol" style="white-space:nowrap;">
<input name="update_cal_button" type=submit value = "$lang{add_calendar}"/>
</div>

<div class="leftcol">
&nbsp;
</div>
<div class="rightcol" style="white-space:nowrap;">
<span class="info_box_text small_note" id="preview_warning">$lang{preview_warning}</span>
</div>

<br style="clear:both;"/>
p1
    }

    $return_text .=<<p1;
</div>
p1
  }
  else  #a user added/edited/deleted an calendar--do checks and perform resulting action
  {
    my @results_messages;
    my $cal_id = $current_cal_id;    # need to validate cal id for add/edit


    my $cal_valid = 1;
    if ($q->param('del_cal_button') ne "")
    {
      #delete calendar
      
      &load_events("all");
      my $del_valid=1;
      
      #check password.
      
      if ($options{disable_passwords} ne "1")
      {
        $input_password = crypt($q->param('cal_password'), substr($q->param('cal_password'), 0, 2));
     
        if ($input_password ne $current_calendar{password} && $input_password ne $master_password)
        {
          $del_valid=0;
          push @results_messages,  "$lang{update_cal_error1}<b>$current_calendar{title}</b>";
        }
      }
      
      # prevent delete of primary calendar
      if ($cal_id eq "0")
      {
        $del_valid=0;
        push @results_messages, $lang{update_cal_error2};
      }
        
      if ($del_valid == 1)
      { #actually delete the calendar.
      
        # first, delete all its events
        my @deleted_event_ids;
        my @updated_event_ids;
        foreach $event_id (keys %events)
        {
          # if the event is only on one calendar, delete it
          if (scalar@{$events{$event_id}{cal_ids}} == 1)
          {
            if ($events{$event_id}{cal_ids}[0] eq $cal_id)
              {push @deleted_event_ids, $event_id;}
            else
              {next;}
          }
          else # otherwise, just remove that calendar from its cal_ids
          {
            my $index=0;
            foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
            {
              if ($temp_cal_id eq $cal_id)
              {
                break;
              }
              $index++;
            }
            splice @{$events{$event_id}{cal_ids}}, $index, 1;
              {push @updated_event_ids, $event_id;}

            
          }
        }
        &delete_events(\@deleted_event_ids);
        &update_events(\@updated_event_ids);
        
        # next, delete the calendar in question
        
        &delete_calendar($cal_id);

        # finally, delete any references in other calendars (background calendars)
        my @cals_to_update;
        foreach $calendar_id (sort {$a <=> $b} keys %calendars)
        {
          if ($calendars{$calendar_id}{local_background_calendars}{$cal_id} eq "1")
          {
            delete $calendars{$calendar_id}{local_background_calendars}{$cal_id};
            push @cals_to_update, $calendar_id;
          }
          if ($calendars{$calendar_id}{selectable_calendars}{$cal_id} eq "1")
          {
            delete $calendars{$calendar_id}{selectable_calendars}{$cal_id};
            push @cals_to_update, $calendar_id;
          }
        }
        &update_calendars(\@cals_to_update);
        my $temp = $lang{update_cal_error3};
        $temp =~ s/###title###/$current_calendar{title}/;
        push @results_messages, $temp;
      }
      
      # properly format errors, warnings
      my @messages = split ("\n",$cal_del_results);
      $cal_del_results="";
  
      foreach $message (@messages)
      {
        $message =~ s/(.*$lang{Warning})/<span class="warning">$1<\/span>/i;
        $message =~ s/(.*$lang{Error})/<span class="error">$1<\/span>/i;
        $cal_del_results .= "$message<br/>\n";
      }
  
      #$event_action_results = join "\n", @messages;
      $cal_del_results = "<ul style=\"font-size:small;\">$cal_del_results</ul>";
      
    }
    else  #the user added/updated an calendar
    {
      &load_new_calendars();
    
      #check all input fields for validity
      my $cal_title = $q->param('cal_title');
      my $cal_link = $q->param('cal_link');
      my $cal_details = $q->param('cal_details');
      
      my @local_background_calendars = $q->param('background_calendars');
      my @selectable_calendars = $q->param('selectable_calendars');
      my $list_background_calendars_together = $q->param('list_background_calendars_together');
      my $background_events_display_style = $q->param('background_events_display_style');
      my $background_events_fade_factor = $q->param('background_events_fade_factor');
      my $background_events_color = $q->param('background_events_color');
      my $new_calendars_automatically_selectable = "y" if ($q->param('new_calendars_automatically_selectable') =~ "y");
      my $allow_remote_calendar_requests = $q->param('allow_remote_calendar_requests');
      my $remote_calendar_requests_require_password = $q->param('remote_calendar_requests_require_password');
      my $remote_calendar_requests_password = $q->param('remote_calendar_requests_password');
      
      my $new_remote_calandars_xml = $q->param('new_remote_calandars_xml');
      my $calendar_events_color = $q->param('calendar_events_color');
      
      my $default_number_of_months = $q->param('default_number_of_months');
      my $max_number_of_months = $q->param('max_months');
      my $gmtime_diff = $q->param('gmtime_diff');
      my $date_format = $q->param('date_format');
      $date_format = lc $date_format;
      my $week_start_day = $q->param('week_start_day');
      my $preload_event_details = $q->param('preload_event_details');
      my $info_window_size = $q->param('popup_window_size');
      if ($info_window_size !~ /^\d{1,}x\d{1,}$/)
      {
        $cal_valid=0;
        my $temp=$lang{update_cal_error4};
        $temp =~ s/###size###/$info_window_size/;
        push @results_messages, $temp;
      }
      
      $preload_event_details = "no" if ($preload_event_details ne "yes");
      
      my $custom_template = $q->param('custom_template');
      $custom_template =~ s/http:\/\///g;
      
      my $custom_stylesheet = $q->param('custom_stylesheet');
      $custom_stylesheet =~ s/http:\/\///g;
      
      my $cal_password = $q->param('cal_password');
      my $new_cal_password = $q->param('new_cal_password');
      my $repeat_new_cal_password = $q->param('repeat_new_cal_password');

      $cal_title =~ s/\r//g;                 # some browsers sneak these in 
      $cal_link =~ s/\r//g;                  # some browsers sneak these in 
      $cal_details =~ s/\r//g;               # some browsers sneak these in 


      #check for required fields
      if ($cal_title eq "")
      {
        $cal_valid=0;
        push @results_messages, $lang{update_cal_error5};
      }
      
      #strip all html from label field
      if ($cal_title =~ m/<(.*)>/)
      {
        push @results_messages, $lang{update_cal_error6};
        $cal_title =~ s/<(.*)>//g;
      }
      
      $cal_link =~ s/http:\/\///g;  #strip http:// from link field



      #check for date format
      if ($date_format !~ /^(mm|dd|yy)\/(mm|dd|yy)\/(mm|dd|yy)$/ )
      {
        $cal_valid=0;
        push @results_messages, $lang{update_cal_error6_5};
      }

      if ($add_edit_cal_action eq "edit")
      {
        if ($options{disable_passwords} ne "1")
        {
          #this action is an edit of an existing calendar, so we need to make a replacement.
          if (!(defined $calendars{$cal_id}))
          {
            $cal_valid=0;
            push @results_messages, $lang{update_cal_error7};
          }
          else
          {
            #check password
            $input_password = crypt($cal_password, substr($cal_password, 0, 2));
 
            if ($input_password ne $calendars{$cal_id}{password} && $input_password ne $master_password)
            {
              $cal_valid=0;
               push @results_messages, "$lang{update_cal_error1} <b>$calendars{$cal_id}{title}</b>";
            }
          }
 
          #check for new password
          if ($new_cal_password ne "" || $repeat_new_cal_password ne "")
          {
            if ($new_cal_password ne $repeat_new_cal_password)
            {
              $cal_valid=0;
              push @results_messages, $lang{update_cal_error8};
            }
            else
            {
              $calendars{$cal_id}{password} = crypt($new_cal_password, substr($new_cal_password, 0, 2));
            }
          }
        }
        
        
        
        # check for gmtime_diff field
        if ($options{force_single_timezone} eq "1" && $cal_id ne "0")
        {
          $gmtime_diff = $calendars{0}{gmtime_diff}
        }

        
        # encrypt remote calendar password
        $remote_calendar_requests_password = crypt($remote_calendar_requests_password, substr($remote_calendar_requests_password, 0, 2));
        
        if ($cal_valid == 1)
        { # update calendar record
          my $xml_data = "";
          $calendars{$cal_id}{title} = $cal_title;
          $calendars{$cal_id}{details} = $cal_details;
          $calendars{$cal_id}{link} = $cal_link;
          $calendars{$cal_id}{new_calendars_automatically_selectable} = $new_calendars_automatically_selectable;
          $calendars{$cal_id}{list_background_calendars_together} = $list_background_calendars_together;
          $calendars{$cal_id}{calendar_events_color} = $calendar_events_color;
          $calendars{$cal_id}{background_events_display_style} = $background_events_display_style;
          $calendars{$cal_id}{background_events_fade_factor} = $background_events_fade_factor;
          $calendars{$cal_id}{background_events_color} = $background_events_color;
          $calendars{$cal_id}{default_number_of_months} = $default_number_of_months;
          $calendars{$cal_id}{max_number_of_months} = $max_number_of_months;
          $calendars{$cal_id}{gmtime_diff} = $gmtime_diff;
          $calendars{$cal_id}{date_format} = $date_format;
          $calendars{$cal_id}{week_start_day} = $week_start_day;
          $calendars{$cal_id}{preload_event_details} = $preload_event_details;
          $calendars{$cal_id}{info_window_size} = $info_window_size;
          $calendars{$cal_id}{custom_template} = $custom_template;
          $calendars{$cal_id}{custom_stylesheet} = $custom_stylesheet;
          $calendars{$cal_id}{allow_remote_calendar_requests} = $allow_remote_calendar_requests;
          $calendars{$cal_id}{remote_calendar_requests_require_password} = $remote_calendar_requests_require_password;
          $calendars{$cal_id}{remote_calendar_requests_password} = $remote_calendar_requests_password;

          
          # update local background calendars            
          foreach $local_background_calendar (keys %{$calendars{$cal_id}{local_background_calendars}})
            {delete $calendars{$cal_id}{local_background_calendars}{$local_background_calendar};}
          foreach $local_background_calendar (@local_background_calendars)
            {$calendars{$cal_id}{local_background_calendars}{$local_background_calendar} = 1;}

          #$debug_info .= "new remote calendars xml: $new_remote_calandars_xml\n";
          
          #delete existing remote background calendars
          
          foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}})
          {
            if ($q->param("delete_remote_calendar_$current_remote_calendar_id") ne "")
            {
              my $temp = $lang{get_remote_calendar5};
              $temp =~ s/###remote url###/$current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url}/g;
              $temp =~ s/###remote id###/$current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id}/g;
              push @results_messages, $temp;
              
              delete $calendars{$current_cal_id}{remote_background_calendars}{$current_remote_calendar_id};
            }
          }
          
          
          
          # update remote background calendars
          unless ($new_remote_calandars_xml eq "")
          {
            my %new_remote_calendars = %{&xml2hash($new_remote_calandars_xml)};
            #$debug_info .= "$new_remote_calendars{remote_calendars}{remote_calendar}\n";
 
            my $new_remote_cal_id = &max(keys %{$calendars{$cal_id}{remote_background_calendars}}) + 1;
            $debug_info .= (scalar keys %{$calendars{$cal_id}{remote_background_calendars}})." remote calendars already\n";
            #$debug_info .= "new_remote_cal_id: $new_remote_cal_id\n";
            
            if ($new_remote_calendars{remote_calendars}{remote_calendar} =~ /array/i) # multiple remote background calendars
            {
              #$debug_info .= "multiple new remote calendars\n";
            
              foreach $temp (@{$new_remote_calendars{remote_calendars}{remote_calendar}})
              {
                my %new_remote_calendar = %{$temp};
                
                $found=0;
                foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}})
                {
                  #$debug_info .= "comparing $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} with $new_remote_calendar{url}\n";

                  if ($current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} eq $new_remote_calendar{url} &&
                      $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{type} eq $new_remote_calendar{type} &&
                      $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{version} eq $new_remote_calendar{version} &&
                      $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{password} eq $new_remote_calendar{password} &&
                      $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id} eq $new_remote_calendar{remote_id})
                        {$found=1;}
                }
                if ($found==0)
                {
                  $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{url} = $new_remote_calendar{url};
                  $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{type} = $new_remote_calendar{type};
                  $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{version} = $new_remote_calendar{version};
                  $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{password} = $new_remote_calendar{password};
                  $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{remote_id} = $new_remote_calendar{remote_id};
                  $new_remote_cal_id++;
                }
                else
                {
                  my $temp = $lang{get_remote_calendar4};
                  $temp =~ s/###remote url###/$new_remote_calendar{url}/g;
                  $temp =~ s/###remote id###/$new_remote_calendar{remote_id}/g;
                  push @results_messages, $temp;
                }
   
                #$debug_info .= "remote calendar: $new_remote_calendar{url}\n";
                #$debug_info .= "type: $new_remote_calendar{type}\n";
              }
            }
            else # single remote background calendar
            {
              # check against existing remote background calendars.
            
              my %new_remote_calendar = %{$new_remote_calendars{remote_calendars}{remote_calendar}};
            
              $found=0;
              foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}})
              {
                #$debug_info .= "comparing $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} with $new_remote_calendar{url}\n";
                if ($current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} eq $new_remote_calendar{url} && 
                    $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{type} eq $new_remote_calendar{type} &&
                    $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{version} eq $new_remote_calendar{version} &&
                    $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{password} eq $new_remote_calendar{password} &&
                    $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id} eq $new_remote_calendar{remote_id})
                      {$found=1;}
              }
              if ($found==0)
              {
                $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{url} = $new_remote_calendar{url};
                $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{type} = $new_remote_calendar{type};
                $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{version} = $new_remote_calendar{version};
                $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{password} = $new_remote_calendar{password};
                $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{remote_id} = $new_remote_calendar{remote_id};
              }
              else
              {
                my $temp = $lang{get_remote_calendar4};
                  $temp =~ s/###remote url###/$new_remote_calendar{url}/g;
                  $temp =~ s/###remote id###/$new_remote_calendar{remote_id}/g;
                push @results_messages, $temp;
              }
            }
          }
                    
          #$calendars{$cal_id}{remote_background_calendars} = $remote_calendar_requests_password;

            
          # update selectable calendars            
          foreach $selectable_calendar (keys %{$calendars{$cal_id}{selectable_calendars}})
            {delete $calendars{$cal_id}{selectable_calendars}{$selectable_calendar};}
          foreach $selectable_calendar (@selectable_calendars)
            {$calendars{$cal_id}{selectable_calendars}{$selectable_calendar} = 1;}
        
          # make sure the calendar can select itself.
          if (scalar keys %{$calendars{$cal_id}{selectable_calendars}} > 0)
            {$calendars{$cal_id}{selectable_calendars}{$cal_id} = 1;}
        }
        
        if ($cal_valid == 1)
        { #all checks successful, add/update calendar!
  
          &update_calendar($cal_id);
          push @results_messages, "<b>$calendars{$current_cal_id}{title}</b> $lang{update_cal_success}";
        }
        else
        {$cal_add_results .= $lang{update_cal_failure};}

      }
      else  #if we need to create a completely new record
      {     
        #check new password
        if ($options{disable_passwords} ne "1")
        {
          if ($new_cal_password ne $repeat_new_cal_password)
          {
            $cal_valid=0;
            push @results_messages, $lang{update_cal_error9};
          }
          elsif ($new_cal_password eq "" || $repeat_new_cal_password eq "" )
          {
            $cal_valid=0;
            push @results_messages, $lang{update_cal_error10};
          }
          else
          {
            $input_password = crypt($new_cal_password, substr($new_cal_password, 0, 2));
          }
        }
        
        my $new_cal_id;
        
        if ($cal_valid == 1)
        {
          $new_cal_id = $max_new_cal_id + 1;
          
          $new_calendars{$new_cal_id}{id} = $new_cal_id;
          $new_calendars{$new_cal_id}{title} = $cal_title;
          $new_calendars{$new_cal_id}{details} = $cal_details;
          $new_calendars{$new_cal_id}{link} = $cal_link;
          $new_calendars{$new_cal_id}{list_background_calendars_together} = $list_background_calendars_together;
          $new_calendars{$new_cal_id}{calendar_events_color} = $calendar_events_color;
          $new_calendars{$new_cal_id}{background_events_fade_factor} = $background_events_fade_factor;
          $new_calendars{$new_cal_id}{background_events_color} = $background_events_color;
          $new_calendars{$new_cal_id}{default_number_of_months} = $default_number_of_months;
          $new_calendars{$new_cal_id}{max_number_of_months} = $max_number_of_months;
          $new_calendars{$new_cal_id}{gmtime_diff} = $gmtime_diff;
          $new_calendars{$new_cal_id}{date_format} = $date_format;
          $new_calendars{$new_cal_id}{week_start_day} = $week_start_day;
          $new_calendars{$new_cal_id}{info_window_size} = $info_window_size;
          $new_calendars{$new_cal_id}{custom_template} = $custom_template;
          $new_calendars{$new_cal_id}{custom_stylesheet} = $custom_stylesheet;
          $new_calendars{$new_cal_id}{password} = $input_password;
          $new_calendars{$new_cal_id}{update_timestamp} = $rightnow;
          $new_calendars{$new_cal_id}{allow_remote_calendar_requests} = $allow_remote_calendar_requests;
          $new_calendars{$new_cal_id}{remote_calendar_requests_require_password} = $remote_calendar_requests_require_password;
          $new_calendars{$new_cal_id}{remote_calendar_requests_password} = $remote_calendar_requests_password;
          
          # local background calendars            
          foreach $local_background_calendar (@local_background_calendars)
            {$new_calendars{$new_cal_id}{local_background_calendars}{$local_background_calendar} = 1;}
            
          # selectable calendars            
          foreach $selectable_calendar (@selectable_calendars)
            {$new_calendars{$new_cal_id}{selectable_calendars}{$selectable_calendar} = 1;}
        }  
          
        # check for refreshes!
        if ($cal_valid == 1)
        {
          if ($new_calendars{$new_cal_id}{title} eq $latest_new_calendar{title} &&
              $new_calendars{$new_cal_id}{details} eq $latest_new_calendar{details} &&
              $new_calendars{$new_cal_id}{link} eq $latest_new_calendar{link})
          {
            $cal_valid = 0;
            push @results_messages, $lang{update_cal_dup};
          }
        }
          
        if ($cal_valid == 1)  #all checks successful, add calendar!
        { 
          &add_new_calendar($new_cal_id);
          
          my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id});
          $new_cal_details =~ s/<a.+Delete this.+<\/a>//;
          $new_cal_details =~ s/Link directly.+<\/a>//s;

          if ($options{new_calendar_request_notify} ne "")
          {
            my $body = <<p1;
$lang{add_cal_email_notify1}
  
$new_cal_details  
  
<a href="$script_url/$name?active_tab=2&add_edit_cal_action=view_pending$consistent_parameter_string">$lang{add_cal_success3}</a>

p1
            &send_email($options{new_calendar_request_notify}, $options{reply_address}, $options{reply_address}, $lang{add_cal_email_notify2}, $body);
          }

          my $temp = $lang{add_cal_success1};  # add successful
          if ($add_edit_cal_action eq "edit")
            {$temp = $lang{add_cal_success4}}; # update successful
        
          $cal_add_results .= <<p1;
<div style="text-align:left;">
<p style="font-weight:bold;">
$temp
</p>

<div class="info_box">
$new_cal_details
</div>

<p style="margin-top:1em;">
$lang{add_cal_success2}
</p>

<ul>
<li><a href="$script_url/$name?active_tab=2&add_edit_cal_action=view_pending$consistent_parameter_string">$lang{add_cal_success3}</a>
</ul>
</div>
p1
          close FH;
        }
        else
        {
          push @results_messages, $lang{add_cal_fail1};
        }
      }
      close FH;
    }
    # properly format errors & warnings
    my $message_results="";
    foreach $results_message (@results_messages)
    {
      $results_message =~ s/(.*$lang{Warning})/<span class="warning">$1<\/span>/i;
      $results_message =~ s/(.*$lang{Error})/<span class="error">$1<\/span>/i;
      $message_results .= "<li>$results_message</li>\n";
    }
  
    $cal_add_results = "<ul style=\"font-size:small;\">$message_results</ul>$cal_add_results";
  }
    
  $return_text .=<<p1;
<div style="text-align:left;">
$cal_add_results
$cal_del_results
</div>
p1
  return $return_text;
} #********************end add_edit_calendars code*****************************


sub view_pending_calendars
{
  my $return_text = "";
  
  if ($q->param('approve_cal_button') eq "")  #view pending calendars main screen
  {    
    $cal_details ="";
    $shared_cal_select_size = scalar keys %calendars;

    $return_text.=<<p1;
<p class="cal_title">
$lang{view_pending_calendars1}
</p>
p1

       
    if (scalar keys %new_calendars == 0)
    {
      $return_text.=<<p1;
<p class="optional_field">
$lang{view_pending_calendars2}
</p>
p1
    }
    else
    {
      $return_text.=<<p1;
<form name="pending_calendars_form" action="">
<input type="hidden" name="active_tab" value="2">
<input type="hidden" name="add_edit_cal_action" value="view_pending">
<input type="hidden" name="cal_id" value="$current_cal_id">
<input type="hidden" name="cal_start_month" value="$cal_start_month">
<input type="hidden" name="cal_start_year" value="$cal_start_year">
<input type="hidden" name="cal_num_months" value="$cal_num_months">
<input type="hidden" name="display_type" value="$display_type">
<input type="hidden" name="special_action" value="$special_action">
<input type="hidden" name="theme_url" value="$theme_url">

p1
    
      foreach $new_cal_id (keys %new_calendars)
      {
        my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id});
        $new_cal_details =~ s/<a.+Delete this.+<\/a>//;
        $new_cal_details =~ s/Link directly.+<\/a>//s;
#Link directly to this calendar:<br/>
#<a href="$script_url/$name?cal_id=$calendar{id}">$script_url/$name?cal_id=$calendar{id}</a>    

        
      
        $return_text.=<<p1;
<div class="info_box" style="float:left;text-align:left;width:40%;margin:10px;clear:both;">
$new_cal_details
</div>
<div style="float:left;text-align:left;margin:10px;">
<br/>
<input type="radio" name="new_cal_$new_cal_id" value="approve"/><span class="optional_field">$lang{view_pending_calendars3}</span><br/><br/>
<input type="radio" name="new_cal_$new_cal_id" value="delete"/><span class="optional_field">$lang{view_pending_calendars4}</span><br/>
</div>
<br style="clear:both;"/>
p1
      }
      $return_text.=<<p1;
<div style="clear:both;"> 

<label for="main_password" class="optional_field">
$calendars{0}{title} Password:
</label>
<input type=password id="main_password" name = "main_password" size=10>
<br/>
<input type=submit name="approve_cal_button" value = "$lang{view_pending_calendars5}">
</form>
</div>

p1
    }
  }
  else  #view pending calendars approve/delete results screen
  {
    my @pending_calendars_to_delete;
    my @calendars_to_add;
    my @calendars_to_update;
    
    $cal_details ="";
    $shared_cal_select_size = scalar keys %calendars;

    $return_text.=<<p1;
<p class="cal_title">
$lang{view_pending_calendars6}
</p>
p1

    #check password
    $input_password = crypt($q->param('main_password'), substr($q->param('main_password'), 0, 2));
    
    if ($options{disable_passwords} ne "1")
    {
      if ($input_password ne $master_password)
      {
        $return_text .=<<p1;
<ul>
<li>$lang{view_pending_calendars7}</li>
</ul>
p1
        return $return_text;
      }
    }
    
    #go through each new calendar in the new calendars file--take appropriate action
    foreach $new_cal_id (keys %new_calendars)
    {
      my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id});

      if ($q->param("new_cal_$new_cal_id") eq "approve")
      {
        #calculate new id # for the new calendar
        $max_cal_id+=1;
        
        foreach $cal_id (keys %calendars)
        {
          if ($calendars{$cal_id}{new_calendars_automatically_selectable} =~ "y")
          {
            $calendars{$cal_id}{selectable_calendars}{$max_cal_id} = 1;
            push @calendars_to_update, $cal_id;
          }
        }
        
        $calendars{$max_cal_id} = $new_calendars{$new_cal_id};
        $calendars{$max_cal_id}{id} = $max_cal_id;
        
        # make sure the calendar can select itself.
        if (scalar keys %{$calendars{$max_cal_id}{selectable_calendars}} > 0)
          {$calendars{$max_cal_id}{selectable_calendars}{$max_cal_id} = 1;}
      
        delete $new_calendars{$new_cal_id};
        push @pending_calendars_to_delete, $new_cal_id;
        push @calendars_to_add, $max_cal_id;

        $approve_or_delete_result = $lang{view_pending_calendars8};
      }
      elsif ($q->param("new_cal_$new_cal_id") eq "delete")
      {
        delete $new_calendars{$new_cal_id};
        push @pending_calendars_to_delete, $new_cal_id;
        $approve_or_delete_result = $lang{view_pending_calendars9};
      }
      else
      {
        $approve_or_delete_result = $lang{view_pending_calendars10};
      }
      
      
      $new_cal_details =~ s/<a.+Delete this.+<\/a>//;
      $new_cal_details =~ s/Link directly.+<\/a>//s;
      
      $return_text .= <<p1;
<div style="float:left;clear:left;width:90%;">
<div class="info_box" style="text-align:left;width:40%;margin:10px;clear:both;float:left;">
$new_cal_details
</div>
<div style="text-align:left;margin:10px;float:left;">
<br/>
$approve_or_delete_result
</div>
</div>
p1
    }
    
    &delete_pending_calendars(\@pending_calendars_to_delete);
    &add_calendars(\@calendars_to_add);
    &update_calendars(\@calendars_to_update);
  }
  
  $return_text.=<<p1;
<br style="clear:both;"/>
p1
  
  return $return_text;
  
} #********************end view_pending_calendars code*****************************


sub do_calendar_list_view()
{
  &normalize_timezone();
  my $return_text = "";  

  my $temp1="";
  my $temp2="";
  if ($q->param('custom_calendar') != 1)
  {
    $temp1 .=<<p1;
<a href="$script_url/$name?cal_id=$current_cal_id&amp;display_type=$display_type&amp;cal_start_month=$previous_cal_start_month&amp;cal_start_year=$previous_cal_start_year&amp;cal_num_months=$cal_num_months ">$prev_string</a>
p1
    $temp2 .=<<p1;
<a href="$script_url/$name?cal_id=$current_cal_id&amp;display_type=$display_type&amp;cal_start_month=$next_cal_start_month&amp;cal_start_year=$next_cal_start_year&amp;cal_num_months=$cal_num_months">$next_string</a>
p1
  }
  
  if ($cal_num_months> 1)
  {
    $cal_title_string .=<<p1;
$months[$cal_start_month] $cal_start_year  - $months[$cal_end_month] $cal_end_year
p1
  }
  else
  {
    $cal_title_string .=<<p1;
$months[$cal_start_month] $cal_start_year
p1
  }
  
  # previous and next month(s) link
  $return_text .=<<p1;
<div style="text-align:center;white-space:nowrap;">
$temp1
<span class="cal_title" style="margin-left:3em;margin-right:3em;">
$cal_title_string
</span>
$temp2
</div>


<div style="clear:both;margin:auto;">
p1

  if ($display_type == 1) #list view
  {
    $return_text .= &generate_list($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
  }
  else  #calendar view
  {
    $return_text .= &generate_calendar($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
  }
    $return_text .=<<p1;
</div>
p1

  return $return_text;

}  ###############end do_calendar_list_view ###################


sub add_edit_events()
{
  my $temp="<link rel=\"stylesheet\" href=\"$theme_url/color_select.css\" type=\"text/css\">";
  $html_output =~ s/<head>/<head>\n$temp\n/;

  my $return_text = "";
  $add_edit_event = "add" if ($add_edit_event eq "");

  if ($q->param('add_event_button') eq "" && $q->param('del_event_button') eq "")  #add event main screen
  {
    $add_edit_string = $lang{add_or_edit1};
    $event_details ="";
    
    $event_start_date = $current_calendar{date_format};
    
    if ($q->param('add_date_timestamp') eq "" || $q->param('add_date_timestamp') =~ /\D/)    # no date supplied--generic add event
    {  # no date supplied--generic add event
      if ($cal_start_year ne "")    
      {
        $event_start_date =~ s/yy/$cal_start_year/;
      }
      else
      {
        $event_start_date =~ s/yy/$rightnow_year/;
      }
    }
    else  # add event on a particular date -- calculate date
    {
      my @event_start_date_array = gmtime $q->param('add_date_timestamp');
      my $mm = $event_start_date_array[4]+1;
      my $md = $event_start_date_array[3];
      my $yy = $event_start_date_array[5]+1900;
      
      $event_start_date =~ s/mm/$mm/;
      $event_start_date =~ s/dd/$md/;
      $event_start_date =~ s/yy/$yy/;
    }
    
    $recur_end_date = $current_calendar{date_format};
    $recur_end_date =~ s/mm/12/;
    $recur_end_date =~ s/dd/31/;
    $recur_end_date =~ s/yy/$rightnow_year/;

    $event_days = "1";
    $event_icon = "blank";
    my %current_event;
    
    my $unit_number_text="";
    if ($add_edit_event eq "add")
    {
      $event_unit_number = "";
    }
    elsif ($add_edit_event eq "edit")
    {
      $add_edit_string = $lang{add_or_edit2};

      #select the appropriate event to edit
      %current_event = %{$events{$q->param('evt_id')}};
      @current_cal_ids = @{$current_event{cal_ids}};
      %current_calendar = %{$calendars{$current_cal_ids[0]}};
      #$cal_title=$calendars{$current_event{cal_id}}{title};
      
      $event_name=$current_event{title};
      $event_details=$current_event{details};
      
      $event_start_date = $current_calendar{date_format};
      my @temp_date = gmtime($current_event{start});
      $temp_date[5] += 1900;
      $temp_date[4] += 1;

      $event_start_date =~ s/mm/$temp_date[4]/;
      $event_start_date =~ s/dd/$temp_date[3]/;
      $event_start_date =~ s/yy/$temp_date[5]/;

      $event_days=$current_event{days};
      $event_icon = $current_event{icon};
      $event_bgcolor = $current_event{bgcolor};
      $event_unit_number = $current_event{unit_number};
      $unit_number_text = $event_unit_number;
      $unit_number_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" alt="" border="0" vspace=0 hspace=0>/g;
    }
      
    $return_text .=<<p1;
<!-- color_select_box 0-->
<div id="color_select_box0" class="color_select_box" style="display:none;">
<!-- cursors -->
<div id="sv_crosshair_horiz_cursor0" class="sv_crosshair_horiz_cursor" style="visibility:hidden;">
</div>
<div id="sv_crosshair_center_cursor0" class="sv_crosshair_center_cursor" style="visibility:hidden;">
</div>
<div id="sv_crosshair_vert_cursor0" class="sv_crosshair_vert_cursor" style="visibility:hidden;">
</div>
<!-- /cursors -->
<div id="sv_select_box_bg0" class="sv_select_box" style="background-color:#0000ff;">
<div id="sv_select_box0" onMouseDown="cs0.sv_select_box_focus=true;color_select_update();"
                      onMouseUp="cs0.sv_select_box_focus=false;color_select_update();"
 style="line-height:256px;height:256px;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true src='$graphics_url/sv_blend.png')">
<br/>
</div>
</div>
<div id="h_select_box0" class="h_select_box" style="margin-left:5px;background-image:url($graphics_url/hue_blend.png)" 
 onMouseDown="cs0.h_select_box_focus=true;color_select_update()" onMouseUp="cs0.h_select_box_focus=false;color_select_update();">
<div id="hue_cursor0" class="hue_cursor" style="visibility:hidden;">
</div>
</div>
<div id="color_box0" class="color_box">
<div id="color_value_box0" class="color_value_box">
</div>
</div>
</div> 
<!-- end color_select_box 0-->    

<p class="cal_title" style="text-align:center;">
$add_edit_string
</p>

<div class="info_box" style="text-align:center;margin-bottom:2em;float:left;">
<span class="optional_field">$lang{fields_text1} <span class="required_field">$lang{fields_text2}</span> $lang{fields_text3}</span>
</div>

<div style="clear:both;width:90%;text-align:left;white-space:nowrap;clear:left;">
<a id="tab0" href="javascript:tab_show(0)" class="info_box_tab active">$lang{add_edit_events_tab0}</a>
<a id="tab1" href="javascript:tab_show(1)" class="info_box_tab">$lang{add_edit_events_tab1}</a>
</div>

<div id="tab_area0" class="info_box" style="width:100%;position:relative;z-index:101;padding-top:1em;margin-bottom:1em;">
p1
    my @selectable_cal_ids;
 
    if ($options{all_calendars_selectable})
    {
      @selectable_cal_ids = keys %calendars;
    }
    else
    {
      @selectable_cal_ids = keys %{$current_calendar{selectable_calendars}}
    }
    
    if ($add_edit_event eq "edit" || scalar keys %{$current_calendar{selectable_calendars}} == 0)  # force event calendar
    {
      $return_text .=<<p1;
<input type="hidden" name="evt_cal_id" value="$current_calendar{id}">
<div class="leftcol">
<span class="optional_field">$lang{event_calendar}</span>
</div>
<div class="rightcol" style="padding-left:.5em;">
$current_calendar{title}
</div>
p1
    }
    else  # user can select event calendar
    {
      $return_text .=<<p1;
<div class="leftcol">
<span class="required_field">$lang{event_calendar}</span>
</div>
<div class="rightcol">
<select name="evt_cal_id">
p1
      
      foreach $cal_ref_id (sort {$calendars{$a}{title} cmp $calendars{$b}{title}} @selectable_cal_ids)
      {
        my $selected = "";
        if ($cal_ref_id eq $current_cal_id)
          {$selected = " selected";}
        $return_text .=<<p1;
<option value = "$cal_ref_id"$selected>$calendars{$cal_ref_id}{title}
p1
      }

    $return_text .=<<p1;
</select>
<span class="small_note"><a href="javascript:display_help('evt_cal_id','$lang{event_calendar}')">$lang{help_on_this}</a></span>
</div>
p1
    }
    
    if ($options{multi_calendar_event_mode} > 0 && $add_edit_event eq "edit")
    {
      $return_text .=<<p1;
<div class="leftcol">
<span class="optional_field">$lang{event_other_calendars}</span>
</div>
<div class="rightcol" style="padding-left:.5em;">
<select multiple name="evt_other_cal_ids">
p1
    
      foreach $cal_ref_id (sort {$calendars{$a}{title} cmp $calendars{$b}{title}} @selectable_cal_ids)
      {
        my $selected = "";
        if ($cal_ref_id eq $current_event{cal_ids}[0])
          {next;}
          
        foreach $selected_cal_id (@{$events{$current_event_id}{cal_ids}})
        {
          if ($cal_ref_id eq $selected_cal_id)
          {
            $selected = " selected";
            last;
          }
        }
          
        $return_text .=<<p1;
<option value = "$cal_ref_id"$selected>$calendars{$cal_ref_id}{title}
p1
      }

    $return_text .=<<p1;
</select>
<span class="small_note"><a href="javascript:display_help('evt_other_cal_ids','$lang{event_other_calendars}')">$lang{help_on_this}</a></span>
</div>
p1
    }
    
    my $all_day_event_checked = "";
    
    if ($options{new_events_all_day})
      {$all_day_event_checked = "checked";}
    
    my $event_start_time = "11:00 am";
    my $event_end_time = "1:00 pm";
    
    if ($add_edit_event eq "edit")
    {
      if ($current_event{all_day_event} ne "1")
        {$all_day_event_checked = "";}
      $event_start_time = &formatted_time($current_event{start},"hh:mm ampm");
      $event_end_time = &formatted_time($current_event{end},"hh:mm ampm");
    }
    
    
    
    my $all_day_event_toggle0_style = "display:none;";
    if ($all_day_event_checked ne "checked")
    {
      $all_day_event_toggle0_style = "";
    }
    
    $return_text .=<<p1;
<div class="leftcol" style="">
<label class="required_field" for="evt_title">$lang{event_title}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="evt_title" name="evt_title" style="width:50%;" value = "$current_event{title}">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('evt_title','$lang{event_title}')">$lang{help_on_this}</a></span>
</div>

<div class="leftcol" style="">
<label class="optional_field" for="evt_details">$lang{event_details}</label>
<br/>
<span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('evt_details','$lang{event_details}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
</div>
<div class="rightcol" style="white-space:nowrap;">
<textarea name="evt_details" id="evt_details" rows=10 cols=0 style="width:100%;">$current_event{details}</textarea>
</div>

<div class="leftcol" style="margin-bottom:0;">
<label class="required_field" for="evt_start_date">$lang{event_start}</label>
</div>
<div class="rightcol" style="margin-bottom:0;white-space:nowrap;">
<input id="evt_start_date" name="evt_start_date" style="width:7em;" value = "$event_start_date">
</div>

<div class="leftcol" style="">
<label class="required_field" for="evt_days">$lang{event_length}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input id="evt_days" name="evt_days" style="width:2em;" value = "$event_days">
<input type="checkbox" id="all_day_event" name="all_day_event" value="1"$all_day_event_checked onChange="all_day_event_toggle(this.checked);">
<label class="optional_field" for="all_day_event">$lang{all_day_event}</label>
</div>

<div id="all_day_event_toggle0" style="$all_day_event_toggle0_style">
<div class="leftcol" style="margin-bottom:0;">
<label class="required_field" for="evt_start_time">$lang{event_start_time}</label>
</div>
<div class="rightcol" style="margin-bottom:0;white-space:nowrap;">
<input id="evt_start_time" name="evt_start_time" style="width:7em;" value = "$event_start_time">
</div>
<div class="leftcol" style="margin-bottom:0;">
<label class="required_field" for="evt_end_time">$lang{event_end_time}</label>
</div>
<div class="rightcol" style="margin-bottom:0;white-space:nowrap;">
<input id="evt_end_time" name="evt_end_time" style="width:7em;" value = "$event_end_time">
</div>
</div>



p1

    $return_text .=<<p1;
<div style="float:right;width:20%;">
<div class="icon_preview_box" style="float:left;">
<div id="icon_preview" style="text-align:cebter;">
<img src="$icons_url/$event_icon\l_32x32.gif" alt='event icon' border="0" vspace=0 hspace=0>
</div>
p1
    if ($options{unit_number_icons} == 1)
    {
      $return_text .=<<p1;
<div id="unit_number_preview" style="margin:3px;">
$unit_number_text
</div>
p1
    }
    $return_text .=<<p1;
</div>
</div>
p1


    $return_text .=<<p1;
<div class="leftcol" style="margin-bottom:0;">
<label class="optional_field" for="evt_icon">$lang{event_icon}</label>
</div>
<div class="rightcol" style="margin-bottom:0;white-space:nowrap;width:auto;">
<select name="evt_icon" id="evt_icon" onChange="update_preview_icon()">
p1
    @icon_menus_data = &assemble_icon_menus($event_icons_menu);
    $icon_menu_index_number = 0;
    $return_text .= &generate_flat_icon_menus(\@icon_menus_data, $event_icon);

    $return_text .=<<p1;
</select>
</div>
p1
    if ($options{unit_number_icons} == 1)
    {
      $return_text .=<<p1;
<div class="leftcol" style="margin-bottom:0;">
<label class="optional_field" for="unit_number">$lang{event_unit_number} </label>
</div>
<div class="rightcol" style="margin-bottom:0;white-space:nowrap;width:40%">
<input id="unit_number" name="unit_number" style="width:6ex;" value = "$event_unit_number" onKeyUp="update_preview_icon()">
</div>
p1
    }
    
    $return_text .=<<p1;
<div class="leftcol" style="">
<label class="optional_field" for="cal_details">$lang{event_background_color}</label>
</div>
<div class="rightcol" style="white-space:nowrap;width:40%;">
<input name="dummy" value="" size=1 style="display:none;">
<select name="evt_bgcolor" onchange="update_bg_color_select_box()" style="width:7em;">
p1
    my $custom_color=1;

    foreach $temp (@event_bgcolors)
    {
      %possible_bgcolor = %{$temp};
      my $selected="";
      if ($possible_bgcolor{color} eq "$event_bgcolor")  #default
      {
        $custom_color=0;
        $selected=" selected";
      }
      my $description = "";
      if ($options{show_event_background_color_descriptions})
        {$description = $possible_bgcolor{title}}
      
      $return_text .=<<p1;
<option value = "$possible_bgcolor{color}" $selected>$description
p1
    }
    
    my $color_select_icon_style="visibility:hidden;";
    if ($custom_color == 1 && $add_edit_event eq "edit")
    {
      $color_select_icon_style="";
      $return_text .=<<p1;
<option value = "$event_bgcolor" selected>$lang{event_background_colorcustom}
p1
    }
    else
    {
      $return_text .=<<p1;
<option id="custom_evt_color" value = "#ffffff">$lang{event_background_colorcustom}
p1
    }
    
    
    $return_text .=<<p1;
</select>
<span id="color_select_icon0" class="color_select_icon" style="$color_select_icon_style vertical-align:top;background-image:url($graphics_url/color_select_icon.gif);" onClick="cs_init();cs0.toggle_color_select();">&nbsp;&nbsp;&nbsp;&nbsp;</span>

</div>
<br style="clear:both;"/>
<br style="clear:both;"/>

</div>



<div id="tab_area1" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:1em;text-align:left;">
p1

    if ($add_edit_event eq "edit")
    {
      if ($current_event{series_id} ne "")
      {
        $return_text .=<<p1;
<input type="hidden" name="recurring_event" value="1">       
<input type="hidden" name="series_id" value="$current_event{series_id}">       
        
<div style="text-align:center;">
$lang{recurring_event_edit1}
</div>

<div class="leftcol" style="margin-bottom:1em;">
<span class="small_note"><a href="javascript:display_help('recurring_event_change_all','$lang{recurring_event_change_all1}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
</div>
<div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
<input type="checkbox" name="all_in_series" value="1" onClick="recur_edit_toggle()"> 
<label class="optional_field">$lang{recurring_event_change_all1}</label>
<div class="small_note style="margin-left:17px;"">$lang{recurring_event_change_all2}</div>
</div>
p1
      }
  
      else
      {
        $return_text .=<<p1;
$lang{recurrence_not_allowed}
p1
      }
        $return_text .=<<p1;
<br style="clear:both;"/>
p1

    }
    else
    {
      $return_text .=<<p1;
<div class="leftcol" style="margin-bottom:1em;">
<span class="small_note"><a href="javascript:display_help('recurring_event','$lang{recurring_event}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
</div>
<div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
<input type="checkbox" name="recurring_event" value="1" onclick="javascript:recur_toggle();"> 
<label class="optional_field">$lang{recurring_event}</label>
</div>

<div class="leftcol" style="margin-bottom:1em;vertical-align:middle;">
<span class="fit_event">
<i>$lang{recurrence_type}</i><br/>
<span class="small_note"><a href="javascript:display_help('recurrence_type','$lang{recurrence_type}')">$lang{help_on_this}</a></span>
</span>
</div>
<div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
<input type="radio" name="recurrence_type" value="same_day_of_month" disabled checked onclick="recurrence_type_update()"> 
<span class="optional_field">$lang{same_day_of_month}</span>
<br/>
<input type="radio" name="recurrence_type" value="same_day_of_week" disabled onclick="recurrence_type_update()"> 
<span class="optional_field">
$lang{same_weekday}
</span>
<select name = "weekday_of_month_type" disabled>
<option value = "every_week">$lang{on_every_week}
<option value = "only_first_week">$lang{on_first_week}
<option value = "only_second_week">$lang{on_second_week}
<option value = "only_third_week">$lang{on_third_week}
<option value = "only_fourth_week">$lang{on_fourth_week}
<option value = "only_fifth_week">$lang{on_fifth_week}
<option value = "only_last_week">$lang{on_last_week}
</select> $lang{of_the_month}
<br/>

<span class="optional_field">
p1

  my $temp =<<p1;
<input name = "every_x_days" disabled/ value="1" style="width:2em;">
p1

  $lang{every_x_days} =~ s/###x###/$temp/;

      $return_text .=<<p1;
<input type="radio" name="recurrence_type" value="every_x_days" disabled onclick="recurrence_type_update()"> 
$lang{every_x_days}
</span>
<br/>

<span class="optional_field">
p1

  my $temp =<<p1;
<input name = "every_x_weeks" disabled/ value="1" style="width:2em;">
p1

  $lang{every_x_weeks} =~ s/###x###/$temp/;

      $return_text .=<<p1;
<input type="radio" name="recurrence_type" value="every_x_weeks" disabled onclick="recurrence_type_update()"> 
$lang{every_x_weeks}
</span>



</div>
      
<div class="leftcol" style="">
<span class="fit_event">
<i>$lang{fit_into_year}</i><br/>
<span class="small_note"><a href="javascript:display_help('fit_into_year','$lang{fit_into_year}')">$lang{help_on_this}</a></span>
</span>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="radio" name="year_fit_type" value="every_month" checked disabled onclick="document.add_event_form.custom_months.disabled=true"> 
<span class="optional_field">
$lang{every_momth}
</span>

<div style="float:left;">
<input type="radio" name="year_fit_type" value="custom_months" disabled onclick="document.add_event_form.custom_months.disabled=false"> 
<span class="optional_field">$lang{certain_months1} </span>
<br/>
<span class="small_note">$lang{certain_months2}</span>
</div>

<div style="float:left;">
<select multiple name = "custom_months" size=4 disabled>
p1

  for ($l1=0;$l1<scalar @months;$l1++)
  {
      $return_text .=<<p1;
<option value = $l1>$months[$l1]
p1
  }

      $return_text .=<<p1;
</select>
</div>

</div>

<div class="leftcol" style="">
<label class="required_field">$lang{recurring_event_ends}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input name="recur_end_date" size=12 value="$recur_end_date" disabled>
</div>
      
<br style="clear:both;"/>
p1
    }
      
    $return_text .=<<p1;
</div>

<div style="margin-top:1em;margin-bottom:1em;float:left;width:48%;text-align:center;font-weight:bold;">
<a href="javascript:preview_event()">$lang{preview_event1}</a>
<p class="small_note active_tab_text">
$lang{preview_event2}
</p>
</div>

<div style="margin-top:1em;margin-bottom:1em;float:left;width:48%;text-align:center;font-weight:bold;">
<a href="javascript:preview_dates()">$lang{preview_dates1}</a>
<p class="small_note active_tab_text">
$lang{preview_dates2}
</p>
</div>
      
<div class="info_box" style="clear:both;">
p1
    if ($options{disable_passwords} ne "1")
    {
      $return_text .=<<p1;
<div class="leftcol" style="">
<label class="required_field" for="evt_cal_password">$lang{cal_password}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="password" id="evt_cal_password" name="evt_cal_password" style="width:30%;">
<span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('evt_cal_password','$lang{cal_password}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
</div>
      
p1
    }
    if ($q->param('add_edit_event') eq "edit")
    {
      $return_text .=<<p1;
<div class="leftcol" style="">
&nbsp;
</div>
<div class="rightcol" style="white-space:nowrap;">
<input name="add_event_button" type="submit" value = "$lang{update_event}">
<div class="small_note">$lang{add_event2_update}</div>
</div>


<div style="text-align:left;">
<input name="del_event_button" class="delete_button" type="submit" value = "$lang{delete_event1}">
<div class="small_note">$lang{delete_event2}</div>
</div>

p1
    }
    else
    {
      $return_text .=<<p1;
<div class="leftcol" style="">
&nbsp;
</div>
<div class="rightcol" style="white-space:nowrap;">
<input name="add_event_button" type="submit" value = "$lang{add_event1}">
<br/>
<span id="preview_note" class="small_note">
$lang{add_event2}
</span>
</div>

<br style="clear:both;"/>
<br style="clear:both;"/>
p1
    }
    $return_text .=<<p1;
</div>
p1

  }
  else  #a user added/edited/deleted an event--do checks and perform resulting action
  {
    my @results_messages;
    my $recurring_event = $q->param('recurring_event');
    my $all_in_series = $q->param('all_in_series');
    #$debug_info .= "recurring_event_change_all: $all_in_series\n";
    
    if ($q->param('evt_cal_id') ne "")
    {
      %current_calendar =%{$calendars{$q->param('evt_cal_id')}};
    }
    
    
    # load (reload) all events (we have to write events beyond the default time window)
    if ($options{data_storage_mode} == 0)
    {
      &load_events("all") unless ($loaded_all_events eq "1");
    }

    if ($q->param('del_event_button') ne "")
    {
      #delete event.  
      $del_valid=1;
      
      # need to validate password against all its cal_ids
      
      if ($options{disable_passwords} ne "1")
      {
        #check password.
        $input_password = crypt($q->param('evt_cal_password'), substr($q->param('evt_cal_password'), 0, 2));
 
        if ($input_password ne $calendars{$current_event{cal_ids}[0]}{password} && $input_password ne $master_password)
        {
          $del_valid=0;
          push @results_messages, ($lang{update_event_err1}.$calendars{$current_event{cal_ids}[0]}{title});
        }
 
        if (! defined $events{$current_event_id})
        {
          $del_valid=0;
          push @results_messages, $lang{update_event_err2};
        }
      }
      
      
        
      if ($del_valid == 1)
      { #actually delete the event(s).
        if ($all_in_series ne "1")
        {
          &delete_event($current_event_id);
        
          $event_action_results .= <<p1;
<p style="font-weight:bold;">$lang{update_event_delete_successful}</p>
p1
        }
        else
        {
          # get the ids of the events in the series.
          my @events_in_series = &get_events_in_series($q->param('series_id'));
          &delete_events(\@events_in_series);
          $event_action_results .= <<p1;
<p style="font-weight:bold;">$lang{update_event_delete_successful_recurring}</p>
p1
        }
      }
      else
      {
        foreach $results_message (@results_messages)
        {
          $results_message =~ s/(.*$lang{Warning})/<span class="warning">$1<\/span>/i;
          $results_message =~ s/(.*$lang{Error})/<span class="error">$1<\/span>/i;
          $message_results .= "<li>$results_message</li>\n";
        }
        $event_action_results = "<ul style=\"font-size:small;\">$message_results</ul>$event_action_results";
      }
    }
    else
    {
      #check all input fields for validity
      my $event_valid = 1;
      my $event_id = $q->param('evt_id');        # only if editing.
      my $event_cal_id = $q->param('evt_cal_id');   
      
      my @evt_other_cal_ids;
      if ($options{multi_calendar_event_mode} > 0)
        {@evt_other_cal_ids = $q->param('evt_other_cal_ids')};
      
      my $event_cal_password = $q->param('evt_cal_password');    
      my $event_title = $q->param('evt_title');
      my $event_icon = $q->param('evt_icon');
      my $event_details = $q->param('evt_details');
      my $event_unit_number = $q->param('unit_number');
      my $event_bgcolor = $q->param('evt_bgcolor');
      my $event_series_id = $q->param('series_id');
      
      my $event_duration = 0;
      my $event_start_timestamp = 0;
      my $event_end_timestamp = 0;
      my $event_start_time_offset = 0;
      
      $recur_end_date = $q->param('recur_end_date');
      my $recur_end_timestamp = 0;
      my $all_day_event = $q->param('all_day_event');
      my $event_start_time = $q->param('evt_start_time');
      my $event_end_time = $q->param('evt_end_time');
      $event_start_date = $q->param('evt_start_date');
      $event_days = $q->param('evt_days');
      
      
      
      # Check data for legitimacy.  
      # some of these checks might be a bit redundant.
      if ($event_cal_id eq "")
      {
        $event_valid=0;
        push @results_messages, $lang{update_event_err3};
      }
      if ($event_title eq "")
      {
        $event_valid=0;
        push @results_messages, $lang{update_event_err4};
      }
      if ($event_icon eq "")
      {
        $event_valid=0;
        push @results_messages, $lang{update_event_err5};
      }

      $event_title =~ s/\r//g;                 # some browsers sneak these in 
      $event_details =~ s/\r//g;               # some browsers sneak these in 


      #strip html
      if ($event_title =~ m/<(.*)>/)
      {
        my $temp = $event_title;
        $temp =~ s/</&lt;/g;
        $temp =~ s/>/&gt;/g;
        
        push @results_messages, $lang{update_event_err7};
        $event_title =~ s/<(.*)>//g;
      }

      # strip out all non-numeric information from unit number
      my $unit_number = $event_unit_number;
      $unit_number =~ s/\D//g;
            
      #check event calendar name against existing calendars
      if (!defined == $calendars{$event_cal_id})
      {
        $event_valid=0;
        push @results_messages, $lang{update_event_err8};
      }
      elsif ($options{disable_passwords} ne "1")
      {
        #$debug_info .= "checking password\n";
        #check password
        
        $input_password = crypt($event_cal_password, substr($event_cal_password, 0, 2));
        
        if ($options{multi_calendar_event_mode} == 0 || $options{multi_calendar_event_mode} == 1)
        {
          my $temp = $q->param("evt_cal_id");
 
          # only the event's calendar's password or the master password is allowed
          if ($temp eq "" || $input_password ne $calendars{$temp}{password} && $input_password ne $master_password)
          {
            $event_valid=0;
            push @results_messages, ($lang{update_event_err1}."<b>".$current_calendar{title}."</b>");
          }
        }
        elsif ($options{multi_calendar_event_mode} == 2) # any of the event's calendars' passwords or the master password aer allowed
        {
          my $cal_password_valid = 0;
          my $temp = $q->param("evt_cal_id");
          if ($temp ne "" && ($input_password eq $calendars{$temp}{password} || $input_password eq $master_password))
          {
            $cal_password_valid= 1;
          }
          
          if ($cal_password_valid == 0)     
          {  
            foreach $cal_id (@evt_other_cal_ids)
            {
              my $temp = $cal_id;
              if ($temp ne "" && ($input_password eq $calendars{$temp}{password}))
                {$cal_password_valid = 1;}
            }
          }
          
          if ($cal_password_valid == 0)
          {
            $event_valid=0;
            push @results_messages, ($lang{update_event_err1}."<b>".$current_calendar{title}."</b>");
          }
        }
      }
      
      # check dates
      if ($event_valid == 1)
      {
        my $results = &verify_date($event_start_date);
        if ($results ne "")
        {
          $event_valid=0;
          $results =~ s/(.+?)\n/<li>$1<\/li>\n/g;      
          push @results_messages, "$lang{update_event_err9}<ul>$results</ul>"
        }
        
        if ($event_days eq "")
        {
          push @results_messages, "$lang{update_event_err9}<ul>$lang{date_verify_err2}</ul>"
        }
        if ($days =~ m/\D/ || $event_days <= 0)
        {
          push @results_messages, "$lang{update_event_err9}<ul>$lang{date_verify_err3}</ul>"
        }
      }
      
      # check recurring "repeat until" date
      if ($event_valid == 1)
      {
        @custom_months = $q->param('custom_months');

        if ($recurring_event ne "" && $add_edit_event eq "add")
        {
          $results = &verify_date($recur_end_date);
          if ($results ne "")
          {        
            $event_valid=0;
            $results =~ s/(.+?)\n/<li>$1<\/li>\n/g;      
            push @results_messages, "$lang{update_event_err10}<ul>$results</ul>"
          }
        }
      }
      
      # check time
      if ($event_valid == 1 && $all_day_event ne "1")
      {
        my $results = &verify_time($event_start_time);
        if ($results ne "")
        {
          $event_valid=0;
          $results =~ s/(.+?)\n/<li>$1<\/li>\n/g;      
          push @results_messages, "$lang{update_event_err14}<ul>$results</ul>"
        }
        
        my $results = &verify_time($event_end_time);
        if ($results ne "")
        {
          $event_valid=0;
          $results =~ s/(.+?)\n/<li>$1<\/li>\n/g;      
          push @results_messages, "$lang{update_event_err15}<ul>$results</ul>"
        }
        
      }
      
      if ($event_valid == 1)
      {
        my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_calendar{date_format});
        $start_mon--;  # convert month to 0-11 format

        if ($all_day_event eq "1")
        {
          $event_start_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year);
          $event_end_timestamp = $event_start_timestamp + ($event_days * 86400) - 1;
        }
        else
        {
          $event_start_time_offset = &time2seconds($event_start_time);
          $event_start_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year) + &time2seconds($event_start_time);
          $event_end_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year) + &time2seconds($event_end_time);
          $event_days = 1;
        }
        $event_duration = $event_end_timestamp - $event_start_timestamp;
        
        #if ($event_start_timestamp == $event_end_timestamp)
        #  {$event_end_timestamp +=1;}  # give all events a duration of at least 1 second
        
        if ($recurring_event ne "" && $add_edit_event eq "add")
        {
          my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recur_end_date, $current_calendar{date_format});
          $recur_end_mon--;
          $recur_end_timestamp=timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year);
        }
        
        # display warning if start timestamp is before present date
        if ($event_start_timestamp < $rightnow-86400)
        {
          push @results_messages, $lang{update_event_err11};
        }
      }
      
      # check for refreshes!
      if ($recurring_event eq "")
      {
        #$debug_info .= "comparing $latest_event{start} (event $latest_event_id) and $event_start_timestamp\n";
      
        if ($latest_event{cal_ids}[0] eq $event_cal_id && 
            $latest_event{start} eq $event_start_timestamp && 
            $latest_event{end} eq $event_end_timestamp && 
            $latest_event{days} eq $event_days && 
            $latest_event{title} eq $event_title && 
            $latest_event{details} eq $event_details && 
            $latest_event{icon} eq $event_icon && 
            $latest_event{bgcolor} eq $event_bgcolor && 
            $latest_event{unit_number} eq $event_unit_number) 
        {
          $event_valid=0;
          push @results_messages, $lang{update_event_err12};
        }
      }
      else # recurring event refresh protection is a little trickier.
      {
        # it's currently not implemented
      }
  
  
      if ($add_edit_event eq "edit")
      {
        #check to make sure the event id matches some event in the data structure.
        #it always should, but we check anyway.
        if (!defined $events{$event_id})
        {
          $event_valid=0;
          push @results_messages, $lang{update_event_err13};
        }
      }
      
      
      # properly format errors & warnings
      $message_results="";
      
      foreach $results_message (@results_messages)
      {
        $results_message =~ s/(.*$lang{Warning})/<span class="warning">$1<\/span>/i;
        $results_message =~ s/(.*$lang{Error})/<span class="error">$1<\/span>/i;
        $message_results .= "<li>$results_message</li>\n";
      }
      $event_action_results = "<ul style=\"font-size:small;\">$message_results</ul>$event_action_results";
      @results_message=();
      
      if ($event_valid == 1)
      { #all checks successful, add/update event!

        unshift @evt_other_cal_ids, $event_cal_id;

        $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}/g;
        $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}/g;
        $event_details_template =~ s/###delete event link###/$lang{event_details_delete_disable}/g;
        $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g;

        if ($add_edit_event eq "add")  # add a new event
        {
          if ($recurring_event eq "")
          {
            my $new_event_id = $max_event_id + 1;
        
            #$debug_info .= "(add_edit_events) event cal id: $event_cal_id\n";
            # add event to %events data structure
            $events{$new_event_id} = {id => $new_event_id, 
                                      cal_ids => \@evt_other_cal_ids, 
                                      start => $event_start_timestamp, 
                                      end => $event_end_timestamp, 
                                      days => $event_days, 
                                      all_day_event => $all_day_event,
                                      title => $event_title, 
                                      details => $event_details,
                                      icon => $event_icon,
                                      bgcolor => $event_bgcolor,
                                      unit_number => $event_unit_number,
                                      update_timestamp => $rightnow};


            &add_event($new_event_id);
            
            #temporarily offset event times by calendar gmtime diff
            $event_box_text .= &generate_event_details($events{$new_event_id});
            
            $event_action_results .= <<p1;
<p style="font-weight:bold;">$lang{update_event_add_successful}</p>
$event_box_text
<ul>
<li><a href="$script_url/$name?active_tab=1$consistent_parameter_string">$lang{update_event_add_successful_add_new}</a></li>
</ul>
p1
          }
          else # recurring events loop
          {
            &load_events("all") unless $loaded_all_events;
            
            $new_series_id = $max_series_id + 1;
          
            my $date_text="";
            
            $event_start_timestamp -= $event_start_time_offset;  # calculate_recurring_events needs events that start at 0:00
                       
            my @recurring_events_timestamps = @{&calculate_recurring_events($event_start_timestamp,$recur_end_timestamp)};
            
            my @recurring_event_ids = ();
            foreach $recurring_event_start_timestamp (@recurring_events_timestamps)
            {
              $recurring_event_start_timestamp += $event_start_time_offset;
              
              $max_event_id += 1;
              my $new_event_id = $max_event_id;
              
              # don't need to offset recurring event timestamps by gmtime_diff 
              # because they're updated at write time.

              my $recurring_event_end_timestamp = $recurring_event_start_timestamp + $event_duration;
              #if ($recurring_event_end_timestamp == $recurring_event_start_timestamp)
              #  {$recurring_event_end_timestamp +=1;}  # give all events a duration of at least 1 second
              
              $events{$new_event_id} = {id => $new_event_id, 
                                      cal_ids => \@evt_other_cal_ids, 
                                      start => $recurring_event_start_timestamp, 
                                      end => $recurring_event_end_timestamp, 
                                      days => $event_days,
                                      all_day_event => $all_day_event,
                                      series_id => $new_series_id, 
                                      title => $event_title, 
                                      details => $event_details,
                                      icon => $event_icon,
                                      bgcolor => $event_bgcolor,
                                      unit_number => $event_unit_number,
                                      update_timestamp => $rightnow};
                                      
              push @recurring_event_ids, $new_event_id;
              
              my $date_range = &nice_date_range_format($recurring_event_start_timestamp, $recurring_event_end_timestamp, "-");

              $date_text .= <<p1;
<li>$date_range</li>
p1
              
            }
            
            &add_events(\@recurring_event_ids);

            $event_box_text .= &generate_event_details($events{$max_event_id});

            $event_action_results .= <<p1;
<p style="font-weight:bold;">$lang{update_event_add_successful_recurring}</p>
<ul>
$date_text
</ul>
$event_box_text
<ul>
<li><a href="$script_url/$name?active_tab=1$consistent_parameter_string">$lang{update_event_add_successful_add_new}</a></li>
<li><a href="$script_url/$name?active_tab=0$consistent_parameter_string">$lang{update_event_back_to_calendar}</a></li>
</ul>
p1
          }
          
        }
        elsif ($add_edit_event eq "edit")  #if we need to replace an existing record
        {
          &load_events("all") unless $loaded_all_events;
        
          if ($recurring_event eq "" || $all_in_series ne "1")
          {
            $events{$event_id} = {id => $event_id,
                                cal_ids => \@evt_other_cal_ids,
                                start => $event_start_timestamp,
                                end => $event_end_timestamp, 
                                days => $event_days,
                                all_day_event => $all_day_event,
                                series_id => $event_series_id, 
                                title => $event_title,
                                details => $event_details,
                                icon => $event_icon,
                                bgcolor => $event_bgcolor,
                                unit_number => $event_unit_number,
                                update_timestamp => $rightnow};
          
          
            &update_event($event_id);

            $event_box_text .= &generate_event_details($events{$new_event_id});
         
            $event_action_results .= <<p1;
<p style="font-weight:bold;">$lang{update_event_update_successful}</p>
p1
          } 
          else  # update recurring events
          {
            #$debug_info .= "updating recurring event series\n";
            
            # get the ids of the events in the series.
            my @events_in_series;
            foreach $event_id (keys %events)
            {
              my %event = %{$events{$event_id}};
              #$debug_info .= "checking event $event_id series id $event{series_id} against ".$q->param('series_id')."\n";
              if ($event{series_id} eq $q->param('series_id'))
              {
                #$debug_info .= "event in series:  $event_id\n";
                push @events_in_series, $event_id;
                
                my @temp = gmtime($event{end});
                
                if ($all_day_event eq "1")
                {
                  # in case it wasn't an all-day event before.
                  my @temp = gmtime($event{start});
                  my $recurring_event_day_start = timegm(0,0,0,$temp[3],$temp[4],$temp[5]+1900);
                  
                  $recurring_event_start_timestamp = $recurring_event_day_start;
                  $recurring_event_end_timestamp = $recurring_event_start_timestamp + ($event_days * 86400) - 1;
                }
                else
                {
                  my @temp = gmtime($event{start});
                  my $recurring_event_day_start = timegm(0,0,0,$temp[3],$temp[4],$temp[5]+1900);
                
                  $recurring_event_start_timestamp = $recurring_event_day_start + &time2seconds($event_start_time);
                  $recurring_event_end_timestamp = $recurring_event_day_start + &time2seconds($event_end_time);
                  $event_days = 1;
                }

                
                #my $recurring_event_start_timestamp = $event{start} + $event_duration;
                #$debug_info .= "event $event_id, start: $recurring_event_start_timestamp, duration: $event_duration\n";
                
                $events{$event_id} = {id => $event_id,
                                      cal_ids => \@evt_other_cal_ids,
                                      start => $recurring_event_start_timestamp,
                                      end => $recurring_event_end_timestamp, 
                                      days => $event_days,  # not stored in file--only used internally
                                      all_day_event => $all_day_event,
                                      series_id => $event{series_id},
                                      title => $event_title,
                                      details => $event_details,
                                      icon => $event_icon,
                                      bgcolor => $event_bgcolor,
                                      unit_number => $event_unit_number,
                                      update_timestamp => $rightnow};
                
              }
            }
            &update_events(\@events_in_series);
            
            $event_action_results .= <<p1;
<p style="font-weight:bold;">$lang{update_event_update_successful_recurring}</p>
p1
          }
        }
      }
    }
  }
      
    
  $return_text .=<<p1;
<div style="text-align:left;">
$event_action_results
</div>
p1

  return $return_text;

} #******************** end add_edit_events *****************************





sub IE_javascript
{
  my $return_string="";
  $return_string .=<<p1;
function mousemove(e) { 
  if (load_flag)
  {
    mouse_x=window.event.clientX+document.body.scrollLeft-4;
    mouse_y=window.event.clientY+document.body.scrollTop-4;
    mouse_window_x=window.event.clientX;
    mouse_window_y=window.event.clientY;
    //if (e.target) event_target = e.target;
    //else if (e.srcElement) var trg = e.srcElement;  

  }
}
  
function window_x() {
  return window.screenLeft;
}

function window_y() {
  return window.screenTop;
}

function get_page_boundaries()
{
  distance_to_right_edge = document.body.clientWidth-mouse_window_x;
  distance_to_bottom = document.body.clientHeight-mouse_window_y;
}


p1
  return $return_string;
}  #***********************end IE javascript************************"


sub NS6_javascript
{
  
  my $return_string="";
  $return_string .=<<p1;
document.captureEvents(Event.MOUSEMOVE);
document.captureEvents(Event.MOUSECLICK);

function mousemove(e) { 
  if (load_flag)
  { 
    mouse_x=e.layerX;
    mouse_y=e.layerY;
    
    mouse_window_x=e.clientX;
    mouse_window_y=e.clientY;
    event_target = e.target;
    //else if (e.srcElement) var trg = e.srcElement;  


    //status = "mouse x: "+mouse_x+"mouse y: "+mouse_y;
    //status = 'asdf';
    //document.getElementById("mouse_info").style.top=0;
    //document.getElementById("mouse_info").style.left=0;
    //document.getElementById("mouse_info").innerHTML = "mouse x: "+mouse_window_x+"mouse y: "+mouse_window_y;
    //document.getElementById("mouse_info").style.visibility = "visible";
    
  }
}

function window_x() {
  return window.screenX;
}  
function window_y() {
  return window.screenY;
}

function get_page_boundaries()
{
  distance_to_right_edge = window.innerWidth-mouse_window_x
  distance_to_bottom = window.innerHeight-mouse_window_y;
}


p1
  return $return_string;

}  #********************end netscape javascript**********************


sub common_javascript
{
  $return_string .=<<p1;
var mouse_x=0;
var mouse_y=0;
var load_flag=0;

var active_event_id="";
var active_series_id="";
var active_day_timestamp="";

var info_window = new Object;
var info_window_width = $info_window_width;
var info_window_height = $info_window_height;

var page_width=0;
var page_height=0;
var event_target= null;

// I hate this kludge!
var context_menu_visible=false;

if (window.name == "")
  window.name="cal_mainwindow";

var main_window_name = window.name

document.onmousemove = mousemove;
document.onclick = hide_contextmenus;

window.onload=page_loaded;
window.onunload=page_unloaded;

function page_loaded()  {
  load_flag=1;
  do_on_load();
}

function page_unloaded()  {
  if (info_window.close)
    {info_window.close();}
}
p1

  my $event_contextmenu_text .= <<p1;
<div id="contextmenu_innerbox" style="padding-top:2px;padding-bottom:2px;">
<div class="context_menuitem" onMouseUp = "edit_event()" onMouseOver = "context_menuitem_highlight(this, '#000000')" onmouseout = "context_menuitem_unhighlight(this)">$lang{context_menu_edit_event}</div>
<div class="context_menuitem" onMouseUp = "delete_event()"onMouseOver = "context_menuitem_highlight(this, '#000000')" onmouseout = "context_menuitem_unhighlight(this)">$lang{context_menu_delete_event}</div>
</div>
p1
 $event_contextmenu_text = '' unless $writable{events_file};

  $event_contextmenu_text =~ s/\//\\\//g;
  $event_contextmenu_text =~ s/\n/\\n/g;
  $event_contextmenu_text =~ s/"/\\"/g;

  $return_string .= <<p1;
  
function show_event_contextmenu(e, event_id, menu_bgcolor, series_id)
{
  if (e.ctrlKey || $options{right_click_menus_enabled} != 1 || context_menu_visible) return true;

  get_page_boundaries();
  
  active_event_id = event_id;
  active_series_id = series_id;
  
  var themenu = document.getElementById("contextmenu")
  themenu.style.top = mouse_y;
  themenu.style.left = mouse_x;
  
  if (distance_to_right_edge < themenu.offsetWidth)
    themenu.style.left = mouse_x - themenu.offsetWidth;
  
  if (distance_to_bottom < themenu.offsetHeight)
    themenu.style.top = mouse_y - themenu.offsetHeight;
  
  themenu.innerHTML = "$event_contextmenu_text";
  document.getElementById("contextmenu_innerbox").style.borderStyle = "solid";
  document.getElementById("contextmenu_innerbox").style.borderWidth = "1px";
  document.getElementById("contextmenu_innerbox").style.borderTopColor = menu_bgcolor;
  document.getElementById("contextmenu_innerbox").style.borderLeftColor = menu_bgcolor;
  themenu.style.visibility = "visible";
  
  context_menu_visible = true;
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation(); 
  
  return false;
}
p1

  my $day_contextmenu_text .= <<p1;
<div id=contextmenu_innerbox style="padding-top:2px;padding-bottom:2px;">
<div class="context_menuitem" onMouseUp = "add_event_on_day()" onMouseOver = "context_menuitem_highlight(this, '#000000')" onmouseout = "context_menuitem_unhighlight(this)">$lang{add_event_on_this_day}</div>
</div>
p1
 $day_contextmenu_text = '' unless $writable{events_file};

  $day_contextmenu_text =~ s/\//\\\//g;
  $day_contextmenu_text =~ s/\n/\\n/g;
  $day_contextmenu_text =~ s/"/\\"/g;

  $return_string .= <<p1;
function show_day_contextmenu(e, day_timestamp)
{
  if (e.ctrlKey || $options{right_click_menus_enabled} != 1 || context_menu_visible) return true;

  get_page_boundaries();
  active_day_timestamp = day_timestamp;
  
  var themenu = document.getElementById("contextmenu")
  themenu.style.top = mouse_y;
  themenu.style.left = mouse_x;
  
  if (distance_to_right_edge < themenu.offsetWidth)
  {
    themenu.style.left = mouse_x - themenu.offsetWidth;
  }
  
  if (distance_to_bottom < themenu.offsetHeight)
  {
    themenu.style.top = mouse_y - themenu.offsetHeight;
  }
  
  themenu.innerHTML = "$day_contextmenu_text";
  document.getElementById("contextmenu_innerbox").style.borderStyle = "solid";
  document.getElementById("contextmenu_innerbox").style.borderWidth = "1px";
  document.getElementById("contextmenu_innerbox").style.borderTopColor = "#ffffff";
  document.getElementById("contextmenu_innerbox").style.borderLeftColor = "#ffffff";
  themenu.style.visibility = "visible";
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation(); 

  return false;
}

function hide_contextmenus()
{
    document.getElementById("contextmenu").style.visibility = "hidden";
    context_menu_visible = false;
}

function context_menuitem_highlight(element, color)
{
    element.className = "context_menuitem_highlight";
}

function context_menuitem_unhighlight(element)
{
    element.className = "context_menuitem";
}

function edit_event()
{
  window.location.href="$name?active_tab=1&add_edit_event=edit&evt_id=" + active_event_id + "$consistent_parameter_string";
}

function add_event_on_day()
{
  window.location.href="$name?active_tab=1&cal_id=$current_cal_id&add_edit_event=add&add_date_timestamp=" + active_day_timestamp + "$consistent_parameter_string";
}
p1

  $delete_event_text .= <<p1;
<p class="cal_title">
$lang{delete_event}
</p>
<div class="info_box">  
<form name="delete_event_form" action="$script_url/$name" method="POST">
<input type="hidden" name="active_tab" value="1">
<input type="hidden" name="cal_id" value="$current_cal_id}">
<input type="hidden" name="cal_start_month" value="$cal_start_month">
<input type="hidden" name="cal_start_year" value="$cal_start_year">
<input type="hidden" name="cal_num_months" value="$cal_num_months">
<input type="hidden" name="display_type" value="$display_type">
<input type="hidden" name="add_edit_cal_action" value="edit">
<input type="hidden" name="del_event_button" value="delete">
<input type="hidden" name="theme_url" value="$theme_url">
p1

  if ($options{disable_passwords} ne "1")
  {
    $delete_event_text .= <<p1;
<span class="required_field">$lang{password}: </span><input type="password" name="evt_cal_password">
p1
  }
  $delete_event_text =~ s/\//\\\//g;
  $delete_event_text =~ s/\n/\\n/g;
  $delete_event_text =~ s/"/\\"/g;

  $delete_series_text .=<<p1;
<br/><input type="checkbox" name="all_in_series" value="1"><span class="small_note">$lang{recurring_event_delete_all2}</span>
p1

  $delete_series_text =~ s/\//\\\//g;
  $delete_series_text =~ s/\n/\\n/g;
  $delete_series_text =~ s/"/\\"/g;

  $return_string .= <<p1;
function delete_event()
{
  var info_window_x = window_x()-400;
  var info_window_y = window_y();

  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=400,height=200");
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{delete_event}<\\/title>');
  doc.write('<base target=\\"'+main_window_name+'\\">');  
  doc.write('<link rel=\\"stylesheet" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('<body onload=\\"document.delete_event_form.evt_cal_password.focus();\\">');
  doc.write("$delete_event_text");
  if (active_series_id)
  {
    doc.write("$delete_series_text");
    doc.write('<input type=\\"hidden\\" name=\\"series_id\\" value=\\"'+active_series_id+'\\">');
  }
  doc.write('<input type=\\"hidden\\" name=\\"evt_id\\" value=\\"'+active_event_id+'\\">');
  doc.write('<br/><input type=\\"submit\\" value= \\"Delete\\">');
  doc.write('<\\/form><\\/div>');
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}


function docjslib_getRealLeft(imgElem) {
  xPos = imgElem.offsetLeft;
  tempEl = imgElem.offsetParent;
    //alert("element " + imgElem.id + "\\nparent "+ tempEl.id);
    //alert("element " + imgElem + "\\nparent "+ tempEl);
    while (tempEl != null) {
      xPos += tempEl.offsetLeft;
      tempEl = tempEl.offsetParent;
    }
  return xPos;
}

function docjslib_getRealTop(imgElem) {
  yPos = imgElem.offsetTop;
  tempEl = imgElem.offsetParent;
  while (tempEl != null) {
      yPos += tempEl.offsetTop;
      tempEl = tempEl.offsetParent;
    }
  return yPos;
}


function removename(el, name) {
  var i, curList, newList;
  // Remove the given class name from the className property of the element.
  newList = new Array();
  curList = el.className.split(" ");
  for (i = 0; i < curList.length; i++)
    if (curList[i] != name)
      newList.push(curList[i]);
  el.className = newList.join(" ");
}



p1
  return $return_string;
}  #********************end common_javascript **********************


sub calendar_view_javascript
{
  my ($events_start_timestamp, $events_end_timestamp) = @_;
  my $return_string="";

  # generate pre-formatted html for each day-zoom view for each day on the
  # current calendar.  This routine is a good example of one of the choices
  # made in the design of this site--gaining client-side processor cycles 
  # at the expense of bandwidth.  It would be possible to send the event details
  # in a javascript array or hash, and have the client's browser dynamically
  # genearate the appropriate html.  But it should be much faster to perform
  # this operation on the server and simply ship html to the client.  The idea is
  # to make the javascript processing as simple as possible, becuase javascript
  # is sloooow.  And even with all that extra html text, each page should still be 
  # less than 100k (not counting images)

  #generate pre-formatted html for each event view

  if ($current_calendar{preload_event_details} =~ /y/)
  {
    $return_string .= &generate_event_details_javascript($events_start_timestamp, $events_end_timestamp);
  }
  
  
  $return_string .=<<p1;
var current_cell_id = -1;

//line globals
var num_lines=3;
var source_x1=0;
var source_y1=0;
var target_obj=null;
var line_color="\#000000";

var result="";

function do_on_load() {
}

function blink(el, times, onoff)
{
  if (times==0) 
  {
    if (onoff == 0 && document.getElementById(el).className.match(/blink/))
      removename (document.getElementById(el),"blink");
    if (onoff == 1 && !document.getElementById(el).className.match(/blink/))
      document.getElementById(el).className += " blink";
    return;
  }
  
  if (document.getElementById(el).className.match(/blink/))
    removename (document.getElementById(el),"blink");
  else
    document.getElementById(el).className += " blink";
  
  setTimeout("blink('"+el+"',"+(times-1)+", "+onoff+")", 100);
  
}

function custom_calendar()
{
 
  var info_window_x = window_x()-400;
  var info_window_y = window_y();
p1

  $custom_form_text .=<<p1;
<div class="cal_title">
$lang{custom_calendar_title}
</div>
  
<form action="$script_url/$name" method="POST">
<input type="hidden" name="custom_calendar" value="1">
<input type="hidden" name="theme_url" value="$theme_url">

<label for="custom_calendar_calendar" class="required_field">
$lang{custom_calendar_choose_calendar}
</label>
<br/>
<select id="custom_calendar_calendar" name="custom_calendar_calendar">
p1

  foreach $cal_id (sort {$a <=> $b} keys %calendars)
  {
    $custom_form_text .=<<p1;
<option value = "$cal_id">$calendars{$cal_id}{title}
p1
  }

  $custom_form_text .=<<p1;
</select>
<br/><br/>
<label for="custom_calendar_background_calendars" class="optional_field">
$lang{custom_calendar_choose_bg_calendar}
</label>
<br/>

<select id="custom_calendar_background_calendars" name="custom_calendar_background_calendars" multiple size=6>
p1

  foreach $cal_id (sort {$a <=> $b} keys %calendars)
  {
    $custom_form_text .=<<p1;
<option value = "$cal_id">$calendars{$cal_id}{title}
p1
  }

  $custom_form_text .=<<p1;
</select>
<br/><br/>
p1

  if ($display_type == 1) {$list_selected = "selected";}
  else {$cal_selected = "selected";}
    
  $custom_form_text .=<<p1;
<label for="display_type" class="required_field">
$lang{custom_calendar_display_type}
</label>
<select name="display_type" onChange="blink('controls_submit_button', 3, 0);">
p1

    #foreach $possible_display_type (@{$options{display_types}})
    for (my $l1=0;$l1<scalar @{$options{display_types}};$l1++)
    {
      if ($options{display_types}[$l1] ne "1")
        {next};
      my $selected="";
      
      if ($l1 eq $display_type) 
        {$selected = "selected";}
        
      $custom_form_text .=<<p1;
<option value="$l1" $selected>$lang{controls_display_type}[$l1]
p1
    }
    $custom_form_text .=<<p1;
</select>
<br/><br/>

<label for="cal_start_month" class="required_field">
$lang{custom_calendar_time_range}
</label>

<table class="layout">
<tr><td nowrap align=right>

$lang{controls_start_month} 
</td><td nowrap>
<select id="cal_start_month" name="cal_start_month">
p1
  #list each month in the year
  $month_index=0;
  foreach $possible_month (@months)
  {
    if ($cal_start_month eq $month_index)
    {
      $custom_form_text .=<<p1;
<option value="$month_index" selected>$possible_month
p1
    }
    else
    {
      $custom_form_text .=<<p1;
<option value="$month_index">$possible_month
p1
    }
    $month_index++;
  }
  $custom_form_text .=<<p1;
</select>
<input name="cal_start_year" value = "$cal_start_year" size=4>
</td></tr>
<tr><td nowrap align=left colspan=2>

$lang{controls_num_months}
<input name="cal_num_months" value = "$cal_num_months" size=3>

</td></tr>
</table>
<br/><br/>

<input type=submit value = "$lang{custom_calendar_make_calendar}">
p1
  $custom_form_text =~ s/\//\\\//g;
  $custom_form_text =~ s/\n/\\n/g;
  $custom_form_text =~ s/"/\\"/g;
  
  $return_string .=<<p1;
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=400,height=500");
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{custom_calendar_title}<\\/title>');
  doc.write('<base target=\\"'+main_window_name+'\\">');  
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('<body>');
  doc.write("$custom_form_text");
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}


function display_event(evt_id)
{
p1

  # Here's another rare occurrence where Mozilla and IE 6+ are incompatible.
  # normally, this would be taken care of in the NS_javascript and IE_javascript
  # subroutines, but this is a special case.  The javascript here is being stored 
  # inside another javascript string, to be written to the details window if 
  # an event is called.  It's not being stored in perl at all, really.  It just 
  # looks that way.
  
  my $javascript_info = "";
  if ($browser_type eq "IE")
  {
    $javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = document.body.clientWidth;
  opener.info_window_height = document.body.clientHeight;
}
//-->
</script> 
p1
  }
  else
  {
    $javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = this.outerWidth;
  opener.info_window_height = this.outerHeight;
}
//-->
</script> 
p1
  }

  $javascript_info =~ s/\//\\\//g;
  $javascript_info =~ s/\n/\\n/g;
  $javascript_info =~ s/"/\\"/g;
  
  $return_string .=<<p1;
  var info_window_x = window_x()-$info_window_width;
  var info_window_y = window_y();
  
  if (evt_id.match(/^r/))
  {
    var URL_string = remote_event_details[evt_id].url;
    info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  }
  else
  {
p1

 
  if ($current_calendar{preload_event_details} =~ /y/)
  {
    $return_string .=<<p1;
  var detail_string = event_details[evt_id].text;
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<head>');
  doc.write('<title>$lang{event_details}<\\/title>');
  //doc.write('<base target=\\"'+main_window_name+'\\">');
  doc.write('<\\/head>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('$javascript_info');
  
  
  doc.write('<body class=\\"event_details_body\\" onResize=\\"javascript:do_onresize()\\">');
  doc.write(detail_string);
  
  doc.write('<\\/body><\\/html>');
  doc.close();
p1
  }
  else
  {
    $return_string .=<<p1;
  var URL_string="$script_url/$name?view_event=1&evt_id="+evt_id;
  info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
p1
  }
  
  $return_string .=<<p1;
  }
  info_window.focus();
}

p1
  return $return_string;
}  #***********************end calendar_view_javascript************************"





sub add_edit_events_javascript
{
  $return_string="";
  
  my $javascript_info = "";
  if ($browser_type eq "IE")
  {
    $javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = document.body.clientWidth;
  opener.info_window_height = document.body.clientHeight;
}
//-->
</script> 
p1
  }
  else
  {
    $javascript_info .=<<p1;
<script  type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = this.outerWidth;
  opener.info_window_height = this.outerHeight;
}
//-->
</script> 
p1
  }
  $javascript_info =~ s/\n/\\n/g;
  $javascript_info =~ s/"/\\"/g;
  $javascript_info =~ s/\//\\\//g;

  $return_string.=<<p1;
  
  var help_text="";
  var info_window_x = window_x()-$info_window_width;
  var info_window_y = window_y();
  
  // color select stuff
  var cs0 = new color_select();
  cs0.setrgb("$current_event{bgcolor}");

  // hook up the color select to the appropriate browser events.
  cs_hookup();


function cs_init()
{
  cs0.sv_image="$graphics_url/sv_blend.png";
    
  // initial values for position
  var temp = document.getElementById("color_select_icon0");
  cs0.x = docjslib_getRealLeft(temp);
  cs0.y = docjslib_getRealTop(temp) + 22;

  // attach the page elements to the appropriate color select handles.
  cs0.color_select_box = document.getElementById("color_select_box0");
  cs0.h_select_box = document.getElementById("h_select_box0");
  cs0.sv_select_box = document.getElementById("sv_select_box0");
  cs0.sv_select_box_bg = document.getElementById("sv_select_box_bg0");
  cs0.color_box = document.getElementById("color_box0");
  cs0.color_value_box = document.getElementById("color_value_box0");

  cs0.hue_cursor = document.getElementById("hue_cursor0");
  cs0.sv_crosshair_horiz_cursor = document.getElementById("sv_crosshair_horiz_cursor0");
  cs0.sv_crosshair_vert_cursor = document.getElementById("sv_crosshair_vert_cursor0");
  
  cs0.update_function = "color_menu0_update";   // NOTE-there are no ()
  cs0.update_color_box();
  
  //cs0.sethsv();
  
  //alert ("cs init done!");
}

function color_menu0_update(new_color)
{
  document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.options.length-1].value = new_color;
  document.add_event_form.evt_bgcolor.style.background = new_color;
  document.getElementById("custom_evt_color").style.background = new_color;
}
  
function do_on_load() {
  
  if (!document.add_event_form.evt_bgcolor)
    return;
  for (i=0; i<document.add_event_form.evt_bgcolor.options.length; i++)
    document.add_event_form.evt_bgcolor[i].style.background = document.add_event_form.evt_bgcolor[i].value;
  update_bg_color_select_box();
}
  
function show_help() {
  
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{help_box_title}<\\/title>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('$javascript_info');
  
  
  doc.write('<body onResize=\\"javascript:do_onresize()\\">');
  doc.write(help_text);
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}

function update_bg_color_select_box() {

    // did the user just select custom?
    if (document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].text == "custom")
    {
      document.getElementById("color_select_icon0").style.visibility = "visible";
    }
    else
    {
      document.getElementById("color_select_icon0").style.visibility = "hidden";
    } 
  
    // take focus off the select (in IE, making a selection highlights it in blue, so you cannot see the actual color you picked.  Removing focus makes this go away)
    document.add_event_form.dummy.style.display='inline';
    document.add_event_form.dummy.focus();
    document.add_event_form.dummy.style.display='none';
  
  if (!document.add_event_form.evt_bgcolor)
    return;
    
  document.add_event_form.evt_bgcolor.style.background = document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].value
  //document.add_event_form.evt_title.focus();
}

function update_preview_icon() {
  
  var icon_preview_area = document.getElementById("icon_preview")
  
  icon_name = document.add_event_form.evt_icon.options[document.add_event_form.evt_icon.selectedIndex].value
  icon_preview_area.innerHTML = "<img src=\\"$icons_url/" + icon_name + "_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>"

  if (!document.add_event_form.unit_number)
    return;

  var unit_number_preview_area = document.getElementById("unit_number_preview")

  // remove non-numeric text from the string
  var unit_number = document.add_event_form.unit_number.value;
  unit_number = unit_number.replace(/[^0-9]/g, "");
  
  // this next part might be really clever or really stupid (using a regex for something like this).
  // regardless, it's only one line, and that's nice.
  var unit_number_graphic_string = unit_number.replace(/([0-9])/g, "<img src=\\"$graphics_url/unit_number_patch_\$1_20x13.gif\\" border=\\"0\\" vspace=0 hspace=0>");
  unit_number_preview_area.innerHTML = unit_number_graphic_string;
  document.add_event_form.unit_number.value = unit_number;
  
  // it would be nice if we could do things with the DOM model, as opposed to innerHTML, but
  // that would be crazy cumbersome.  The following is a non-working stab at it.  Maybe useful someday.
  //preview_area.nodeValue = "unit num";
  //preview_area.appendChild(document.createTextNode("unit <img name=\\"event_icon\\" src=\\"$icons_url/eagle_medal_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>"));
  
}


function all_day_event_toggle(value)
{
  var el0 = document.getElementById("all_day_event_toggle0");
  el0.style.display="";

  if (value)
    el0.style.display="none";
}

function tab_show(tab_num) 
{
  if (tab_num == null) return;
  
  var elList, i;
  i=0;
  // update all tabs.
  while (document.getElementById("tab"+i) && i<100)
  {
    if (i == tab_num) 
    {
    // If the tab is the new active tab, activate it. 
      document.getElementById("tab"+i).className += " active";
      document.getElementById("tab_area"+i).style.display=""
      document.getElementById("tab"+i).blur();
    }
    else
    {
      // Otherwise, make sure the tab is deactivated.
      removename (document.getElementById("tab"+i),"active");
      document.getElementById("tab_area"+i).style.display="none"
    }
    i++;
  }
}

function preview_event() {
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,width=300,height=200");
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{event_preview_title}<\\/title>');
  doc.write('<body bgcolor=\\"#ffffff\\" style=\\"font-family:arial,helvetica\\">');
  doc.write('<font size=5><font color=\\"0049df\\">$lang{generating_preview}<\\/font>');
  doc.write('<\\/body><\\/html>');
  doc.close();
  
  document.add_event_form.special_action.value = "preview_event";
  document.add_event_form.target = "info_window";
  document.add_event_form.submit();
  document.add_event_form.special_action.value = "";
  document.add_event_form.target = "";
  
  info_window.focus();
}

function recur_toggle() {
  
  if (document.add_event_form.recurring_event.checked)
  {
    document.add_event_form.recurrence_type[0].disabled=false;
    document.add_event_form.recurrence_type[1].disabled=false;
    document.add_event_form.recurrence_type[2].disabled=false;
    document.add_event_form.recurrence_type[3].disabled=false;
    document.add_event_form.weekday_of_month_type.disabled=false;
    document.add_event_form.custom_months.disabled=false;
    document.add_event_form.year_fit_type[0].disabled=false;
    document.add_event_form.year_fit_type[1].disabled=false;
    document.add_event_form.custom_months.disabled=false;
    
    if (!document.add_event_form.recurrence_type[1].checked)
      document.add_event_form.weekday_of_month_type.disabled=true;
    if (document.add_event_form.year_fit_type[0].checked)
      document.add_event_form.custom_months.disabled=true;
      
      
    document.add_event_form.recur_end_date.disabled=false;
  }
  else
  {
    document.add_event_form.recurrence_type[0].disabled=true;
    document.add_event_form.recurrence_type[1].disabled=true;
    document.add_event_form.recurrence_type[2].disabled=true;
    document.add_event_form.recurrence_type[3].disabled=true;
    setTimeout("document.add_event_form.every_x_days.disabled=true",100);
    setTimeout("document.add_event_form.every_x_weeks.disabled=true",100);
    setTimeout("document.add_event_form.weekday_of_month_type.disabled=true",100);
    setTimeout("document.add_event_form.custom_months.disabled=true",100);
    document.add_event_form.year_fit_type[0].disabled=true;
    document.add_event_form.year_fit_type[1].disabled=true;
    document.add_event_form.custom_months.disabled=true;
    document.add_event_form.recur_end_date.disabled=true;
  }
  
  recurrence_type_update();
  //alert(document.add_event_form.recurring_event.checked);
}
function recurrence_type_update(last)
{
  
  document.add_event_form.weekday_of_month_type.disabled=true;
  document.add_event_form.every_x_days.disabled=true; 
  document.add_event_form.every_x_weeks.disabled=true; 
  
  if (document.add_event_form.recurrence_type[1].checked && !document.add_event_form.recurrence_type[1].disabled)
  {
    document.add_event_form.weekday_of_month_type.disabled=false;
  }
  if (document.add_event_form.recurrence_type[2].checked  && !document.add_event_form.recurrence_type[2].disabled)
  {
    document.add_event_form.every_x_days.disabled=false; 
  }
  if (document.add_event_form.recurrence_type[3].checked  && !document.add_event_form.recurrence_type[3].disabled)
  {
    document.add_event_form.every_x_weeks.disabled=false; 
  }
  
  if (!last) setTimeout("recurrence_type_update(true)",100);
}

function recur_edit_toggle()
{
  if (document.add_event_form.all_in_series.checked)
  {
    document.add_event_form.add_event_button.value="$lang{recurring_event_update_all1}";
    document.add_event_form.del_event_button.value="$lang{recurring_event_delete_all1}";
  }
  else
  {
    document.add_event_form.add_event_button.value="$lang{update_event}";
    document.add_event_form.del_event_button.value="$lang{delete_event1}";
  }
}


function preview_dates() {
  var i = 0;
  var j = 0;
  var info_window_x = window_x()-$info_window_width;
  var info_window_y = window_y();
  
  var evt_start_date = document.add_event_form.evt_start_date.value;
  var evt_days = document.add_event_form.evt_days.value;
  var recurring_event = "";
  var every_x_days;
  var every_x_weeks;
  var recur_end_date;
  var recurrence_type = "";
  var year_fit_type = "";
  var weekday_of_month_type = "";
    
  if (document.add_event_form.recur_end_date)
  {
    every_x_days = document.add_event_form.every_x_days.value;
    every_x_weeks = document.add_event_form.every_x_weeks.value;
    recur_end_date = document.add_event_form.recur_end_date.value;
  
      if (document.add_event_form.recurring_event.checked)
        recurring_event = document.add_event_form.recurring_event.value;

    for (i=0; i<document.add_event_form.recurrence_type.length; i++)
      if (document.add_event_form.recurrence_type[i].checked)
        recurrence_type = document.add_event_form.recurrence_type[i].value;
        
    for (i=0; i<document.add_event_form.year_fit_type.length; i++)
      if (document.add_event_form.year_fit_type[i].checked)
        year_fit_type = document.add_event_form.year_fit_type[i].value;

    if (document.add_event_form.weekday_of_month_type.selectedIndex > -1)
      weekday_of_month_type = document.add_event_form.weekday_of_month_type.options[document.add_event_form.weekday_of_month_type.selectedIndex].value
    
    var selects = new Array();
    var custom_months = "";

    if (document.add_event_form.custom_months.selectedIndex > -1)
      for (j=0, i=document.add_event_form.custom_months.selectedIndex; i<document.add_event_form.custom_months.options.length;i++)
        if (document.add_event_form.custom_months.options[i].selected) selects[j++] = document.add_event_form.custom_months.options[i].value;
  
    for (j=0;j<selects.length; j++)
      custom_months += selects[j] + ' ';
  }
  
  var URL_string="$script_url/$name?special_action=preview_date&amp;evt_start_date="+evt_start_date+
                 "&amp;evt_cal_id="+document.add_event_form.evt_cal_id.value+
                 "&amp;recur_end_date="+recur_end_date+
                 "&amp;recurring_event="+recurring_event+
                 "&amp;recurrence_type="+recurrence_type+
                 "&amp;year_fit_type="+year_fit_type+
                 "&amp;every_x_days="+every_x_days+
                 "&amp;every_x_weeks="+every_x_weeks+
                 "&amp;weekday_of_month_type="+weekday_of_month_type+
                 "&amp;custom_months="+custom_months+
                 "&amp;evt_days="+evt_days;
  
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height");
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<head>');
  doc.write('<title>$lang{event_preview_computing}<\\/title>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('<\\/head>');
  doc.write('<body style=\\"font-family:arial;\\">');
  doc.write('$lang{event_preview_computing}');
  doc.write('<\\/body><\\/html>');
  doc.close();
  
  info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height");
  info_window.focus();
}
p1


  my %help_text_map = ("evt_cal_id" => "help_evt_calendar",
                       "evt_title" => "help_evt_title",
                       "evt_details" => "help_evt_details",
                       "recurring_event" => "help_recurring_event",
                       "recurrence_type" => "help_recurrence_type",
                       "fit_into_year" => "help_fit_into_year",
                       "evt_cal_password" => "help_evt_cal_password",
                       "recurring_event_change_all" => "help_recurring_event_change_all",
                       );

  my $help_text_javascript = "";                       
  foreach $key (keys %help_text_map)
  {
    my  $help_text=<<p1;
<div class="help_box">
$lang{$help_text_map{$key}}
</div>
p1
    $help_text =~ s/\n/\\n/g;
    $help_text =~ s/"/\\"/g;
    $help_text =~ s/'/\\'/g;
    $help_text =~ s/\//\\\//g;

  
    $help_text_javascript .=<<p1;
    if (topic == "$key")
      help_text += "$help_text";
p1

  }

  $return_string .=<<p1;
  function display_help(topic, title) {
    help_text = "";
    $help_text_javascript
    if (help_text != "")
    {
      help_text = "<div class=\\"help_title\\">$lang{help_box_title} - "+title+"</div>" + help_text;
      show_help();
    }
  }
p1

  
  return $return_string
}  #********************end add_edit_events_javascript**********************

sub add_edit_calendars_javascript
{
  my $return_string = "";
  
  
  $return_string.=<<p1;
function set_merge_xml(merge_xml) {
  var results = merge_xml.match(/\\/remote_calendar>/g);
  //var num_merged_calendars = results.length;
  
  if (results)
    if (results.length > 1)
      document.getElementById("remote_background_calendars_status").innerHTML = results.length + " $lang{get_remote_calendar2_plural} $current_calendar{title}<br/>";
    else
      document.getElementById("remote_background_calendars_status").innerHTML = results.length + " $lang{get_remote_calendar2_singular} $current_calendar{title}<br/>";
      
  else 
    document.getElementById("remote_background_calendars_status").innerHTML = "$lang{get_remote_calendar3}";
  
  //for(var i =0; i < results.length; i++)
  //  document.getElementById("remote_background_calendars_status").innerHTML +="calendar "+i+"<br/>";

  
  document.update_cal_form.new_remote_calandars_xml.value = merge_xml;
  //alert (num_merged_calendars +" new calendars to merge!")
  //alert(merge_xml);
}

p1


  my $popup_javascript_info = "";
  if ($browser_type eq "IE")
  {
    $popup_javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = document.body.clientWidth;
  opener.info_window_height = document.body.clientHeight;
}
//-->
</script> 
p1
  }
  else
  {
    $popup_javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = this.outerWidth;
  opener.info_window_height = this.outerHeight;
}
//-->
</script> 
p1
  }

  $popup_javascript_info =~ s/\n/\\n/g;
  $popup_javascript_info =~ s/"/\\"/g;
  $popup_javascript_info =~ s/\//\\\//g;


  $return_string.=<<p1;

function do_on_load() {
  update_remote_calendar_requests();
  update_cal_color_select_box();
}
p1

  my $get_remote_calendars_html =<<p1;
<br/>
<form name="detect_remote_calendars" action="$script_url/$name" method="POST">
<input type="hidden" name="detect_remote_calendars" value="1"/>
$lang{get_remote_calendars_url}<br/>
<input name="remote_calendar_url" value="http://" style="width:90%;">
<br/>
<input type="submit" value="Go!" style="width:5em;">
</form>
p1
  $get_remote_calendars_html =~ s/\n/\\n/g;
  $get_remote_calendars_html =~ s/"/\\"/g;
  $get_remote_calendars_html =~ s/\//\\\//g;

  $return_string.=<<p1;
function get_remote_calendars() {
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{get_remote_calendars}<\\/title>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('$popup_javascript_info');
  doc.write('<body onResize=\\"javascript:do_onresize()\\">');
  doc.write("<div class=\\"info_box\\" style=\\"padding:5px;\\"><br\\/>");
  doc.write('$get_remote_calendars_html');
  doc.write("<\\/div>");
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}

  
function update_remote_calendar_requests()
{
  if (!document.update_cal_form || !document.update_cal_form.allow_remote_calendar_requests)
    return;

  if (document.update_cal_form.allow_remote_calendar_requests.checked)
  {
    document.update_cal_form.remote_calendar_requests_require_password.disabled = false;
    if (document.update_cal_form.remote_calendar_requests_require_password.checked)
      document.update_cal_form.remote_calendar_requests_password.disabled = false;
  } 
}  
  
  
// color select stuff
var cs0 = new color_select();
cs0.setrgb("$current_calendar{background_events_color}");

var cs1 = new color_select();
cs1.setrgb("$current_calendar{calendar_events_color}");

// hook up the color select to the appropriate browser events.
cs_hookup();

function cs_init()
{
  cs0.sv_image="$graphics_url/sv_blend.png";
    
  // initial values for position
  var temp = document.getElementById("color_select_icon0");
  cs0.x = docjslib_getRealLeft(temp);
  cs0.y = docjslib_getRealTop(temp) + 22;

  // attach the page elements to the appropriate color select handles.
  cs0.color_select_box = document.getElementById("color_select_box0");
  cs0.h_select_box = document.getElementById("h_select_box0");
  cs0.sv_select_box = document.getElementById("sv_select_box0");
  cs0.sv_select_box_bg = document.getElementById("sv_select_box_bg0");
  cs0.color_box = document.getElementById("color_box0");
  cs0.color_value_box = document.getElementById("color_value_box0");

  cs0.hue_cursor = document.getElementById("hue_cursor0");
  cs0.sv_crosshair_horiz_cursor = document.getElementById("sv_crosshair_horiz_cursor0");
  cs0.sv_crosshair_vert_cursor = document.getElementById("sv_crosshair_vert_cursor0");
  
  cs0.update_function = "color_menu0_update";   // NOTE-there are no ()
  cs0.update_color_box();
  
  
  cs1.sv_image="$graphics_url/sv_blend.png";
    
  // initial values for position
  var temp = document.getElementById("color_select_icon1");
  cs1.x = docjslib_getRealLeft(temp);
  cs1.y = docjslib_getRealTop(temp) + 22;

  // attach the page elements to the appropriate color select handles.
  cs1.color_select_box = document.getElementById("color_select_box1");
  cs1.h_select_box = document.getElementById("h_select_box1");
  cs1.sv_select_box = document.getElementById("sv_select_box1");
  cs1.sv_select_box_bg = document.getElementById("sv_select_box_bg1");
  cs1.color_box = document.getElementById("color_box1");
  cs1.color_value_box = document.getElementById("color_value_box1");

  cs1.hue_cursor = document.getElementById("hue_cursor1");
  cs1.sv_crosshair_horiz_cursor = document.getElementById("sv_crosshair_horiz_cursor1");
  cs1.sv_crosshair_vert_cursor = document.getElementById("sv_crosshair_vert_cursor1");
  
  cs1.update_function = "color_menu1_update";   // NOTE-there are no ()
  cs1.update_color_box();
  
  
}

function color_menu0_update(new_color)
{
  if (document.update_cal_form.background_events_display_style2.checked)
  {
    document.update_cal_form.background_events_color.value = new_color;
    document.getElementById("bg_preview_e1").style.background = new_color;
    document.getElementById("bg_preview_e2").style.background = new_color;
  }
}

function color_menu1_update(new_color)
{
  //if (new_color == "#000000") return;
  if (document.getElementById("color_select_icon1").style.visibility != "visible") return;
  
  document.update_cal_form.calendar_events_color[document.update_cal_form.calendar_events_color.options.length-1].value = new_color;
  document.update_cal_form.calendar_events_color.style.background = new_color;
  document.getElementById("custom_evt_color").style.background = new_color;
  document.getElementById("preview_e1").style.background = new_color;
  document.getElementById("preview_e2").style.background = new_color;
}


function update_cal_color_select_box() {
  if (!document.update_cal_form) return;
  if (!document.update_cal_form.calendar_events_color) return;

  var current_color = document.update_cal_form.calendar_events_color[document.update_cal_form.calendar_events_color.selectedIndex].value;
  
  if (current_color == "")
  {
    document.getElementById('preview_e1').style.background = '#ffffcc';
    document.getElementById('preview_e2').style.background = '#ccffcc';
    document.getElementById("color_select_icon1").style.visibility = "hidden";
    document.update_cal_form.calendar_events_color.style.background = "#ffffff";
    return;
  }
  
  if (document.update_cal_form.calendar_events_color.selectedIndex == document.update_cal_form.calendar_events_color.options.length-1) 
  {
    document.getElementById("color_select_icon1").style.visibility = "visible";
    
    var current_custom_color = document.getElementById("custom_evt_color").value;
    document.getElementById("preview_e1").style.background = current_custom_color;
    document.getElementById("preview_e2").style.background = current_custom_color;
    document.update_cal_form.calendar_events_color.style.background = current_custom_color;
    return;
  }
  else
  {
    cs1.setrgb(current_color);
    
    document.getElementById("color_select_icon1").style.visibility = "hidden";
    document.getElementById("preview_e1").style.background = current_color;
    document.getElementById("preview_e2").style.background = current_color;
    document.update_cal_form.calendar_events_color.style.background = current_color;
    
    // take focus off the select (in IE, making a selection highlights it in blue, so you cannot see the actual color you picked.  Removing focus makes this go away)
    document.update_cal_form.dummy.style.display='inline';
    document.update_cal_form.dummy.focus();
    document.update_cal_form.dummy.style.display='none';
  } 
  
  //document.add_event_form.evt_bgcolor.style.background = document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].value

  
  //document.update_cal_form.evt_title.focus();
}




function fade_preview()
{
  document.getElementById("bg_preview_e1").style.background = fade("#ffffcc", (1+parseInt(document.update_cal_form.background_events_fade_factor.value)));
  document.getElementById("bg_preview_e2").style.background = fade("#ccffff", (1+parseInt(document.update_cal_form.background_events_fade_factor.value)));

}

function fade(color, fade_factor)
{
  if (!color.match(/#([0-9]|[A-F]){6}/i))  // valid hex #color?
    return false;
  var rgb = hex2rgb(color.substring(1,7));
  var hsv = rgb2hsv(rgb);
  hsv[1] = hsv[1] / fade_factor;
  var new_rgb = hsv2rgb(hsv);
  return "rgb("+new_rgb[0]+","+new_rgb[1]+","+new_rgb[2]+")";
}
// end color_select stuff
p1

  $return_string.=<<p1;
  var help_text="";
  var info_window_x = window_x()-$info_window_width;
  var info_window_y = window_y() + 200;

function show_help() {
  
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{help_box_title}<\\/title>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('$popup_javascript_info');
  
  doc.write('<body onResize=\\"javascript:do_onresize()\\">');
  doc.write(help_text);
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}

function preview_cal() {
  var cal_title = document.update_cal_form.cal_title.value
  var cal_link = document.update_cal_form.cal_link.value
  var cal_details = document.update_cal_form.cal_details.value;
  
  if (cal_title == "") {
    evt_label = "<span style=\\"color:#ff0000\\">$lang{preview_calendar_temp_title}<\\/span>";
    add_disable = true;
  }
  
  //
  if (document.getElementById("preview_warning"))
  {
    document.getElementById("preview_warning").innerHTML="";
  }
  
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{preview_calendar_title}<\\/title>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('$popup_javascript_info');
  
  doc.write('<body onResize=\\"javascript:do_onresize()\\">');
  doc.write("<div class=\\"info_box\\" style=\\"padding:5px;\\"><br/><div style=\\"white-space:nowrap;\\"><span class=\\"cal_title\\">");
  doc.write("<a target=\\"_blank\\" href=\\""+cal_link+"\\">"+cal_title+"<\\/a><\\/span><\\/div><br/><div>"+cal_details+"<\\/div><\\/div>");
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}

function tab_show(tab_num) 
{
  if (tab_num == null) return;
  
  var elList, i;
  i=0;
  // update all tabs.
  while (document.getElementById("tab"+i) && i<100)
  {
    if (i == tab_num) 
    {
    // If the tab is the new active tab, activate it. 
      document.getElementById("tab"+i).className += " active";
      document.getElementById("tab_area"+i).style.display=""
      document.getElementById("tab"+i).blur();
    }
    else
    {
      // Otherwise, make sure the tab is deactivated.
      removename (document.getElementById("tab"+i),"active");
      document.getElementById("tab_area"+i).style.display="none"
    }
    i++;
  }
}
p1

  my %help_text_map = ("cal_title" => "help_cal_title",
                       "cal_link" => "help_cal_link",
                       "cal_details" => "help_cal_details",
                       "cal_password" => "help_new_cal_password",
                       "current_cal_password" => "help_current_cal_password",
                       "change_cal_password" => "help_change_cal_password",
                       "selectable_calendars" => "help_cal_selectable_calendars",
                       "cal_background_calendars" => "help_cal_background_calendars",
                       "help_remote_background_calendars" => "help_remote_background_calendars",
                       "background_events_display_style" => "help_cal_background_events_display_style",
                       "calendar_events_display_style" => "help_calendar_events_display_style",
                       "list_background_calendars_together" => "help_cal_list_background_calendars_together",
                       "number_of_months" => "help_cal_number_of_months",
                       "max_months" => "help_cal_max_months",
                       "gmtime_diff" => "help_cal_gmtime_diff",
                       "date_format" => "help_cal_date_format",
                       "week_start_day" => "help_cal_week_start_day",
                       "new_calendars_automatically_selectable" => "help_cal_new_calendars_automatically_selectable",
                       "allow_remote_calendar_requests" => "help_cal_allow_remote_calendar_requests",
                       "remote_calendar_requests_password" => "help_remote_calendar_requests_password",
                       "preload_event_details" => "help_cal_preload_event_details",
                       "popup_window_size" => "help_cal_popup_window_size",
                       "custom_stylesheet" => "help_cal_custom_stylesheet",
                       "custom_template" => "help_cal_custom_template",
                       );

  my $help_text_javascript = "";                       
  foreach $key (keys %help_text_map)
  {
    my  $help_text=<<p1;
<div class="help_box">
$lang{$help_text_map{$key}}
</div>
p1
    $help_text =~ s/\n/\\n/g;
    $help_text =~ s/"/\\"/g;
    $help_text =~ s/'/\\'/g;
    $help_text =~ s/\//\\\//g;

  
    $help_text_javascript .=<<p1;
    if (topic == "$key")
      help_text += "$help_text";
p1

  }


  $return_string .=<<p1;
function display_help(topic, title) {
  help_text = "";
  $help_text_javascript
  if (help_text != "")
  {
    help_text = "<div class=\\"help_title\\">$lang{help_box_title} - "+title+"</div>" + help_text;
    show_help();
  }
}
p1


  return $return_string
}  #********************end add_edit_calendars_javascript**********************

sub generate_calendar
{
  my $return_text = "";
  my $week_events = {};
  my $week_slots = {};

  my ($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year, $selected_events) = @_;
  #initialize loop variables
  my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year);
  my $cal_end_timestamp = find_end_of_month($cal_end_month, $cal_end_year);

  my $current_month = $cal_start_month;
  my $current_year = $cal_start_year;

  while ($current_year < $cal_end_year || ($current_year == $cal_end_year && $current_month <= $cal_end_month))
  {
    foreach $key (keys %week_events) {delete $week_events{$key};}
    foreach $key (keys %week_slots) {delete $week_slots{$key};}

    #for calendars with multiple months, display the name of each month above the calendar
    if ($cal_num_months > 1)
    {
      $return_text .=<<p1;
<p class="cal_month_title" style="padding:5px;">
$months[$current_month] $current_year
</p>
p1
    }
    #calculate where to start the calendar (first sunday)
    #first, calculate what day of the week this month begins on
  
    #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); 
  
    my $cal_month_start_date = timegm(0,0,0,1, $current_month, $current_year);
    my @cal_month_start_date_array = gmtime $cal_month_start_date;

    my $cal_start_day_offset = $cal_month_start_date_array[6] - $current_calendar{week_start_day};
    if ($cal_start_day_offset < 0)
    {
      $cal_start_day_offset += 7;
    }

    my $cal_start_date = $cal_month_start_date - (86400 * $cal_start_day_offset);
    
    my @cal_start_date_array = gmtime $cal_start_date;
  
    my $cal_end_date = $cal_start_date + 86400*37;
    
    my $next_month = $current_month+1;
    if ($next_month == 12)
    { $next_month=0;}
    
    #cal_date keeps track of the date (in timestamp format)
    #as the calendar loop iterates through each day on the calendar page
    my $cal_date = $cal_start_date;
    my @cal_date_array = gmtime $cal_date;
    
    my %max_day_events;
    my %week_max_slots;

    #make a first pass through the month, assemble event week events structure:
    #week_events{week_index}{id} ={}
    #this hash has 4 keys--start_weekday, start_day, length and slot_order (slot_order will be calculated in the second pass)
    for ($l1=0;$cal_date_array[4] != $next_month;$l1++)  #each calendar has 5 or 6 weeks
    {
      $week_start_timestamp = $cal_date;
      $week_end_timestamp = $week_start_timestamp + 604800;
      $max_day_events{$l1} = 0;
      
      @cal_date_array = gmtime $cal_date;
      foreach $event_id (keys %events)
      {

        my %event = %{$events{$event_id}};
        
        #$debug_info .= "checking event $event_id ($event{start}, $event{end})\n";
        #$debug_info .= "checking event $event_id ($event{start} - $event{end}) against week $l1 ($week_start_timestamp - $week_end_timestamp)\n";
        if (time_overlap($event{start}, $event{end}, $week_start_timestamp, $week_end_timestamp))
        {
          #$debug_info .= "event $event_id\n";
          #$debug_info .= "event $event_id ($event{days} days) in week $l1\n";
          #$debug_info .= "check passed!\n";
      
          @event_date_array = gmtime $event{start};
          $event_start_weekday = $event_date_array[6] - $current_calendar{week_start_day};

          my $days_before_week_start = 0;
          my $days_after_week_end = 0;
          # the event might fall completely within the week boundary, or it
          # might overlap event begins or ends outside the week boundaries
          # (there are four possible cases):
          
          #the event both starts and ends outside this week
          if ($event{start} < $week_start_timestamp && $event{end} > $week_end_timestamp)
          {
            $week_events{$l1}{$event{id}}{start_weekday} = 0;
            $week_events{$l1}{$event{id}}{length} = 7;
          }
          #the event starts before this week and ends within it
          elsif ($event{start} < $week_start_timestamp)
          {
            $days_before_week_start = int(($week_start_timestamp - $event{start})/86400);
            $week_events{$l1}{$event{id}}{start_weekday} = 0;
            $week_events{$l1}{$event{id}}{length} = $event{days} - $days_before_week_start;
          }
          #the event starts within this week and ends after it
          elsif ($event{end} > $week_end_timestamp)
          {
            $days_after_week_end = int(($event{end} - $week_end_timestamp)/86400);
            $week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
            $week_events{$l1}{$event{id}}{length} = $event{days} - $days_after_week_end - 1;  # <-- the -1 is necessary
          }
          #the event begins and ends within the week
          else
          {
            $week_events{$l1}{$event{id}}{length} = $event{days};
            $week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
          }

          if ($week_events{$l1}{$event{id}}{start_weekday} < 0)
          {
            $week_events{$l1}{$event{id}}{start_weekday} += 7;
          }
          elsif ($week_events{$l1}{$event{id}}{start_weekday} > 6)
          {
            $week_events{$l1}{$event{id}}{start_weekday} -= 7;
          }
        }
      }
      
      $temp_debug_info = "";
      $cal_date += 604800;
      
      # each day has at least two slots (the date, and a blank box beneath it)
      for ($l2=0;$l2<7;$l2++)
      {
        $week_slots{$l1}{$l2}{0}{width}=1;
        $week_slots{$l1}{$l2}{0}{depth}=1;
        $week_slots{$l1}{$l2}{1}{width}=1;
        $week_slots{$l1}{$l2}{1}{depth}=1;
      }
      
      
      #order the week_events
      #fill in the %slots data structure:
      # $week_slots{week_index}{day_index}{slot_index}
      #   $width      = colspan
      #   $depth      = rowspan
      #   $spacer     = 1 if spacer slot.
      #   @ids        = event ids
  
  
      # hey man, that's a sharp-lookin' sort you got there.
      foreach $week_event_id (sort {
                                     if ($week_events{$l1}{$b}{length} == $week_events{$l1}{$a}{length})
                                     {
                                       if ($events{$b}{all_day_event} ne "" || $events{$a}{all_day_event} ne "")
                                         {return $events{$b}{all_day_event} cmp $events{$a}{all_day_event}}
                                       else
                                         {return $events{$a}{start} <=> $events{$b}{start};}
                                     }
                                     else
                                       {return $week_events{$l1}{$b}{length} <=> $week_events{$l1}{$a}{length};}
                                   }  keys %{$week_events{$l1}})
      {
        #$debug_info .= "length: $week_events{$l1}{$week_event_id}{length} start: $events{$week_event_id}{start}\n";
        
        $empty_slot = 0;
        
        #starting at 1 leaves a row of empty slots (row 0), where the calendar dates will go.
        for ($l4=1; $empty_slot != 1; $l4++)   
        {
          $empty_slot = 1;
          #check each day of the week_event, to make sure the slot is empty
          for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++) 
          {
            $day_index=$l2+$week_events{$l1}{$week_event_id}{start_weekday};

            if (scalar @{$week_slots{$l1}{$day_index}{$l4}{ids}} > 0)
            {
              $empty_slot = 0;
            }
          }
          $slot_index=$l4;
        }
        
        $temp_debug_info .= "<br/>event: $week_event start weekday $week_events{$l1}{$week_event_id}{start_weekday} slot: $slot_index<br/>";
        
        #fill up $week_slots with the new event (extend horizontally)
        for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++) 
        {
          #$slots_in_row{$l1}{$slot_index}++;

          $day_index = $l2+$week_events{$l1}{$week_event_id}{start_weekday};
          push @{$week_slots{$l1}{$day_index}{$slot_index}{ids}}, $week_event_id;
         
          if ($l2==0)  # first slot gets the width
            {$week_slots{$l1}{$day_index}{$slot_index}{width} = $week_events{$l1}{$week_event_id}{length};}
          else         # other slots get 0 for length (they get absorbed later)
            {$week_slots{$l1}{$day_index}{$slot_index}{width} = 0;}
          $week_slots{$l1}{$day_index}{$slot_index}{depth} = 1;
        }
        
        #keep track of the maximum number of slots each week has
        if ($slot_index > $week_max_slots{$l1})
        {
          $week_max_slots{$l1} = $slot_index;
          $max_day_events{$l1} = $slot_index;

        }
      }
      
      # give all blank slots width and depth of 1
      for ($l2=0;$l2<7;$l2++)
      {
        for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++)   # for each slot
        {
          
          if ($week_slots{$l1}{$l2}{$l3}{depth} eq "" || $week_slots{$l1}{$l2}{$l3}{width} eq "")
          {
            $week_slots{$l1}{$l2}{$l3}{width}=1;
            $week_slots{$l1}{$l2}{$l3}{depth}=1;
          }
        }
      }
      
      #$debug_info .= "week $l1 day 0, slot 2: ".$week_slots{$l1}{0}{2}{ids}[0]."\n";
      
      my $total_spacers=0;
      # insert spacer slots below multi-day events.
      for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++)   # for each slot
      {
        my $inserted_spacers=0;
        for ($l2=0;$l2<7;$l2++)
        {
          #if ($l3 != 3) {next};
          
          if ($week_slots{$l1}{$l2}{$l3}{width} > 1)  #multi-day event, add spacers beneath
          {
            # create spacer row 
            if ($inserted_spacers == 0)
            {
              # move everything else down and increment the number of rows
              $week_max_slots{$l1}++;
              
              for ($l4=0;$l4<7;$l4++)   # insert blank slots
              {
                for ($l5=$week_max_slots{$l1};$l5>$l3+1;$l5--)   # count backwards
                {
                  $week_slots{$l1}{$l4}{$l5} = &deep_copy($week_slots{$l1}{$l4}{$l5-1});
                }
              
                $week_slots{$l1}{$l4}{$l3+1}{width}=1;
                $week_slots{$l1}{$l4}{$l3+1}{depth}=1;
                $week_slots{$l1}{$l4}{$l3+1}{spacer}=0;
                $week_slots{$l1}{$l4}{$l3+1}{ids}=();
              }
              $inserted_spacers=1
            }
            
            # insert spacers into previously created row.
            for ($l4=$l2;$l4<$l2+$week_slots{$l1}{$l2}{$l3}{width};$l4++)   
            {
              $week_slots{$l1}{$l4}{$l3+1}{spacer}=1;
              #$debug_info .= "inserted spacer into row: ".($l3+1).", column $l4, event ".($week_slots{$l1}{$l4}{$l3}{ids}[0])."\n";
              $total_spacers++;
            }      
            #$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n";
            
          }
        }
      }
      
      #$debug_info .= "$total_spacers spacers inserted for week $l1.\n";
      #$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n";


      #$debug_info .= "week $l1, event slots in row 1:  $slots_in_row{$l1}{1}\n";
      
      # calculate slots in each row:
      #for ($l2=0;$l2<7;needed for pre-5.8.3 way of calculating trim.
      {
        for ($l3=1;$l3<$week_max_slots{$l1};$l3++)   # for each slot
        {
          if ((scalar @{$week_slots{$l1}{$l2}{$l3}{ids}}) > 0 )
          {
            $slots_in_row{$l1}{$l3} += $week_slots{$l1}{$l2}{$l3}{width};
            #$debug_info .= "event in row $l1.  Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n";
          }
          if ($week_slots{$l1}{$l2}{$l3}{spacer} == 1)
          {
            $slots_in_row{$l1}{$l3}++;
            #$debug_info .= "spacer in row $l1.  Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n";
          }
        }
      }
      #$debug_info .= "week $l1, event slots in row 1:  $slots_in_row{$l1}{1}\n";




      #$slots_in_row{$l1}{$slot_index}++;

      # extend event slots vertically.
      for ($l2=0;$l2<7;$l2++)   # for each day of the week
      {
        for ($l3=1;$l3<$week_max_slots{$l1};$l3++)   # for each slot
        {
          if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0 && $week_slots{$l1}{$l2}{$l3}{width} > 0) # if this slot begins an event
          {
            my $start_slot = $l3+1;
            for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++)
            {
              #$debug_info .= "checking slot $l4 below event slot ($l2, $l3)\n";
              #if ($week_slots{$l1}{$l2}{$l4}{width} == 0)
              #  {next;}
            
              if (scalar @{$week_slots{$l1}{$l2}{$l4}{ids}} > 0 && $week_slots{$l1}{$l2}{$l4}{width} eq $week_slots{$l1}{$l2}{$l3}{width}) # another event below this one, with the same width.
              {
                #if ($l1 eq "4" && $l2 eq "4" && $l3 eq "2")
                #  {$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";}
                #$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";
                #$debug_info .= "same-width event slot below week $l1, slot ($l2, $l3)\n";
                $week_slots{$l1}{$l2}{$l4}{width}=0;
                $week_slots{$l1}{$l2}{$l4}{depth}=0;
                $week_slots{$l1}{$l2}{$l3}{depth}++;
                push @{$week_slots{$l1}{$l2}{$l3}{ids}}, @{$week_slots{$l1}{$l2}{$l4}{ids}};

                #$slots_in_row{$l1}{$l4}--;

              }
              elsif ($week_slots{$l1}{$l2}{$l3}{width} == 1 && (scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}) == 0 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0) # blank slot below 1-slot wide event slot
              {
                #if ($l1 eq "4" && $l2 eq "4" && $l3 eq "2")
                #  {$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";}
                #$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";
                #$debug_info .= "week $l1 slot ($l2, $l4) # ids:".scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}."\n";
                #$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n";
                $week_slots{$l1}{$l2}{$l4}{width}=0;
                $week_slots{$l1}{$l2}{$l4}{depth}=0;
                $week_slots{$l1}{$l2}{$l3}{depth}++;
                #$debug_info .= "week $l1, slot ($l2, $l3) depth: $week_slots{$l1}{$l2}{$l3}{depth} \n";
              }
              else
              {
                #$debug_info .= "week $l1 slot ($l2, $l4) occupied.  Finished attempting to extend slot $l3\n";
                last;
              }
            }
          }
        }
      }
      #$debug_info .= "week $l1, event slots in row 1:  $slots_in_row{$l1}{1}\n";
      
      # extend blank slots vertically into other blank slots.
      for ($l2=0;$l2<7;$l2++)   # for each day of the week
      {
        for ($l3=1;$l3<$week_max_slots{$l1};$l3++)   # for each slot
        {
          if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0)
            {next;}
        
          if ($week_slots{$l1}{$l2}{$l3}{width} > 0 && $week_slots{$l1}{$l2}{$l3}{spacer} == 0)  # if it's blank (but not a spacer)
          {
            my $start_slot = $l3+1;
            for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++)   
            {
              if ($week_slots{$l1}{$l2}{$l4}{width} == 1 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0)
              {
                #$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n";
                $week_slots{$l1}{$l2}{$l4}{width}=0;
                $week_slots{$l1}{$l2}{$l4}{depth}=0;
                $week_slots{$l1}{$l2}{$l3}{depth}++;
              }
              else
                {last;}
            }
          }
        }
      }
      #$debug_info .= "week $l1, event slots in row 1:  $slots_in_row{$l1}{1}\n";
      #$debug_info .= "week $l1 slot (4, 1) depth: $week_slots{$l1}{4}{1}{depth}\n";
      #$debug_info .= "week $l1 slot (0, 1) width: $week_slots{$l1}{0}{1}{width}\n";




      # yet another pass. trim vertical depth and re-calculate max_slots
      
      # calculate trim
      my $trim = 0;
      #$debug_info .= " week $l1 max slots: $week_max_slots{$l1}\n";
      
      my $max_week_needed_slots=0;
      my %max_day_needed_slots;
      
      for ($l2=0;$l2<7;$l2++)   # for each day of the week
      {
        my $found_single_day_event=0;
        for ($l3=1;$l3<=$week_max_slots{$l1};$l3++)
        {
          if ($week_slots{$l1}{$l2}{$l3}{width} > 1) # if multi-day, or a spacer
          {
            #$debug_info .= "week $l1, found multi-day event (day $l2, width $week_slots{$l1}{$l2}{$l3}{width})\n";
            for ($l4=0;$l4<$week_slots{$l1}{$l2}{$l3}{width};$l4++)
            {
              #$debug_info .= "week $l1, adding needed slot to day ".($l2+$l4)."\n";
              $max_day_needed_slots{$l2+$l4}++;
            }
          }
          elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0)
          {
            $max_day_needed_slots{$l2}++;
            #$debug_info .= "week $l1, found spacer (day $l2)\n";
  
          }
          elsif (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0) # single-day event
          {
            $found_single_day_event=1;
            #$debug_info .= "week $l1, found single day event (day $l2)\n";
          }
        }
        $max_day_needed_slots{$l2} += $found_single_day_event;
      }
      #$debug_info .= "week $l1, max_day_needed_slots: $max_day_needed_slots{0} $max_day_needed_slots{1} $max_day_needed_slots{2} $max_day_needed_slots{3} $max_day_needed_slots{4} $max_day_needed_slots{5} $max_day_needed_slots{6} $max_day_needed_slots{7}\n";
      
      $max_week_needed_slots = max(values %max_day_needed_slots);
      
      #if ($max_day_needed_slots >$max_week_needed_slots)
      #  {$max_week_needed_slots = $max_day_needed_slots;}
      #$debug_info .= "max needed slots for week $l1, $max_week_needed_slots\n";
      
      my $trim = $week_max_slots{$l1} - $max_week_needed_slots;     
      
      
      # apply trim
      #$debug_info .= "trim for week $l1, $trim\n";
      for ($l2=0;$l2<7;$l2++)   # for each day of the week
      {
        for ($l3=$week_max_slots{$l1};$l3>0;$l3--)   # for each slot, counting backwards (upwards)
        {
          if ($week_slots{$l1}{$l2}{$l3}{depth} > 0)  # blank or non-blank, with depth > 0
          {
            #$debug_info .= "trimming week $l1, slot ($l2, $l3) by $trim\n";
            $week_slots{$l1}{$l2}{$l3}{depth} = $week_slots{$l1}{$l2}{$l3}{depth} - $trim;
            last;
          }
        }
      }
    
      $week_max_slots{$l1} = $week_max_slots{$l1} - $trim;
    
    }  # repeat for next week




    # print day names
    $return_text .=<<p1;
<table class="calendar">
<tr>
<td class="day_names">$weekday_sequence[0]</td>
<td class="day_names">$weekday_sequence[1]</td>
<td class="day_names">$weekday_sequence[2]</td>
<td class="day_names">$weekday_sequence[3]</td>
<td class="day_names">$weekday_sequence[4]</td>
<td class="day_names">$weekday_sequence[5]</td>
<td class="day_names">$weekday_sequence[6]</td>
</tr>
p1
    #cal_date keeps track of the date (in timestamp format)
    #as the calendar loop iterates through each day on the calendar page
    $cal_date = $cal_start_date;
    @cal_date_array = gmtime $cal_date;
    
    #locked and loaded, data structures assembled--now it's time to kick it, calendar-style.
    for ($l1=0;$cal_date_array[4] != $next_month; $l1++)  #each calendar has 5 or 6 weeks
    {
      my $last_week=0;
      my $timestamp_next_week = $cal_date+604800;
      my @timestamp_next_week_array = gmtime $timestamp_next_week;
    
      if ($timestamp_next_week_array[4] == $next_month)
      {
        $last_week = 1;
      }

      my $week_date_index = $cal_date;


      # draw the table!
      for ($l3=0;$l3<$week_max_slots{$l1}+1;$l3++)
      {     
        $return_text .="<tr>";

        $week_date_index = $cal_date;
        for ($l2=0;$l2<7;$l2++) # 7 days / week
        {
          @cal_date_array = gmtime $week_date_index;
          my $td_class = "day ".lc($day_names[$l2]);
          if ($cal_date_array[4] == $rightnow_month && 
              $cal_date_array[3] == $rightnow_mday && 
              $cal_date_array[5]+1900 == $rightnow_year)
            {$td_class .= " today";}
            
          #display date numbers differently, depending on whether they are
          #in the current month or not
          if ($cal_date_array[4] != $current_month)
            {$td_class .= " other_month";}
      
          #if ($l2 == $week_events{$l1}{$week_slots{$l1}{$l2}{$l3}{id}}{start_weekday} && $week_events{$l1}{$week_slots{$l1}{$l2}{$l3}{id}}{start_weekday} ne "")
          
          
          if ($l3 == 0)  #if it's the top blank slot, put the date in there.
          {
            $td_style="border-bottom-width:0px;";
            
            #display the cell differently if it is today.
            if ($cal_date_array[4] == $rightnow_month && 
                $cal_date_array[3] == $rightnow_mday && 
                $cal_date_array[5]+1900 == $rightnow_year)
            {
              # offset the date number a few pixels
              # (so it will be in the center of the red circle)
              # offset a bit more for a double-digit day number.
              # small touches are the difference between good and great :)
                
              my $date_div_style = "";
              if ($rightnow_mday > 10)
                {$date_div_style = "text-indent: 11px;";}

              $return_text .=<<p1;
<td class="$td_class" style="$td_style" onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
<div class="date today" style="$date_div_style"><a id="today"></a>$cal_date_array[3]</div>
</td>
p1
            }
            else
            {
              $return_text .=<<p1;
<td class="$td_class" style="$td_style" onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
<div class="date">$cal_date_array[3]</div>
</td>
p1
            }
          }
          elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0)  # spacer slot
          {
            my $spacer_class = "spacer";
            if ($l3 == $week_max_slots{$l1}-1)
            {
              $spacer_class .= " bottom";
            }
            $return_text .=<<p1;
<td class="$td_class $spacer_class" style="$td_style" colspan=1 rowspan=1 onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
</td>
p1
          }
          elsif ($week_slots{$l1}{$l2}{$l3}{width} != 0)  # slot containing events
          {
            $num_cols = $week_slots{$l1}{$l2}{$l3}{width};
            $num_rows = $week_slots{$l1}{$l2}{$l3}{depth};
          
            if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0)
            {
            
              $td_style="border-top-width:0px;border-bottom-width:0px;";
              
#($l2,$l3) $num_cols\lx$num_rows
              $return_text .=<<p1;
<td class="$td_class" style="$td_style" colspan=$num_cols rowspan=$num_rows onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
p1
            
              foreach $event_id (@{$week_slots{$l1}{$l2}{$l3}{ids}})
              {
                my $event_bgcolor = $events{$event_id}{bgcolor};
                
                if ($current_calendar{calendar_events_color} ne "")
                  {$event_bgcolor = $current_calendar{calendar_events_color};}
                
                my $event_box_class = "event_box";
            
                my $event_in_current_calendar = 0;
                
                foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
                {
                  if ($temp_cal_id eq $current_calendar{id})
                  {
                    $event_in_current_calendar = 1;
                    last;
                  }
                }
            
                # handle link
                my $event_link = "javascript:display_event('$event_id');";
                if ($events{$event_id}{details_url} eq "1")
                  {$event_link = "$events{$event_id}{details}";}
            
                if ($event_in_current_calendar eq "0")
                {
                  $event_box_class .= " background";
                 
                  if ($calendars{$events{$event_id}{cal_ids}[0]}{calendar_events_color} ne "")
                    {$event_bgcolor = $calendars{$events{$event_id}{cal_ids}[0]}{calendar_events_color};}

                    
                  if ($current_calendar{background_events_display_style} eq "single_color")
                    {$event_bgcolor = $current_calendar{background_events_color};}
                  elsif ($current_calendar{background_events_display_style} eq "faded")
                  {
                    # create "faded" look for background event
                    my $faded_color = $event_bgcolor;
                 
                    #convert rgb values from hex (00-FF) to decimal integer (0-255)
                    my $r = hex substr $faded_color,1,2;
                    my $g = hex substr $faded_color,3,2;
                    my $b = hex substr $faded_color,5,2;
                  
                    #convert integer rgb values to hsv
                    my @hsv_array = &rgb2hsv($r,$g,$b);
                  
                    #convert s and v from percentages to decimal
                    $hsv_array[1] = $hsv_array[1]/100;
                    $hsv_array[2] = $hsv_array[2]/100;
                    
                    #"fade" the color (decrease saturation)
                    $hsv_array[1] = $hsv_array[1]/$current_calendar{background_events_fade_factor};
                  
                    my @new_rgb_array = &hsv2rgb($hsv_array[0],$hsv_array[1],$hsv_array[2]);
  
                    #convert back to hex
                    $r = (sprintf ("%1.1X",$new_rgb_array[0]));
                    $g = (sprintf ("%1.1X",$new_rgb_array[1]));
                    $b = (sprintf ("%1.1X",$new_rgb_array[2]));
                  
                   #$debug_info .= "<table><tr><td>initial:$intial_values<br/>$hsv_values<br/>new:$new_rgb_values</td><td bgcolor=$events{$week_slots{$l1}{$l2}{$l3}{id}}{bgcolor}>color</td>   <td bgcolor=$faded_color>faded color</td></tr></table><br/>\n";
                    $event_bgcolor = "#$r$g$b";
                  }
                }
              
                # handle icon
                my $icon_text = "";
                my $unit_icon_text = "";
                if ($events{$event_id}{unit_number} ne "")
                {
                  $unit_icon_text = $events{$event_id}{unit_number};
                  $unit_icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" border="0" alt=\"\" vspace=0 hspace=0 style="vertical-align:middle;">/g;
                }
              
                my $link_style="";
                if ($events{$event_id}{icon} ne "blank")
                {
                  $icon_text = <<p1;
<img align="bottom" src = "$icons_url/$events{$event_id}{icon}_16x16.gif" style="margin-left:-22px;margin-right:5px;margin-bottom:-5px;" alt="">
p1
                  chomp $icon_text;
                  $link_style="padding-left:29px";
                }
              
                # context menu stuff
                my $event_context_menu_text="onmousedown=\"if (event.shiftKey) return show_event_contextmenu(event, $event_id, '$event_bgcolor', '$events{$event_id}{series_id}'); else return false; \" oncontextmenu=\"return show_event_contextmenu(event, $event_id, '$event_bgcolor', '$events{$event_id}{series_id}');\"";
                if ($event_id =~ /\D/)
                  {$event_context_menu_text=""}
              
                if ($week_slots{$l1}{$l2}{$l3}{width} == 1)
                {
                  my $event_time = "";
                  if ($events{$event_id}{all_day_event} ne "1")
                  {
                    $event_time = &nice_time_range_format($events{$event_id}{start}, $events{$event_id}{end});
                    $event_time = "<span class=\"event_time\">$event_time</span> ";
                  }
                  $return_text .=<<p1;
<a href="$event_link" class="$event_box_class" style="display:block;text-align:left;$link_style;background-color:$event_bgcolor;cursor:pointer;cursor:hand;" $event_context_menu_text>
$icon_text$unit_icon_text<span style="margin-left:5px;">$event_time$events{$event_id}{title}</span></a>
p1
                }
                else # multi-day-event
                {
                  # handle the case where an event is < 24 hours and crosses midnight.
                  my $temp="";
                  my $event_time = "";
                  if ($events{$event_id}{all_day_event} ne "1")
                  {
                    #my $offset = int(100*($events{$event_id}{start} - $week_date_index)/(86400*$week_slots{$l1}{$l2}{$l3}{width}));
                    #my $width = int(100*($events{$event_id}{end} - $events{$event_id}{start})/(86400*$week_slots{$l1}{$l2}{$l3}{width}));
                    my $offset = 25;
                    my $width = 50;
                    $temp = "width:$width%;position:relative;left:$offset%;";
                    $event_time = &nice_time_range_format($events{$event_id}{start}, $events{$event_id}{end});
                    $event_time = "<span class=\"event_time\">$event_time</span>";
                  }
                
                  if ($events{$event_id}{icon} ne "blank")
                  {
                    $icon_text = <<p1;
<img src="$icons_url/$events{$event_id}{icon}_16x16.gif" style="vertical-align:middle;margin-right:5px;" alt="">
p1
                    chomp $icon_text;
                  }

                
                  $return_text .=<<p1;
<a href="$event_link" class="$event_box_class" style="display:block;text-align:center;background-color:$event_bgcolor;cursor:pointer;cursor:hand;$temp" $event_context_menu_text>
$icon_text$unit_icon_text<span style="margin-left:5px;">$event_time $events{$event_id}{title}</span></a>
p1
p1
                }

              }  # next event id
            
              $return_text .=<<p1;
</td>
p1
            }
            elsif ($week_slots{$l1}{$l2}{$l3}{ids} eq "" && $week_slots{$l1}{$l2}{$l3}{width} > 0)  # blank slot
            {
              $td_style="border-top-width:0px;border-bottom-width:0px;";
            
#($l2,$l3) blank $num_cols\lx$num_rows
              $return_text .=<<p1;
<td class="$td_class" style="$td_style" colspan=$num_cols rowspan=$num_rows onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
</td>
p1
            }
          }
          $week_date_index += 86400;
        }  # next day
        
        #right border
        $return_text .=<<p1;
</tr>
p1
      } # event slot index

      
      # this little trick is the cat's pajamas.  It's another row of 
      # table cells that cause each calendar day to come down a little
      # bit below the lowest event.  It makes the calendar
      # look sharp.

      # Also, if the week has a small number of
      # events, we expand the height of the bottom cell.  
      # This makes all the calendar cells look square, 
      # which is the bee's knees.
      
      my $bottom_height_style = "";
      if ($max_day_events{$l1} < 2)
      {
        my $height = (4-$max_day_events{$l1}) . "em";   # this algorithm was developed by guess & check
        #my $height = "100px";   # this algorithm was developed by guess & check
        $bottom_height_style = "line-height:$height;";
      }
      $return_text .=<<p1;
<tr style="$bottom_height_style">
p1
      $week_date_index = $cal_date;
      for ($l2=0;$l2<7;$l2++) #each week has 7 days(!)
      {
        my $td_class = "";
        @cal_date_array = gmtime $week_date_index;
        $td_class .= "day ".lc($day_names[$l2])." cell_bottom";

        if ($cal_date_array[4] != $current_month)
        {
          $td_class .= " other_month";
        }
        
        if ($cal_date_array[4] == $rightnow_month && 
            $cal_date_array[3] == $rightnow_mday && 
            $cal_date_array[5]+1900 == $rightnow_year)
        {$td_class .= " today";}
        
        $return_text .=<<p1;
<td class="$td_class" style="line-height:5px;border-top-width:0px;$bottom_height_style"  onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">&nbsp;</td>
p1
        $week_date_index+=86400;
      }
      $return_text .=<<p1;
</tr>
p1
     $cal_date+=604800;

    }
    
    $return_text .=<<p1;
</table>
<br style="page-break-after:always;">
p1

    #increment to the next month--the method used 
    #here is the most painless way of making 
    #this work the right way in all cases.
    $current_month++;
    if ($current_month == 12)
    {
      $current_month=0;
      $current_year++;
    }
  }
  
  return $return_text;
}  #********************end generate_calendar subroutine**********************



sub generate_list
{
  my $return_text = "";
  ($start_month, $start_year, $end_month, $end_year) = @_;
    
  #calculate where to start and end the list
  
  #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); 
  my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
  my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
  
  # loop through all the events.  
  
  #Create an array of events which fall 
  # within the current list view dates
  my @selected_cal_events;
  
  #and a funky data structure for the background calendars 
  # each element of this hash will be an array.
  my $shared_cal_events={};  #empty hash
  
  foreach $event_id (keys %events)
  {
    if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
    {
      my $event_in_current_calendar = 0;
      
      foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
      {
        if ($temp_cal_id eq $current_cal_id)
          {push @selected_cal_events, $event_id;}
          
        foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
        {
          if ($temp_cal_id eq $background_cal_id)
            {push @{$shared_cal_events{$background_cal_id}}, $event_id;}
        }
      }
    }
  }
  
  # initialize loop variables
  $current_month = $start_month;
  $current_year = $start_year;
  
    $return_text .=<<p1;
p1
 
  while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month))
  {
    my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
    my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
  
    $return_text .=<<p1;
<div class="list_month_box">
p1

    if ($cal_num_months> 1)
    {
      $return_text .=<<p1;
$months[$current_month] $current_year
p1
    }
    
    $return_text .=<<p1;
<ul class="list_cal_box" style="list-style-type:none;float:left;text-align:left;">
<li style="text-align:center;font-weight:bold;">$calendars{$current_cal_id}{title}</li>
p1
    #display events for selected calendar
    foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events)
    {
      %event = %{$events{$event_id}};
      if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
      {  
        @event_start_timestamp_array = gmtime $event{start};
        
        if ($event{days} == 1)
        { #single-day event
          $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
        }
        else #multi-day event
        {
          @event_end_timestamp_array = gmtime $event{end};
          if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4])
          {
            $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]";
          }
          else
          {
            $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $months_abv[$event_end_timestamp_array[4]] $event_end_timestamp_array[3]";
          }
        }
        
        my $icon_text="";
        my $unit_icon_text="";
        if ($event{unit_number} ne "")
        {
          $icon_text = $event{unit_number};
          $icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" style=\"vertical-align:middle;\" alt=\"\">/g;
        }

        if ($event{icon} eq "blank")
        {
          $icon_text .= "$unit_icon_text";
        }
        else
        {
          $icon_text .= "$unit_icon_text<img src = \"$icons_url/$event{icon}_16x16.gif\" style=\"vertical-align:middle;\" alt=\"\">";
        }

        my $event_context_menu_text="onmousedown=\"if (event.shiftKey) return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$event{series_id}'); else return false;\" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$event{series_id}');\"";
        if ($event_id =~ /\D/)
          {$event_context_menu_text=""}

        # event time
        my $event_time = "";
        if ($event{all_day_event} ne "1")
        {
          $event_time = &nice_time_range_format($event{start}, $event{end});
          $event_time = "<span class=\"event_time\">$event_time</span>";
        }
        
        my $event_link = "javascript:display_event('$event{id}');";
        if ($event{details_url} eq "1")
          {$event_link = "$event{details}";}
       
        $return_text .=<<p1;
<li style="margin-top:10px;margin-bottom:4px;"$event_context_menu_text>
<span class="small_note" style="border:0;vertical-align:middle;width:7em;white-space:nowrap;text-align:right;cursor:pointer;cursor:hand;"  onclick="display_event('$event_id')"> $date_string </span>
<a class="event_box" style="text-align:left;white-space:nowrap;margin-bottom:2px;background-color:$event{bgcolor};" href="$event_link"> $icon_text $event_time $event{title}</a>
</li>
p1
      }
    }


    if ($current_calendar{list_background_calendars_together} ne "yes")
    {
      $return_text .=<<p1;
</ul>
p1
    }
    
    foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
    {
      if ($current_calendar{list_background_calendars_together} eq "no")
      {
        $return_text .=<<p1;
<ul class="list_cal_box background" style="list-style-type:none;float:left;text-align:left;">
<li style="text-align:center;font-weight:bold;">$calendars{$background_cal_id}{title}</li>
p1
      }
      #list events for that calendar
      foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
      {
        
        %event = %{$events{$event_id}};
        if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
        {  
          @event_start_timestamp_array = gmtime $event{start};
          #if the event headline is longer than 30 characters,
          #split it into another line after the second word.
          if ($event{days} == 1)
          { #single-day event
            $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
          }
          else #multi-day event
          {
            @event_end_timestamp_array = gmtime $event{end};
            if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4])
            {
              $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]";
            }
            else
            {
              $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $months_abv[$event_end_timestamp_array[4]] $event_end_timestamp_array[3]";
            }
          }
          
          my $icon_text="";
          if ($event{unit_number} ne "")
          {
            $icon_text = $event{unit_number};
            $icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" style=\"vertical-align:middle;\" alt=\"\" vspace=0>/g;
          }

          if ($event{icon} eq "blank")
          {
            $icon_text .= "$unit_icon_text";
          }
          else
          {
            $icon_text .= "$unit_icon_text<img src = \"$icons_url/$event{icon}_16x16.gif\" style=\"vertical-align:middle;\" alt=\"\" vspace=0>";
          }
          
          my $date_style="line-height:120%;";
          if ($icon_text eq "")
            {$date_style="";}

          my $event_context_menu_text="onmousedown=\"if (event.shiftKey) return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$event{series_id}'); else return false;\" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$event{series_id}');\"";
          if ($event_id =~ /\D/)
            {$event_context_menu_text=""}

          # event time
          my $event_time = "";
          if ($event{all_day_event} ne "1")
          {
            $event_time = &nice_time_range_format($event{start}, $event{end});
            $event_time = "<span class=\"event_time\">$event_time</span>";
          }



          #if ($event_id == 184 || $event_id == 185 || $event_id == 213 || $event_id == 161)
          #{
          #  $debug_info .= "event $event_id, all-day: $event{all_day_event}\n";
          #}

        my $event_link = "javascript:display_event('$event{id}');";
        if ($event{details_url} eq "1")
          {$event_link = "$event{details}";}


          $return_text .=<<p1;
<li style="margin-top:10px;margin-bottom:4px;white-space:nowrap;" $event_context_menu_text>
<span class="small_note" style="border:0;vertical-align:middle;width:7em;white-space:nowrap;text-align:right;cursor:pointer;cursor:hand;"> $date_string </span>
<a class="event_box" style="text-align:left;white-space:nowrap;margin-bottom:2px;background-color:$event{bgcolor};" href="$event_link"> $icon_text $event_time $event{title}</a>
</li>
p1
        }
      }
      if ($current_calendar{list_background_calendars_together} ne "yes")
      {

        $return_text .=<<p1;
</ul>
<br style="clear:both;"/>  <!--needed because IE sucks-->
p1
      }
    }
    
    if ($current_calendar{list_background_calendars_together} eq "yes")
    {
      $return_text .=<<p1;
</ul>
p1
    }

        $return_text .=<<p1;
<br style="clear:both;"/> <!-- because IE sucks-->
<br style="clear:both;"/> <!-- because IE sucks-->
</div>
<br style="clear:both;"/> <!-- because IE sucks-->
<br style="clear:both;"/> <!-- because IE sucks-->
p1
    
    #increment to the next month--the method used 
    #here is the most painless way of making 
    #this work the right way in all cases.
    $current_month +=1;
    if ($current_month == 12)
    {
      $current_month=0;
      $current_year++;
    }
  }
  
  $return_text .=<<p1;
p1
  return $return_text;
  
}  #********************end generate_list subroutine**********************


sub generate_event_details_javascript
{
  my ($events_start_timestamp, $events_end_timestamp) = @_;
  
  my $return_string="";
 
  my $num_events = 0;
  my $num_remote_events = 0;
  my $event_defs="";
  my $remote_event_defs="";

  $index=0;

  #loop through the events, check to see if they fall 
  #within the current calendar month
  foreach $event_id (keys %events)
  {
    my %event = %{$events{$event_id}};
    if (&time_overlap($event{start},$event{end},$events_start_timestamp,$events_end_timestamp))
    {
    
      if ($event_id =~ /^r/)
      {
        $num_remote_events++;
        $remote_event_defs .= <<p1;
remote_event_details["$event_id"] = new Object;
remote_event_details["$event_id"].url = "$event{remote_calendar}{url}?view_event=1&evt_id=$event{remote_event_id}";
p1

      }
      else
      {
        $num_events++;
        my $event_details = &generate_event_details(\%event);
 
        $event_detail_text =<<p1;
$event_details      
p1

        #prepare event detail text to be stored in a javascript array
        $event_detail_text =~ s/\n/\\n/g;
        $event_detail_text =~ s/"/\\"/g;
        $event_detail_text =~ s/\//\\\//g;

        $event_defs .= <<p1;
event_details[$event_id] = new Object;
event_details[$event_id].id = "$event_id";
event_details[$event_id].text = "$event_detail_text";
p1
        $index++;
      }
    }
  }

  $return_string .=<<p1;
var remote_event_details = new Array($num_remote_events);
$remote_event_defs
var event_details = new Array($num_events);
$event_defs
p1
  return $return_string;
      
}  #********************end generate_event_details_javascript subroutine**********************

sub cal_info_view_javascript
{
  my $return_string ="";
  
  $return_string .= &generate_cal_details_javascript();

  my $javascript_info = "";
  if ($browser_type eq "IE")
  {
    $javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = document.body.clientWidth;
  opener.info_window_height = document.body.clientHeight;
}
//-->
</script> 
p1
  }
  else
  {
    $javascript_info .=<<p1;
<script type="text/javascript" ><!--
function do_onresize()
{
  opener.info_window_width = this.outerWidth;
  opener.info_window_height = this.outerHeight;
}
//-->
</script> 
p1
  }
  

  $javascript_info =~ s/\n/\\n/g;
  $javascript_info =~ s/"/\\"/g;
  $javascript_info =~ s/\//\\\//g;

  
  $return_string .=<<p1;
function display_cal_info(cal_id) {
  
  if (cal_id == "")
  {
    return;
  }
  info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
  
  doc = info_window.document;
  doc.open('text/html');
  doc.write('<html>');
  doc.write('<title>$lang{calendar_details}<\\/title>');
  doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
  doc.write('<base target=\\"'+main_window_name+'\\">');
  doc.write('$javascript_info');
  
  doc.write('<body onResize=\\"javascript:do_onresize()\\">');
  doc.write(cal_details[cal_id].text);
  doc.write('<\\/body><\\/html>');
  doc.close();
  info_window.focus();
}

function do_on_load() {
}
p1
  
  return $return_string;
}  #********************end cal_view_inf0_javascript subroutine**********************

sub generate_cal_details()
{
  my ($calendar_ref) = @_;
  
  my %calendar = %{$calendar_ref};
  
  my $return_text = <<p1;
<div class="cal_title">
$calendar{title}
</div>

<div>
$calendar{details}
</div>
p1

$writable{calendar_file}  and $return_text .= <<p1;
<div style="white-space:nowrap;">
<span class="small_note">
<a href="$script_url/$name?active_tab=2&amp;add_edit_cal_action=edit&amp;cal_id=$calendar{id}">$lang{calendar_add_edit}</a>
</span>
</div>
p1

  $return_text .= <<p1;
<div style="white-space:nowrap;margin-top:2em;">
<span class="small_note">
$lang{calendar_direct_link}<br/>
<a href="$script_url/$name?cal_id=$calendar{id}">$script_url/$name?cal_id=$calendar{id}</a>
</span>
</div>


p1

  return $return_text;
}




sub generate_cal_details_javascript()
{
  my $return_string ="";
  my $cal_detail_text = "";

  foreach $cal_id (sort {$a <=> $b} keys %calendars)
  {
    $cal_detail_text = &generate_cal_details($calendars{$cal_id});
  
    $cal_detail_text =~ s/\n/\\n/g;
    #$cal_detail_text =~ s/\n/adsf/g;
    $cal_detail_text =~ s/"/\\"/g;
    $cal_detail_text =~ s/\//\\\//g;
  
    $cal_defs .=<<p1;
cal_details[$cal_id] = new Object;
cal_details[$cal_id].text = "$cal_detail_text";
p1
  }
  
  
  $num_calendars = scalar keys %calendars;
  $return_string .=<<p1;
var cal_details = new Array($num_calendars);  // array to hold calendar details
$cal_defs
p1

  return $return_string;

}  #********************end generate_cal_details_javascript subroutine**********************


sub csv_file
{

  ($start_month, $start_year, $end_month, $end_year) = @_;
    
  #calculate where to start and end the list
  
  #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); 
  my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
  my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
  
  #@cal_month_start_date_array = gmtime $cal_month_start_date;

  # loop through all the events.  
  
  #Create an array of events which fall 
  # within the current list view dates
  my @selected_cal_events;
  
  #and a funky data structure for the background calendars 
  # each element of this hash will be an array.
  my $shared_cal_events={};  #empty hash
  
  foreach $event_id (keys %events)
  {
    if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
    {
      my $event_in_current_calendar = 0;
      
      foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
      {
        if ($temp_cal_id eq $current_cal_id)
          {push @selected_cal_events, $event_id;}
        foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
        {
          if ($temp_cal_id eq $background_cal_id)
            {push @{$shared_cal_events{$background_cal_id}}, $event_id;}
        }
      }
    }
  }
  
  $html_output =<<p1;
Cache-control: no-cache,no-store,private
Content-disposition: filename="events.csv"
Content-Type: text/plain; charset=$lang{charset}\n\n
p1
  #initialize loop variables
  #$current_timestamp = $list_start_timestamp;
  $current_month = $start_month;
  $current_year = $start_year;

  $html_output .=<<p1;
"Subject","Start Date","Start Time","End Date","End Time","All day event","Reminder on/off","Reminder Date","Reminder Time","Meeting Organizer","Required Attendees","Optional Attendees","Meeting Resources","Billing Information","Categories","Description","Location","Mileage","Priority","Private","Sensitivity","Show time as"
p1

  
  while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month))
  {
    my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
    my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
    #display events for selected calendar
    foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events)
    {
      my %event = %{$events{$event_id}};

      if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
      {
        my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})";
      
        @event_start_timestamp_array = gmtime $event{start};
        my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
        my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]);
        
        @event_end_timestamp_array = gmtime $event{end};
        my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
        my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]);
        
        my $csv_description = $event{details};
        $csv_description =~ s/"/""/g;
        $csv_description =~ s/\n/\\n/g;
         
        if ($event{days} != 1)
        {
          @event_end_timestamp_array = gmtime $event{end};
          $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
        }
        
        $html_output .=<<p1;
"$csv_subject","$csv_start_date","$csv_start_time",$csv_end_date,"$csv_end_time","True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1"
p1
      }
    }
    foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
    {
      #list events for that calendar
      foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
      {
        my %event = %{$events{$event_id}};

        if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
        {
          my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})";
      
          @event_start_timestamp_array = gmtime $event{start};
          my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
          my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]);
 
          @event_end_timestamp_array = gmtime $event{end};
          my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
          my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]);
 
          my $csv_description = $event{details};
          $csv_description =~ s/"/""/g;
          $csv_description =~ s/\n/\\n/g;

          $csv_description =~ s/"/""/g;
          $csv_description =~ s/\n/\\n/g;
        
        
          if ($event{days} != 1)
          {
            @event_end_timestamp_array = gmtime $event{end};
            $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
          }
        
          $html_output .=<<p1;
"$csv_subject","$csv_start_date","$csv_start_time",$csv_end_date,"$csv_end_time","True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1"
p1
        }
      }
    }
    
    #increment to the next month--the method used 
    #here is the most painless way of making 
    #this work the right way in all cases.
    $current_month +=1;
    if ($current_month == 12)
    {
      $current_month=0;

      $current_year++;
    }
  }
  $html_output .= $debug_info;
  print $html_output;
}


sub vcalendar_export_cal
{
  ($start_month, $start_year, $end_month, $end_year) = @_;
    
  #calculate where to start and end the list
  
  #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); 
  my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
  my $list_end_timestamp = &find_end_of_month($end_month, $end_year);

  # loop through all the events.  
  
  #Create an array of events which fall 
  # within the current list view dates
  my @selected_cal_events;
  
  #and a funky data structure for the background calendars 
  # each element of this hash will be an array.
  my $shared_cal_events={};  #empty hash
  
  foreach $event_id (keys %events)
  {
    if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
    {
      my $event_in_current_calendar = 0;
      
      foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
      {
        if ($temp_cal_id eq $current_cal_id)
          {push @selected_cal_events, $event_id;}
        foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
        {
          if ($temp_cal_id eq $background_cal_id)
            {push @{$shared_cal_events{$background_cal_id}}, $event_id;}
        }
      }
    }
  }

  
  my $csv_string = "";
  
  $html_output =<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/csv; charset=$lang{charset}
Content-disposition: filename="events.csv"

p1
  #initialize loop variables
  #$current_timestamp = $list_start_timestamp;
  $current_month = $start_month;
  $current_year = $start_year;

  $html_output .=<<p1;
CSV datebook: Category, Private, Description, Note, Event, Begin, End, Alarm, Advance, Advance Units, Repeat Type, Repeat Forever, Repeat End, Repeat Frequency, Repeat Day, Repeat Days, Week Start, Number of Exceptions, Exceptions
p1

  
  while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month))
  {
    my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
    my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
    #display events for selected calendar
    foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events)
    {
      my %event = %{$events{$event_id}};

      if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
      {
        my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})";
      
        @event_start_timestamp_array = gmtime $event{start};
        my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
        my $csv_end_date = $csv_start_date;
        my $csv_description = $event{details};
        $csv_description =~ s/"/""/g;
        $csv_description =~ s/\n/\\n/g;

        
        if ($event{days} != 1)
        {
          @event_end_timestamp_array = gmtime $event{end};
          $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
        }
        $html_output .= &event2vcal(\%event)."\n";
      }
    }
    foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
    {
      #list events for that calendar
      foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
      {
        my %event = %{$events{$event_id}};

        if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
        {
          my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})";
      
          @event_start_timestamp_array = gmtime $event{start};
          my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
          my $csv_end_date = $csv_start_date;
          my $csv_description = $event{details};
          $csv_description =~ s/"/""/g;
          $csv_description =~ s/\n/\\n/g;
        
        
          if ($event{days} != 1)
          {
            @event_end_timestamp_array = gmtime $event{end};
            $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
          }
        
          $html_output .= &event2vcal(\%event)."\n";
        }
      }
    }
    
    #increment to the next month--the method used 
    #here is the most painless way of making 
    #this work the right way in all cases.
    $current_month +=1;
    if ($current_month == 12)
    {
      $current_month=0;

      $current_year++;
    }
  }
  $html_output .= $debug_info;
  print $html_output;
}




sub ascii_text_cal
{

  ($start_month, $start_year, $end_month, $end_year) = @_;
    
  #calculate where to start and end the list
  
  #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); 
  my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
  my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
  
  # loop through all the events.  
  
  #Create an array of events which fall 
  # within the current list view dates
  my @selected_cal_events;
  
  #and a funky data structure for the background calendars 
  # each element of this hash will be an array.
  my $shared_cal_events={};  #empty hash
  
  foreach $event_id (keys %events)
  {
    if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
    {
      my $done = 0;
      foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
      {
        if ($temp_cal_id eq $current_cal_id)
          {push @selected_cal_events, $event_id;}
        foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
        {
          if ($temp_cal_id eq $background_cal_id)
          {
            push @{$shared_cal_events{$background_cal_id}}, $event_id;
            $done = 1;
            last;
          }
        }
        if ($done == 1) {last;}
      }
    }
  }

  $html_output =<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/plain; charset=$lang{charset}\n\n
p1
  #initialize loop variables
  #$current_timestamp = $list_start_timestamp;

  $current_month = $start_month;
  $current_year = $start_year;
  
  while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month))
  {
    my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
    my $current_month_end_timestamp = &find_end_of_month($current_month,$current_year);
  
    $html_output .=<<p1;
    
*******************************************
$months[$current_month] $current_year 
*******************************************

* $current_calendar{title}
p1
    #display events for selected calendar
    foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events)
    {
      %event = %{$events{$event_id}};

      if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
      {  
        @event_start_timestamp_array = gmtime $event{start};
        my $event_time = "";
        if ($event{days} == 1)
        { #single-day event
          $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] ".($event_start_timestamp_array[5]+1900);
          if ($event{all_day_event} ne "1")
          {
            $event_time = &nice_time_range_format($event{start}, $event{end});
            $event_time = " ($event_time)";
          }
        }
        else #multi-day event
        {
          $date_string = &nice_date_range_format($event{start}, $event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
        }
        my $event_details = $event{details};
        $event_details =~ s/\n\s+/\n/g;
        $event_details =~ s/\n{2,}/\n/g;
        chomp $event_details;
        
        #indent each line of the details 
        $event_details =~ s/\n/\n    /g;

        
        $html_output .="  $date_string$event_time: $event{title}\n";
        if ($event_details ne "")
        {
          $html_output .= "    $event_details\n\n";
        }
      }
    }
    
    foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
    {
      $html_output .=<<p1;
* $calendars{$background_cal_id}{title}
p1
      #list events for that calendar
      foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
      {
        my %event = %{$events{$event_id}};
  
        if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
        {  
          @event_start_timestamp_array = gmtime $event{start};
          my $event_time = "";
          if ($event{days} == 1)
          { #single-day event
            $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] ".($event_start_timestamp_array[5]+1900);
            if ($event{all_day_event} ne "1")
            {
            $event_time = &nice_time_range_format($event{start}, $event{end});
              $event_time = " ($event_time)";
            }
          }
          else #multi-day event
          {
            $date_string = &nice_date_range_format($event{start}, $event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
          }
          my $event_details = $event{details};
          $event_details =~ s/\n\s+/\n/g;
          $event_details =~ s/\n{2,}/\n/g;
          chomp $event_details;
 
          #indent each line of the details
          $event_details =~ s/\n/\n    /g;

 
          $html_output .="  $date_string$event_time: $event{title}\n";
          if ($event_details ne "")
          {
            $html_output .= "    $event_details\n\n";
          }
        }
      }
    }
    
    #increment to the next month--the method used 
    #here is the most painless way of making 
    #this work the right way in all cases.
    $current_month +=1;
    if ($current_month == 12)
    {
      $current_month=0;
      $current_year++;
    }
  }
  $html_output .= $debug_info;
  print $html_output;
  
}  #********************end ascii_text_cal subroutine**********************

sub ascii_text_event
{
  $html_output =<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/plain; charset=$lang{charset}\n\n

p1

  my @event_start_timestamp_array = gmtime $current_event{start};
  my $date_string="";
  
  my $event_time = "";
  if ($current_event{days} == 1)
  { #single-day event
    $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] ".($event_start_timestamp_array[5]+1900);
    if ($current_event{all_day_event} ne "1")
    {
      $event_time = &nice_time_range_format($current_event{start}, $current_event{end});
      $event_time = "($event_time)";
    }
  }
  else #multi-day event
  {
    $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
  }
  my $event_details = $current_event{details};
  $event_details =~ s/\n\s+/\n/g;
  $event_details =~ s/\n{2,}/\n/g;
  chomp $event_details;
  
  #indent each line of the details 
  $event_details =~ s/\n/\n    /g;

  
  $html_output .="  $date_string$event_time: $current_event{title}\n";
  if ($event_details ne "")
  {
    $html_output .= "    $event_details\n\n";
  }
  $html_output .= $debug_info;
  print $html_output;
  
}  #********************end ascii_text_event subroutine**********************



sub icalendar_export_event  # only for 1 event
{
  # when exporting to outlook, plans uses the vcalendar standard.
  # (http://www.imc.org/rfc2445)
  # This standard is horribly supported by MS outlook (outlook 2000, at the 
  # time of this writing.  Outlook refuses to correctly interpret the
  # date-time strings in the following ways:
  
  # 1.  If the date-time parameter does not specify a time (only a date), do you 
  # think outlook sets its "all-day event" flag?  Nope.  It just assumes the 
  # event occurs at 000000 hours (12 midnight).
  
  # 2.  if no time zone is specified, the date-time string is supposed to be 
  # interpreted as if it applied to the *current* timezone the user's computer 
  # is in (according to the standard).  Do you think outlook does this?  Nope. 
  # If no timezone is specified, outlook assumes the time zone is GMT.  As if this
  # weren't enough, outlook "helpfully" adjusts the time to the user's time zone.  
  # Depending on how far a user is from GMT, this may cause the day to change.
  
  # Since there's no way to predict what time zone a user is in, it is impossible 
  # to compensate on the server side for outlook's stupidity.  The workaround is 
  # to generate event times for each event (even though this is misleading because 
  # the events are all-day events), and force all the event times to 12 noon.  
  # This puts them as far from the previous and next days as possible, giving the 
  # least chance for outlook to screw up the day when it does its adjustment.
    
    
  my $ical_string = &event2ical(\%current_event);
  $ical_string_length = length $ical_string;

#Content-type: text/plain
#Last-modified: Wed, 30 Jan 2002 22:43:12 GMT
  $html_output =<<p1;
Content-type: text/x-vcalendar
Content-length: $ical_string_length
Content-disposition: filename="event.ics"
Accept-ranges: bytes

$ical_string

p1
  print $html_output;

}  #********************end vcalendar_export subroutine**********************


sub vcalendar_export_event  # only for 1 event
{
    
  my $csv_string =  <<p1;
CSV datebook: Category, Private, Description, Note, Event, Begin, End, Alarm, Advance, Advance Units, Repeat Type, Repeat Forever, Repeat End, Repeat Frequency, Repeat Day, Repeat Days, Week Start, Number of Exceptions, Exceptions
p1
  $csv_string .= &event2vcal(\%current_event);

  $csv_string_length = length $csv_string;

  #my $last_modified = &formatted_time($rightnow, "md mn yy hh:mm:ss GMT");
  #Last-modified: $last_modified

#Content-type: text/plain
  $html_output =<<p1;
Content-type: text/vcs
Content-length: $csv_string_length
Content-disposition: filename="event.vcs"
Accept-ranges: bytes

$csv_string

p1
  print $html_output;

}  #********************end vcalendar_export_event subroutine**********************



sub calculate_recurring_events
{
  my ($start_timestamp, $recur_end_timestamp) = @_;
  
  
  
  
  my @recurring_events_array = ();
 
  my @timestamp_array = gmtime $start_timestamp;
  
  #$debug_info .= "start timestamp: $start_timestamp\n";
  #foreach $custom_month (@custom_months)
  #  {$debug_info .= "custom month: $custom_month\n";}
  
  #my $start_timestamp = $start_timestamp+50;
  #calculate the weekday_in_month_count for the start timestamp
  # (is it the first tuesday?  second saturday?  This is required for
  # things to work right.
  
  $real_year = 1900 + $timestamp_array[5];
  $temp_start_timestamp = timegm(0,0,0,1,$timestamp_array[4],$real_year);
  @temp_start_timestamp_array = gmtime($temp_start_timestamp);
  
#  $debug_info .= <<p1;
#start timestamp: $start_timestamp<br/>
#end timestamp: $recur_end_timestamp<br/>
#the start timestamp ($months[$timestamp_array[4]] $timestamp_array[3], $real_year) <br/>
#the temp start timestamp ($months[$temp_start_timestamp_array[4]] $temp_start_timestamp_array[3], $temp_start_timestamp_array[5]) <br/>
#p1
  
  my $weekday_in_month_count = 0;
  #figure out what weekday of the month the start timestamp is
  for (;$temp_start_timestamp < $start_timestamp;$temp_start_timestamp+=86400)
  {
    @temp_start_timestamp_array = gmtime($temp_start_timestamp);
    if ($temp_start_timestamp_array[6] == $timestamp_array[6])
    {
      $weekday_in_month_count++;
    }
  }

  #this must be done, or the week-of-month recurring dates will be hosed
  #@temp_array = gmtime $start_timestamp;
  #my $current_month = $temp_array[4];
  my $last_week=0;
  
  
  # The recurring event algorithm loops through each day in the timeframe
  # and tests its validity against the recurrence parameters.
  
  # These tests take the form of "assumed valid unless proven otherwise"
  # Doing it this way lets the various recurrence type tests operate
  # independently of each other, while looping only once through the timeframe
  
  for ($recur_timestamp = $start_timestamp; $recur_timestamp <= $recur_end_timestamp; $recur_timestamp += 86400)
  {
    $last_week=0;
    my @recur_timestamp_array = gmtime $recur_timestamp;
    my $current_month = $recur_timestamp_array[4];
    
    #look a week ahead, to see if the current weekday is the last one in the month
    my $recur_timestamp_next_week = $recur_timestamp+604800;
    my @recur_timestamp_next_week_array = gmtime $recur_timestamp_next_week;
    
    if ($current_month != $recur_timestamp_next_week_array[4])
      {$last_week = 1;}
    
    $real_year = 1900 + $recur_timestamp_array[5];
    
    $recur_timestamp_valid=1;
    if ($q->param('recurrence_type') eq "same_day_of_month")
    {
      if ($recur_timestamp_array[3] != $timestamp_array[3])
        {$recur_timestamp_valid=0;}
    }

    elsif ($q->param('recurrence_type') eq "same_day_of_week")
    {
      if ($recur_timestamp_array[6] != $timestamp_array[6])
      {
        $recur_timestamp_valid=0;
      }
      elsif ($q->param('weekday_of_month_type') eq "only_first_week")
      {
        if ($weekday_in_month_count != 0)
          {$recur_timestamp_valid=0;}
      }
      elsif ($q->param('weekday_of_month_type') eq "only_second_week")
      {
        if ($weekday_in_month_count != 1)
          {$recur_timestamp_valid=0;}
      }
      elsif ($q->param('weekday_of_month_type') eq "only_third_week")
      {
        if ($weekday_in_month_count != 2)
          {$recur_timestamp_valid=0;}
      }
      elsif ($q->param('weekday_of_month_type') eq "only_fourth_week")
      {
        if ($weekday_in_month_count != 3)
          {$recur_timestamp_valid=0;}
      }
      elsif ($q->param('weekday_of_month_type') eq "only_fifth_week")
      {
        if ($weekday_in_month_count != 4)
          {$recur_timestamp_valid=0;}
      }
      elsif ($q->param('weekday_of_month_type') eq "only_last_week")
      {
        if ($last_week != 1)
          {$recur_timestamp_valid=0;}
        else
        {
          #$debug_info .= "timestamp: $recur_timestamp\n";
          #$debug_info .= "current month: $current_month\n";
          #$debug_info .= "lookahead timestamp: $recur_timestamp_next_week\n";
          #$debug_info .= "lookahead month: $recur_timestamp_next_week_array[4]\n";
        }
      }
    }
    
    elsif ($q->param('recurrence_type') eq "every_x_days")
    {
      #$debug_info .= $q->param('every_x_days');
      #$debug_info .= "\n";

      if (($recur_timestamp - $start_timestamp) % (86400 * $q->param('every_x_days')) !=0)
        {$recur_timestamp_valid=0;}
    }
    
    elsif ($q->param('recurrence_type') eq "every_x_weeks")
    {
      #$debug_info .= ($q->param('every_x_weeks')."\n");
      
      if (($recur_timestamp - $start_timestamp) % (86400 * 7 * $q->param('every_x_weeks')) !=0)
        {$recur_timestamp_valid=0;}
    }
    
    if ($q->param('year_fit_type') eq "every_month")
    {
    }
    elsif ($q->param('year_fit_type') eq "custom_months")
    {
      my $month_valid=0;
      foreach $custom_month (@custom_months)
      {
        if ($custom_month == $recur_timestamp_array[4])
          {$month_valid=1;}
      }
      
      if ($month_valid == 0)
        {$recur_timestamp_valid=0;}
    }
    

    if ($recur_timestamp_valid == 1)
    {
      push @recurring_events_array, $recur_timestamp;
      
      my $real_year = $recur_timestamp_array[5]+1900;
    }
    
    #count how many of the event's weekdays we have come across in 
    #each month.  This is for validating events that occur on the 
    #second tuesday, fifth monday, etc.
    if ($recur_timestamp_array[6] == $timestamp_array[6])
    {
      $weekday_in_month_count++;
    }
    
    #reset week_in_month count if this is the last week in the month
    if ($last_week == 1 && $recur_timestamp_array[6] == $timestamp_array[6])
      {$weekday_in_month_count=0;}
  }
  
  if (scalar @recurring_events_array == 0)
  {
    $debug_info .= "Error!  No valid recurring event dates found!\n";
  }
  return \@recurring_events_array;
}


sub verify_date()
{
  # $date is of the format similar to mm/dd/yy (or a permutation like dd/mm/yy)
  my ($date) = @_;
  my $results="";
  
  if ($date !~ /^(\w{1,2}\/\w{1,2}\/\w{2,4}|\w{1,2}\/\w{2,4}\/\w{1,2}|\w{2,4}\/\w{1,2}\/\w{1,2})$/)
  {
    $lang{date_verify_err0} =~ s/###date###/$date/;
    $lang{date_verify_err0} =~ s/###format###/$current_calendar{date_format}/;
    $results .= $lang{date_verify_err0}."\n";
  }
  
    if ($q->param('recurrence_type') eq "every_x_days")
    {
    
      if ($q->param('every_x_days') == 0)
        {$results .= $lang{date_verify_err7}."\n"};
    }
    elsif ($q->param('recurrence_type') eq "every_x_weeks")
    {
    
      if ($q->param('every_x_weeks') == 0)
        {$results .= $lang{date_verify_err8}."\n"};
    }
  
  
  
  if ($date eq "")
  {
    $results .= $lang{date_verify_err1}."\n";
  }
  
  my ($mon, $day, $year) = &format2mdy($date, $current_calendar{date_format});

  if ($mon < 1 || $mon > 12)
  {
    $lang{date_verify_err4} =~ s/###month###/$mon/;
    $results .= $lang{date_verify_err4}."\n";
  }

  $mon --;  # convert month to 0-11 format
  
  if ($day < 1 || $day > 31)
  {
    $lang{date_verify_err5} =~ s/###day###/$day/;
    $results .= $lang{date_verify_err5}."\n";
  }

  if ($year < 100) {$year+=2000;}
  
  if ($year < 1902 || $year > 2037)
  {
    $lang{date_verify_err6} =~ s/###year###/$year/;
    $results .= $lang{date_verify_err6}."\n";
  }
  
  
  return $results;
}

sub verify_time
{
  my ($time) = @_;
  my $results="";
  
  if ($time !~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/)
  {
    $lang{time_verify_err0} =~ s/\{0\}/$time/;
    $results .= $lang{time_verify_err0};
  }
  else
  {
    my $hours = $1;
    my $minutes = $2;
    my $ampm = $3;
    
    if ($hours > 12 || $hours < 0)
    {
      $lang{time_verify_err1} =~ s/\{0\}/$hours/;
      $results .= $lang{time_verify_err1};
    }
    
    if ($minutes > 60 || $minutes < 0)
    {
      $lang{time_verify_err2} =~ s/\{0\}/$minutes/;
      $results .= $lang{time_verify_err2};
    }
    
  }
  return $results;
}

sub time2seconds
{
  my ($time) = @_;
  $time =~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/;
  my $hours = $1;
  my $minutes = $2;
  my $ampm = $3;
  
  my $seconds = 3600*$hours + 60*$minutes;
  
  if ($ampm eq $lang{pm} && $hours < 12)
  {
    $seconds += 3600*12;
  }
  
  if ($ampm eq $lang{am} && $hours == 12)
  {
    $seconds -= 3600*12;
  }

  return $seconds;
}



sub preview_date
{
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="pragma" content="no-cache">
<link rel="stylesheet" href="$css_path" type="text/css" media=screen>
<title>$lang{date_preview_title}</title>
</head>
<body>

<div class="info_box">
<span class="cal_title">
$lang{date_preview_title}
</span>
p1

  $recurring_event = $q->param('recurring_event');
  $event_start_date = $q->param('evt_start_date');
  $recur_end_date = $q->param('recur_end_date');
  $event_days = $q->param('evt_days');
  $event_cal_id = $q->param('evt_cal_id');
  %current_calendar = %{$calendars{$event_cal_id}};

  my $custom_months_string = $q->param('custom_months');
  local @custom_months = split (/\s/, $custom_months_string);
  
  #//
  
  my $date_valid = &verify_date($event_start_date);
  
  if ($event_days eq "")
  {
    $date_valid=$lang{date_verify_err2};
  }
  if ($days =~ m/\D/ || $event_days <= 0)
  {
    $date_valid=$lang{date_verify_err3};
  }

  
  if ($recurring_event)
  {
    my $temp .= &verify_date($recur_end_date);
    if ($temp ne "")
    {
      $date_valid .= "\n$lang{date_verify_for_recurring_end_date}\n<p style=\"margin:0;padding-left:1em;\">$temp</p>";
    }
  }
  
  if ($date_valid eq "")
  {
    my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_calendar{date_format});
    my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recur_end_date, $current_calendar{date_format});
    $start_mon--;
    $recur_end_mon--;
  
    #calculate start timestamp
    $event_start_timestamp=timegm(0,0,0,$start_mday,$start_mon,$start_year);
    @timestamp_array = gmtime $event_start_timestamp;
    my $real_year = $timestamp_array[5]+1900;
    
    if ($recurring_event == 1)
    {
      #calculate end timestamp
      $recur_end_timestamp=timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year);
  
      $html_output .= <<p1;
<p>$lang{date_preview_recurring_event_falls_on}</p>
p1

      my @recurring_events_array = @{&calculate_recurring_events($event_start_timestamp, $recur_end_timestamp)};
      foreach $recurring_event_timestamp (@recurring_events_array)
      {
        $timestamp1 = $recurring_event_timestamp;
        $timestamp2 = $recurring_event_timestamp + 86400 * ($event_days-1);
        if ($timestamp1 == $timestamp2) {$timestamp2++;}
          
        $date_range = &nice_date_range_format($timestamp1, $timestamp2, "-");
        $html_output .= <<p1;
<p style="font-weight:bold;">$date_range</p>
p1
      }
      
            
    }
    else
    {
      my $date = "";
      $timestamp1 = $event_start_timestamp;
      $timestamp2 = $event_start_timestamp + 86400 * ($event_days-1);
      if ($timestamp1 == $timestamp2) {$timestamp2++;}
      $date_range = &nice_date_range_format($timestamp1, $timestamp2, "-");

        $html_output .= <<p1;
<p>$lang{date_preview_this_event_falls_on}</p>
<p style="font-weight:bold;">
$date_range
</p>
p1
    }
  
  }
  else
  {
    $date_valid =~ s/\n/<br\/>/g;
    $html_output .= "<p>$date_valid</p>";
  }
  
  

  $html_output .=<<p1;
</div>
p1
  
  #$html_output .="$debug_info";
    
  $html_output .=<<p1;
$debug_info
</body>
</html>
p1

print $html_output;
}  # end preview date subroutine

sub preview_event
{
  $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}<\/i>/g;
  $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}<\/i>/g;
  $event_details_template =~ s/###delete event link###/$lang{event_details_delete_disable}<\/i>/g;
  $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g;
  
  my $event_info = &generate_event_details({title => $q->param('evt_title'), 
                                            details => $q->param('evt_details'),
                                            cal_id => $q->param('evt_cal_id'),
                                            icon => $q->param('evt_icon'),
                                            bgcolor => $q->param('evt_bgcolor'),
                                            start => "",
                                            end => "",
                                            unit_number => $q->param('unit_number')}, 1);
  
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="pragma" content="no-cache">
<link rel="stylesheet" href="$css_path" type="text/css" media=screen>
<title>$lang{event_preview_title}</title>
</head>
<body>
<span class="cal_title">
$lang{event_preview_title}
</span>
$event_info
</body>
</html>
p1

print $html_output;
}  # preview_event

sub view_event
{
  my $event_info = &generate_event_details(\%current_event);
  $debug_info =~ s/\n/<br\/>\n/g;
  
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="pragma" content="no-cache">
<link rel="stylesheet" href="$css_path" type="text/css" media=screen>
<title>$current_event{title}</title>
</head>
<body>
$event_info
$debug_info
</body>
</html>
p1

print $html_output;
}  # view_event


sub email_reminder_prompt
{
  $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, " - ");
  my $title = "<title>$current_event{title}$lang{email_reminder_title}</title>";
  
  my $results .=<<p1;
<script type="text/javascript" ><!--
var clicked = false;

function address_focus() {
  if (!clicked) {
    document.email_reminder_submit.email_address.value = "";
    clicked=1;
  }
}
</script>

<body>
<div class="event_details" style="background-color:$current_event{bgcolor};text-align:left;">
<p class="title">
$current_event{title}
</p><p>
$lang{email_reminder_text1}
<br/><span class="date">$date_string</span>
</p>
<form name="email_reminder_submit" action="$script_url/$name" method="POST">
<input type="hidden" name="evt_id" value="$current_event{id}"/>
<input type="hidden" name="email_reminder_confirm" value="1"/>
$lang{email_reminder_text2}<br/>
<input name="email_address" style="width:90%;" value="your_email\@address.com"/ onfocus="address_focus()">
<br/><br/>
<select name="reminder_time">
<option value="604800, $lang{email_reminder_option1}">$lang{email_reminder_option1}</option>
<option value="172800, $lang{email_reminder_option2}">$lang{email_reminder_option2}</option>
<option value="86400, $lang{email_reminder_option3}">$lang{email_reminder_option3}</option>
<option value="3600, $lang{email_reminder_option4}">$lang{email_reminder_option4}</option>
<option value="1800, $lang{email_reminder_option5}">$lang{email_reminder_option5}</option>
<option value="900, $lang{email_reminder_option6}">$lang{email_reminder_option6}</option>
</select>
$lang{email_reminder_text3}
<br/><br/>
$lang{email_reminder_text7}
<textarea name="extra_text" style="width:90%" rows="4">
</textarea>
<br/><br/>
<input type="checkbox" name="send_test_now" value="1"> $lang{email_reminder_text4}
<br/><br/>
p1

if ($current_event{series_id} ne "")
{
  $results .=<<p1;
<input type="checkbox" name="all_in_series" value="1"/> $lang{email_reminder_text6}
<br/><br/>
p1
}
  $results .=<<p1;
<input type="submit" value="$lang{email_reminder_text5}"/>
</form>
</div>
</body>
p1

  $template_html =~ s/<title>.*<\/title>/$title/s;
  $template_html =~ s/<body.*>.*<\/body>/$results/s;
  $template_html =~ s/###css file###/$css_path/g;

  print <<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
$template_html
p1
}  # email_reminder_prompt


sub email_reminder_confirm
{
  my $reminder_results = "";
  my $to_address = $q->param('email_address');
  my $extra_text = $q->param('extra_text');
  $to_address =~ s/\s//g;
  $to_address =~ s/;/,/g;
  chomp $to_address;
  
  my ($reminder_seconds, $reminder_time) = split(/, ?/,$q->param('reminder_time'));
  $reminder_time = lc $reminder_time;
  
  my $email_valid = &validate_emails($to_address);
  
  if ($email_valid ne "")
  {
    $reminder_results = $lang{email_reminder_invalid_address};
    $reminder_results =~ s/###address###/$email_valid/g;
  }
  else
  {
    my @event_reminder_ids=($current_event{id});
    if ($q->param('all_in_series') ne "")
    {
      @event_reminder_ids = &get_events_in_series($current_event{series_id});
    }
    
    foreach $event_reminder_id (@event_reminder_ids)
    {
      # assemble email reminder xml
      my $reminder_xml = "";
      $reminder_xml .= &xml_store($event_reminder_id, "evt_id").
                     &xml_store($reminder_seconds, "before").
                     &xml_store($to_address, "email_address").
                     &xml_store($extra_text, "extra_text").
                     &xml_store("$script_url/$name", "script_url").
                     &xml_store($rightnow, "timestamp");
      $reminder_xml = "<email_reminder>$reminder_xml</email_reminder>\n";
  
      # write email reminder to file
      open (FH, ">>$options{email_reminders_datafile}") || ($debug_info .="<br/>Unable to open email reminders data file $options{email_reminders_datafile} for writing<br/>");
      print FH $reminder_xml;
      close FH;
    }
  
    my $test_reminder_results = "";
    if ($q->param('send_test_now') == 1)
    {
      my $reminder_text = $lang{email_reminder_test_text};
      $reminder_text =~ s/###reminder_time###/$reminder_time/g;

      my $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, " - ");
  
      my $event_time = "";
      if ($current_event{all_day_event} ne "1")
      {
        $event_time = &nice_time_range_format($current_event{start}, $current_event{end});
      }
      $reminder_text =~ s/###time###/$event_time/g;
      $reminder_text =~ s/###title###/$current_event{title}/g;
      $reminder_text =~ s/###date###/$date_string/g;
      $reminder_text =~ s/###extra text###/$extra_text/g;
      $reminder_text =~ s/###details###/$current_event{details}/g;
      $reminder_text =~ s/###link###/$script_url\/$name?view_event=1&evt_id=$current_event{id}/g;

      #$debug_info .= "$reminder_text\n";

      $test_reminder_results = &send_email_reminder(\%current_event, $to_address, $reminder_text);
      if ($test_reminder_results eq "1")
      {
        $test_reminder_results = $lang{email_reminder_test_success};
        $test_reminder_results =~ s/###address###/$to_address/g;
      }
      else
      {
        $test_reminder_results = $lang{email_reminder_test_fail};
        $test_reminder_results =~ s/###results###/$test_reminder_results/g;
      }
    }
  
    $lang{email_reminder_results1} =~ s/###address###/$to_address/g; 
    $lang{email_reminder_results1} =~ s/###reminder time###/$reminder_time/g; 
    
    if ($q->param('send_test_now') == 1)
      {$lang{email_reminder_results1} .= $lang{email_reminder_results3}}
    else
      {$lang{email_reminder_results1} .= $lang{email_reminder_results2}}
    

    $reminder_results = <<p1;
$lang{email_reminder_results1}
<br/><br/>
$test_reminder_results
p1
  }
  
  $debug_info =~ s/\n/<br\/>\n/g;
  
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="pragma" content="no-cache">
<link rel="stylesheet" href="$css_path" type="text/css" media=screen>
<title>$current_event{title}$lang{email_reminder_title}</title>
</head>

<body>
<div class="event_details" style="background-color:$current_event{bgcolor};text-align:left;">
<p style="margin-top:20px;margin-bottom:20px;">
$reminder_results
</p>
</div>
$debug_info
</body>
</html>
p1

print $html_output;
}  # email_reminder_confirm

sub detect_remote_calendars()
{
  my $remote_calendar_url = $q->param('remote_calendar_url');
  $remote_calendar_url =~ s/\?.+//;
  #$debug_info .= "url: $remote_calendar_url\n";
  
  $remote_calendar_base_url = $remote_calendar_url;
  $remote_calendar_url .= "?remote_calendar_request=1&get_public_calendars=1";

  my $xml_results = &get_remote_file($remote_calendar_url);
  #$results =~ s/>/&gt;/g;
  #$results =~ s/</&lt;/g;
  
  my %remote_calendars = %{&xml2hash($xml_results)};
  
  my @public_calendars;
  
  if (ref $remote_calendars{'xml'}{public_calendar} eq "ARRAY")
  {
    @public_calendars = @{$remote_calendars{'xml'}{public_calendar}};
  }
  else
  {
    push @public_calendars, $remote_calendars{'xml'}{public_calendar}
  }
  
      $remote_calendar_info .= <<p1;
<p style="clear:both;">
$lang{detect_remote_calendars1} <a target="_blank" href="$remote_calendar_base_url">$remote_calendar_base_url</a>:
</p>
<div style="float:left;width:95%;border:solid 1px #000;">
<form name="cal_merge_form">
p1
  
  my $index = 0;
  foreach $temp (@public_calendars)
  {
    my %public_calendar = %{$temp};
    my $list_class="list_odd";
    
    my $merge_xml = <<p1;
<remote_calendar>
<type>plans</type><version>$remote_calendars{'xml'}{'plans_version'}</version>
<url>$remote_calendar_base_url</url>
<remote_id>$public_calendar{id}</remote_id>
<password>###password###</password>
</remote_calendar>
p1

    #$merge_xml =~ s/\//\\\//g;
    $merge_xml =~ s/\n//g;
    $merge_xml =~ s/"/\\"/g;

    
    if ($index%2 == 0)
      {$list_class="list_even"}
    
    $remote_calendar_info .= <<p1;
<div class="$list_class" style="float:left;clear:left;width:100%;">
p1
    #$remote_calendar_info .= "public calendar: ".$remote_calendars{'xml'}{public_calendar}."<br/>";
    $remote_calendar_info .= <<p1;
<div style="float:left;width:8em;font-weight:bold;padding:3px;white-space:nowrap;">$public_calendar{title}</div>
p1
    
    $remote_calendar_info .= <<p1;
<div style="float:left;padding:3px;white-space:nowrap;">$lang{detect_remote_calendars2}<input type="checkbox" id="remote_cal_$index" name="remote_cal_$index" value = "$merge_xml">
p1
    if ($public_calendar{requires_password} ne "")
    {
      $remote_calendar_info .= <<p1;
<span style="margin-left:1em;white-space:nowrap;">($lang{detect_remote_calendars3}): <input id="password_$index" name="password_$index" style="width:6em;"></span>
p1
    }
    $remote_calendar_info .= <<p1;
</div>      
p1
    
    
    $remote_calendar_info .= <<p1;
</div>      
p1
    $index++;
  }
  $remote_calendar_info .= <<p1;
</form>
</div>
p1

  if ($index > 0)
  {
    $remote_calendar_info .= <<p1;
<p style="clear:both;padding-top:1em;"><a href="javascript:merge_selected()">$lang{detect_remote_calendars4}</a></p>
<br/><br/>
p1
  }
  else
  {
    $remote_calendar_info .= <<p1;
<p style="clear:both;padding-top:1em;">$lang{detect_remote_calendars5}</p>
<br/><br/>
p1
  }
#<br style="clear:both;"/>
#<br style="clear:both;"/>
  
  
  #my $temp_xml_results = $xml_results;
  #$temp_xml_results =~ s/>/&gt;/g;
  #$temp_xml_results =~ s/</&lt;/g;
  #$debug_info .= $temp_xml_results;


  my $popup_javascript_info = "";
  
    $popup_javascript_info .=<<p1;
<script type="text/javascript" ><!--
p1

  if ($browser_type eq "IE")
  {
    $popup_javascript_info .=<<p1;
function do_onresize()
{
  opener.info_window_width = document.body.clientWidth;
  opener.info_window_height = document.body.clientHeight;
}
p1
  }
  else
  {
    $popup_javascript_info .=<<p1;
function do_onresize()
{
  opener.info_window_width = this.outerWidth;
  opener.info_window_height = this.outerHeight;
}
p1
  }
  
    $popup_javascript_info .=<<p1;
function opener_test() {
  //alert("about to test opener " + opener.info_window_width);
  //opener.test();
}

function merge_selected() {

  var l1=0;
  var merge_xml="";
  while (document.getElementById("remote_cal_"+l1))
  {
    var el = document.getElementById("remote_cal_"+l1);
    
    if (el.checked)  {
      var temp = "";
      if (document.getElementById("password_"+l1))
        temp = el.value.replace(/###password###/, document.getElementById("password_"+l1).value);
      else
        temp = el.value.replace(/###password###/, "");
      merge_xml += temp;
    }
    
    l1++;
  }
  if (merge_xml != "")
    opener.set_merge_xml("<remote_calendars>"+merge_xml+"</remote_calendars>");
    
  window.close();
}

//-->
</script> 
p1

  
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n

p1

  $debug_info =~ s/\n/<br\/>\n/g;

  $html_output .=<<p1;
<html>
<head>
<title>$lang{get_remote_calendars}</title>
<link rel="stylesheet" href="$css_path" type="text/css" media="screen"/>
</head>
<body onResize="javascript:do_onresize();" onload="opener_test();">
$popup_javascript_info
<div class="info_box" style="padding:5px;"><br/>
p1

#

  $html_output .=<<p1;
$remote_calendar_info
<br/><br/>
$debug_info
</div>
</body></html>
p1
  print $html_output;

}


sub remote_calendar_request()
{
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/xml; charset=$lang{charset}\n

p1
  my $results = "";
  my $current_cal_ids_string = $q->param('cal_id');

  $results .=<<p1;
<plans_version>$plans_version</plans_version>
p1

  #$debug_info .= "remote calendar request!";

  # if the client requests a list of all calendars that are publically share-able.
  if ($q->param('get_public_calendars') eq "1")
  {
    foreach $cal_id (keys %calendars)
    {
      if ($calendars{$cal_id}{allow_remote_calendar_requests})
      {
        my $temp=$calendars{$cal_id}{remote_calendar_requests_require_password};
        $results .=<<p1;
<public_calendar><id>$cal_id</id><title>$calendars{$cal_id}{title}</title><requires_password>$temp</requires_password></public_calendar>
p1
      }
    }
  }
  else  # return xml data for the events.
  {
    my @current_cal_ids = ();
    my @temp = split (",",$current_cal_ids_string);
    
    my $cal_id_valid=1;
    
    foreach $cal_id (@temp)
    {
      if ($cal_id !~ /\D/)
      {
        push @current_cal_ids, $cal_id;
      }
      else
      {
        $cal_id_valid=0;
        $results .= "<error>Invalid calendar ID: $cal_id</error>";
        last;
      }
    }
    if ($cal_id_valid)
    {
      foreach $current_cal_id (@current_cal_ids)
      {
          $results .=<<p1;
<calendar><id>$current_cal_id</id><title>$calendars{$current_cal_id}{title}</title><gmtime_diff>$calendars{$current_cal_id}{gmtime_diff}</gmtime_diff></calendar>  
p1
      }
    
      foreach $current_cal_id (@current_cal_ids)
      {
        foreach $event_id (keys %events)
        {        
        
          my $event_in_current_calendar = 0;
 
          foreach $temp_cal_id (@{$events{$event_id}{cal_ids}})
          {
            if ($temp_cal_id eq $current_cal_id)
            {
              $event_in_current_calendar = 1;
              last;
            }
          }

          if ($event_in_current_calendar == 0)
          {next;}
        
          my $xml_data = &event2xml($events{$event_id});
          $results .=<<p1;
$xml_data      
p1
        }
      }
    }
  }

  if ($debug_info ne "")
    {$results .= "<debug_info>$debug_info</debug_info>";}

  $html_output .= "<xml>$results</xml>";

  print $html_output;

}








#******************* the following subroutines don't display any HTML **********



sub wmatch 
{
  #Try to match words of the strings.  return the number of matching words.
  
  my($A, $B) = @_;
  $A=lc $A;
  $B=lc $B;
  my $temp = "input: \"$A\" and \"$B\"<br/>";
    
  @awords=split(' ', $A);
  @bwords=split(' ', $B);
  $score=0;
  foreach $aword (@awords)
  {
      if ((index $B,$aword) != -1)
      {
#        print "$temp";
#        print "pruned to \"$A\" and \"$B\"<br/>";
#        print "wmatch matched $aword and $bword<br/><br/>";
        $score++;
      }
  }
  
  return $score;
}


sub rgb2hsv {

    # r,g,b values are from 0 to 255
    # h = [0..360], s = [0..100], v = [0..100]
    #    if s == 0, then h = -1 (undefined)
    
    my ($r,$g,$b) = @_;
    
    $r /= 255;
    $g /= 255;
    $b /= 255;

    my ($h, $s, $v);
    my ($min, $max, $delta);
    
    $min = &min ( $r, $g, $b );
    $max = &max ( $r, $g, $b );

    # value is just the brightest rgb value
    $v = $max;

    # account for shades of gray:
    $delta = $max - $min;
    if ($delta == 0 ) {
      $s = 0; # no hue, so it can't be saturated!
      $h = -1; # hue is really undefined, but...
      return ($h, $s, $v*100);
    }

    # saturation is intensity/blandness of color:
    $s = $delta / $max;  # max > 0 or delta would be 0

    # hue depends on the relative strengths of the colors:
    if( $r == $max ) {
      $h = ( $g - $b ) / $delta;  # between yellow & magenta
    } elsif( $g == $max ) {
      $h = 2 + (( $b - $r ) / $delta);  # between cyan & yellow
    } else {
      $h = 4 + (( $r - $g ) / $delta);  # between magenta & cyan
    }

    # it's also calculated as degrees on a color wheel
    $h *= 60;  # degrees
    $h += 360 if ($h < 0); 

    # s and v are percentages
    $s *= 100;
    $v *= 100;
    
    return (int( $h ), int($s), int($v));
}

sub hsv2rgb {
  my ($hue, $sat, $val) = @_;
  my @hsv_map = 
  (
   'vkm', 'nvm', 'mvk', 'mnv', 'kmv', 'vmn'
  );
  # HSV conversions from pages 401-403 "Procedural Elements for Computer 
  # Graphics", 1985, ISBN 0-07-053534-5.

  my @result;
  if ($sat <= 0) {

    return ( 255 * $val, 255 * $val, 255 * $val );
  }
  else {
    $val >= 0 or $val = 0;
    $val <= 1 or $val = 1;
    $sat <= 1 or $sat = 1;
    $hue >= 360 and $hue %= 360;
    $hue < 0 and $hue += 360;
    $hue /= 60.0;
    my $i = int($hue);
    my $f = $hue - $i;
    $val *= 255;
    my $m = $val * (1.0 - $sat);
    my $n = $val * (1.0 - $sat * $f);

    my $k = $val * (1.0 - $sat * (1 - $f));
    my $v = $val;
    my %fields = ( 'm'=>$m, 'n'=>$n, 'v'=>$v, 'k'=>$k, );
    return @fields{split //, $hsv_map[$i]};
  }
}

sub make_consistent
{
  my ($string) = @_;
  my $input = $q->param($string);
  
  if ($input ne "")
    {$consistent_parameter_string .= "&amp;$string=$input";}
}

sub remove_consistent
{
  my ($string) = @_;
  my $return_string = $consistent_parameter_string;
  $return_string =~ s/&$string=.+?&/&/;
  return $return_string;
}


sub diagnostic_mode()
{
  $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=$lang{charset}\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>Diagnostic mode</title>
</head>
<body style="font-family: arial;">

<br/><br/>
<h2>Plans Diagnostic information</h2>
<br/><br/>
<b>Script Name:</b>$name<br/>
<b>Data Storage Mode:</b> $options{data_storage_mode}<br/>
<br/>
p1

 if ($options{email_mode} && !$writable{email_reminders_datafile})
 {
   $html_output .=<<p1;
<b>Warning:</b> The email reminders data file: $options{email_reminders_datafile} is not writable.  This will 
cause some email functions to be disabled or not work correctly.<br/>
p1
 }
 if ($options{data_storage_mode} == 0 && !$writable{calendars_file})
 {
   $html_output .=<<p1;
<b>Warning:</b> The calendars data file: $options{calendars_file} is not writable.  The add/edit calendars tab won't appear 
unless this file is writable.<br/>
p1
 }
 if ($options{data_storage_mode} == 0 && !$writable{new_calendars_file})
 {
   $html_output .=<<p1;
<b>Warning:</b> The new calendars data file: $options{new_calendars_file} is not writable.  The add/edit calendars tab won't appear 
unless this file is writable.<br/>
p1
 }
 if ($options{data_storage_mode} == 0 && !$writable{events_file})
 {
   $html_output .=<<p1;
<b>Warning:</b> The events data file: $options{events_file} is not writable.  The add/edit events tab won't appear 
unless this file is writable.<br/>
p1
 }


  $html_output .=<<p1;

<b>Plans version:</b> $plans_version<br/>
<b>Perl version:</b> $perl_version<br/>
<b>script name:</b> $name<br/>
<b>script url path:</b> $script_url<br/>
<br/>
<b>Theme url:</b> $theme_url<br/>
<b>graphics url:</b> $graphics_url<br/>
<b>icons url:</b> $icons_url<br/>
<br/>
<b>Default template path:</b> $options{default_template_path}<br/>
<b>Email mode:</b> $options{email_mode}<br/>
<br/>
<b>events file:</b> $options{events_file}<br/>
<b>calendars file:</b> $options{calendars_file}<br/>
<br/>
<b>Options:</b><br/>
p1

  foreach $option (keys %options)
  {
  $html_output .=<<p1;
<b>$option:</b> $options{$option}<br/>
p1
  }

  $html_output .=<<p1;
<br/><br/>
<b>Debug info:</b><br/>
<div style="color=:#0000ff;">
$debug_info
</div>
</body>
</html>

p1

  print $html_output;
}       # end diagnostic subroutine


sub assemble_icon_menus()
{
  # this function extracts a data structure for the icon menus from the xml definition
  my ($data)= @_;
  
  # first, get the menuitems
  my @new_menuitems=();
  
  my @menuitems = &xml_extract($data, "menuitem", 0);
  if (scalar @menuitems == 0)
  {
    $debug_info .= "Warning.  There's a menu with no menuitems.  This may be caused by an older version of Perl ( < 5.6).\n";
    $debug_info .= "$data";
  }
  else
  {
    foreach my $menuitem (@menuitems)
    {
      #$debug_info .= "menuitem: $menuitem->{data} ($menuitem->{position})<br/>";
      my $icon_name = $menuitem->{attributes}{"value"};
      my $icon_description = $menuitem->{data};
      $icon_description = &encode($icon_description);
      $new_menuitems[$menuitem->{position}] = [$icon_name,$icon_description];
      #$new_menuitems[$menuitem->{position}] = "name,description";
    }
  }
  
  # then get the submenus
  my @submenus = &xml_extract($data, "menu", 0);
  foreach $submenu (@submenus)
  {
    my $temp = $submenu->{data};
    my $temp2 = $submenu->{attributes}{name};
    my @submenuitems = assemble_icon_menus($temp);
    #$debug_info .= "submenu: $temp2 ($submenu->{position})<br/>";
    $new_menuitems[$submenu->{position}] = [$temp2, \@submenuitems];
  }

  return @new_menuitems;
}   #******************** end assemble_icon_menus **********************


sub generate_flat_icon_menus
{
  my ($icons_list, $selected_icon) = @_;
  my $return_text="";
  #$debug_info .= "selected icon: $selected_icon<br/>";

  my $indent = " ";
  for ($l1=0;$l1<$index_number;$l1++)
  {
    $indent .= "  "; 
  }
    
  foreach $icon_ref (@{$icons_list})
  {
    my $identifier = @{$icon_ref}[1];
    
    if ($identifier =~ /ARRAY/)   # if it's a submenu
    {
     $icon_menu_index_number++;
     my $submenu_name = @{$icon_ref}[0];
     
     #$debug_info .= "submenu $submenu_name<br/>";
     
     $return_text .= <<p1;
<optgroup label="$submenu_name">
p1
     $return_text .= &generate_flat_icon_menus(@{$icon_ref}[1], $selected_icon);
     $return_text .= <<p1;
</optgroup>
p1
    }
    else  # if it's a menu item
    {
      my $icon_filename = @{$icon_ref}[0];
      my $icon_name = @{$icon_ref}[1];
      
      $icon_name = &decode($icon_name);
      #$debug_info .= "icon name: $icon_name <br/>";
      #$debug_info .= "icon filename: $icon_filename <br/>";
      #$debug_info .= "<br/>";
      
      if ($icon_filename eq $selected_icon)
      {
      $return_text .= <<p1;
<option value = "$icon_filename" selected>$icon_name</option>
p1
      }
      else
      {
      $return_text .= <<p1;
<option value = "$icon_filename">$icon_name</option>
p1
      }
    
    }
  }
  return $return_text;

}   #******************** end generate_flat_icon_menus **********************

sub export_calendar_link()
{
  my $results = "";
  
  $results .=<<p1;
<a href="javascript:document.export_cal_form.submit();">$lang{export}</a> $lang{these_events_to}
<form name="export_cal_form" target="_blank" action="$script_url/$name" method="POST">
<input type="hidden" name="export_calendar" value=1 >
<input type="hidden" name="display_type" value="$display_type">
<input type="hidden" name="cal_id" value="$current_cal_id">
<input type="hidden" name="cal_start_month" value="$cal_start_month">
<input type="hidden" name="cal_start_year" value="$cal_start_year">
<input type="hidden" name="cal_num_months" value="$cal_num_months">
<input type="hidden" name="theme_url" value="$theme_url">

<select name="export_type">
<option value="ascii_text">$lang{text_option}
<option value="csv_file">$lang{csv_file}
<option value="vcalendar">$lang{vcalendar_option}
</select>
</form>
p1

}


sub format2mdy()  
{  # takes a format string (which can be "dd/mm/yy", "yy,mm,dd", etc.)
   # and a date in that format, and returns the month, day, and year.
  my ($date, $format) = @_;

  my @temp_date = split ('/', $date);
  my @temp_format = split ('/', $format);
  my %temp_format_map;
  
  for (my $l1=0;$l1<3;$l1++)
  {
    $temp_format_map{$temp_format[$l1]} = $temp_date[$l1];
  }

  my $mon = $temp_format_map{"mm"};
  my $day = $temp_format_map{"dd"};
  my $year = $temp_format_map{"yy"};

  return ($mon, $day, $year);
}

sub fatal_error()
{
  $error_info =~ s/\n/<br>/g;

  $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/html; charset=iso-8859-1\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Plans error!</title>
</head>
<body>

<b>Plans error:</b><br>
$error_info
p1
  if ($debug_info ne "")
  {
    $debug_info =~ s/\n/<br>/g;
    $html_output .=<<p1;
<hr>
Debug info:<br>
$debug_info
p1

  }

  $html_output .=<<p1;
</body>
</html>
p1

  print $html_output;
  exit(0);
}
