<?php

/**
 * iCalEasyReader is an easy to understood class, loads a "ics" format string and returns an array with the traditional iCal fields
 *
 * @category	Parser
 * @author		Matias Perrone <matias.perrone at gmail dot com>
 * @author		Timo Henke <phpstuff@thenke.de> (Some ideas taken partially from iCalParse on http://www.phpclasses.org/)
 * @license		http://www.opensource.org/licenses/mit-license.php MIT License
 * @version		1.4.1
 * @param	string	$data	ics file string content
 * @param	array|false	$data $makeItEasy	the idea is to convert this "keys" into the "values", converting the DATE and DATE-TIME values to the respective DateTime type of PHP, also all the keys are lowercased
 * @return	array|false
 */
class iCalEasyReader
{
	private $ical = null;
	private $_lastitem = null;

	public function &load($data)
	{
		$this->ical = false;
		$regex_opt = 'mib';

		// Lines in the string
		$lines = mb_split( '[\r\n]+', $data );

		// Delete empty ones
		$last = count( $lines );
		for($i = 0; $i < $last; $i ++)
		{
			if (trim( $lines[$i] ) == '')
				unset( $lines[$i] );
		}
		$lines = array_values( $lines );

		// First and last items
		$first = 0;
		$last = count( $lines ) - 1;

		if (! ( mb_ereg_match( '^BEGIN:VCALENDAR', $lines[$first], $regex_opt ) and mb_ereg_match( '^END:VCALENDAR', $lines[$last], $regex_opt ) ))
		{
			$first = null;
			$last = null;
			foreach ( $lines as $i => &$line )
			{
				if (mb_ereg_match( '^BEGIN:VCALENDAR', $line, $regex_opt ))
					$first = $i;

				if (mb_ereg_match( '^END:VCALENDAR', $line, $regex_opt ))
				{
					$last = $i;
					break;
				}
			}
		}

		// Procesing
		if (! is_null( $first ) and ! is_null( $last ))
		{
			$lines = array_slice( $lines, $first + 1, ( $last - $first - 1 ), true );

			$group = null;
			$parentgroup = null;
			$this->ical = array();
			$addTo = array();
			$addToElement = null;
			foreach ( $lines as $line )
			{
				$clave = null;
				$pattern = '^(BEGIN|END)\:(.+)$'; // (VALARM|VTODO|VJOURNAL|VEVENT|VFREEBUSY|VCALENDAR|DAYLIGHT|VTIMEZONE|STANDARD)
				mb_ereg_search_init( $line );
				$regs = mb_ereg_search_regs( $pattern, $regex_opt );
				if ($regs)
				{
					// $regs
					// 0 => BEGIN:VEVENT
					// 1 => BEGIN
					// 2 => VEVENT
					switch ( $regs[1] )
					{
						case 'BEGIN' :
							if (! is_null( $group ))
								$parentgroup = $group;

							$group = trim( $regs[2] );

							// Adding new values to groups
							if (is_null( $parentgroup ))
							{
								if (! array_key_exists( $group, $this->ical ))
									$this->ical[$group] = array(null);
								else
									$this->ical[$group][] = null;
							}
							else
							{
								if (! array_key_exists( $parentgroup, $this->ical ))
									$this->ical[$parentgroup] = array($group => array(null))/*  [$group => [null]] */;

								if (! array_key_exists( $group, $this->ical[$parentgroup] ))
								    $this->ical[$parentgroup][$group] = array(null);
								else
									$this->ical[$parentgroup][$group][] = null;
							}

							break;
						case 'END' :
							if (is_null( $group ))
								$parentgroup = null;

							$group = null;
							break;
					}
					continue;
				}

				if (! in_array( $line[0], array(" ", "\t") ))
					$this->addItem( $line, $group, $parentgroup );
				else
					$this->concatItem( $line );
			}
		}

		return $this->ical;
	}

	public function addType(&$value, $item)
	{
		$type = explode( '=', $item );

		if (count( $type ) > 1 and $type[0] == 'VALUE')
			$value['type'] = $type[1];
		else
			$value[$type[0]] = $type[1];

		return $value;
	}

	public function addItem($line, $group, $parentgroup)
	{
		$line = $this->transformLine( $line );
		$item = explode( ':', $line, 2 );
		// If $group is null is an independent value
		if (is_null( $group ))
		{
			$this->ical[$item[0]] = ( count( $item ) > 1 ? $item[1] : null );
			$this->_lastitem = &$this->ical[$item[0]];
		}
		// If $group is set then is an item of a group
		else
		{
			$subitem = explode( ';', $item[0], 2 );
			if (count( $subitem ) == 1)
				$value = ( count( $item ) > 1 ? $item[1] : null );
			else
			{
			    $value = array('value' => $item[1]);
				$this->addType( $value, $subitem[1] );
			}

			// Multi value
			if (is_string( $value ))
			{
				$z = explode( ';', $value );
				if (count( $z ) > 1)
				{
					$value = array();
					foreach ( $z as &$v )
					{
						$t = explode( '=', $v );
						$value[$t[0]] = $t[count( $t ) - 1];
					}
				}
				unset( $z );
			}

			if (is_null( $parentgroup ))
			{
				$this->ical[$group][count( $this->ical[$group] ) - 1][$subitem[0]] = $value;
				$this->_lastitem = &$this->ical[$group][count( $this->ical[$group] ) - 1][$subitem[0]];
			}
			else
			{
				$this->ical[$parentgroup][$group][count( $this->ical[$parentgroup][$group] ) - 1][$subitem[0]] = $value;
				$this->_lastitem = &$this->ical[$parentgroup][$group][count( $this->ical[$parentgroup][$group] ) - 1][$subitem[0]];
			}
		}
	}

	public function concatItem($line)
	{
		$line = mb_substr( $line, 1 );
		if (is_array( $this->_lastitem ))
		{
			$line = $this->transformLine( $this->_lastitem['value'] . $line );
			$this->_lastitem['value'] = $line;
		}
		else
		{
			$line = $this->transformLine( $this->_lastitem . $line );
			$this->_lastitem = $line;
		}
	}

	public function transformLine($line)
	{
		$patterns = array('\\\\[n]', '\\\\[t]', '\\\\,', '\\\\;');
		$replacements = array("\n", "\t", ",", ";");
		
		

		return $this->mb_eregi_replace_all( $patterns, $replacements, $line );
	}

	public function mb_eregi_replace_all($pattern, $replacement, $string)
	{
		if (is_array( $pattern ) and is_array( $replacement ))
		{
			foreach ( $pattern as $i => $patron )
			{
				if (array_key_exists( $i, $replacement ))
					$reemplazo = $replacement[$i];
				else
					$reemplazo = '';

				$string = mb_eregi_replace( $patron, $reemplazo, $string );
			}
		}
		elseif (is_string( $pattern ) and is_string( $replacement ))
			$string = mb_eregi_replace( $pattern, $replacement, $string );

		return $string;
	}
}
