#!/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

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


# some global variables (more further down)
local $debug_info;
local $plans_version = "5.6.3";        # version
local $perl_version = (sprintf ("%vd",$^V));
local $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_cal;
local %latest_cal;
local %latest_new_cal;
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 $default_template_file = "";
local $theme_path = "";
local $choose_themes = "";
local $graphics_path = "";
local $icons_path = "";
local $input_cal_id_valid = 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/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 (-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 (-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 $language_file)
{
  $module_found=0;
  foreach $temp_path (@INC)
  {
    if (-r "$temp_path/$language_file")
      {$module_found=1;}
  }
  if ($module_found == 0)
  {
    $fatal_error=1;
    $error_info .= "Unable to locate language file <b>$language_file</b>!  It should be in the same directory as plans.cgi!\n";
  }
  else {require $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 ($choose_themes)
{
  $theme_url=$q->param('theme_url');
  $theme_path=$theme_url;
} 

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

$graphics_path ="$theme_path/graphics";                      # where misc. graphics are 
$icons_path = "$theme_path/icons";                           # where icons are
$css_path = "$theme_path/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');
local $current_cal_id = $q->param('cal_id');
$current_cal_id = 0 if ($current_cal_id eq "" || $current_cal_id =~ /\D/);
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 $cal_or_list = $q->param('cal_or_list');


# 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();


foreach $cal_id (keys %calendars)
{
  if ($cal_id eq $current_cal_id && $cal_id ne "")
    {$input_cal_id_valid = 1;}
}


if (!$input_cal_id_valid)
{
  $current_cal_id=0;
  #$q->param(-name=>'cal_id',-values=>[0]);
}


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

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

# time-related globals
$rightnow = time() + 3600 * $current_cal{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_cal{custom_stylesheet} ne "")
{
  $css_path = "http://$current_cal{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_cal = %{$calendars{$current_cal_id}};
}

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


# set info window height & width
my ($info_window_width, $info_window_height) = split("x", $current_cal{info_window_size});

# rotate weekday_sequence by the offset defined in the week start day.
for ($l1=0;$l1 < $current_cal{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) = split (/\s/, $temp_line);
  push @event_bgcolors, $hex_color;
}

my $template_html;



#load template
my $custom_template_file_found=1;

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

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


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

# 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 = "";
}



if($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') > 2 || $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_cal{max_number_of_months})
{
  $cal_num_months = "$current_cal{default_number_of_months}";
}

if ($cal_num_months eq "" || $cal_num_months > $current_cal{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_cal{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}};
}





#calculate next and previous start months & years
$previous_cal_start_month=$cal_start_month-$cal_num_months;
$previous_cal_start_year=$cal_start_year;
if ($previous_cal_start_month < 0)
{
  $previous_cal_start_month +=12;
  $previous_cal_start_year--;
}
if ($cal_num_months > 1)
{
  $prev_string = $lang{previous_months};
  $prev_string =~ s/###num###/$cal_num_months/;
}
else
{
  $prev_string = $lang{previous_month};
}

$next_cal_start_month=$cal_start_month+$cal_num_months;
$next_cal_start_year=$cal_start_year;
if ($next_cal_start_month > 11)
{
  $next_cal_start_month -= 12;
  $next_cal_start_year++;
}
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 ("cal_or_list");
&make_consistent ("theme_url");

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

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

if ($q->param('export_calendar') eq "1")
{
  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);
  }
}

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 "vcalendar")
  {
    #&csv_file($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
    &vcalendar_export();
    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=iso-8859-1\n

$template_html
p1

  $html_output =~ s/###current calendar title###/$current_cal{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="event_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_cal{selectable_calendars}};
    if (scalar keys %{$current_cal{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} keys %{$current_cal{selectable_calendars}})
      {
        my $selected ="";
        $selected =" selected" if ($selectable_calendar_id eq $current_cal{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_cal{title}</span>
<input type="hidden" name="cal_id" value="$current_cal{id}">
p1
    }
      $cal_controls_text .=<<p1;
</div>
p1
    
    if ($cal_or_list eq "list") {$list_selected = "selected";}
    else {$cal_selected = "selected";}
    
    $cal_controls_text .=<<p1;
<div style="margin:5px;padding:2px;float:left;text-align:left;">
$lang{controls_display_label}<br/>
<select name="cal_or_list" onChange="blink('controls_submit_button', 3, 0);">
<option value="calendar" $cal_selected>$lang{controls_calendar}
<option value="list" $list_selected>$lang{controls_list}
</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_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;cal_or_list=$cal_or_list&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;cal_or_list=$cal_or_list&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="cal_or_list" value="$cal_or_list">
<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_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_path/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 = "cal_or_list" value="$cal_or_list">
<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_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_path/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_path/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');
  my $cal_or_list = $q->param('cal_or_list');

  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_cal = %default_cal;}
    
    $add_edit_string = "$lang{edit_calendar} ($current_cal{title})" if ($add_edit_cal_action eq "edit");
    
    my %checked;
    $checked{list_background_calendars_together} = " checked" if ($current_cal{list_background_calendars_together} eq "yes");
    $checked{background_events_display_style1} = " checked" if ($current_cal{background_events_display_style} eq "normal");
    $checked{background_events_display_style2} = " checked" if ($current_cal{background_events_display_style} eq "single_color");
    $checked{background_events_display_style3} = " checked" if ($current_cal{background_events_display_style} eq "faded");
    
    $current_cal{custom_stylesheet} = "http://$current_cal{custom_stylesheet}";
    $current_cal{custom_template} = "http://$current_cal{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_path/sv_blend.png')">
<br>
</div>
</div>
<div id="h_select_box0" class="h_select_box" style="margin-left:5px;background-image:url($graphics_path/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-->    
    
<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_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="cal_or_list" value="$cal_or_list">
<input type="hidden" name="theme_url" value="$theme_url">

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

<div class="info_box" style="text-align:center;margin-bottom:2em;">
<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;">
<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>
</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_cal{title}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('cal_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_cal{link}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('cal_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{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_cal{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:49%;text-align:left;"> 
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{help_on_this}</a></span>

</label>
<select multiple size=8 style="display:block;clear:left;" name="background_calendars" id="background_calendars" onKeyPress="if (event.keyCode == 13) return false;">
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_cal{id})
          {next;}

        #$debug_info .= "$current_cal{title} local_background_calendars{$cal_id} = $current_cal{local_background_calendars}{$cal_id}\n";
        my $selected="";
        
        if ($current_cal{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
    }

    if (scalar (keys %calendars) > 1 || $add_edit_cal_action ne "edit")
    {
  $return_text .=<<p1;
<label class="optional_field" style="float:left;margin-top:3ex;" 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{help_on_this}</a></span>
</label>
<select multiple size=8 style="display:block;clear:left;" name="selectable_calendars" id="selectable_calendars" onKeyPress="if (event.keyCode == 13) return false;">
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_cal{id})
          {next;}
        my $selected="";
    
        if ($current_cal{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 ($new_calendars_automatically_selectable =~ /y/)
    {
      my $temp="";
      if ($current_cal{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 onKeyPress="if (event.keyCode == 13) return false;">
<label class="optional_field" for="new_calendars_automatically_selectable">$lang{new_calendars_automatically_selectable}</label>
<br/><span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('new_calendars_automatically_selectable')">$lang{help_on_this}</a></span>
</div>
p1
    }
    
    
    $return_text .=<<p1;

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

<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{help_on_this}</a></span>
</div>

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

<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" onKeyPress="if (event.keyCode == 13) return false;" $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" onKeyPress="if (event.keyCode == 13) return false;" $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_path/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" onKeyPress="if (event.keyCode == 13) return false;" $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" onKeyPress="if (event.keyCode == 13) return false;" onChange="fade_preview();">
p1
    for ($i=1;$i<8;$i++)
    {
      my $selected="";
      $selected = " selected" if ($i eq $current_cal{background_events_fade_factor});
        $return_text .=<<p1;
<option value="$i"$selected>$i\l0\% faded
p1
    }

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

<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 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>
</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="margin-top:2ex;">
<input type="checkbox" id="list_background_calendars_together" name="list_background_calendars_together" value = "yes" onKeyPress="if (event.keyCode == 13) return false;" $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{help_on_this}</a></span>
</div>

</div>

<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 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_cal{default_number_of_months}" style="width:5ex;vertical-align:bottom;" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('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_cal{max_number_of_months}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('max_months')">$lang{help_on_this}</a></span>
</div>
<br style="line-height:0px;height:0px;clear:both;"/>


<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_cal{gmtime_diff}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('gmtime_diff')">$lang{help_on_this}</a></span>

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

<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_cal{date_format}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('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" onKeyPress="if (event.keyCode == 13) return false;">
p1
    
    for ($i=0;$i<7;$i++)
    {
      my $selected="";
      $selected = " selected" if ($i eq $current_cal{week_start_day});
        $return_text .=<<p1;
<option value="$i"$selected>$day_names[$i]
p1
    }
    
    my $temp1;
    if ($current_cal{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{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 onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('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_cal{info_window_size}" onKeyPress="if (event.keyCode == 13) return false;">
<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{help_on_this}</a></span>
</div>

<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_cal{custom_stylesheet}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('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_cal{custom_template}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('custom_template')">$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")
    {
      $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 onKeyPress="if (event.keyCode == 13) return false;" />
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('current_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{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 onKeyPress="if (event.keyCode == 13) return false;" />
<span class="small_note" style="vertical-align:top;">$lang{new_password} </span>
<br/>
<input type="password" name="repeat_new_cal_password" size=12 onKeyPress="if (event.keyCode == 13) return false;" />
<span class="small_note" style="vertical-align:top;">$lang{repeat_new_password}</span>
</div>

<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 onKeyPress="if (event.keyCode == 13) return false;" />
<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{help_on_this}</a></span>

<br/>
<input type="password" name="repeat_new_cal_password" size=12 onKeyPress="if (event.keyCode == 13) return false;" />
<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.
      $input_password = crypt($q->param('cal_password'), substr($q->param('cal_password'), 0, 2));
     
      if ($input_password ne $current_cal{password} && $input_password ne $master_password)
      {
        $del_valid=0;
        push @results_messages,  "$lang{update_cal_error1}<b>$current_cal{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;
        foreach $event_id (keys %events)
        {
          if ($events{$event_id}{cal_id} eq $cal_id)
            {push @deleted_event_ids, $event_id;}
        }
        &delete_events(\@deleted_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_cal{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 $new_calendars_automatically_selectable = $q->param('new_calendars_automatically_selectable');
      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 $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;
      }
      
      $new_calendars_automatically_selectable = "no" if ($new_calendars_automatically_selectable ne "yes");
      $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")
      {
        #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));
          }
        }
        
        if ($cal_valid == 1)
        { # make new 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}{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;
          
          # 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;}
            
          # 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 ($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}{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;
          
          # 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_cal{title} &&
              $new_calendars{$new_cal_id}{details} eq $latest_new_cal{details} &&
              $new_calendars{$new_cal_id}{link} eq $latest_new_cal{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;
        
          $cal_add_results .= <<p1;
<div style="text-align:left;">
<p style="font-weight:bold;">
$lang{add_cal_success1}
</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, "Calendar <b>not</b> added!";
        }
      }
      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="cal_or_list" value="$cal_or_list">
<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 ($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()
{
  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;cal_or_list=$cal_or_list&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;cal_or_list=$cal_or_list&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 ($cal_or_list eq "list") #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_path/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_cal{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_cal{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_id=$current_event{cal_id};
      %current_cal = %{$calendars{$current_event{cal_id}}};
      $cal_title=$calendars{$current_event{cal_id}}{title};
      
      $event_name=$current_event{title};
      $event_details=$current_event{details};
      
      $event_start_date = $current_cal{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_path\/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_path/sv_blend.png')">
<br>
</div>
</div>
<div id="h_select_box0" class="h_select_box" style="margin-left:5px;background-image:url($graphics_path/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;">
<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;">
<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
    if ($add_edit_event eq "edit" || scalar keys %{$current_cal{selectable_calendars}} == 0)  # force event calendar
    {
      $return_text .=<<p1;
<input type="hidden" name="evt_cal_id" value="$current_cal{id}">
<div class="leftcol">
<span class="optional_field">$lang{event_calendar}</span>
</div>
<div class="rightcol" style="padding-left:.5em;">
$current_cal{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}} keys %{$current_cal{selectable_calendars}})
      {
        if ($cal_ref_id eq $current_cal_id)
        {
          $return_text .=<<p1;
<option value = "$cal_ref_id" selected>$calendars{$cal_ref_id}{title}
p1
        }
        else
        {
          $return_text .=<<p1;
<option value = "$cal_ref_id">$calendars{$cal_ref_id}{title}
p1
        }
      }

    $return_text .=<<p1;
</select>
<span class="small_note"><a href="javascript:display_help('evt_cal_id')">$lang{help_on_this}</a></span>
</div>
p1
    }
    $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}" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('evt_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{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" onKeyPress="if (event.keyCode == 13) return false;">
</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" onKeyPress="if (event.keyCode == 13) return false;">
</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_path/$event_icon\l_32x32.gif" alt='event icon' border="0" vspace=0 hspace=0>
</div>
p1
    if ($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 ($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 $possible_bgcolor (@event_bgcolors)
    {
      my $selected="";
      if ($possible_bgcolor eq "$event_bgcolor")  #default
      {
        $custom_color=0;
        $selected=" selected";
      }
      $return_text .=<<p1;
<option value = "$possible_bgcolor" $selected>&nbsp;&nbsp;&nbsp;
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_path/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{help_on_this}</a>&nbsp;&nbsp;</span>
</div>
<div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
<input type="checkbox" name="recurring_event_change_all" 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{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{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 onfocus="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 onfocus="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 onfocus="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 onfocus="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{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>
p1
      
      $return_text .=<<p1;
      
<div class="info_box" style="clear:both;">

<div class="leftcol" style="">
<label class="required_field" for="evt_cal_password">$lang{event_calendar_password}</label>
</div>
<div class="rightcol" style="white-space:nowrap;">
<input type="password" id="evt_cal_password" name="evt_cal_password" style="width:30%;" onKeyPress="if (event.keyCode == 13) return false;">
<span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('evt_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 $recurring_event_change_all = $q->param('recurring_event_change_all');
    #$debug_info .= "recurring_event_change_all: $recurring_event_change_all\n";
    
    if ($q->param('evt_cal_id') ne "")
    {
      %current_cal =%{$calendars{$q->param('evt_cal_id')}};
    }
    
    
    # load (reload) all events (we have to write the 
    # entire data file, and we might not have loaded all events already)
    if ($data_storage_mode == 0 )  # flat text files
      {&load_events("all");}

    if ($q->param('del_event_button') ne "")
    {
      #delete event.  
      $del_valid=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_id}}{password} && $input_password ne $master_password)
      {
        $del_valid=0;
        push @results_messages, ($lang{update_event_err1}.$calendars{$current_event{cal_id}}{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 ($recurring_event eq "" || $recurring_event_change_all 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;
          foreach $event_id (keys %events)
          {
            my %event = %{$events{$event_id}};
            if ($event{series_id} eq $q->param('series_id'))
            {
              push @events_in_series, $event_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 $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');
      $recur_end_date = $q->param('recur_end_date');
      my $recur_end_timestamp = 0;
      $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};
      }
      if ($event_cal_password eq "")
      {
        $event_valid=0;
        push @results_messages, $lang{update_event_err6};
      }

      $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};
      }
      else
      {
        #check password
        $input_password = crypt($event_cal_password, substr($event_cal_password, 0, 2));
        
        my $temp=$q->param("evt_cal_id");
      
        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_cal{title}."</b>");
        }
      }
      
      # check dates
      if ($event_valid == 1)
      {
        my $results = &verify_date_input_new($event_start_date, $event_days);
        if ($results ne "")
        {
          $event_valid=0;
          $results =~ s/(.+?)\n/<li>$1<\/li>\n/g;      
          push @results_messages, "$lang{update_event_err9}<ul>$results</ul>"

        }
      }
      
      # check recurring dates
      if ($event_valid == 1)
      {
        @custom_months = $q->param('custom_months');

        if ($recurring_event ne "" && $add_edit_event eq "add")
        {
          $results = &verify_date_input_new($recur_end_date, 1);
          if ($results ne "")
          {        
            $event_valid=0;
            $results =~ s/(.+?)\n/<li>$1<\/li>\n/g;      
            push @results_messages, "$lang{update_event_err10}<ul>$results</ul>"
          }
        }
      }
      
      if ($event_valid == 1)
      {
        my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_cal{date_format});
        $start_mon--;  # convert month to 0-11 format
        
        $event_start_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year);
        
        $event_end_timestamp = $event_start_timestamp + ($event_days * 86400) - 1;
        #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_cal{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 "")
      {
        if ($latest_event{cal_id} 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!

        $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;
        
            # add event to %events data structure
            $events{$new_event_id} = {id => $new_event_id, 
                                      cal_id => $event_cal_id, 
                                      start => $event_start_timestamp, 
                                      end => $event_end_timestamp, 
                                      days => $event_days, 
                                      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);
            
            $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="";
            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)
            {
              $max_event_id += 1;
              my $new_event_id = $max_event_id;

              my $recurring_event_end_timestamp = $recurring_event_start_timestamp + ($event_days-1) * 86400;
              $recurring_event_end_timestamp = $recurring_event_start_timestamp + ($event_days * 86400) - 1;
              #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_id => $event_cal_id, 
                                      start => $recurring_event_start_timestamp, 
                                      end => $recurring_event_end_timestamp, 
                                      days => $event_days, 
                                      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
        {
          if ($recurring_event eq "" || $recurring_event_change_all ne "1")
          {
            $events{$event_id} = {id => $event_id,
                                cal_id => $event_cal_id,
                                start => $event_start_timestamp,
                                end => $event_end_timestamp, 
                                days => $event_days,
                                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{$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;
                
                $events{$event_id} = {id => $event_id,
                                      cal_id => $event_cal_id,
                                      start => $event{start},
                                      end => $event{end}, 
                                      days => $event{days},
                                      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_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 already_showed_context_menu=false;

if (name == "")
{
  name="cal_mainwindow";
}

var main_window_name=name;

window.name = main_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(event_id, menu_bgcolor)
{
  get_page_boundaries();
  
  active_event_id = event_id;
  
  var themenu = document.getElementById("event_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";
  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(day_timestamp)
{
  get_page_boundaries();
  active_day_timestamp = day_timestamp;
  
  var themenu = document.getElementById("event_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";

  return false;
}

function hide_contextmenus()
{
    document.getElementById("event_contextmenu").style.visibility = "hidden";
}

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 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=cal_or_list value="$ical_or_list">
<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">
<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;

  $return_string .= <<p1;
function delete_event(event_id)
{
  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>');
  doc.write("$delete_event_text");
  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_cal{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 ($cal_or_list eq "list") {$list_selected = "selected";}
  else {$cal_selected = "selected";}
    
  $custom_form_text .=<<p1;
<label for="cal_or_list" class="required_field">
$lang{custom_calendar_cal_or_list}
</label>

<select id="cal_or_list" name="cal_or_list">
<option value="calendar" $cal_selected>$lang{controls_calendar}
<option value="list" $list_selected>$lang{controls_list}
</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();
  
p1
 
  if ($current_cal{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_path/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_path/" + 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_path/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_path/eagle_medal_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>"));
  
}

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.recurring_event_change_all.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

  $help_text=<<p1;
<div class="help_title">
$lang{help_evt_calendar1}
</div>
<div class="help_box">
$lang{help_evt_calendar2}
</div>
p1

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

  $return_string .=<<p1;
  function display_help(topic) {

    if (topic == "evt_cal_id")
    {
      help_text="$help_text";

      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_evt_title1}
</div>
<div class="help_box">
$lang{help_evt_title2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "evt_title")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_evt_details1}
</div>
<div class="help_box">
$lang{help_evt_details2}
</div>
p1


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

  $return_string .=<<p1;
    if (topic == "evt_details")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_recurring_event1}
</div>
<div class="help_box">
$lang{help_recurring_event2}
</div>
p1


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

  $return_string .=<<p1;
    if (topic == "recurring_event")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_recurrence_type1}
</div>
<div class="help_box">
$lang{help_recurrence_type2}
</div>
p1


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

  $return_string .=<<p1;
    if (topic == "recurrence_type")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_fit_into_year1}
</div>
<div class="help_box">
$lang{help_fit_into_year2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "fit_into_year")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_evt_cal_password1}
</div>
<div class="help_box">
$lang{help_evt_cal_password2}
</div>
p1


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

  $return_string .=<<p1;
    if (topic == "evt_cal_password")
    {
      help_text="$help_text";
      show_help();
    }
p1



  $help_text=<<p1;
<div class="help_title">
$lang{help_recurring_event_change_all1}
</div>
<div class="help_box">
$lang{help_recurring_event_change_all2}
</div>
p1



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

  $return_string .=<<p1;
    if (topic == "recurring_event_change_all")
    {
      help_text="$help_text";
      show_help();
    }
  }
p1

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

sub add_edit_calendars_javascript
{
  my $return_string = "";

  $return_string.=<<p1;
// color select stuff
var cs0 = new color_select();
cs0.setrgb("$current_cal{background_events_color}");

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

function cs_init()
{
  cs0.sv_image="$graphics_path/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();
}

function color_menu0_update(new_color)
{
  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 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

  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() + 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('$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('$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

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_title1}
</div>
<div class="help_box">
$lang{help_cal_title2}
</div>
p1

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

  $return_string .=<<p1;
  function display_help(topic) {

    if (topic == "cal_title")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_link1}
</div>
<div class="help_box">
$lang{help_cal_link2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "cal_link")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_details1}
</div>
<div class="help_box">
$lang{help_cal_details2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "cal_details")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_new_cal_password1}
</div>
<div class="help_box">
$lang{help_new_cal_password2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "new_cal_password")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_current_cal_password1}
</div>
<div class="help_box">
$lang{help_current_cal_password2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "current_cal_password")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_change_cal_password1}
</div>
<div class="help_box">
$lang{help_change_cal_password2}
</div>
p1

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

  $return_string .=<<p1;
    if (topic == "change_cal_password")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_background_calendars1}
</div>
<div class="help_box">
$lang{help_cal_background_calendars2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "cal_background_calendars")
    {
      help_text="$help_text";
      show_help();
    }
p1
    

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_selectable_calendars1}
</div>
<div class="help_box">
$lang{help_cal_selectable_calendars2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "selectable_calendars")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_background_events_display_style1}
</div>
<div class="help_box">
$lang{help_cal_background_events_display_style2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "background_events_display_style")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_list_background_calendars_together1}
</div>
<div class="help_box">
$lang{help_cal_list_background_calendars_together2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "list_background_calendars_together")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_number_of_months1}
</div>
<div class="help_box">
$lang{help_cal_number_of_months2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "number_of_months")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_max_months1}
</div>
<div class="help_box">
$lang{help_cal_max_months2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "max_months")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_gmtime_diff1}
</div>
<div class="help_box">
$lang{help_cal_gmtime_diff2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "gmtime_diff")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_date_format1}
</div>
<div class="help_box">
$lang{help_cal_date_format2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "date_format")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_week_start_day1}
</div>
<div class="help_box">
$lang{help_cal_week_start_day2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "week_start_day")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_new_calendars_automatically_selectable1}
</div>
<div class="help_box">
$lang{help_cal_new_calendars_automatically_selectable2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "new_calendars_automatically_selectable")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_preload_event_details1}
</div>
<div class="help_box">
$lang{help_cal_preload_event_details2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "preload_event_details")
    {
      help_text="$help_text";
      show_help();
    }
p1


  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_popup_window_size1}
</div>
<div class="help_box">
$lang{help_cal_popup_window_size2}
</div>
p1
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "popup_window_size")
    {
      help_text="$help_text";
      show_help();
    }
p1



  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_custom_stylesheet1}
</div>
<div class="help_box">
$lang{help_cal_custom_stylesheet2}
</div>
p1

  $help_text =~ s/###css file###/$css_path/g;
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "custom_stylesheet")
    {
      help_text="$help_text";
      show_help();
    }
p1

  $help_text=<<p1;
<div class="help_title">
$lang{help_cal_custom_template1}
</div>
<div class="help_box">
$lang{help_cal_custom_template2}
</div>
p1

  $help_text =~ s/###template file###/$theme_path\/plans.template/g;
  $help_text =~ s/\n/\\n/g;
  $help_text =~ s/"/\\"/g;
  $help_text =~ s/'/\\'/g;
  $help_text =~ s/\//\\\//g;

  $return_string .=<<p1;
    if (topic == "custom_template")
    {
      help_text="$help_text";
      show_help();
    }
p1
    
  $return_string .=<<p1;
  }
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_cal{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;
    
    #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}) 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_cal{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
      #   @ids        = event ids

      foreach $week_event_id (sort {$week_events{$l1}{$b}{length} <=> $week_events{$l1}{$a}{length}}  keys %{$week_events{$l1}})
      {
        $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)
            {$week_slots{$l1}{$day_index}{$slot_index}{width} = $week_events{$l1}{$week_event_id}{length};}
          else
            {$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;
          }
        }
      }
     
      # 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 slot below this one, that's 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) # 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;
              }
            }
          }
        }
      }
      
      # extend blank 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)
            {next;}
        
          if ( $week_slots{$l1}{$l2}{$l3}{width} > 0)  # if it's blank
          {
            my $start_slot = $l3+1;
            for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++)   
            {
              if ($week_slots{$l1}{$l2}{$l4}{width} == 1)
              {
                #$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 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.  re-calculate max_slots and trim vertical depth
      my $trim = 0;
    
      for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++)
      {
        if ($slots_in_row{$l1}{$l3} == 0)
          {$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";
          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" oncontextmenu="if (event.ctrlKey){return true;}else{show_day_contextmenu($week_date_index);return false;}">
<div class="date today" style="$date_div_style">$cal_date_array[3]</div>
</td>
p1
            }
            else
            {
              $return_text .=<<p1;
<td class="$td_class" style="$td_style" oncontextmenu="if (event.ctrlKey){return true;}else{show_day_contextmenu($week_date_index);return false;}">
<div class="date">$cal_date_array[3]</div>
</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 oncontextmenu="if (event.ctrlKey){return true;}else if(already_showed_context_menu){already_showed_context_menu=false;return false;}else{show_day_contextmenu($week_date_index);return false;}">
p1
            
              foreach $event_id (@{$week_slots{$l1}{$l2}{$l3}{ids}})
              {
                my $event_bgcolor = $events{$event_id}{bgcolor};
                my $event_box_class = "event_box";
            
                if ($events{$event_id}{cal_id} != $current_cal{id})
                {
                  $event_box_class .= " background";
                    
                  if ($current_cal{background_events_display_style} eq "single_color")
                    {$event_bgcolor = $current_cal{background_events_color};}
                  elsif ($current_cal{background_events_display_style} eq "faded")
                  {
                    # create "faded" look for background event
                    my $faded_color = $events{$event_id}{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_cal{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";
                  }
                }
              
                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_path\/unit_number_patch_$1_16x10.gif" border="0" alt=\"\" vspace=0 hspace=0 style="vertical-align:middle;">/g;
                }
              
                if ($events{$event_id}{icon} ne "blank")
                {
                  $icon_text = <<p1;
<img align="bottom" src = "$icons_path/$events{$event_id}{icon}_16x16.gif" alt="" hspace=2 vspace=0>
p1
                }
              
                $icon_text = "$unit_icon_text$icon_text";
              
                if ($week_slots{$l1}{$l2}{$l3}{width} == 1)
                {
                  $return_text .=<<p1;
<a href="javascript:display_event('$event_id');" class="$event_box_class" style="display:block;padding-left:29px;text-align:left;background-color:$event_bgcolor;cursor:pointer;cursor:hand;"  oncontextmenu="if (event.ctrlKey){return true;}else{show_event_contextmenu($event_id, '$event_bgcolor');already_showed_context_menu=true;return false;}">
<img src="$icons_path/$events{$event_id}{icon}_16x16.gif" style="margin-left:-22px;margin-right:5px;margin-bottom:-5px;">$unit_icon_text<span style="margin-left:5px;">$events{$event_id}{title}</span></a>
p1
                }
                else
                {
                  $return_text .=<<p1;
<a href="javascript:display_event('$event_id');" class="$event_box_class" style="display:block;text-align:center;background-color:$event_bgcolor;cursor:pointer;cursor:hand;"  oncontextmenu="if (event.ctrlKey){return true;}else{show_event_contextmenu($event_id, '$event_bgcolor');already_showed_context_menu=true;return false;}">
<img src="$icons_path/$events{$event_id}{icon}_16x16.gif" style="vertical-align:middle;margin-right:5px;">$unit_icon_text<span style="margin-left:5px;">$events{$event_id}{title}</span></a>
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 oncontextmenu="if (event.ctrlKey){return true;}else if(already_showed_context_menu){already_showed_context_menu=false;return false;}else{show_day_contextmenu($week_date_index);return false;}">
</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 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" oncontextmenu="if (event.ctrlKey){return true;}else{show_day_contextmenu($week_date_index);return false;}">&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.
  foreach $event_id (keys %events)
  {
    if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
    {
      if ($events{$event_id}{cal_id} eq $current_cal_id)
        {push @selected_cal_events, $event_id;}
      else
        {push @list_events, $event_id;}
    }
  }
  
  # take the results of the previous sort and create a
  # funky data structure (broken down according to the calendars currently
  # selected)
  
  # create hash to hold that data structure
  # each element of this hash will be an array.
  $shared_cal_events={};  #empty hash
  
  #fill up that hash
  foreach $background_cal_id (keys %{$current_cal{local_background_calendars}})
  {
    foreach $event_id (@list_events)
    {
      if ($events{$event_id}{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_path\/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_path/$event{icon}_16x16.gif\" style=\"vertical-align:middle;\" alt=\"\">";
        }
       
        $return_text .=<<p1;
<li style="margin-top:10px;margin-bottom:4px;">
<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')" oncontextmenu="if (event.ctrlKey){return true;}else{show_event_contextmenu($event{id}, '$event{bgcolor}');already_showed_context_menu=true;return false;}"> $date_string </span>
<a class="event_box" style="text-align:left;white-space:nowrap;margin-bottom:2px;background-color:$event{bgcolor};" href="javascript:display_event('$event{id}')"> $icon_text $event{title}</a>
</li>
p1
      }
    }


    if ($current_cal{list_background_calendars_together} ne "yes")
    {
      $return_text .=<<p1;
</ul>
p1
    }
    
    foreach $background_cal_id (keys %{$current_cal{local_background_calendars}})
    {
      if ($current_cal{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_path\/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_path/$event{icon}_16x16.gif\" style=\"vertical-align:middle;\" alt=\"\" vspace=0>";
          }
          
          my $date_style="line-height:120%;";
          if ($icon_text eq "")
            {$date_style="";}
            
          $return_text .=<<p1;
<li style="margin-top:10px;margin-bottom:4px;white-space:nowrap;">
<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')" oncontextmenu="if (event.ctrlKey){return true;}else{show_event_contextmenu($event{id}, '$event{bgcolor}');already_showed_context_menu=true;return false;}"> $date_string </span>
<a class="event_box" style="text-align:left;white-space:nowrap;margin-bottom:2px;background-color:$event{bgcolor};" href="javascript:display_event('$event{id}')"> $icon_text $event{title}</a>
</li>
p1
        }
      }
      if ($current_cal{list_background_calendars_together} ne "yes")
      {

        $return_text .=<<p1;
</ul>
<br style="clear:both;"/>  <!--needed because IE sucks-->
p1
      }
    }
    
    if ($current_cal{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;
  $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))
    {

      $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 event_details = new Array($num_events);  // array to hold days in current month view
$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 calendar view dates.
  foreach $event_id (keys %events)
  {
    my %event = %{$events{$event_id}};
    if (&time_overlap($event{start},$event{end},$list_start_timestamp,$list_end_timestamp))
    {
      if ($event{cal_id} eq $current_cal_id)
        {push @selected_cal_events, $event_id;}
      else
        {push @list_events, $event_id;}
    }
  }
  
  #take the results of the previous sort and arrange them into a
  #funky data structure (broken down according to the calendars currently
  #selected)
  
  #create hash to hold that data structure
  #each element of this hash will be an array.
  $shared_cal_events={};  #empty hash
  
  #fill up that hash
  foreach $background_cal_id (keys %{$calendars{$current_cal_id}{local_background_calendars}})
  {
    foreach $event_id (@list_events)
    {
      if ($events{$event_id}{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-Type: text/plain; charset=iso-8859-1\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_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 .=<<p1;
"$csv_subject","$csv_start_date",,$csv_end_date,,"True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1"
p1
      }
    }
    foreach $background_cal_id (keys %{$current_cal{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 .=<<p1;
"$csv_subject","$csv_start_date",,$csv_end_date,,"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 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);
  
  #@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 calendar view dates.
  foreach $event_id (keys %events)
  {
    if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
    {
      if ($events{$event_id}{cal_id} eq $current_cal_id)
        {push @selected_cal_events, $event_id;}

      else
        {push @list_events, $event_id;}
    }
  }
  
  #take the results of the previous sort and arrange them into a
  #funky data structure (broken down according to the calendars currently
  #selected)
  
  #create hash to hold that data structure
  #each element of this hash will be an array.
  $shared_cal_events={};  #empty hash
  
  #fill up that hash
  foreach $background_cal_id (keys %{$current_cal{local_background_calendars}})
  {
    foreach $event_id (@list_events)
    {
      if ($events{$event_id}{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-Type: text/plain; charset=iso-8859-1\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_cal{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};
        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 $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{title}\n";
        if ($event_details ne "")
        {
          $html_output .= "    $event_details\n\n";
        }
      }
    }
    foreach $background_cal_id (keys %{$current_cal{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};
          @event_end_timestamp_array = gmtime $event{end};
          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
          {
            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]";
            }
          }
          $html_output .=<<p1;
  $date_string: $event{title}
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;
  
}  #********************end ascii_text_cal subroutine**********************

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

p1

  my @event_start_timestamp_array = gmtime $current_event{start};
  my $date_string="";
    #display events for selected calendar
  if ($current_event{days} eq "1")
  { #single-day event
    $date_string="$day_names[$event_start_timestamp_array[6]], $months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
  }
  else #multi-day event
  {
    @event_end_timestamp_array = gmtime $current_event{end};
    if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4])
    {
      $date_string="$day_names[$event_start_timestamp_array[6]]$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 $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: $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 vcalendar_export
{
  # 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.

  $the_event = $current_event;
    
  my $start_timestamp = $current_event{start};
  my $end_timestamp = $current_event{end};

  my $dtstart_string = &outlook_date_time($start_timestamp);
  my $dtend_string = &outlook_date_time($end_timestamp);


  $cal_name=$calendars{$current_event{cal_id}}{title};

  # replace newlines with carraige-returns (otherwise two newlines in a row
  # causes errors.  Not sure whether this is an outlook error or an IE error.
  
  $current_event{details} =~ s/\n/\r/g;
  $current_event{title} =~ s/\n/\r/g;

$ical_string =<<p1;
BEGIN:VCALENDAR
PRODID:-//Plans//EN
VERSION:3.0
METHOD:PUBLISH
BEGIN:VEVENT
ORGANIZER:
DTSTART:$dtstart_string
DTEND:$dtend_string
TRANSP:OPAQUE
SEQUENCE:0
UID:
DTSTAMP:20020322T043444Z
DESCRIPTION:$current_event{details}
SUMMARY:$current_event{title} ($cal_name)
PRIORITY:5
CLASS:PUBLIC
END:VEVENT
END:VCALENDAR
p1


  $ical_string_length = length $ical_string;

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

$ical_string

p1



  print $html_output;

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


sub outlook_date_time
{
  my ($timestamp) = @_;
  
  my @timestamp_array = gmtime($timestamp);
  my $year_string = 1900 + $timestamp_array[5];
  
  my $month_string = $timestamp_array[4]+1;
  if ($month_string < 10)
    {$month_string="0".$month_string;}
  
  my $mday_string = $timestamp_array[3];
  if ($mday_string < 10)
    {$mday_string="0".$mday_string;}
    
  my $hour_string = $timestamp_array[2];
  if ($hour_string < 10)
    {$hour_string="0".$hour_string;}
    
  $hour_string="12";
  
  my $dt_string="$year_string$month_string$mday_string";
  $dt_string .= "T".$hour_string."0000Z";
  #$dt_string .= "T".$hour_string."0000";

  return $dt_string;
}


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<br>\n";
          $debug_info .= "current month: $current_month<br>\n";
          $debug_info .= "lookahead timestamp: $recur_timestamp_next_week<br>\n";
          $debug_info .= "lookahead month: $recur_timestamp_next_week_array[4]<br>\n";
          $debug_info .= "<br>\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_input_new()
{
  # $date is of the format similar to mm/dd/yy (or a permutation like dd/mm/yy)
  my ($date, $days) = @_;
  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_cal{date_format}/;
    $results .= $lang{date_verify_err0}."\n";
  }
  
  if ($date eq "")
  {
    $results .= $lang{date_verify_err1}."\n";
  }
  if ($days eq "")
  {
    $results .= $lang{date_verify_err2}."\n";
  }
  if ($days =~ m/\D/ || $days <= 0)
  {
    $results .= $lang{date_verify_err3}."\n";
  }
  
  my ($mon, $day, $year) = &format2mdy($date, $current_cal{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 preview_date
{
  my $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>
<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_cal = %{$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_input_new($event_start_date, $event_days);
  if ($recurring_event)
  {
    my $temp .= &verify_date_input_new($recur_end_date, 1);
    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_cal{date_format});
    my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recur_end_date, $current_cal{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'),
                                            unit_number => $q->param('unit_number')});
  
  my $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>
<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);
  
  my $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>
<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
</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 $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>
<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>

<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/>
<input type="checkbox" name="send_test_now"/ value="1"> $lang{email_reminder_text4}
<br/><br/>
<input type="submit" value="$lang{email_reminder_text5}"/>
</form>
</div>
</body>
</html>
p1

print $html_output;
}  # email_reminder_prompt


sub email_reminder_confirm
{
  my $reminder_results = "";
  my $to_address = $q->param('email_address');
  $to_address =~ s/\s//g;
  chomp $to_address;
  
  my ($reminder_seconds, $reminder_time) = split(/, ?/,$q->param('reminder_time'));
  $reminder_time = lc $reminder_time;
  
  
  if (!($to_address =~ /^[\w\-\_\.]+\@([\w\-\_]+\.)+[a-zA-Z]{2,}$/))
  {
    $reminder_results = $lang{email_reminder_invalid_address};
    $reminder_results =~ s/###address###/$to_address/g;
  }
  else
  {
    # assemble email reminder xml
    my $reminder_xml = "";
    $reminder_xml .= &xml_store($current_event{id}, "evt_id").
                     &xml_store($reminder_seconds, "before").
                     &xml_store($to_address, "email_address").
                     &xml_store($rightnow, "timestamp");
    $reminder_xml = "<email_reminder>$reminder_xml</email_reminder>\n";

  
    # write email reminder to file
    open (FH, ">>$email_reminders_datafile") || ($debug_info .="<br/>Unable to open email reminders data file $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}, " - ");
  
      $reminder_text =~ s/###title###/$current_event{title}/g;
      $reminder_text =~ s/###date###/$date_string/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;

      $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_results} =~ s/###address###/$to_address/g; 
    $lang{email_reminder_results} =~ s/###reminder time###/$reminder_time/g; 

    $reminder_results = <<p1;
$lang{email_reminder_results}
<br/><br/>
$test_reminder_results
p1
  }
  
  
  my $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>
<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 remote_calendar_request()
{
  my $html_output .=<<p1;
Cache-control: no-cache,no-store,private
Content-Type: text/xml; charset=iso-8859-1\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)
    {
      $results .=<<p1;
<public_calendar><id>$cal_id</id><title>$calendars{$cal_id}{title}</title></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</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 (keys %events)
        {
          if ($events{$event}{cal_id} ne $current_cal_id)
          {next;}
        
          my $xml_data = &event2xml($events{$event});
          $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 min { @_ = sort @_; shift; }
sub max { @_ = sort @_; pop; }

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=iso-8859-1\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>
<b>Config information</b>
<br><br>
<b>Script Name:</b>$name<br>
<b>Config file:</b> $config_file<br>
<b>Default template file:</b> $default_template_file<br>
<b>events file:</b> $events_file<br>
<b>calendars file:</b> $calendars_file<br>
<b>graphics path:</b> $graphics_path<br>
<b>icons path:</b> $icons_path<br>

<br><br>
<b>Options</b>
<br><br>
<b>Debug info:</b><br>
<font color="#0000ff">
$debug_info
</font>
</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="cal_or_list" value="$cal_or_list">
<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{plain_text}
<option value="csv_file">$lang{csv_file}
</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);
}

