Location: PHPKode > scripts > tiCalFile > tiCalFile-3.2/tiCalFile.class.php
<?php
/**
 * tiCalFile 3.2
 *
 * Class creating iCal test files.
 *
 * copyright (c) 2011-2013 Kjell-Inge Gustafsson kigkonsult
 * kigkonsult.se/tiCalFile/index.php
 * kigkonsult.se/contact/index.php
 * updated 20121226
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Creates iCal test files with timezone/event/todo/journal/vfreebusy components
 *
**/
class tiCalFile {
  const   version = 'tiCalFile 3.2';
  private $config;
  private $filemtime;
  private $fp;
  private $lockFile;
  private $log;
  private $removeTime;
  private $COMPTYPEScheck;
  private $DIRFILEcheck;
  private $limitCheck;
  private static $compProps;
  private static $baseValues;
  private static $singleton_Instance; // store the singleton instance
  /** Getter method for creating/returning the single instance of this class */
  public static function singleton( & $log=FALSE, $config = array() ) {
    if( !self::$singleton_Instance )
      self::$singleton_Instance = new tiCalFile( $log, $config = array() );
    return self::$singleton_Instance;
  }
  /** create instance */
  public function __construct( & $log=FALSE, $config = array()) {
    $this->log    = $log;
    $this->config = array( 'VERSION' => tiCalFile::version.' (Kjell-Inge Gustafsson, kigkonsult.se)' );
    $this->_log( $this->config['VERSION'].' '.__METHOD__.' start', LOG_INFO );
          // set defaults
    $this->setBaseValues();
    if( !isset( $config['CALDIR'] ))
      $config['CALDIR']     = 'calendars';
    if( !isset( $config['FILENAMES'] ))
      $config['FILENAMES']  = array( 0 => 'testFile.ics' );
    if( !isset( $config['LOCKFILE'] ))
      $config['LOCKFILE']   = 'tiCalFile.lck';
    if( !isset( $config['COMPTYPES'] ))
      $config['COMPTYPES']  = array( 0 => array( 'event' => 100 ));
                                                // default 100% events in 'FILENAMES' array[0] file
    if( !isset( $config['THISDATE'] ))
      $config['THISDATE']   = date( 'YmdHis' ); // now
    if( !isset( $config['METHOD'] ))
      $config['METHOD']     = 'PUBLISH';
    if( !isset( $config['UNIQUE'] ))
      $config['UNIQUE']     = 'kigkonsult.se';
    $tz = date_default_timezone_get();
    if( !isset( $config['X-WR-TIMEZONE'] ))
      $config['X-WR-TIMEZONE'] = ( !empty( $tz ) && ( 'UTC' != strtoupper( $tz ))) ? $tz : FALSE;
    if( !isset( $config['CALAGE'] ))
      $config['CALAGE']     = 1;                // one hour
    if( !isset( $config['DAYCNT'] ))
      $config['DAYCNT']     = 10;               // ten days
    if( !isset( $config['COMPCNT'] ))
      $config['COMPCNT']    = 5;                // five components every day
    if( !isset( $config['COMPSTART'] ))
      $config['COMPSTART']  = 7;                // start between seven..
    if( !isset( $config['COMPEND'] ))
      $config['COMPEND']    = 18;               // .. and 18
    if( !isset( $config['COMPDURMIN'] ))
      $config['COMPDURMIN'] = 1;                // event duration from one..
    if( !isset( $config['COMPDURMAX'] ))
      $config['COMPDURMAX'] = 36;               // .. to 36 hours
    if( !isset( $config['LANGUAGE'] ))
      $config['LANGUAGE']   = FALSE;
    if( !isset( $config['ALTREP'] ))
      $config['ALTREP']     = FALSE;
    if( !isset( $config['X-PARAM'] ))
      $config['X-PARAM']    = FALSE;
    if( !isset( $config['TZID'] ))
      $config['TZID']       = FALSE;
    foreach( $config as $key => $value )
      $this->setConfig( $key,   $value );
          // check config settings
    if( FALSE === $this->config['X-WR-TIMEZONE'] )
      unset( $this->config['X-WR-TIMEZONE'] );
    $this->limitChecker();
    $this->DIRFILEchecker();
    $this->COMPTYPESchecker();
  }
  public function __destruct() {
    foreach( $this as $key => $value )
      unset( $this->$key );
  }
  private function _log( $msg, $prio ) {
    if( !empty( $this->log ))
      $this->log->log( $msg, $prio );
  }
  private function _flush() {
    if( !empty( $this->log ))
      $this->log->flush();
  }
            /* check occurrence */
  private function accepted( $occurrParam ) {
    if( !isset( $this->config[$occurrParam] ))
      $this->config[$occurrParam] = 50;
    if( empty( $this->config[$occurrParam] ))
      return FALSE;
    if( 100 == $this->config[$occurrParam] )
      return TRUE;
    return ( $this->config[$occurrParam] >= mt_rand( 1, 99 )) ? TRUE : FALSE;
  }
  private function COMPTYPESchecker() {
    $this->_log( __METHOD__.' start', LOG_INFO );
            /** make sure every occurrence in 'FILENAMES' maps to one in 'COMPTYPES' */
    if( count( $this->config['FILENAMES'] ) > count( $this->config['COMPTYPES'] )) {
      $filler = end( $this->config['COMPTYPES'] );
      while( count( $this->config['FILENAMES'] ) > count( $this->config['COMPTYPES'] )) {
        $this->config['COMPTYPES'][]= $filler;
        $this->_log( "COMPTYPESchecker (a) : to fit count filenames, added comptype ".var_export( $filler, TRUE ), LOG_NOTICE );
      }
    }
            /** remove unmatched 'COMPTYPES' */
    while( count( $this->config['FILENAMES'] ) < count( $this->config['COMPTYPES'] )) {
      $r = array_pop( $this->config['COMPTYPES'] );
      $this->_log( "COMPTYPESchecker (b) : to fit count filenames, removed comptype ".var_export( $r, TRUE ), LOG_NOTICE );
    }
            /** check component type, if unvalid set to 'event' */
    foreach( $this->config['COMPTYPES'] as $cix => $fileCompsTypeProps ) {
      $sum = 0;
      $a =  $r = array();
      foreach( $this->config['COMPTYPES'][$cix] as $compType => $proportion ) {
        $sum += $proportion;
        $ct   = strtolower( $compType );
        if( !in_array( $ct, array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy' ))) {
          $ct = 'vevent';
          if( !isset( $this->config['COMPTYPES'][$cix][$ct] )) { // mark changes
            if( isset( $a[$ct] ))
              $a[$ct] += $proportion;
            else
              $a[$ct]  = $proportion;
            $r[]       = $compType;
          }
          else {                                                 // add proportion
            $this->config['COMPTYPES'][$cix][$ct] += $proportion;
            $this->_log( "COMPTYPESchecker (1) : compType[$cix][$compType] added (=$proportion)", LOG_NOTICE );
            $r[]       = $compType;
          }
        }
      }
      if(( 0 < count( $a )) && ( 0 < count( $r ))) {             // make changes
        $rix = 0;
        foreach( $a as $compType => $proportion ) {
          $this->config['COMPTYPES'][$cix][$compType] = $proportion;
          $this->_log( "COMPTYPESchecker (2) : compType[$cix][$compType] added (=$proportion)", LOG_NOTICE );
          $rix += 1;
        }
        foreach( $r as $compType ) {
          unset( $this->config['COMPTYPES'][$cix][$compType] );
          $this->_log( "COMPTYPESchecker (3) : compType[$cix][$compType] removed", LOG_NOTICE );
        }
      }
            /** check component type proportions, always 100% */
      foreach( $this->config['COMPTYPES'][$cix] as $compType => $proportion ) {
        if( 100 != $sum ) {
          $this->config['COMPTYPES'][$cix][$compType] = (int) ceil( $proportion / $sum * 100 );
          $addText = "% (fr. $proportion)";
        }
        else
          $addText = '%';
        $this->_log( "COMPTYPESchecker (4) : compType[$cix][".str_pad($compType,9)."] = ".$this->config['COMPTYPES'][$cix][$compType].$addText, LOG_NOTICE );
      }
    }
    $this->COMPTYPEScheck = TRUE;
  }
  private function createTestFile( $fix ) {
    $start = microtime( TRUE );
    $this->_log( __METHOD__.' start', LOG_INFO );
    $arglist  = func_get_args();
    foreach( $arglist as $aix => $arg )
      $this->_log( "argument [$aix]=".var_export( $arg, TRUE ), LOG_DEBUG );
            /** compute the right mix of components */
    $max = 0;
    $sum = $this->config['COMPCNT'] * $this->config['DAYCNT'];
    $compTypes = array();
    foreach( $this->config['COMPTYPES'][$fix] as $compType => $proportion ) {
      $max = (int) ceil(( $proportion / 100 ) * $sum );
      $ix  = 1;
      do { $compTypes[] = $compType; }
        while( $ix++ < $max );
    }
    shuffle( $compTypes );
            /** create iCalcreator object instance */
    $calcfg = array( 'directory' => $this->config['CALDIR']
                   , 'filename'  => $this->config['FILENAMES'][$fix] );
    if( isset( $this->config['UNIQUE'] )   && !empty( $this->config['UNIQUE'] ))
      $calcfg['unique_id'] =  $this->config['UNIQUE'];
    if( isset( $this->config['LANGUAGE'] ) && !empty( $this->config['LANGUAGE'] ))
      $calcfg['language']  = $this->config['LANGUAGE'];
    $calendar = new vcalendar( $calcfg );
    if( isset( $this->config['METHOD'] )   && !empty( $this->config['METHOD'] ))
      $calendar->setProperty( 'METHOD',        $this->config['METHOD'] );
    $calendar->setProperty( 'X-WR-CALNAME',  $this->config['VERSION'].' test calendar file' );
    $calendar->setProperty( 'X-WR-CALDESC',  'A test calendar file created ('.date( 'Y-m-d H:i:s' ).') by '.$this->config['VERSION'].' utilizing '.ICALCREATOR_VERSION );
    if( isset( $this->config['X-WR-TIMEZONE'] ) && !empty( $this->config['X-WR-TIMEZONE'] ))
      $calendar->setProperty( 'X-WR-TIMEZONE', $this->config['X-WR-TIMEZONE'] );
    if( $this->accepted( 'X_PROP1STCALOCCURRENCE' ))
      $calendar->setProperty( 'X-PROP1', $this->getValue( 'descriptions' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), 0 ));
    if( $this->accepted( 'X_PROP2NDCALOCCURRENCE' ))
      $calendar->setProperty( 'X-PROP2', $this->getValue( 'descriptions' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), 0 ));
    $uniqueId     = $calendar->getConfig( 'unique_id' );
    $date = $dat2 = mktime( 0, 0, 0, (int) substr( $this->config['THISDATE'], 4, 2 ), (int) substr( $this->config['THISDATE'], 6, 2 ), (int) substr( $this->config['THISDATE'], 0, 4 ));
    $stopDate     = $date + ( $this->config['DAYCNT'] * 24 * 3600 );
    $compCount    = 0;
    $previous     = array();
            /** create components.. . */
    while( $date < $stopDate ) {
      $dayCount   = 0;
      while( $dayCount < $this->config['COMPCNT'] ) {
        $compCount++;
        $dayCount++;
        $compType = array_pop( $compTypes );
        $comp     = & $calendar->newComponent( $compType );
        $compDate = $date + ( mt_rand( $this->config['COMPSTART'], $this->config['COMPEND'] ) * 3600 ); // random start hour, 7 to 18
        $duration = mt_rand( $this->config['COMPDURMIN'], $this->config['COMPDURMAX'] ) * 3600;
        $this->_log( "creating a new $compType with startdate=".date( 'Y-m-d H:i:s', $compDate ),LOG_DEBUG );
            /** DTSTART */
        if( 'vfreebusy' == $compType ) {
          $allDayEvent = FALSE;
          $comp->setProperty( 'DTSTART',  array( 'timestamp' => $compDate ), $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          $duration = 24 * 3600;
          if( $this->accepted( 'DTENDOCCURRENCE' ))
            $comp->setProperty( 'DTEND',  array( 'timestamp' => ( $compDate + $duration )), $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          elseif( $this->accepted( 'DURATIONDOCCURRENCE' ))
            $comp->setProperty( 'DURATION', array( 'sec' => $duration ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
        }
        elseif( 'vtodo' != $compType ) { // vevent/vjournal
          if( $this->accepted( 'ALLDAYEVENTOCCURRENCE' )) {
            $comp->setProperty( 'DTSTART',  array( 'timestamp' => $date), $this->fixParameters( array( 'VALUE' => 'DATE', 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            $allDayEvent = TRUE;
          }
          else {
            $allDayEvent = FALSE;
            $comp->setProperty( 'DTSTART',  array( 'timestamp' => $compDate ), $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            if( $this->accepted( 'DTENDOCCURRENCE' ))
              $comp->setProperty( 'DTEND',  array( 'timestamp' => ( $compDate + $duration )), $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            elseif( $this->accepted( 'DURATIONDOCCURRENCE' ))
              $comp->setProperty( 'DURATION', array( 'sec' => $duration ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          }
        }
        else { // vtodo only
          if( $this->accepted( 'ALLDAYEVENTOCCURRENCE' )) {
            $comp->setProperty( 'DTSTART',  array( 'timestamp' => $date), $this->fixParameters( array( 'VALUE' => 'DATE', 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            $allDayEvent = TRUE;
          }
          else {
            $allDayEvent = FALSE;
            $comp->setProperty( 'DTSTART',  array( 'timestamp' => $compDate ), $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            if( $this->accepted( 'DTENDOCCURRENCE' ))
              $comp->setProperty( 'DUE',  array( 'timestamp' => ( $compDate + $duration )), $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            elseif( $this->accepted( 'DURATIONDOCCURRENCE' ))
              $comp->setProperty( 'DURATION', array( 'sec' => $duration ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          }
        }
            /** UID */
        $thisUID = $comp->getProperty( 'UID' );
        $previous[$compCount] = array( 'DTSTART' => $comp->getProperty( 'DTSTART', FALSE, TRUE ), 'UID' => $thisUID, 'SEQUENCE' => 0 );
            /** ATTACH */
        if( in_array( 'ATTACH', self::$compProps[$compType] ) && $this->accepted( 'ATTACHOCCURRENCE' ))
          $comp->setProperty( 'ATTACH', "http://$uniqueId/info/info.rtf", $this->fixParameters( array( "FMTTYPE" => "application/binary", 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** Attendee */
        if( in_array( 'ATTENDEE', self::$compProps[$compType] )) {
          if( $this->accepted( 'ATTENDEE1STOCCURRENCE' ))
            $comp->setProperty( 'ATTENDEE', $this->getValue( 'attendees' ));
          if( $this->accepted( 'ATTENDEE2NDOCCURRENCE' ))
            $comp->setProperty( 'ATTENDEE', $this->getValue( 'attendees' ));
        }
            /** CLASS */
        if( in_array( 'CLASS', self::$compProps[$compType] ) && $this->accepted( 'CLASS' ))
          $comp->setProperty( 'CLASS', $this->getValue( 'class' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** CATEGORIES, selects 1 of 10 categories */
        if( in_array( 'CATEGORIES', self::$compProps[$compType] )) {
          $pValue = 'Category #'.mt_rand( 1, 10);
          $comp->setProperty( 'CATEGORIES', $pValue, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** 2nd property Categories, 3rd occurence (3rd ocurrence in 2nd), 0=none */
          if( $this->accepted( 'CATEGORIES2NDOCCURRENCE' )) {
            $pValue = 'Category #A'.mt_rand( 1, 10 );
            if( $this->accepted( 'CATEGORIES3RDOCCURRENCE' ))
              $pValue .= ',Category #XB'.mt_rand( 1, 10 );
            $comp->setProperty( 'CATEGORIES', $pValue, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          }
        }
            /** Comment */
        if( in_array( 'COMMENT', self::$compProps[$compType] )) {
          if( $this->accepted( 'COMMENT1STOCCURRENCE' ))
            $comp->setProperty( 'COMMENT',  $this->getValue( 'comments' ), $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          if( $this->accepted( 'COMMENT2NDOCCURRENCE' ))
            $comp->setProperty( 'COMMENT',  $this->getValue( 'comments' ), $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
        }
            /** COMPLETED */
        if(  in_array( 'COMPLETED', self::$compProps[$compType] ) && $this->accepted( 'COMPLETEDDOCCURRENCE' ))
          $comp->setProperty( 'COMPLETED',  array( 'timestamp' => ($compDate + (3*24*3600))), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount )); // fake three days after event startdate
            /** CONTACT */
        if( in_array( 'CONTACT', self::$compProps[$compType] ) && $this->accepted( 'CONTACTOCCURRENCE' ))
          $comp->setProperty( 'CONTACT', $this->getValue( 'attendees' ), $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** CREATED */
        if(  in_array( 'CREATED', self::$compProps[$compType] ) && $this->accepted( 'CREATEDOCCURRENCE' ))
          $comp->setProperty( 'CREATED',  array( 'timestamp' => ($compDate - (2*24*3600))), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount )); // fake two days before event startdate
            /** DESCRIPTION property in every event/todo, two in journal */
        if( in_array( 'DESCRIPTION', self::$compProps[$compType] )) {
          $description = $this->getValue( 'descriptions' );
          $comp->setProperty( 'DESCRIPTION', $description, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          if( 'vjournal' == $compType ) {
            $description = $this->getValue( 'descriptions' );
            $comp->setProperty( 'DESCRIPTION', $description, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          }
        }
            /** SEQUENCE and RECURRENCE-ID */
        $setRecurrenceId = 0;
        if(( 1 < $compCount ) && ( 0 < count( $previous )) && in_array( 'SEQUENCE', self::$compProps[$compType] ) && $this->accepted( 'SEQUENCEOCCURRENCE' )) {
          $pix = FALSE;
          $six = 0;
          do {
            $pix = mt_rand( 1, ( count( $previous ) - 1 ));
            $six++;
          } while(( 10 > $six ) && ( $thisUID != $previous[$pix]['UID'] ));
          if( $pix ) {
            $previous[$pix]['SEQUENCE'] += 1;
            $comp->setProperty( 'SEQUENCE',      $previous[$pix]['SEQUENCE'], $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            $comp->setProperty( 'RECURRENCE-ID', $previous[$pix]['DTSTART']['value'], $previous[$pix]['DTSTART']['params'] );
            $comp->setProperty( 'UID',           $previous[$pix]['UID'] );
            $setRecurrenceId = 1; // no recurrence properties in component where RECURRENCE-ID is set
          }
        }
            /** EXDATE */
        $setExdate = 0;
        if( empty( $setRecurrenceId ) && in_array( 'EXDATE', self::$compProps[$compType] ) && $this->accepted( 'EXDATEOCCURRENCE' ))
          $setExdate = 1;
            /** FREEBUSY */
        $freebusySw = FALSE;
        if(  in_array( 'FREEBUSY', self::$compProps[$compType] ) && $this->accepted( 'FREEBUSYOCCURRENCE' )) {
          $freebusySw = TRUE;
          $case  = mt_rand(1, 3 );
          $pend  = $compDate + $duration;
          $start = mt_rand( $compDate, $pend );
          switch( $case ) {
            case 3:  // period:  DATE-TIME/DATE-TIME
              $end        = mt_rand( $start, $pend );
              $fbPeriod   = array( array( array( 'timestamp' => $start ), array( 'timestamp' => $end )));
              $comp->setProperty( 'FREEBUSY', 'BUSY', $fbPeriod, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
              break;
            case 2:  // period:  DATE-TIME/DURATION
              $duration   = mt_rand( $start, $pend ) - $compDate;
              $fbPeriod   = array( array( array( 'timestamp' => $start ), array( 'sec' => $duration )));
              $comp->setProperty( 'FREEBUSY', 'BUSY', $fbPeriod, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
              break;
            case 1:
            default: // periods:  DATE-TIME/DATE-TIME, DATE-TIME/DURATION
              $end        = mt_rand( $start, $pend );
              $fbPeriod   = array( array( array( 'timestamp' => $start ),  array( 'timestamp' => $end )));
              $start      = mt_rand( $end, $pend );
              $end        = mt_rand( $start, $pend ) - $start;
              $fbPeriod[] = array( array( 'timestamp' => $start ), array( 'sec' => $end ));
              $comp->setProperty( 'FREEBUSY', 'BUSY', $fbPeriod, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
              break;
          }
        }
            /** GEO */
        if(  in_array( 'GEO', self::$compProps[$compType] ) && $this->accepted( 'GEOOCCURRENCE' )) {
          $fraction  = pow( 10, mt_rand( 0, 6 ));
          $latitude  = sprintf( '%1.6f', ( mt_rand( 0, (2*( 90 * $fraction ))) - ( 90 * $fraction )) / $fraction );
          $latitude  = rtrim( rtrim( $latitude, '0' ), '.' );
          $fraction  = pow( 10, mt_rand( 0, 6 ));
          $longitude = sprintf( '%1.6f', ( mt_rand( 0, (2*( 180 * $fraction ))) - ( 180 * $fraction )) / $fraction );
          $longitude = rtrim( rtrim( $longitude, '0' ), '.' );
          $comp->setProperty( 'GEO', $latitude, $longitude );
        }
            /** LAST-MODIFIED */
        if(  in_array( 'LAST-MODIFIED', self::$compProps[$compType] ) && $this->accepted( 'LAST_MODIFIEDOCCURRENCE' ))
          $comp->setProperty( 'LAST-MODIFIED', array( 'timestamp' => ($compDate - (23*3600))), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount )); // fake 25 hours before event startdate
            /** LOCATION */
        if(  in_array( 'LOCATION', self::$compProps[$compType] ) && $this->accepted( 'LOCATIONOCCURRENCE' ))
          $comp->setProperty( 'LOCATION', "Location #$compCount", $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** ORGANIZER */
        if(  in_array( 'ORGANIZER', self::$compProps[$compType] ) && ( $freebusySw || $this->accepted( 'ORGANIZEROCCURRENCE' )))
          $comp->setProperty( 'ORGANIZER', $this->getValue( 'attendees' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** PERCENT-COMPLETE */
        if(  in_array( 'PERCENT-COMPLETE', self::$compProps[$compType] ) && $this->accepted( 'PERCENT_COMPLETEOCCURRENCE' ))
          $comp->setProperty( 'PERCENT-COMPLETE',  mt_rand( 1, 99 ));
            /** PRIORITY */
        if(  in_array( 'PRIORITY', self::$compProps[$compType] ) && $this->accepted( 'PRIORITYOCCURRENCE' )) // priority, 1 to 9. HIGH (1-4), MEDIUM (5), LOW (6-9)
          $comp->setProperty( 'PRIORITY',  $this->getValue( 'prioArr' ));
            /** RESOURCES, selects 1 of 10 resources */
        if( in_array( 'RESOURCES', self::$compProps[$compType] )) {
          $pValue = 'Resource R'.mt_rand( 1, 10);
          $comp->setProperty( 'RESOURCES', $pValue, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** percent 2nd property Resources, 3rd occurence (3rd percent ocurrence in 2nd), 0=none */
          if( $this->accepted( 'RESOURCES2NDOCCURRENCE' )) {
            $pValue = 'Resource #P'.mt_rand( 1, 10);
            if( $this->accepted( 'RESOURCES3RDOCCURRENCE' ))
              $pValue .= ',Resource #XP'.mt_rand( 1, 10);
            $comp->setProperty( 'RESOURCES', $pValue, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          }
        }
            /** RDATE */
        if( empty( $setRecurrenceId ) && in_array( 'RDATE', self::$compProps[$compType] ) && $this->accepted( 'RDATEOCCURRENCE' )) {  // fake one week after event start date
          if( $allDayEvent )
            $params = $this->fixParameters( array( 'VALUE' => 'DATE', 'X-PARAM' => $this->config['X-PARAM'] ), $compCount );
          else
            $params = $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount );
          $comp->setProperty( 'RDATE', array( array( 'timestamp' => ($compDate + (7*24*3600)))), $params );
          $setExdate += 1;
        }
            /** RELATED-TO */
        if(( 1 < $compCount ) && ( 0 < count( $previous )) &&  in_array( 'RELATED-TO', self::$compProps[$compType] ) && $this->accepted( 'RELATED_TOOCCURRENCE' )) {
          $pix = FALSE;
          $six = 0;
          do {
            $pix = mt_rand( 1, ( count( $previous ) - 1 ));
            $six++;
          } while(( 10 > $six ) && ( 0 == $previous[$pix]['SEQUENCE'] ) && ( $thisUID != $previous[$pix]['UID'] ));
          if( $pix )
            $comp->setProperty( 'RELATED-TO', $previous[$pix]['UID'], $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
        }
            /** REQUEST-STATUS */
        if( in_array( 'REQUEST-STATUS', self::$compProps[$compType] ) && $this->accepted( 'REQUEST_STATUSOCCURRENCE' ))
          $comp->setProperty( 'REQUEST-STATUS', 3.11, 'REQUEST-STATUS text', FALSE, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** RRULE */
        if( empty( $setRecurrenceId ) && in_array( 'RRULE', self::$compProps[$compType] ) && $this->accepted( 'RRULEOCCURRENCE' )) {
          $recur = (( $compCount % 2 ) == 0 ) ? array( 'FREQ' => 'WEEKLY' ) : array( 'FREQ' => 'MONTHLY' );
          if(( $compCount % 2 ) == 0 ) {
            if( 'WEEKLY' == $recur['FREQ'] ) {
              if( $allDayEvent )
                $recur['UNTIL'] = date( 'Ymd',          $compDate + ((24*3600) * mt_rand( 20, 30 ))); // end within 20-30 days, 3-5 weeks
              else
                $recur['UNTIL'] = array( 'timestamp' => $compDate + ((24*3600) * mt_rand( 20, 30 ))); // end within 20-30 days, 3-5 weeks
            }
            elseif( $allDayEvent )
              $recur['UNTIL'] = date( 'Ymd',            $compDate + ((24*3600) * mt_rand( 20, 30 ))); // end within 40-70 days, 2-3 month
            else
              $recur['UNTIL'] = array( 'timestamp' =>   $compDate + ((24*3600) * mt_rand( 40, 70 ))); // end within 40-70 days, 2-3 month
          }
          else
            $recur['COUNT'] = mt_rand( 3, 5 );
          $x = mt_rand( 0, 5 );
          if( 1 < $x )
            $recur['BYDAY'] = self::$baseValues['bydays'][$x];
          elseif( 0 < $x )
            $recur['BYDAY'] = array( 'DAY' => self::$baseValues['days'][date( 'w', $compDate )] );
          $comp->setProperty( 'RRULE',  $recur );
          $setExdate += 1;
        } // end - if( $this->accepted( 'RRULEOCCURRENCE' ))
        if( 2 <= $setExdate ) { // exclude event startdate
          if( $allDayEvent )
            $params = $this->fixParameters( array( 'VALUE' => 'DATE', 'X-PARAM' => $this->config['X-PARAM'] ), $compCount );
          else
            $params = $this->fixParameters( array( 'TZID' => $this->config['TZID'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount );
          $comp->setProperty( 'EXDATE', array( array( 'timestamp' => $compDate )), $params );
        }
            /** STATUS */
        if( in_array( 'STATUS', self::$compProps[$compType] ) && $this->accepted( 'STATUSOCCURRENCE' ))
          $comp->setProperty( 'STATUS', $this->getValue( 'status'.$compType ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** SUMMARY property in every event (none in freebusy) */
        if( in_array( 'SUMMARY', self::$compProps[$compType] )) {
          $summary = "Event #$compCount. ".$this->getValue( 'summaries' );
          $comp->setProperty( 'SUMMARY',   $summary, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
        }
            /** TRANSP */
        if( in_array( 'TRANSP', self::$compProps[$compType] ) && $this->accepted( 'TRANSPOCCURRENCE' ))
          $comp->setProperty( 'TRANSP', $this->getValue( 'transp' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** URL */
        if( in_array( 'URL', self::$compProps[$compType] ) && $this->accepted( 'URLOCCURRENCE' ))
          $comp->setProperty( 'URL', "http://$uniqueId/info/index.php?event=".$compCount, $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** X-prop */
        if( $this->accepted( 'X_PROP1STOCCURRENCE' ))
          $comp->setProperty( 'X-PROP1', $this->getValue( 'descriptions' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
        if( $this->accepted( 'X_PROP2NDOCCURRENCE' ))
          $comp->setProperty( 'X-PROP2', $this->getValue( 'descriptions' ), $this->fixParameters( array( 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
            /** create ALARMs? */
        if(( 'vjournal' == $compType ) || ( 'vfreebusy' == $compType ))
          continue;
            /** AUDIO ALARM */
        if( $this->accepted( 'AUDIOALARMOCCURRENCE' )) {
          $alarm = & $comp->newComponent( 'valarm' );
          $alarm->setProperty( 'ACTION', 'AUDIO' );
          $alarm->setProperty( 'ATTACH', "ftp://$uniqueId/sounds/bell-01.aud", $this->fixParameters( array( "FMTTYPE" => "audio/basic", 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          $alarm->setProperty( 'DURATION', 'PT1H' );
          $alarm->setProperty( 'REPEAT', 2 );
          if( !isset( $this->config['AUDIOALARMTRIGGER'] ) || !ctype_digit((string) $this->config['AUDIOALARMTRIGGER'] ))
            $trigger = array( 'hour' => 1 );
          elseif( 23 < $this->config['AUDIOALARMTRIGGER'] )
            $trigger = array( 'day' => floor( $this->config['AUDIOALARMTRIGGER'] / 24 ), 'hour' => $this->config['AUDIOALARMTRIGGER'] % 24 );
          else
            $trigger = array( 'hour' => $this->config['AUDIOALARMTRIGGER'] );
          $alarm->setProperty( 'TRIGGER', $trigger );
        } // end - if( $this->accepted( 'AUDIOALARMOCCURRENCE' ))
            /** DISPLAY ALARM */
        if( $this->accepted( 'DISPLAYALARMOCCURRENCE' )) {
          $alarm = & $comp->newComponent( 'valarm' );
          $alarm->setProperty( 'ACTION', 'DISPLAY' );
          if( FALSE !== ( $v = $comp->getProperty( 'description' )))
            $alarm->setProperty( 'DESCRIPTION', $v, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          if( !isset( $this->config['DISPLAYALARMTRIGGER'] ) || !ctype_digit((string) $this->config['DISPLAYALARMTRIGGER'] ))
            $trigger = array( 'hour' => 4 );
          elseif( 23 < $this->config['DISPLAYALARMTRIGGER'] )
            $trigger = array( 'day' => floor( $this->config['DISPLAYALARMTRIGGER'] / 24 ), 'hour' => $this->config['DISPLAYALARMTRIGGER'] % 24 );
          else
            $trigger = array( 'hour' => $this->config['DISPLAYALARMTRIGGER'] );
          $alarm->setProperty( 'TRIGGER', $trigger );
        } // end - if( $this->accepted( 'DISPLAYALARMOCCURRENCE' ))
            /** EMAIL ALARM */
        if( $this->accepted( 'EMAILALARMOCCURRENCE' )) {
          $alarm = & $comp->newComponent( 'valarm' );
          $alarm->setProperty( 'ACTION', 'EMAIL' );
          if( FALSE !== ( $v = $comp->getProperty( 'description' )))
            $alarm->setProperty( 'DESCRIPTION', $v, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          if( FALSE !== ( $v = $comp->getProperty( 'summary' )))
            $alarm->setProperty( 'SUMMARY',     $v, $this->fixParameters( array( 'ALTREP' => $this->config['ALTREP'], 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          if( $this->accepted( 'ATTACHOCCURRENCE' ))
            $alarm->setProperty( 'ATTACH', "http://$uniqueId/info/info.doc", $this->fixParameters( array( "FMTTYPE" => "application/binary", 'X-PARAM' => $this->config['X-PARAM'] ), $compCount ));
          $alarm->setProperty( 'attendee',    $this->getValue( 'attendees' ));
          $alarm->setProperty( 'attendee',    $this->getValue( 'attendees' ));
          if( !isset( $this->config['EMAILALARMTRIGGER'] ) || !ctype_digit((string) $this->config['EMAILALARMTRIGGER'] ))
            $trigger = array( 'hour' => 24 );
          elseif( 23 < $this->config['EMAILALARMTRIGGER'] )
            $trigger = array( 'day' => floor( $this->config['EMAILALARMTRIGGER'] / 24 ), 'hour' => $this->config['EMAILALARMTRIGGER'] % 24 );
          else
            $trigger = array( 'hour' => $this->config['EMAILALARMTRIGGER'] );
          $alarm->setProperty( 'trigger',     $trigger );
        } // end - if( $this->accepted( 'EMAILALARMOCCURRENCE' ))
      } // end - while( $dayCount < $this->config['COMPCNT'] )
      $date += (24*3600);
    } // end - while( $date < $stopDate )
    $calendar->sort();
    if( isset( $this->config['X-WR-TIMEZONE'] ) && !empty( $this->config['X-WR-TIMEZONE'] ))
      iCalUtilityFunctions::createTimezone( $calendar, $this->config['X-WR-TIMEZONE'] );
    $calendar->saveCalendar();
    unset( $calendar );
    $this->_log( 'Created \''.$this->config['CALDIR'].$this->config['FILENAMES'][$fix].'\', start '.date( 'Y-m-d', $dat2 )." with $compCount components(".number_format(( microtime( TRUE ) - $start ), 5 ).' msec)', LOG_DEBUG );
    return TRUE;
  }
  public function createTestFiles() {
    $start = microtime( TRUE );
    $this->_log( __METHOD__.' start', LOG_INFO );
    if( !$this->limitCheck )
      $this->limitChecker();
    if( !$this->DIRFILEcheck && ( FALSE === $this->DIRFILEchecker()))
      return FALSE;
    if( !$this->COMPTYPEScheck )
      $this->COMPTYPESchecker();
    if( !isset( $this->config['LOCKFILE'] ) || empty( $this->config['LOCKFILE'] ))
      $this->config['LOCKFILE']  = 'tiCalFile.lck';
    $this->lockFile = $this->config['LOCKDIR'].$this->config['LOCKFILE'];
    foreach($this->config as $k => $v ) {
      if( is_array( $v ))
        $v = str_replace( PHP_EOL, '', var_export( $v, TRUE ));
      $this->_log( "$k: $v", LOG_DEBUG );
    }
    $fileCount    = 0;
    $this->removeTime = time() - ( $this->config['CALAGE'] * 3600 );
    $this->_log(   'checking file remove time: '.date( 'Y-m-d H:i:s', $this->removeTime ), LOG_INFO );
    if( $this->lockfileChecker()) {
      foreach( $this->config['FILENAMES'] as $fix => $filename ) {
        if( $this->createTestFile( $fix ))
          $fileCount   += 1;
      }
      $this->updLockfile();
    }
    else
      $this->_log( 'No action now due to previous lock file creation at '.date( 'Y-m-d H:i:s', $this->filemtime ), LOG_INFO );
    if( FALSE !== ( $this->fp ))
      $this->freeLockfile();
    $this->_log( "Created $fileCount test iCal files (".number_format(( microtime( TRUE ) - $start ), 5 ).' msec)', LOG_NOTICE );
    $this->_flush();
    return TRUE;
  }
  private function directoryChecker( & $directory) {
    $this->_log( __METHOD__." start, directory=$directory", LOG_INFO );
    $directory  = realpath( $directory );
    $dssl         = strlen( DIRECTORY_SEPARATOR );
    if( DIRECTORY_SEPARATOR != substr( $directory, ( 0 - $dssl )))
      $directory .= DIRECTORY_SEPARATOR;
    $this->_log( "directoryChecker: '$directory'", LOG_INFO );
    return ( is_dir( $directory ) && is_writable( $directory )) ? TRUE : FALSE;
  }
  private function DIRFILEchecker() {
    $this->_log( __METHOD__.' start', LOG_INFO );
    if( !isset( $this->config['CALDIR'] ) || empty( $this->config['CALDIR'] ))
      $this->config['CALDIR']    = '.';
    if( FALSE === $this->directoryChecker( $this->config['CALDIR'] )) {
      $this->_log( "DIRFILEchecker (1) no write rights in '".$this->config['CALDIR']."', check directory!!", LOG_ALERT );
      $this->_flush();
      return FALSE;
    }
    if( !isset( $this->config['FILENAMES'] ) || empty( $this->config['FILENAMES'] ))
      $this->config['FILENAMES'] = array( 'testFile.ics' );
    elseif( !is_array( $this->config['FILENAMES'] ))
      $this->config['FILENAMES'] = array( $this->config['FILENAMES'] );
    $r = array(); // check filename dbls
    foreach( $this->config['FILENAMES'] as $fix => $fileName ) {
      $dbls = array_keys( $this->config['FILENAMES'], $fileName );
      if( 1 < count( $dbls )) {
        array_shift( $dbls );
        foreach( $dbls as $dbl )
          $r[] = $dbl;
      }
    }
    if( !empty( $r )) {
      foreach( $r as $key ) {
        if( !isset( $this->config['FILENAMES'][$key] ))
          continue;
        $this->_log( "DIRFILEchecker (3) : removing dbl filename $key ".$this->config['FILENAMES'][$key], LOG_NOTICE );
        unset( $this->config['FILENAMES'][$key] ); // remove and sync fileNamns and compTypes
        if( !isset( $this->config['COMPTYPES'][$key] ))
          continue;
        $this->_log( "DIRFILEchecker (3) : removing dbl comptype $key", LOG_NOTICE );
        unset( $this->config['COMPTYPES'][$key] );
      }
      $this->config['FILENAMES'] = array_values( $this->config['FILENAMES'] );
      $this->config['COMPTYPES'] = array_values( $this->config['COMPTYPES'] );
    }
    if( !isset( $this->config['LOCKDIR'] ) || empty( $this->config['LOCKDIR'] ))
      $this->config['LOCKDIR']   = $this->config['CALDIR'];
    elseif( FALSE === $this->directoryChecker( $this->config['LOCKDIR'] )) {
      $this->_log( "DIRFILEchecker (3) no write rights in '".$this->config['LOCKDIR']."', check directory!!", LOG_ALERT );
      $this->_flush();
      return FALSE;
    }
    if( !isset( $this->config['LOCKFILE'] ) || empty( $this->config['LOCKFILE'] ))
      $this->config['LOCKFILE']  = 'tiCalFile.lck';
    $this->_log( "DIRFILEchecker (4) CALDIR=".$this->config['CALDIR'], LOG_NOTICE );
    $this->_log( "DIRFILEchecker (5) LOCK=".$this->config['LOCKDIR'].$this->config['LOCKFILE'], LOG_NOTICE );
    $this->DIRFILEcheck = TRUE;
    return TRUE;
  }
            /* check and create (opt.) parameters */
  private function fixParameters( $params, $unique ) {
    $output = array();
    foreach( $params as $pkey => $pvalue ) {
      if( !$pvalue )
        continue;
      $output[$pkey] = ( 'X-' != substr( $pkey, 0, 2 )) ? $pvalue : $pvalue.$unique;
    }
    return ( empty( $output )) ? null : $output;
  }
  private function freeLockfile() {
    @flock( $this->fp, LOCK_UN);
    @fclose( $this->fp );
  }
  public function getConfig( $key ) {
    $key = strtoupper( $key );
    return ( isset( $this->config[$key] ) && !empty( $this->config[$key] )) ? $this->config[$key] : FALSE;
  }
  private function getValue( $spec ) {
    if( !isset( self::$baseValues[$spec] ) || empty( self::$baseValues[$spec] ))
      return '';
    $max = count( self::$baseValues[$spec] ) - 1;
    return self::$baseValues[$spec][mt_rand( 0, $max )];
  }
  private function limitChecker() {
    $this->_log( __METHOD__.' start', LOG_INFO );
    if( empty( $this->config['DAYCNT'] )     || !ctype_digit((string) $this->config['DAYCNT'] )) {
               $this->config['DAYCNT']      = 10;
      $this->_log( "limitChecker (1) : unvalid 'DAYCNT', set to 10", LOG_ERR );
    }
    if( empty( $this->config['COMPCNT'] )    || !ctype_digit((string) $this->config['COMPCNT'] )) {
               $this->config['COMPCNT']     = 5;
      $this->_log( "limitChecker (2) : unvalid 'COMPCNT', set to 5", LOG_ERR );
    }
    if( empty( $this->config['COMPSTART'] )  || !ctype_digit((string) $this->config['COMPSTART'] )) {
               $this->config['COMPSTART']   = 7;
      $this->_log( "limitChecker (3) : unvalid 'COMPSTART', set to 7", LOG_ERR );
    }
    if( empty( $this->config['COMPEND'] )    || !ctype_digit((string) $this->config['COMPSTART'] )) {
               $this->config['COMPEND']     = 18;
      $this->_log( "limitChecker (4) : unvalid 'COMPEND', set to 18", LOG_ERR );
    }
    if( empty( $this->config['COMPDURMIN'] ) || !ctype_digit((string) $this->config['COMPDURMIN'] )) {
               $this->config['COMPDURMIN']  = 1;
      $this->_log( "limitChecker (5) : unvalid 'COMPDURMIN', set to 1", LOG_ERR );
    }
    if( empty( $this->config['COMPDURMAX'] ) || !ctype_digit((string) $this->config['COMPDURMAX'] )) {
               $this->config['COMPDURMAX']  = 36;
      $this->_log( "limitChecker (6) : unvalid 'COMPDURMAX', set to 36", LOG_ERR );
    }
    $this->limitCheck = TRUE;
  }
  private function lockfileChecker() {
    $this->_log( __METHOD__.' start', LOG_INFO );
    $this->_log( 'lockfile=\''.$this->lockFile.'\'', LOG_DEBUG );
    if( FALSE !== ( $this->fp = @fopen( $this->lockFile, 'a+' ))) {
      if( FALSE !== ( flock( $this->fp, LOCK_EX ))) {
        $filesize        = filesize( $this->lockFile );
        $this->filemtime = filemtime( $this->lockFile );
        $this->_log( 'actual lock file time:     '.date( 'Y-m-d H:i:s', $this->filemtime )." filesize=$filesize", LOG_INFO );
        return (( 10 > $filesize ) || ( $this->filemtime < $this->removeTime )) ? TRUE : FALSE;
      }
      $this->_log( 'lockfileChecker (17) creating lock on file \''.$this->lockFile.'\', check directory/file!!', LOG_ERR );
      $this->_flush();
      return FALSE;
    }
    $this->_log( 'lockfileChecker (16) opening lock file \''.$this->lockFile.'\', check directory/file!!', LOG_ERR );
    $this->_flush();
    return FALSE;
  }
  private function setBaseValues() {
    $this->_log( __METHOD__.' start', LOG_INFO );
    self::$compProps = array( 'vevent'    => array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'CONTACT'
                                                  , 'CREATED', 'DESCRIPTION', 'DTEND', 'DTSTART', 'DURATION', 'EXDATE'
                                                  , 'EXRULE', 'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER', 'PRIORITY'
                                                  , 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RESOURCES', 'REQUEST-STATUS'
                                                  , 'RRULE', 'SEQUENCE', 'STATUS', 'SUMMARY', 'TRANSP', 'URL' )
                            , 'vtodo'     => array( 'ATTACH', 'ATTENDEE', 'CLASS', 'CATEGORIES', 'COMMENT', 'COMPLETED'
                                                  , 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTSTART', 'DURATION', 'DUE'
                                                  , 'EXDATE', 'EXRULE', 'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER'
                                                  , 'PERCENT-COMPLETE', 'PRIORITY', 'RDATE', 'RECURRENCE-ID', 'RRULE'
                                                  , 'SEQUENCE', 'RELATED-TO', 'RESOURCES', 'REQUEST-STATUS', 'STATUS', 'SUMMARY', 'URL' )
                            , 'vjournal'  => array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'CONTACT'
                                                  , 'CREATED', 'DESCRIPTION', 'DTSTART', 'EXDATE', 'EXRULE', 'LAST-MODIFIED'
                                                  , 'ORGANIZER', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'REQUEST-STATUS'
                                                  , 'RRULE','SEQUENCE', 'STATUS', 'SUMMARY', 'URL' )
                            , 'vfreebusy' => array( 'ATTENDEE', 'COMMENT', 'CONTACT', 'DTEND', 'DTSTART', 'DURATION'
                                                  , 'FREEBUSY', 'ORGANIZER', 'REQUEST-STATUS', 'URL', ));
    self::$baseValues = array();
            // array to randomly select a summary from
    self::$baseValues['summaries']    = array(
      'Duis ac dui sit amet ante auctor euismod.'
    , 'Suspendisse_pellentesque_velit_in_tortor.'
    , 'Mauris vulputate.'
    , 'Nulla sapien pede, dapibus sed.'
    , 'Maecenas tristique, pede_id_sollicitudin_posuere, enim nibh mollis odio.'
    , 'Lorem ipsum dolor sit amet, consectetuerAdipiscingElit.' );
            // array to randomly select a description from
    self::$baseValues['descriptions'] = array(
      'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus tempus erat vel risus. Aenean augue velit, bibendum ac, porttitor ut, egestas vel, massa.'
    , 'Sed varius dignissim est. Integer venenatis, odio vel imperdiet tincidunt, felis mi consectetur quam, at consequat justo dui eu ante. Nam nec lectus.'
    , 'Aenean vel lorem sed tortor venenatis scelerisque. Integer eget felis. Sed id justo. Sed ullamcorper mauris nec eros. Praesent mattis ligula non est.'
    , 'Donec libero dolor, tincidunt vel, fermentum at, condimentum ut, ante. Nam mi. Aliquam lobortis enim at mi. Donec ornare varius turpis.'
    , 'Phasellus tempor dui nec velit. Quisque viverra, nunc vel facilisis accumsan, lorem lacus consequat libero, sed lobortis justo nisl at odio.'
    , 'Pellentesque bibendum, ipsum et rutrum volutpat, arcu libero accumsan turpis, et egestas nunc purus et erat.'  );
            // random priority, 1 to 9. HIGH (1-4), MEDIUM (5), LOW (6-9)
            // reversed prio; HIGH: weight 1, MEDIUM weight 4, LOW: weight 8
    self::$baseValues['prioArr'] = array();
    for( $r=1; $r<=9; $r++) {
      $weight = ( 5 < $r ) ? 1 : ( 5 > $r ) ? 8 : 4;
      for( $r1=1; $r1<=$weight; $r1++)
        self::$baseValues['prioArr'][] = $r;
    }
    mt_srand();
    shuffle( self::$baseValues['prioArr'] );
            // arrays to randomly select names and site from
    $sNames       = array(  'Martin', 'Bernard', 'Dubois', 'Thomas', 'Robert', 'Richard'
                          , 'Kim', 'Khan', 'Chandra', 'Nayak', 'Singh', 'Castillo', 'Diaz'
                          , 'Michel', 'Garcia', 'David', 'Bertrand', 'Roux', 'Vincent', 'Fournier'



                         );
    $fNames       = array(  'Sem', 'Sophie', 'Lucas', 'Julia', 'Milan', 'Emma', 'Daan'
                          , 'Jing', 'Li', 'Hussain', 'Wei', 'Nalda', 'Chan', 'Riel'
                          , 'Thomas', 'Sanne', 'Thijs', 'Noa', 'Jesse', 'Anna', 'Luuk'
                         );
    $sites        = array( '@kigkonsult.se', '@siteOnThe.net', '@org.org' );
    if( isset( $this->config['UNIQUE'] ) && !empty( $this->config['UNIQUE'] ))
      $sites[2]   = '@'.$this->config['UNIQUE'];
    self::$baseValues['attendees']       = array();
    $sv = $fNv = TRUE;
    foreach( $sNames as $sName ) {
      foreach( $fNames as $fName ) {
        if( $fNv )
          $fName = $fName{0};
        $sep = ( $sv ) ? '.' : '';
        self::$baseValues['attendees'][] = $fName.$sep.$sName.$sites[mt_rand( 0, 2 )];
        $fNv = !$fNv;
      }
      $sv  = !$sv;
    }
            // array to randomly select a comment from
    self::$baseValues['comments']     = array(
      'Praesent eros nibh, posuere at, hendrerit non, aliquam a, sapien. Curabitur commodo orci eget neque. Vivamus tempor posuere sapien.'
    , 'Fusce id nisl ut enim consectetur pulvinar. Ut auctor elit at lorem. Maecenas purus arcu, faucibus eu, iaculis quis, pretium quis, velit.'
    , 'Fusce vel sem quis felis dictum venenatis. Sed ipsum. Fusce vel diam sit amet sapien pretium pretium.'
    , 'Sed nunc ligula, consequat vel, facilisis eu, vulputate sed, libero. Maecenas vel augue mattis risus elementum mattis.'
    , 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur tempor sodales ante.');
            // arrays, rrule/exrule
    self::$baseValues['days']         = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' );
    self::$baseValues['bydays']       = array();
    self::$baseValues['bydays'][2]    = array( array( 'DAY' => 'MO' ), array( 'DAY' => 'TU' ), array( 'DAY' => 'WE' ), array( 'DAY' => 'TH' ), array( 'DAY' => 'FR' ));
    self::$baseValues['bydays'][3]    = array( array( 'DAY' => 'TU' ), array( 'DAY' => 'TH' ));
    self::$baseValues['bydays'][4]    = array( array( 'DAY' => 'MO' ), array( 'DAY' => 'WE' ), array( 'DAY' => 'FR' ));
    self::$baseValues['bydays'][5]    = array( array( 'DAY' => 'SA' ), array( 'DAY' => 'SU' ));
            // array to randomly select a class from
    self::$baseValues['class']          = array( 'PUBLIC', 'PRIVATE', 'CONFIDENTIAL' );
            // array to randomly select a status from
    self::$baseValues['statusvevent']   = array( 'TENTATIVE', 'CONFIRMED', 'CANCELLED' );
    self::$baseValues['statusvtodo']    = array( 'NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED' );
    self::$baseValues['statusvjournal'] = array( 'DRAFT', 'FINAL', 'CANCELLED' );
            // array to randomly select TRANSP from
    self::$baseValues['transp']       = array( 'OPAQUE', 'TRANSPARENT' );
  }
  public function setConfig( $key, $value ) {
    $key         = strtoupper( $key );
    if( 'EVENT' == substr( $key, 0, 5 ))
      $key       = 'COMP'.substr( $key, 5 );
    $this->config[$key] = $value;
    if( in_array( $key, array( 'CALDIR', 'FILENAMES', 'LOCKDIR' )))
      $this->DIRFILEcheck = FALSE;
    if( in_array( $key, array( 'FILENAMES', 'COMPTYPES' )))
      $this->COMPTYPEScheck = FALSE;
  }
  private function updLockfile() {
    $this->_log( __METHOD__.' start', LOG_INFO );
    ftruncate( $this->fp, 0 );
    fwrite( $this->fp, date( 'Y-m-d H:i:s' ));
    fflush( $this->fp );
    $this->_log( "updLockfile: '".$this->lockFile."' ".date( 'Y-m-d H:i:s' ), LOG_INFO );
  }
}
?>
Return current item: tiCalFile