<commit_before><?php

/*
 * The ICal* classes in this file together partially implement RFC 2445.
 *
 */

require_once('TimeRange.php');

class ICalendarException extends Exception {
}

abstract class ICalObject {
  protected $classname;

  public function get_name() {
    return $this->classname;
  }

  public function set_attribute($attr, $value, $params=null) {
  }

  public function get_attribute($attr) {
  }
}

class ICalTodo extends ICalObject {
  public function __construct() {
    $this->classname = 'VTODO';
  }
}

class ICalJournal extends ICalObject {
  public function __construct() {
    $this->classname = 'VJOURNAL';
  }
}

class ICalFreeBusy extends ICalObject {
  public function __construct() {
    $this->classname = 'VFREEBUSY';
  }
}

class ICalTimeZone extends ICalObject {
  public $tzid;

  public function __construct() {
    $this->classname = 'VTIMEZONE';
  }

  public function set_attribute($attr, $value, $params=NULL) {
    switch ($attr) {
    case 'TZID':
      $this->tzid = $value;
      break;
    }
  }
}

class ICalDaylight extends ICalTimeZone {
  public function __construct() {
    $this->classname = 'DAYLIGHT';
  }
}

class ICalStandard extends ICalTimeZone {
  public function __construct() {
    $this->classname = 'STANDARD';
  }
}

class ICalAlarm extends ICalObject {
  public function __construct() {
    $this->classname = 'VALARM';
  }
}

class ICalEvent extends ICalObject {

  protected $uid;
  protected $recurid = NULL;
  protected $range;
  protected $summary;
  protected $description;
  protected $location;
  protected $tzid;
  protected $url;
  protected $updated;
  protected $categories=array();
  protected $properties=array();

  // attributes that will be populated only if recurring
  protected $recur = FALSE;
  protected $occurrences; // start times only
  protected $until;
  protected $exdates = Array();
  protected $incrementor;
  protected $interval = 1;
  
  public function getEventCategories() {
    return array();
  }

  protected function standardAttributes()
  {
    return array(
    'summary', 
    'location', 
    'description', 
    'uid', 
    'start', 
    'end', 
    'url', 
    'categories',
    'datetime',
  );
  }
  
  public function apiArray()
  {
    
	 $arr= array (
	 	'id'=>crc32($this->get_uid()) >>1,
	 	'title'=>$this->get_summary(),
	 	'start'=>$this->get_start(),
	 	'end'=>$this->get_end()
	 );

    if ($urlLink = $this->get_url()) {
        $arr['url'] = $urlLink;
    }
    if ($location = $this->get_location()) {
        $arr['location'] = $location;
    }
    if ($description = $this->get_description()) {
        $arr['description'] = $description;
    }
    
	 return $arr;

  }
  
  public function get_uid() {
    return $this->uid;
  }

  public function get_recurid() {
    return $this->recurid;
  }

  public function get_range() {
    return $this->range;
  }

  public function get_series_range() {
    return new TimeRange($this->get_start(), $this->get_end());
  }

  public function get_start() {
    return $this->range->get_start();
  }

  public function get_end() {
    if ($this->recur) {
      return $this->until;
    } else {
      return $this->range->get_end();
    }
  }

  public function get_summary() {
    return $this->summary;
  }

  public function get_url() {
    return $this->url;
  }

  public function get_description() {
    return $this->description;
  }

  public function get_location() {
    return $this->location;
  }
  
  public function get_categories() {
    return $this->categories;
  }

  public function is_recurring() {
    return $this->recur;
  }

  public function get_occurrences() {
    return $this->occurrences;
  }

  protected function compare_ranges(TimeRange $range, $compare_type) {
    if ($this->recur) {
      // check if $range is within this series at all
      $event_range = new TimeRange($this->get_start(), $this->get_end());
      if (!$event_range->$compare_type($range)) {
    return Array();
      } else {
    $duration = $this->range->get_end() - $this->range->get_start();
    $results = Array();
    $starts = $this->occurrences;
    while ($starts[0] < $this->until) {
      foreach ($starts as $start) {
        if ($start > $this->until)
          break 2;
        if (in_array($start, $this->exdates))
          continue;
        $event_range = new TimeRange($start, $start + $duration);
        if ($event_range->$compare_type($range)) {
          $results[] = new ICalEvent($this->summary, $event_range);
        }
      }
      $starts = $this->increment_set($starts);
    }
      }
      return $results;
    } else {
      return $this->range->$compare_type($range);
    }
  }

  public function overlaps(TimeRange $range) {
    return $this->compare_ranges($range, 'overlaps');
  }

  public function contains(TimeRange $range) {
    return $this->compare_ranges($range, 'contains');
  }

  public function contained_by(TimeRange $range) {
    return $this->compare_ranges($range, 'contained_by');
  }
  
  public function get_attribute($attr) {
    if (in_array($attr, $this->standardAttributes())) {
      if ($attr == 'datetime') {
        return $this->range;
      } else {
        $method = "get_$attr";
        return $this->$method();
      }
    } else {
      return isset($this->properties[$attr]) ? $this->properties[$attr] : null;
    }
  }
  
  public function get_all_attributes() {
    return array_merge($this->standardAttributes(), array_keys($this->properties));
  }

  public function set_attribute($attr, $value, $params=NULL) {
    switch ($attr) {
    case 'UID':
      if (strpos($value, '@') !== FALSE) {
        $this->uid .= substr($value, 0, strpos($value, '@'));
      } else {
        $this->uid .= $value;
      }
      break;
    case 'RECURRENCE-ID':
      $this->recurid = $value;
      break;
    case 'DESCRIPTION':
      $this->description = iCalendar::ical_unescape_text($value);
      break;
    case 'LOCATION':
      $this->location = iCalendar::ical_unescape_text($value);
      break;
    case 'SUMMARY':
      $this->summary = iCalendar::ical_unescape_text($value);
      break;
    case 'CATEGORIES':
        $categories = explode(',', $value);
        $this->categories = array();
        foreach ($categories as $category) {
            $this->categories[] = trim(iCalendar::ical_unescape_text($category));
        }
        break;
    case 'URL':
        $this->url = iCalendar::ical_unescape_text($value);
        break;
    case 'DTSTAMP':

        if (array_key_exists('TZID', $params)) {
            $datetime = new DateTime($value, new DateTimeZone($params['TZID']));
        } else {
            $datetime = new DateTime($value);
        }
      $this->updated = $datetime->format('U');
        break;
    case 'DTSTART':
    case 'DTEND':
        if (array_key_exists('TZID', $params)) {
            $datetime = new DateTime($value, new DateTimeZone($params['TZID']));
        } else {
            $datetime = new DateTime($value);
        }

      $timestamp = $datetime->format('U');

      if (!$this->range) {
        if (strpos($value, 'T')!== FALSE) {
            $this->range = new TimeRange($timestamp);
        } else {
            $this->range = new DayRange($timestamp);
        }
      } else {
        if ($attr=='DTEND' && ($timestamp > $this->get_start()) && (($timestamp - $this->get_start()) % 86400 == 0)) {
            // make all day events end at 11:59:59 so they don't overlap next day
            $timestamp -= 1;
         }
         
         switch ($attr)
         {
            case 'DTSTART':
                $this->range->set_start($timestamp);
                break;
            case 'DTEND':
                $this->range->set_end($timestamp);
                break;
         }
      }
      break;
    case 'DURATION':
      // todo:
      // if this tag comes before DTSTART we will break
      $this->range->set_end($this->get_start() + $value);
      break;
    case 'RRULE':
      $this->add_rrule($value);
      break;
    case 'EXDATE':
        if (array_key_exists('TZID', $params)) {
            $datetime = new DateTime($value, new DateTimeZone($params['TZID']));
        } else {
            $datetime = new DateTime($value);
        }

        $this->exdates[] = $datetime->format('U');
      break;
    case 'TZID': // this only gets called by ICalendar::__construct
      $this->tzid = $value;
      break;
    default:
        $this->properties[$attr] = iCalendar::ical_unescape_text($value);
        break;
    }
  }

  protected function increment_set($set) {
    return array_map(
      $this->incrementor,
      $set,
      array_fill(0, count($set), $this->interval)
      );
  }

  protected function add_rrule($rrule_string) {
    $rules = explode(';', $rrule_string);
    $this->recur = TRUE;
    if ($this->occurrences === NULL) {
      $this->occurrences = Array();
    }

    // read attributes from rrule_string
    $limit_type = '';
    $limit = '';

    $incrementors = Array(
      'SECONDLY' => 'increment_second',
      'MINUTELY' => 'increment_minute',
      'HOURLY' => 'increment_hour',
      'DAILY' => 'increment_day',   
      'WEEKLY' => 'increment_week',
      'MONTHLY' => 'increment_month',
      'YEARLY' => 'increment_year',
      );

    $occurs_by_list = Array();

    foreach ($rules as $rule) {
      $namevalue = explode('=', $rule);
      $rulename = $namevalue[0];
      $rulevalue = $namevalue[1];
      switch ($rulename) {
      case 'FREQ': // always present
    $this->incrementor = $incrementors[$rulevalue];
    break;
      case 'INTERVAL':
    $this->interval = $rulevalue;
      case 'UNTIL':
    $limit_type = 'UNTIL';
    $this->until = ICalendar::ical2unix($rulevalue);
    break;
      case 'COUNT':
    $limit_type = 'COUNT';<commit_msg>fixed a typo that affects recurrence rules<commit_after><?php

/*
 * The ICal* classes in this file together partially implement RFC 2445.
 *
 */

require_once('TimeRange.php');

class ICalendarException extends Exception {
}

abstract class ICalObject {
  protected $classname;

  public function get_name() {
    return $this->classname;
  }

  public function set_attribute($attr, $value, $params=null) {
  }

  public function get_attribute($attr) {
  }
}

class ICalTodo extends ICalObject {
  public function __construct() {
    $this->classname = 'VTODO';
  }
}

class ICalJournal extends ICalObject {
  public function __construct() {
    $this->classname = 'VJOURNAL';
  }
}

class ICalFreeBusy extends ICalObject {
  public function __construct() {
    $this->classname = 'VFREEBUSY';
  }
}

class ICalTimeZone extends ICalObject {
  public $tzid;

  public function __construct() {
    $this->classname = 'VTIMEZONE';
  }

  public function set_attribute($attr, $value, $params=NULL) {
    switch ($attr) {
    case 'TZID':
      $this->tzid = $value;
      break;
    }
  }
}

class ICalDaylight extends ICalTimeZone {
  public function __construct() {
    $this->classname = 'DAYLIGHT';
  }
}

class ICalStandard extends ICalTimeZone {
  public function __construct() {
    $this->classname = 'STANDARD';
  }
}

class ICalAlarm extends ICalObject {
  public function __construct() {
    $this->classname = 'VALARM';
  }
}

class ICalEvent extends ICalObject {

  protected $uid;
  protected $recurid = NULL;
  protected $range;
  protected $summary;
  protected $description;
  protected $location;
  protected $tzid;
  protected $url;
  protected $updated;
  protected $categories=array();
  protected $properties=array();

  // attributes that will be populated only if recurring
  protected $recur = FALSE;
  protected $occurrences; // start times only
  protected $until;
  protected $exdates = Array();
  protected $incrementor;
  protected $interval = 1;
  
  public function getEventCategories() {
    return array();
  }

  protected function standardAttributes()
  {
    return array(
    'summary', 
    'location', 
    'description', 
    'uid', 
    'start', 
    'end', 
    'url', 
    'categories',
    'datetime',
  );
  }
  
  public function apiArray()
  {
    
	 $arr= array (
	 	'id'=>crc32($this->get_uid()) >>1,
	 	'title'=>$this->get_summary(),
	 	'start'=>$this->get_start(),
	 	'end'=>$this->get_end()
	 );

    if ($urlLink = $this->get_url()) {
        $arr['url'] = $urlLink;
    }
    if ($location = $this->get_location()) {
        $arr['location'] = $location;
    }
    if ($description = $this->get_description()) {
        $arr['description'] = $description;
    }
    
	 return $arr;

  }
  
  public function get_uid() {
    return $this->uid;
  }

  public function get_recurid() {
    return $this->recurid;
  }

  public function get_range() {
    return $this->range;
  }

  public function get_series_range() {
    return new TimeRange($this->get_start(), $this->get_end());
  }

  public function get_start() {
    return $this->range->get_start();
  }

  public function get_end() {
    if ($this->recur) {
      return $this->until;
    } else {
      return $this->range->get_end();
    }
  }

  public function get_summary() {
    return $this->summary;
  }

  public function get_url() {
    return $this->url;
  }

  public function get_description() {
    return $this->description;
  }

  public function get_location() {
    return $this->location;
  }
  
  public function get_categories() {
    return $this->categories;
  }

  public function is_recurring() {
    return $this->recur;
  }

  public function get_occurrences() {
    return $this->occurrences;
  }

  protected function compare_ranges(TimeRange $range, $compare_type) {
    if ($this->recur) {
      // check if $range is within this series at all
      $event_range = new TimeRange($this->get_start(), $this->get_end());
      if (!$event_range->$compare_type($range)) {
    return Array();
      } else {
    $duration = $this->range->get_end() - $this->range->get_start();
    $results = Array();
    $starts = $this->occurrences;
    while ($starts[0] < $this->until) {
      foreach ($starts as $start) {
        if ($start > $this->until)
          break 2;
        if (in_array($start, $this->exdates))
          continue;
        $event_range = new TimeRange($start, $start + $duration);
        if ($event_range->$compare_type($range)) {
          $results[] = new ICalEvent($this->summary, $event_range);
        }
      }
      $starts = $this->increment_set($starts);
    }
      }
      return $results;
    } else {
      return $this->range->$compare_type($range);
    }
  }

  public function overlaps(TimeRange $range) {
    return $this->compare_ranges($range, 'overlaps');
  }

  public function contains(TimeRange $range) {
    return $this->compare_ranges($range, 'contains');
  }

  public function contained_by(TimeRange $range) {
    return $this->compare_ranges($range, 'contained_by');
  }
  
  public function get_attribute($attr) {
    if (in_array($attr, $this->standardAttributes())) {
      if ($attr == 'datetime') {
        return $this->range;
      } else {
        $method = "get_$attr";
        return $this->$method();
      }
    } else {
      return isset($this->properties[$attr]) ? $this->properties[$attr] : null;
    }
  }
  
  public function get_all_attributes() {
    return array_merge($this->standardAttributes(), array_keys($this->properties));
  }

  public function set_attribute($attr, $value, $params=NULL) {
    switch ($attr) {
    case 'UID':
      if (strpos($value, '@') !== FALSE) {
        $this->uid .= substr($value, 0, strpos($value, '@'));
      } else {
        $this->uid .= $value;
      }
      break;
    case 'RECURRENCE-ID':
      $this->recurid = $value;
      break;
    case 'DESCRIPTION':
      $this->description = iCalendar::ical_unescape_text($value);
      break;
    case 'LOCATION':
      $this->location = iCalendar::ical_unescape_text($value);
      break;
    case 'SUMMARY':
      $this->summary = iCalendar::ical_unescape_text($value);
      break;
    case 'CATEGORIES':
        $categories = explode(',', $value);
        $this->categories = array();
        foreach ($categories as $category) {
            $this->categories[] = trim(iCalendar::ical_unescape_text($category));
        }
        break;
    case 'URL':
        $this->url = iCalendar::ical_unescape_text($value);
        break;
    case 'DTSTAMP':

        if (array_key_exists('TZID', $params)) {
            $datetime = new DateTime($value, new DateTimeZone($params['TZID']));
        } else {
            $datetime = new DateTime($value);
        }
      $this->updated = $datetime->format('U');
        break;
    case 'DTSTART':
    case 'DTEND':
        if (array_key_exists('TZID', $params)) {
            $datetime = new DateTime($value, new DateTimeZone($params['TZID']));
        } else {
            $datetime = new DateTime($value);
        }

      $timestamp = $datetime->format('U');

      if (!$this->range) {
        if (strpos($value, 'T')!== FALSE) {
            $this->range = new TimeRange($timestamp);
        } else {
            $this->range = new DayRange($timestamp);
        }
      } else {
        if ($attr=='DTEND' && ($timestamp > $this->get_start()) && (($timestamp - $this->get_start()) % 86400 == 0)) {
            // make all day events end at 11:59:59 so they don't overlap next day
            $timestamp -= 1;
         }
         
         switch ($attr)
         {
            case 'DTSTART':
                $this->range->set_start($timestamp);
                break;
            case 'DTEND':
                $this->range->set_end($timestamp);
                break;
         }
      }
      break;
    case 'DURATION':
      // todo:
      // if this tag comes before DTSTART we will break
      $this->range->set_end($this->get_start() + $value);
      break;
    case 'RRULE':
      $this->add_rrule($value);
      break;
    case 'EXDATE':
        if (array_key_exists('TZID', $params)) {
            $datetime = new DateTime($value, new DateTimeZone($params['TZID']));
        } else {
            $datetime = new DateTime($value);
        }

        $this->exdates[] = $datetime->format('U');
      break;
    case 'TZID': // this only gets called by ICalendar::__construct
      $this->tzid = $value;
      break;
    default:
        $this->properties[$attr] = iCalendar::ical_unescape_text($value);
        break;
    }
  }

  protected function increment_set($set) {
    return array_map(
      $this->incrementor,
      $set,
      array_fill(0, count($set), $this->interval)
      );
  }

  protected function add_rrule($rrule_string) {
    $rules = explode(';', $rrule_string);
    $this->recur = TRUE;
    if ($this->occurrences === NULL) {
      $this->occurrences = Array();
    }

    // read attributes from rrule_string
    $limit_type = '';
    $limit = '';

    $incrementors = Array(
      'SECONDLY' => 'increment_second',
      'MINUTELY' => 'increment_minute',
      'HOURLY' => 'increment_hour',
      'DAILY' => 'increment_day',   
      'WEEKLY' => 'increment_week',
      'MONTHLY' => 'increment_month',
      'YEARLY' => 'increment_year',
      );

    $occurs_by_list = Array();

    foreach ($rules as $rule) {
      $namevalue = explode('=', $rule);
      $rulename = $namevalue[0];
      $rulevalue = $namevalue[1];
      switch ($rulename) {
      case 'FREQ': // always present
    $this->incrementor = $incrementors[$rulevalue];
    break;
      case 'INTERVAL':
    $this->interval = $rulevalue;
        break;
      case 'UNTIL':
    $limit_type = 'UNTIL';
    $this->until = ICalendar::ical2unix($rulevalue);
    break;
      case 'COUNT':
    $limit_type = 'COUNT';
{'fraction_non_alphanumeric': 0.15396760721197922, 'fraction_numerical': 0.002852195171641031, 'mean_word_length': 2.5908924652523773, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 229, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4591902', 'n_tokens_mistral': 6365, 'n_tokens_neox': 6187, 'n_words': 1350}