<?php if(!defined('PmWiki')) exit();

error_reporting(E_ALL);

/**

SYNTAX:
´´´´´´

 dcalin is a markup that fills an array with information that will be displayed
 afterwards by dcal.

 dcalin is done as a markup expression so it can be written to a page independent 
 of dcal position, so dcalin entries written before and after the dcal markup will
 be showed by dcal.

 {(dcalin
    id="alpha num"  defaults to to "dcal" and defines to which calendar this entry belongs

    ut or utime="num" give dcalin unixtime an it will do the rest, defaults to empty

    y or year="num" defaults to current year with 4 digits 0000 ... 9999
    m or month="num" defaults to current month with 1 to 2 digits. 1 ... 12
    d or day="num" defaults to current day with one to two digits. 1 ... 31
    h or hour="num" defaults to current hour from 0 to 23
    mn or minute="num" defaults to current minute from 0 to 59

    ln or link="alpha num char" defaults to nothing
    tt or title="alpaha num char" defaults to a translatable $[empty] string
    tx or text="alpaha num char" defaults to a translatable $[empty] string

    dr or duration="num" defaults to the value in $DcalinDefaultDuration
    pr or periodicity="hourly,daily,weekly,monthly,yearly" defaults to normal

    fmt="alpha num char" includes the format that will be used to format dcalin items inside dcal
                         can be a entry in $DcalItemFmt or sections in any page.
 )}

 dcal makes the table with headers, prev and next links, caption with current month,
 creates links or just display text related to each dcalin entry.

 (:dcal
    id="alpha num" defaults to to "dcal" sets the calendar id <table id="dcal-?????">
          helps defining dynamic month and year for each calendar and selection of dcalin entries

    y or year="num" defaults to current year 
    m or month="num" defaults to current month

    ws or weekstart="num" default to sunday=0 defines the day in which weeknames will start
    wl or weekdaylength="num" defines the number of letters week names will have

    tt or title ="alpha num char" defaults to monthname
    tu or titleurl="alpha num char" defaults to nothing, a link to other place inside or outside the wiki

    pmu or prevmonthurl="alpha num char" defaults to (month - 1)
    nmu or nextmonthurl="alpha num char" defaults to (month + 1)
    pmd or prevmonthdecor="alpha num char" defaults to html entitie &lsaquo
    nmd or nextmonthdecor="alpha num char" defaults to html entitie &rsaquo

    pyu or prevyearhurl="alpha num char" defaults to (year - 1)
    nyu or nextyearurl="alpha num char" defaults to (year + 1)
    pyd or prevyeardecor="alpha num char" defaults to html entitie &laquo
    nyd or nextyeardecor="alpha num char" defaults to html entitie &raquo

    w or width="num + (%|px|em|ex)" defines width for the whole calendar

    dn or dynamic="num" make dcal accept parameters sent trough the GET and POST,
                  store it in cookies (if >1) 
    tp or type="alpha" [calendar|list] render a calendar or a list of days
    hd or header="num" defaults to 0 showing a caption with month and year,
                       1 shows a caption with month and year or linked title with provided titleurl  (options above)
                       2 shows a caption with month and year plus links for previous 
                         and next month and year with or without provided links
                       3 shows a caption with a select form for month and year as the title

    sw or showeek="num" shows week number defaults to 0 (no show)
    sd or showday="num" shows day nymber defaults to 1 (show)
    swd or showeekday="num" shows week day names defaults to 1 (show)

    fmt="alpha num char" includes the format that will override dcalin format
                         can be an entry in $DcalItemFmt or any page section

 :)

CHANGELOG:
´´´´´´´´´´
* now PR functions will leave periodicity intact for new items
* create styles for both views
* fix styles for prevnext and select
* fix styles for each viewgen
* now dcal fmt is being respected and item['fmt'] too
* included RetrieveSectionAuth for text option
* removed DcalGetSection
* changed fmt handling inside dcal
* fixed dynamic cookie and request handling
* included check to see if any css styles coming
  from files or from DcalStylesFmt are not already
  loaded in $HTMLHeaderFmt and HTMStylesFmt
* added css file calling and css style calling to dcal
* added title to dcalin
* included default sizes in listgen and calgen
* implemented yearly, monthly, weekly, daily events
* changed DcaPrevNext and Select to use $args directly
* included a title field to dcalin
* implement a better fmt for dcal and dcalin
* create a fmt option that works similarly to the pagelist one
* implement duration
* create periodicity handlers for yearly, weekly, monthly and daily
* DcalListGen fully implemented
* included option showeekday for DcalListGen
* dcalin can set a different fmt for each entry but it is overuled by dcal fmt
* created DcalItemFmt to help style each entry in dcal
* created DcalFmtV variables that help formatting an entry
* changed the way css styles work inside the script. *Still needs work*
* separated calendar rendering from main dcal processing
* separated DcalSelect and DcalPrevNext from Dcal
* made dcal to process a new dcalin format
* made dcalin store info differently from the old array style
* Made DcalSelect work with and without javascript
* changed firstday to weekstart
* included option to change the name of each calendar title and titleurl
* next and prev can include a link to somewhere else
* use parameters sent trough $_POST for some vars (year|month|day)
* included next and prev to change the calendar year
* cleaned hour, minute, item loop
* implement "showeek" option
* removed "d or day="num" defaults to current day" from dcal markup
* separated the script in different functions
* changed a lot of stuff from first version that was done in 3 days on and off


TODO:
´´´´´
* sanitize all dcal options and cookies we use
* include options from get and post for other options ?!?

*/

$RecipeInfo['Dcal']['Version'] = '20111020';

// A dedicatory
// please don't remove
// it does nothing
$Dedicatory['CarlosAB'] = array(
  'GP' => 'ESG-OZG-FB-AMB',
  'P' => 'DZG-JAB',
  'B' => 'LBS-TLB',
  'FB' => 'JABJ-GB',
  'SBL' => 'RS-RCDB',
  'N' => 'SB-RJS-LCS'
);
// 
// page variables to be used with dcalin utime
$FmtPV['$ULastModified'] = '$page["time"]';

// limit of entries for Dcalin
SDV($DcalinItemLimit, 1000);

// standsrd duration of an entry
SDV($DcalinDefaultDuration, 30);

// cookies expire in one hour
SDV($DcalCookieExpire, ($Now+3600));

SDV($DcalFmtVars , array(
  'year' => "date('Y',\$item['utime'])",
  'month' => "date('n',\$item['utime'])",
  'day' => "date('j',\$item['utime'])",
  'hour' => "date('G',\$item['utime'])",
  'minute' => "date('i',\$item['utime'])",
  'link' => "\$item['link']",
  'title' => "\$item['title']",
  'text' => "\$item['text']",
  'period' => "\$item['periodicity']",
  'duration' => "\$item['duration']",
  'dcalid' => "\$id"
));

SDV($DcalPRHandler, array(
  'yearly' => 'DcalPRYearly',
  'monthly' => 'DcalPRMonthly',
  'weekly' => 'DcalPRWeekly',
  'daily' => 'DcalPRDaily'
));

SDV($DcalStylesFmt, array(
  'green' => '
  div#green table.calgen caption.monthandyear { border:1px solid green; }
  div#green table.calgen { border:1px solid green; }
  div#green table.calgen td { border:1px solid green; }
  div#green table.calgen .colspan { background:#eee;border:1px solid green; }
  div#green table.calgen th { border:1px solid green; }
  div#green table.calgen div.daynumber { background:green; }
  div#green table.calgen .today { background:green; }

  div#green table.listgen caption.monthandyear { border:1px solid green; }
  div#green table.listgen { color:black;border:1px solid green; }
  div#green table.listgen table th { border:1px solid green; }
'
));

SDV($DcalItemFmt , array(
'default' => '
<!--{$year}/{$month}/{$day} - default -{$dcalid} -->
<div class="item" style="clear:both;max-width:150px;margin:5px;border:1px solid black" >
  <div style="border:1px solid black;padding:2px;margin:0">
    <span>{$year}</span>/<span>{$month}</span>/<span>{$day}</span> <span>{$hour}</span>:<span>{$minute}</span>
  </div>
  <div style="border:1px solid black;padding:2px;margin:0">
    <a href="{$link}">{$title}</a>
  </div>
  <div style="border:1px solid black;padding:2px;margin:0">
    {$text}
  </div>
</div>
',

'byside' => '
<!--{$year}/{$month}/{$day} - byside - {$dcalid} -->
<div style="float:left;margin:5px;padding:0;border:1px solid black" >
  <div style="border:1px solid black;padding:2px;margin:0">
    <span>{$year}</span>/<span>{$month}</span>/<span>{$day}</span> <span>{$hour}</span>:<span>{$minute}</span>
  </div>
  <div style="border:1px solid black;padding:2px;margin:0">
    <span>{$duration}</span>|<span>{$period}</span>
  </div>
  <div style="border:1px solid black;padding:2px;margin:0">
    <a href="{$link}">{$title}</a>
  </div>
  <div style="border:1px solid black;padding:2px;margin:0">
    {$text}
  </div>
</div>
',
));

// markup definitions for the Dcal recipe
Markup('Dcal' , 'directives','/\\(:dcal(.*?):\\)/e' , "Keep(Dcal(\$pagename,PSS('$1')))");
//Markup('DcalIn' , '<directives','/\\(:dcalin(.*?):\\)/e' , "DcalIn(\$pagename,PSS('$1'))");
SDVA($MarkupExpr, array('dcalin' => 'DcalIn($pagename,$argp)'));
Markup('DcalPrnt' , '<directives','/\(:dcalprnt:\)/ei' , "Keep(DcalPrnt())");
Markup('test' , 'directives','/\\(:test(.*?):\\)/e' , "\"<pre>\".var_export(ParseArgs(PSS('$1')),true).\"</pre>\"");

// function to expose DcalItems array
function DcalPrnt(){
global $DcalItems;
$x = var_export($DcalItems,true);
return "<pre style='padding:2px;border:1px solid black;height:200px;overflow:auto'>$x</pre>";
}

function DcalPRWeekly($pn,$y,$m,$a){
$utime = $a['utime'];
$year = date('Y',$utime);
$month= date('n',$utime);
$hour = date('G',$utime);
$minute = date('i',$utime);
$daysmonth = date('t',$utime);
$prevmonth = $month - 1;
$daysprevmonth = date('t',mktime(0,0,1,$prevmonth,1,$year));
$lastweek = date('W',mktime(0,0,1,$month,$daysmonth,$year));
$prevweek = date('W',mktime(0,0,1,$prevmonth,$daysprevmonth, $year));
$weeksinmonth = ($lastweek - $prevweek)+1;
$day = date('j',$utime);
$cweek = ceil((date("d", $utime) - date("w",$utime)-1)/7)+1;

$beforeweeks = $cweek-1;
$afterweeks = $weeksinmonth - $cweek ;


if($y == $year && $m == $month){

  if($beforeweeks > 1){
    $beforetime = mktime($hour,$minute,30,$m,$day,$y);
    for($bf=1;$bf<=$beforeweeks;$bf++){
      $beforetime = $beforetime - 604800;
      $tbitem = $a;
      $tbitem['utime'] = $beforetime;
      $tmpitems[] = $tbitem;
    }
  }

  if($weeksinmonth > $afterweeks){
    $aftertime = mktime($hour,$minute,30,$m,$day,$y);
    for($af=1;$af<=$afterweeks;$af++){
      $aftertime = $aftertime + 604800;
      $taitem = $a;
      $taitem['utime'] = $aftertime;
      $tmpitems[] = $taitem;
    }
  }

}else{

    $weektime = mktime($hour,$minute,30,$m,$day,$y);
    for($wi=1;$wi<=$weeksinmonth;$wi++){
      $weektime = $weektime + 604800;
      $twitem = $a;
      $twitem['utime'] = $weektime;
      $tmpitems[] = $twitem;
    }

}

return $tmpitems;

}

function DcalPRYearly($pn,$y,$m,$a){

$utime = $a['utime'];
$year = date('Y',$utime);
$month= date('n',$utime);
$day = date('j',$utime);
$hour = date('G',$utime);
$minute = date('i',$utime);

  if($year != $y){
    $yearlytime = mktime($hour,$minute,30,$month,$day,$y);
    $tyitem = $a;
    $tyitem['utime'] = $yearlytime;
    $tmpitem[] = $tyitem;
    return $tmpitem;
  }
}

function DcalPRMonthly($pn,$y,$m,$a){

$utime = $a['utime'];
$year = date('Y',$utime);
$month= date('n',$utime);
$day = date('j',$utime);
$hour = date('G',$utime);
$minute = date('i',$utime);

  if($month != $m){
    $monthlytime = mktime($hour,$minute,30,$m,$day,$y);
    $tmitem = $a;
    $tmitem['utime'] = $monthlytime;
    $tmpitem[] = $tmitem;
    return $tmpitem;
  }
}

function DcalPRDaily($pn,$y,$m,$a){
global $DcalItems;

$utime = $a['utime'];
$year = date('Y',$utime);
$month= date('n',$utime);
$day = date('j',$utime);
$hour = date('G',$utime);
$minute = date('i',$utime);

$daysinmonth = date('t',mktime(0,0,1,$m,1,$y));

if($m == $month && $y == $year){
  for($mi=1;$mi<=$daysinmonth;$mi++){
    if($mi != $day){
      $dailytime = mktime($hour,$minute,30,$m,$mi,$y);
      $tditem = $a;
      $tditem['utime'] = $dailytime;
      $tmpitems[] = $tditem;
    }
  }
}else{
 for($mi=1;$mi<=$daysinmonth;$mi++){
    $dailytime = mktime($hour,$minute,30,$m,$mi,$y);
    $tditem = $a;
    $tditem['utime'] = $dailytime;
    $tmpitems[] = $tditem;
  }
}

return $tmpitems;

}

function DcalIn($pagename,$args){

StopWatch('Dcalin begin');

global  $DcalinItemLimit,$DcalinDefaultDuration,
        $DcalItems,$Now;

// parse args
$a = $args;

//makes keys lower case
$a = array_change_key_case($a,CASE_LOWER);

// today year, month, day, hour and minute
$tyear = strftime('%Y',$Now) * 1;
$tmonth = strftime('%m',$Now) * 1;
$tday = strftime('%d',$Now) * 1;
$thour = strftime('%H',$Now) * 1;
$tmin = strftime('%M',$Now) * 1;

// options and shortcuts
if(@$a['id']) $id = @$a['id'];
  else $id = 'dcal';
if(@$a['utime'] != '') $utime = $a['utime']; 
  elseif(@$a['ut'] != '') $utime = $a['ut'];
    else $utime = '';
if(@$a['year'] != '') $year = $a['year'];
  elseif(@$a['y'] != '') $year = $a['y'];
    elseif($utime != '') $year = strftime('%Y',$utime);
      else $year = $tyear;
        $year = $year * 1;
if(@$a['month'] != '')$month = $a['month'];
  elseif(@$a['m'] != '')$month = $a['m'];
    elseif($utime != '') $month = strftime('%m',$utime);
      else $month = $tmonth;
        $month = $month * 1;
if(@$a['day'] != '') $day = $a['day'];
  elseif(@$a['d'] != '') $day = $a['d'];
    elseif($utime != '') $day = strftime('%d',$utime);
      else $day = $tday;
        $day = $day * 1;
if(@$a['hour'] != '') $hour = $a['hour'];
  elseif(@$a['h'] != '') $hour = $a['h'];
    elseif($utime != '') $hour = strftime('%H',$utime);
      else $hour = $thour;
        $hour = $hour * 1;
if(@$a['min'] != '') $min = $a['min'];
  elseif(@$a['mn'] != '') $min = $a['mn'];
    elseif($utime != '') $min = strftime('%H',$utime);
      else $min = $tmin;
        $min = $min * 1;

// we create unix time just to be sure
$itime  = mktime($hour,$min,1,$month,$day,$year);

// DcalItems items
$empty = FmtPagename('$[empty]',$pagename);
if(@$a['fmt'] != '') $fmt = $a['fmt'];
  else $fmt = "default";
if(@$a['link'] != '') $link = $a['link'];
  elseif(@$a['ln'] != '') $link = urlencode($a['ln']);
    else $link = $empty;
if(@$a['title'] != '') $title = $a['title'];
  elseif(@$a['tt'] != '') $title = $a['tt'];
    else $title = $empty;
if(@$a['text'] != '') $text = $a['text'];
  elseif(@$a['tx'] != '') $text = $a['tx'];
    else $text = $empty;
if(@$a['periodicity'] != '') $periodicity = strtolower($a['periodicity']);
  elseif(@$a['pr'] != '') $periodicity = strtolower($a['pr']);
    else $periodicity = 'normal' ;
if(@$a['duration'] != '') $duration = $a['duration'];
  elseif(@$a['dr'] != '') $duration = $a['dr'];
    else $duration = $DcalinDefaultDuration;

static $DcalinItemCounter=0;

if( $DcalinItemCounter <= $DcalinItemLimit ){

  $DcalItems[] = array(
                    'id' => $id,
                    #--------------
                    'utime' => $itime,
                    'periodicity' => @$periodicity,
                    'duration' => @$duration,
                    #--------------
                    'link' => @$link ,
                    'title' => @$title,
                    'text' => @$text,
                    'format' => @$fmt
      );

     $DcalinItemCounter++;
}

StopWatch('Dcalin end');

}


// dcal function that processes all the vars and options
// and passes it on to the function that will render the calendar
function Dcal($pagename,$args){

StopWatch('Dcal begin');

global  $HTMLHeaderFmt,$HTMLStylesFmt,$DcalStylesFmt,
  $FarmPubDirUrl,$PubDirUrl,$DcalItems,$FarmD,
  $DcalCookieExpire,$DcalItemFmt,
  $DcalFmtVars,$DcalPRHandler,$Now;

// today year, month, day, hour and minute
$tyear = strftime('%Y',$Now) * 1;
$tmonth = strftime('%m',$Now) * 1;
$tweek = date('W') * 1;
$tday = strftime('%d',$Now) * 1;
$thour = strftime('%H',$Now) * 1;
$tmin = strftime('%M',$Now) * 1;

// retrieve PageUrl
$pageurl = PageVar($pagename, '$PageUrl');

// parse args
$a = ParseArgs($args);

//makes keys lower case
$a = array_change_key_case($a,CASE_LOWER);

// options and shortcuts
if(@$a['id'] != '') $id = @$a['id'];
  else $id = 'dcal'; // id helps with choosing diferent style sheets for dcal
if(@$a['year'] != '') $year = $a['year'];
  elseif(@$a['y'] != '') $year = $a['y'];
    else $year = $tyear;
      $year = $year * 1;
if(@$a['month'] != '')$month = $a['month'];
  elseif(@$a['m'] != '') $month = $a['m'];
    else $month = $tmonth;
      $month = $month *1;
if(@$a['type'] != '') $type = $a['type'];
  elseif(@$a['tp'] != '') $type = $a['tp'];
    else $type = 'calendar';
if(@$a['dynamic'] != '') $dynamic = $a['dynamic'];
  elseif(@$a['dn'] != '') $dynamic = $a['dn'];
    else $dynamic = 0;
if(@$a['header'] != '') $header = $a['header'];
  elseif(@$a['hd'] != '') $header = $a['hd'];
    else $header = 0;
if(@$a['title'] != '') $title = $a['title'];
  elseif(@$a['tt'] != '') $title = $a['tt'];
   else $title = '';
if(@$a['titleurl'] != '') $titleurl = $a['titleurl'];
  elseif(@$a['tu'] != '') $titleurl = $a['tu'];
   else $titleurl = '';
if(@$a['showeek'] != '') $showeek = $a['showeek'];
  elseif(@$a['sw']) $showeek = $a['sw'];
    else $showeek = 0;
if(@$a['showday'] != '') $showday = $a['showday'];
  elseif(@$a['sd'] != '') $showday = $a['sd'];
    else $showday = 1;
if(@$a['showeekday'] != '') $showeekday = $a['showeekday'];
  elseif(@$a['swd'] != '') $showeekday = $a['swd'];
    else $showeekday = 1;
if(@$a['weekstart'] != '') $weekstart = $a['weekstart'];
  elseif(@$a['ws'] != '') $weekstart = $a['ws'];
    else $weekstart = 0;
if(@$a['weekdaylength'] != '') $weekdaylength = $a['weekdaylength'];
  elseif(@$a['wl'] != '') $weekdaylength = $a['wl'];
    else $weekdaylength = 3;
if(@$a['width'] != '') $width = $a['width'];
  elseif(@$a['w'] != '') $width = $a['w'];
    else $width = '100%';
if(@$a['prevmonthurl'] != '') $prevmonthurl = $a['prevmonthurl'];
  elseif(@$a['pmu'] != '') $prevmonthurl = $a['pmu'];
    else $prevmonthurl = '';
if(@$a['nextmonthurl'] != '') $nextmonthurl = $a['nextmonthurl'];
  elseif(@$a['nmu'] != '') $nextmonthurl = $a['nmu'];
    else $nextmonthurl = '';
if(@$a['prevyearurl'] != '') $prevyearurl = $a['prevyearurl'];
  elseif(@$a['pyu'] != '') $prevyearurl = $a['pyu'];
    else $prevyearurl = '';
if(@$a['nextyearurl'] != '') $nextyearurl = $a['nextyearurl'];
  elseif(@$a['nyu'] != '') $nextyearurl = $a['nyu'];
    else $nextyearurl = '';
if(@$a['prevmonthdecor'] != '') $prevmonthdecor = $a['prevmonthdecor'];
  elseif(@$a['pmd'] != '') $prevmonthdecor = $a['pmd'];
    else $prevmonthdecor = "&lsaquo;";
if(@$a['nextmonthdecor'] != '') $nextmonthdecor = $a['nextmonthdecor'];
  elseif(@$a['nmd'] != '') $nextmonthdecor = $a['nmd'];
    else $nextmonthdecor = "&rsaquo;";
if(@$a['prevyeardecor'] != '') $prevyeardecor = $a['prevyeardecor'];
  elseif(@$a['pyd'] != '') $prevyeardecor = $a['pyd'];
    else $prevyeardecor = "&laquo;";
if(@$a['nextyeardecor'] != '') $nextyeardecor = $a['nextyeardecor'];
  elseif(@$a['nyd'] != '') $nextyeardecor = $a['nyd'];
    else $nextyeardecor = "&raquo;";
if(@$a['fmt'] != '') $fmt = $a['fmt'];
  if(@$DcalItemFmt[$fmt] != '') $fmt = $DcalItemFmt[$fmt];
    elseif(strpos($fmt,'#') !== false) $fmt = RetrieveAuthSection($pagename,$fmt);
      if($fmt == false) $fmt = '';

if($dynamic >= 1){

$input = array_merge($_GET, $_POST);
$cookie = $_COOKIE;

  $requestid = @$input['id'];
  $requestyear = @$input['year'];
  $requestmonth = @$input['month'];

  $cookieidyear = @$cookie['dcal'][$id]['year'];
  $cookieidmonth = @$cookie['dcal'][$id]['month'];

  if($id == $requestid && 
     $requestid != '' &&
     $requestyear != '' &&
     $requestmonth != '' &&
     is_numeric($requestyear) &&
     is_numeric($requestmonth)){

    $dyear = $requestyear * 1 ;
    $dmonth = $requestmonth * 1;

  }elseif($cookieidyear != '' &&
     $cookieidmonth != '' ){

    $dyear = $cookieidyear ;
    $dmonth = $cookieidmonth;

  }

  // store cookie with year and month
  if($dynamic >= 2){

    if($id == $requestid &&
       $requestyear != '' &&
       $requestmonth != '' &&
       $requestid != '' &&
       is_numeric($requestyear) &&
       is_numeric($requestmonth) &&
       isset($dyear) && is_numeric($dyear) &&
       isset($dmonth) && is_numeric($dmonth)){

      setcookie('dcal['.$requestid.'][month]',$dmonth,$DcalCookieExpire);
      setcookie('dcal['.$requestid.'][year]',$dyear,$DcalCookieExpire);

    }

  }

  // dynamic year and month
  if(isset($dyear) &&
     is_numeric($dyear)) $year = $dyear;
  if(isset($dmonth) && 
     is_numeric($dyear) &&
     $dmonth <= 12 && $dmonth >=1) $month = $dmonth;

}

// search path for $id.css file, if any
// took from blocal
if(!isset($FarmPubDirUrl)) $FarmPubDirUrl = $PubDirUrl;
SDV($DcalCssFileListFmt, array (
       "pub/dcal/$id.css"        => "$PubDirUrl/dcal/$id.css",
       "$FarmD/pub/dcal/$id.css" => "$FarmPubDirUrl/dcal/$id.css" 
));

// load table styles for current dcal calendar from files
foreach((array)$DcalCssFileListFmt as $k=>$v) {
  if(file_exists(FmtPageName($k,$pagename))){
    if(!isset($HTMLHeaderFmt['dcal'.$id]))
      $HTMLHeaderFmt['dcal'.$id] =
           "<link rel='stylesheet' type='text/css' href='$v' media='screen' />\n";
  }
}

// load css styles from $DcalStylesFmt
if(isset($DcalStylesFmt[$id])){
  if(!isset($HTMLStylesFmt['dcal'.$id]))
     $HTMLStylesFmt['dcal'.$id] = $DcalStylesFmt[$id];
}

// days in current month
$daysinmonth = date('t',mktime(0,0,0,$month,1,$year));

// handle periodicity
foreach($DcalItems as $k => $item){
  $itempr = strtolower($item['periodicity']);
  if($itempr != 'normal' && 
     @$DcalPRHandler[$itempr] != ''){
    $prhandler = $DcalPRHandler[$itempr];
    $newitems = $prhandler($pagename,$year,$month,$item);
    if(is_array($newitems))
      foreach($newitems as $k => $n) $PRSelect[] = $n;
    $prhandler = ''; $newitems = '';
  }
}

// create InternalItems
$InternalItems = $DcalItems;
if(is_array(@$PRSelect)){
  foreach($PRSelect as $k => $item)
    $InternalItems[] = $item;
}

// select per current id, year and month
for($s1=0;$s1<=(count($InternalItems)-1);$s1++){
  if(isset($InternalItems[$s1]['id'])){
    $itemid = &$InternalItems[$s1]['id'];
    $itemyear = strftime('%Y',$InternalItems[$s1]['utime']);
    $itemonth = strftime('%m',$InternalItems[$s1]['utime']);
    if($itemid == $id && $itemyear == $year 
       && $itemonth == $month){
      $YearMonthSelect[] = $InternalItems[$s1];
    }
  }
}

if(is_array(@$YearMonthSelect)){

  //sort array ascending by secondary key
  foreach($YearMonthSelect as $k => $r) $t[$k] = $r['utime'];
  array_multisort($t,SORT_ASC,$YearMonthSelect);

  // creat new day selection of items
  for($s2=0;$s2<=(count(@$YearMonthSelect)-1);$s2++){
    for($ds=1;$ds<=$daysinmonth;$ds++){
      $itemday = date('j',$YearMonthSelect[$s2]['utime']);
      if($itemday == $ds){ 
        @$DaySelect[$ds][] = $YearMonthSelect[$s2];
      }
    }
  }

  // create final format for each day in a new var
  for($s3=1;$s3<=$daysinmonth;$s3++){
    if(@$DaySelect[$s3] != ''){
      for($s4=0;$s4<=(count($DaySelect[$s3])-1);$s4++){
        if($DaySelect[$s3][$s4] != ''){
          $item = $DaySelect[$s3][$s4];
          if(strpos($item['text'],'#') !== false)
            $item['text'] = RetrieveAuthSection($pagename,$item['text']);
            $item['text'] = MarkupToHTML($pagename,$item['text']);
          if($fmt != ''){
            $tmpfmt = $fmt;
          }else{
            $itemfmt = $item['format'];
            if(@$DcalItemFmt[$itemfmt] != ''){ 
              $tmpfmt = $DcalItemFmt[$itemfmt];
            }elseif(strpos($itemfmt,'#') !== false){
              $tmpfmt = RetrieveAuthSection($pagename,$itemfmt);
              $tohtml = 1;
            }
            if($tmpfmt == false) $tmpfmt = $DcalItemFmt['default'];
            if($tmpfmt == '') $tmpfmt = $DcalItemFmt['default'];
          }
          foreach($DcalFmtVars as $k => $v){
            $v = eval("return $v;");
            $tmpfmt = preg_replace('/\\{\\$'.$k.'\\}/',$v,$tmpfmt);
          }
          if(@$tohtml == 1){
            $tmpfmt = MarkupToHTML($pagename,$tmpfmt);
            $tohtml = '';
          }
          @$FinalDayFmt[$s3] .= $tmpfmt;
          $tmpfmt = '';
        }
      }
    }
  }

} //if is array

// var for calling DcalCalGen
// and DcalListGen
$calgenargs = array(
  'id' => $id,
  'dynamic' => $dynamic,
  'width' => $width,
  'header' => $header,
  'showeek' => $showeek,
  'showday' => $showday,
  'showeekday' => $showeekday,

  'year' => $year,
  'month' => $month,
  'tyear' => $tyear,
  'tmonth' => $tmonth,
  'tday' => $tday,

  'title' => $title,
  'titleurl' => $titleurl,

  'pageurl' => $pageurl,

  'prevmonthurl' => $prevmonthurl,
  'prevmonthdecor' => $prevmonthdecor,
  'nextmonthurl' => $nextmonthurl,
  'nextmonthdecor' => $nextmonthdecor,
  'prevyearurl' => $prevyearurl,
  'prevyeardecor' => $prevyeardecor,
  'nextyearurl' => $nextyearurl,
  'nextyeardecor' => $nextyeardecor,

  'weekdaylength' => $weekdaylength,
  'weekstart' => $weekstart
);

// hold outuput of DcalCalGen
// or DcalListGen
if($type == 'calendar'){
  $out = DcalCalGen($pagename, $calgenargs);
}elseif($type == 'list'){
  $out = DcalListGen($pagename, $calgenargs);
}

// FmtPageName the out put o dcalgens
  $out = FmtPageName($out,$pagename);

// replace hardcoded days
// with content
for($i=1;$i<=$daysinmonth;$i++){
  if(@$FinalDayFmt[$i]!= '')
    $out = preg_replace('/\\{day'.$i.'\\}/',@$FinalDayFmt[$i],$out);
  else 
    $out = preg_replace('/\\{day'.$i.'\\}/','&nbsp;',$out);
}

StopWatch('Dcal end');

return $out;

}

function DcalCalGen($pagename,$args){
global  $HTMLStylesFmt,$DcalCalGenStyle;

StopWatch('DcalCalGen begin');

foreach($args as $a => $v) $$a = $v;

SDV($DcalCalGenStyle , "
  table.calgen caption.monthandyear { padding:.2ex;border:1px solid black;font-size:1.2em }
  table.calgen { margin:0;padding:0;border-collapse:collapse;color:black;
            border:1px solid black;width:100%; }
  table.calgen .td { width:15%;padding:0;border:1px solid black; }
  table.calgen .colspan { background:#eee;padding:1px;border:1px solid black; }
  table.calgen table th { border:1px solid black; }
  table.calgen .week { text-align:center;width:5%; }
  table.calgen div.daynumber { width:2em;margin:0;padding:0;text-align:center;background:black;
            color:white;display:block; }
  table.calgen .today { background:#ccc; }
");

if(!isset($HTMLStylesFmt['dcalcalgen'])){
  $HTMLStylesFmt['dcalcalgen'] = $DcalCalGenStyle;
}

// gen vars
$firstofmonth = mktime(0,0,0,$month,1,$year);
$daysinmonth = date('t',@$firstofmonth);
$weekday = ((strftime('%w',$firstofmonth))+7-$weekstart)%7; // adjust for $firstday
$monthname = strftime('%B',$firstofmonth);
$week = date('W',$firstofmonth) * 1;

// month name and link
if(@$title) $title = ucfirst($title);
else $title = "$[".ucfirst($monthname).'] '.$year;

if(@$titleurl) 
  $titlelinked = '<a href="'.urlencode($titleurl).'">'.$title.'</a>';
else $titlelinked = $title ;

// include titlelinked in args
$args['titlelinked'] = $titlelinked;

// prev next args

// Begin calendar
$out = '<div id="'.$id.'" class="wrapper">';
$out .= '<table class="calgen" border="1" '.
        'summary="$[Calendar of] '.$title.'" width="'.$width.'">';

if(@$header == 3){ 
  $out .= '<caption class="monthandyear" >'.
     DcalSelect($pagename,$args).'</caption>';
}elseif(@$header == 2){
  $out .= '<caption class="monthandyear" >'.
     DcalPrevNext($pagename,$args).'</caption>';
}elseif(@$header == 1){
 $out .= '<caption class="monthandyear" >'.$titlelinked.'</caption>' ;
}else{
  $out .= '<caption class="monthandyear" >'.$title.'</caption>';
}

// generate all the day names according to the current locale
$daynames = array(); 
  for($n=0,$t=(4+$weekstart)*86400; $n<7; $n++,$t+=86400){ // January 4, 1970 was a Sunday
    $daynames[$n] = ucfirst(strftime('%A',$t)); // %A means full textual day name
  }

// shown week names ($weeknamelength > 0) if  >3 full name will be printed
if($showeekday){ 
  $out .= '<thead><tr>';
  if(@$showeek) $out .= '<th width="5%" class="week">$[Week]</th>';
    foreach($daynames as $dn){
      $out .= '<th width="13%" abbr="$['.htmlentities($dn).']" title="$['.htmlentities($dn).']">';
      if($weekdaylength < 4)  $out .= "$[".substr($dn,0,$weekdaylength).']</th>';
      else $out .= '$['.$dn.']</th>';
    }
  $out .= '</tr></thead>';
}

$out .= '<tbody>';

// initial 'empty' days 
if(@$showeek){
  if(@$weekday > 0){
    $out .= '<tr><td class="week" width="5%" align="center">'.$week.
            '</td><td class="colspan" colspan="'.$weekday.
            '">&nbsp;</td>';
  }else{
      $out .= '<tr><td class="week" width="5%" align="center">'.$week.'</td>';
  }
}else{
  if(@$weekday > 0){
      $out .= '<tr><td class="colspan" colspan="'.$weekday.'">&nbsp;</td>';
  }
}

// start loop 
for($day=1,$dm = $daysinmonth; $day<=$dm; $day++,$weekday++){

  if(@$weekday == 7){
    $weekday = 0; // start a new week
    $week = $week + 1;
    $out .= "</tr><tr>";
    if(@$showeek){
      $out .= '<td class="week" width="5%" align="center">'.$week.'</td>';
    }
  }

// Is it today?
  if($year == $tyear && $month == $tmonth && $day == $tday) $today = 1;
  else $today = 0 ;

  if($today == 1) $out .= '<td width="13%" valign="top" class="today day day'.$day.'">';
  else $out .= '<td width="13%" valign="top" class="day day'.$day.'">' ;

  if($showday) $out .= '<div class="daynumber">'.$day.'</div>';
  $out .= '{day'.$day.'}</td>';

} /*end loop*/

if($weekday != 7) { // remaining "empty" days
  $out .= '<td class="colspan" colspan="'.(7-$weekday).'">&nbsp;</td></tr>';
}

$out .= '</tbody></table></div>';

StopWatch('DcalCalGen end');

return $out;

}

function DcalListGen($pagename,$args){

global $HTMLStylesFmt,$DcalListGenStyle;

StopWatch('DcalListGen end');

foreach($args as $a => $v) $$a = $v;

SDV($DcalListGenStyle , "
  table.listgen caption.monthandyear { padding:.2ex;border:1px solid black;font-size:1.2em; }
  table.listgen { margin:0;padding:0;border-collapse:collapse;color:black;
            border:1px solid black;width:100%; }
  table.listgen table th { border:1px solid black; }
  table.listgen .week { text-align:center;width:5%; }
");

if(!isset($HTMLStylesFmt['dcallistgen'])){
  $HTMLStylesFmt['dcallistgen'] = $DcalListGenStyle;
}

// gen vars
$firstofmonth = mktime(0,0,0,$month,1,$year);
$daysinmonth = date('t',@$firstofmonth);
$weekday = ((strftime('%w',$firstofmonth))+7-$weekstart)%7; // adjust for $firstday
$monthname = strftime('%B',$firstofmonth);
$week = date('W',$firstofmonth) * 1;

// month name and link
if(@$title) $title = ucfirst($title);
else $title = "$[".ucfirst($monthname).'] '.$year;

if(@$titleurl) 
  $titlelinked = '<a class="titlelinked" href="'.urlencode($titleurl).'">'.$title.'</a>';
else $titlelinked = $title ;

// include titlelinked in args
$args['titlelinked'] = $titlelinked;

// generate all the day names
$daynames = array(); 
  for($n=0,$t=(4+$weekstart)*86400; $n<7; $n++,$t+=86400){ // January 4, 1970 was a Sunday
    $daynames[$n] = ucfirst(strftime('%A',$t)); 
  }

// Begin calendar
$out = '<div id="'.$id.'" class="wrapper">';
$out .= '<table class="listgen" border="1" '.
        'summary="$[Calendar list of] '.$title.'" width="'.$width.'">';

if(@$header == 3){ 
  $out .= '<caption class="monthandyear" >'.
           DcalSelect($pagename,$args).'</caption>';
}elseif(@$header == 2){
  $out .= '<caption class="monthandyear" >'.
           DcalPrevNext($pagename,$args).'</caption>';
}elseif(@$header == 1){
 $out .= '<caption class="monthandyear" >'.$titlelinked.'</caption>' ;
}else{
  $out .= '<caption class="monthandyear" >'.$title.'</caption>';
}

// generate header
$out .= "<thead><tr>";
if($showeek == 1) $out .= '<th width="5%">$[Week]</th>';
if($showeekday == 1) $out .=  '<th width="5%">$[Weekday]</th>';
if($showday == 1) $out .=  '<th width="3%">$[Day]</th>';
$out .= '<th width="87%">$[Items]</th>';
$out .= "</tr></thead>";

// start body
$out .= "<tbody>";

// start loop
for($day=1,$dm = $daysinmonth; $day<=$dm; $day++,$weekday++){

  if($weekday == 7){
    $weekday = 0; // start a new week
    $week = $week + 1;
  }

  $dayname = $daynames[$weekday];
  $weekbreak = $dm-7;

  $out .= "<tr>";
  if($showeek == 1){
    if($day <= $weekbreak && $day == 1 && $weekday == 0)
      $out .= '<td class="week" width="5%" align="center" rowspan="7">'.$week.'</td>';
    if($day <= $weekbreak && $day == 1 && $weekday > 0)
      $out .= '<td class="week" width="5%" align="center" rowspan="'.(7-$weekday).'">'.$week.'</td>';
    if($day <= $weekbreak && $day > 1 && $weekday == 0)
      $out .= '<td class="week" width="5%" align="center" rowspan="7">'.$week.'</td>';
    if($day > $weekbreak && $day > 1 && $weekday == 0)
      $out .= '<td class="week" width="5%" align="center" rowspan="'.(7-$weekday).'">'.$week.'</td>';
  }
  if($showeekday == 1){
    $out .= '<td class="weekday" width="5%" align="center" ';
    $out .= 'abbr="$['.$dayname.']" ';
    $out .= 'title="$['.$dayname.']">';
     if($weekdaylength < 4)
       $out .= '$['.substr($dayname,0,$weekdaylength).']';
     else 
       $out .= '$['.$dayname.']</td>';
  }
  if($showday == 1) $out .= '<td class="day" width="3%" align="center">$['.$day.']</td>';
  $out .= '<td class="item" width="87%">';
  $out .= '{day'.$day.'}';
  $out .= "</td></tr>";


} //end of loop

// end body
$out .= "</tbody></table></div>";

StopWatch('DcalListGen end');

return $out;

}

function DcalPrevNext($pn,$args){

global $HTMLStylesFmt,$DcalPrevNextStyles;

StopWatch('DcalPrevNext end');

if($pn == '' || $args == '') return;

// unfold args
foreach($args as $a => $v) $$a = $v;

SDV($DcalPrevNextStyles , "
  .dcalprevyear { margin:.2ex;text-decoration:none; }
  .dcalprevyear a { text-decoration:none; }
  .dcalnextyear { margin:.2ex;text-decoration:none; }
  .dcalnextyear a { text-decoration:none; }
  .dcalprevmonth { margin:.2ex;text-decoration:none; }
  .dcalprevmonth a { text-decoration:none; }
  .dcalnextmonth { margin:.2ex;text-decoration:none; }
  .dcalnextmonth a { text-decoration:none; }
");

if(!isset($HTMLStylesFmt['dccalprevnext'])){
  $HTMLStylesFmt['dcalprevnext'] = $DcalPrevNextStyles;
}

// minus/plus months
$m = $month;
$mP1 = ($m<=11)?$m+1:($m+1)-12;
$mM1 = ($m>=2)?$m-1:12;

// minus/plus years
$y = $year;
$yP1 = $y+1;
$yM1 = $y-1;

// setting urls for prev and next month and year


if(@$prevmonthurl) continue;
else{
  if($month < 1 ){
    $prevmonthurl = $pageurl."?id=".$id."'&month=12&year=".$yM1;
  }else{
    $prevmonthurl = $pageurl."?id=".$id."&month=".$mM1."&year=".$year;
  }
}

if(@$nextmonthurl) continue;
else{
  if($month > 12){
    $nextmonthurl = $pageurl."?id=".$id."&month=1&year=".$yP1;
  }else{
    $nextmonthurl = $pageurl."?id=".$id."&month=".$mP1."&year=".$year;
  }
}

if(@$prevyearurl) continue;
else{
  $prevyearurl = $pageurl."?id=".$id."&month=".$month."&year=".$yM1;
}

if(@$nextyearurl) continue;
else{
  $nextyearurl = $pageurl."?id=".$id."&month=".$month."&year=".$yP1 ;
}

// create links for prev and next year and month

$prevmonth = '<span class="dcalprevmonth">'.
              '<a href="'.PUE($prevmonthurl).'" title="$[Previous month]" >'.
              $prevmonthdecor.'</a></span>&nbsp;';
$nextmonth = '&nbsp;<span class="dcalnextmonth">'.
              '<a href="'.PUE($nextmonthurl).'" title="$[Next month]" >'.
              $nextmonthdecor.'</a></span>';
$prevyear  = '<span class="dcalprevyear">'.
              '<a href="'.PUE($prevyearurl).'" title="$[Previous year]" >'.
              $prevyeardecor.'</a></span>&nbsp;';
$nextyear  = '&nbsp;<span class="dcalnextyear">'.
              '<a href="'.PUE($nextyearurl).'" title="$[Next year]" >'.
              $nextyeardecor.'</a></span>';

$prevnexts = $prevyear.$prevmonth.$titlelinked.$nextmonth.$nextyear;

StopWatch('DcalPrevNext end');

return $prevnexts;

}

function DcalSelect($pn,$args){
global $HTMLStylesFmt,$DcalSelectStyles;

StopWatch('DcalSelect begin');

if($pn == '' || $args == '' ) return;

// unfold args
foreach($args as $a => $v) $$a = $v;

SDV($DcalSelectStyles , "
  .dcalselect { margin:0; }
  .dcalselectblock { margin:.2ex;display:inline-block; }
  .dcalselectblock form { margin:0;padding:0; }
");

if(!isset($HTMLStylesFmt['dcalselect'])){
  $HTMLStylesFmt['dcalselect'] = $DcalSelectStyles;
}

// minus/plus months
$m = $month;

$mP5 = ($m<=7)?$m+5:($m+5)-12;
$mP4 = ($m<=8)?$m+4:($m+4)-12;
$mP3 = ($m<=9)?$m+3:($m+3)-12;
$mP2 = ($m<=10)?$m+2:($m+2)-12;
$mP1 = ($m<=11)?$m+1:($m+1)-12;

$mM1 = ($m>=2)?$m-1:12;
$mM2 = ($m>=3)?$m-2:(12-2)+$m;
$mM3 = ($m>=4)?$m-3:(12-3)+$m;
$mM4 = ($m>=5)?$m-4:(12-4)+$m;
$mM5 = ($m>=6)?$m-5:(12-5)+$m;

// minus/plus years
$y = $year;

$yP5 = $y+5; $yP4 = $y+4;
$yP3 = $y+3; $yP2 = $y+2;
$yP1 = $y+1;

$yM1 = $y-1; $yM2 = $y-2;
$yM3 = $y-3; $yM4 = $y-4; 
$yM5 = $y-5;

$selectmonthyear = '<div class="dcalselectblock">'.
      '<form class="dcalselectform" action="'.$pageurl.'" method="post">'.
      '<input type="hidden" name="id" value="'.$id.'" />'.
      '<select title="$[Select a new month]" class="dcalselects"'.
      ' name="month" onchange="this.form.submit();">'.
      '<option '.($m==1 ?'selected="selected"':'').' value="1" >$[january]</option>'.
      '<option '.($m==2 ?'selected="selected"':'').' value="2" >$[february]</option>'.
      '<option '.($m==3 ?'selected="selected"':'').' value="3" >$[march]</option>'.
      '<option '.($m==4 ?'selected="selected"':'').' value="4" >$[april]</option>'.
      '<option '.($m==5 ?'selected="selected"':'').' value="5" >$[may]</option>'.
      '<option '.($m==6 ?'selected="selected"':'').' value="6" >$[june]</option>'.
      '<option '.($m==7 ?'selected="selected"':'').' value="7" >$[july]</option>'.
      '<option '.($m==8 ?'selected="selected"':'').' value="8" >$[august]</option>'.
      '<option '.($m==9 ?'selected="selected"':'').' value="9" >$[september]</option>'.
      '<option '.($m==10 ?'selected="selected"':'').' value="10">$[october]</option>'.
      '<option '.($m==11 ?'selected="selected"':'').' value="11">$[november]</option>'.
      '<option '.($m==12 ?'selected="selected"':'').' value="12">$[december]</option>'.
      '</select> '.
      '<select title="$[Select a new year]" class="dcalselects"'.
      ' name="year" onchange="this.form.submit();">'.
      '<option value="'.$yP5.'">'.$yP5.'</option>'.
      '<option value="'.$yP4.'">'.$yP4.'</option>'.
      '<option value="'.$yP3.'">'.$yP3.'</option>'.
      '<option value="'.$yP2.'">'.$yP2.'</option>'.
      '<option value="'.$yP1.'">'.$yP1.'</option>'.
      '<option selected="selected" value="'.$year.'">'.$year.'</option>'.
      '<option value="'.$yM1.'">'.$yM1.'</option>'.
      '<option value="'.$yM2.'">'.$yM2.'</option>'.
      '<option value="'.$yM3.'">'.$yM3.'</option>'.
      '<option value="'.$yM4.'">'.$yM4.'</option>'.
      '<option value="'.$yM5.'">'.$yM5.'</option>'.
      '</select> '.
      '<noscript>'.
      '<input title="$[Apply changes]" class="dcalsubmit" type="submit" value="&raquo;" />'.
      '</noscript>'.
      '</form></div>';

$selectprevmonth = '<div class="dcalselectblock">'.
      '<form title="$[Previous month]" class="dcalselectform" action="'.$pageurl.'" method="post" >'.
      '<input class="dcalselects" type="hidden" name="id" value="'.$id.'" /> '.
      '<input class="dcalselects" type="hidden" name="year" value="'.$year.'" /> '.
      '<input class="dcalselects" type="hidden" name="month" value="'.$mM1.'" /> '.
      '<input class="dcalselects" type="submit" value="&lsaquo;" /> '.
      '</form></div>';

$selectnextmonth = '<div class="dcalselectblock">'.
      '<form title="$[Next month]" class="dcalselectform" action="'.$pageurl.'" method="post" >'.
      '<input class="dcalselects" type="hidden" name="id" value="'.$id.'" /> '.
      '<input class="dcalselects" type="hidden" name="year" value="'.$year.'" /> '.
      '<input class="dcalselects" type="hidden" name="month" value="'.$mP1.'" /> '.
      '<input class="dcalselects" type="submit" value="&rsaquo;" /> '.
      '</form></div>';

$selectprevyear = '<div class="dcalselectblock">'.
      '<form title="$[Previous year]" class="dcalselectform" action="'.$pageurl.'" method="post" >'.
      '<input class="dcalselects" type="hidden" name="id" value="'.$id.'" />'.
      '<input class="dcalselects" type="hidden" name="year" value="'.$yM1.'" />'.
      '<input class="dcalselects" type="hidden" name="month" value="'.$month.'" />'.
      '<input class="dcalselects" type="submit" value="&laquo;" />'.
      '</form></div>';

$selectnextyear = '<div class="dcalselectblock">'.
      '<form title="$[Next year]" class="dcalselectform" action="'.$pageurl.'" method="post" >'.
      '<input type="hidden" name="id" value="'.$id.'" />'.
      '<input type="hidden" name="year" value="'.$yP1.'" />'.
      '<input type="hidden" name="month" value="'.$month.'" />'.
      '<input class="dcalsubmit" type="submit" value="&raquo;" />'.
      '</form></div>';

$selects = $selectprevyear.$selectprevmonth.$selectmonthyear.
              $selectnextmonth.$selectnextyear;

$selects = '<div class="dcalselect">'.$selects.'</div>';

StopWatch('DcalSelect end');

return $selects;

}