<?php
/* Copyright (C) 2008-2011 Laurent Destailleur  <eldy@users.sourceforge.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 *  \file       htdocs/core/lib/xcal.lib.php
 *  \brief      Function to manage calendar files (vcal/ical/...)
 */

/**
 *	Build a file from an array of events
 *  All input params and data must be encoded in $conf->charset_output
 *
 *	@param		string	$format				'vcal' or 'ical'
 *	@param		string	$title				Title of export
 *	@param		string	$desc				Description of export
 *	@param		array	$events_array		Array of events ('eid','startdate','duration','enddate','title','summary','category','email','url','desc','author')
 *	@param		string	$outputfile			Output file
 *	@return		int							<0 if ko, Nb of events in file if ok
 */
function build_calfile($format,$title,$desc,$events_array,$outputfile)
{
	global $conf,$langs;

	dol_syslog("xcal.lib.php::build_calfile Build cal file ".$outputfile." to format ".$format);

	if (empty($outputfile)) return -1;

    // Note: A cal file is an UTF8 encoded file
	$calfileh=fopen($outputfile,'w');
	if ($calfileh)
	{
	    include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
		$now=dol_now();

		$encoding='';
		if ($format == 'vcal') $encoding='ENCODING=QUOTED-PRINTABLE:';

		// Print header
		fwrite($calfileh,"BEGIN:VCALENDAR\n");
		fwrite($calfileh,"VERSION:2.0\n");
		fwrite($calfileh,"METHOD:PUBLISH\n");
		//fwrite($calfileh,"PRODID:-//DOLIBARR ".DOL_VERSION."//EN\n");
		fwrite($calfileh,"PRODID:-//DOLIBARR ".DOL_VERSION."\n");
		fwrite($calfileh,"CALSCALE:GREGORIAN\n");
		fwrite($calfileh,"X-WR-CALNAME:".$encoding.format_cal($format,$title)."\n");
        fwrite($calfileh,"X-WR-CALDESC:".$encoding.format_cal($format,$desc)."\n");
        //fwrite($calfileh,"X-WR-TIMEZONE:Europe/Paris\n");
        if (! empty($conf->global->MAIN_AGENDA_EXPORT_CACHE)
        && $conf->global->MAIN_AGENDA_EXPORT_CACHE > 60){
	        $hh=convertSecondToTime($conf->global->MAIN_AGENDA_EXPORT_CACHE,'hour');
	        $mm=convertSecondToTime($conf->global->MAIN_AGENDA_EXPORT_CACHE,'min');
	        $ss=convertSecondToTime($conf->global->MAIN_AGENDA_EXPORT_CACHE,'sec'); 
	        fwrite($calfileh,"X-PUBLISHED-TTL: P".$hh."H".$mm."M".$ss."S\n");
        }

		foreach ($events_array as $date => $event)
		{
			$eventqualified=true;
			if ($eventqualified)
			{
				// See http://fr.wikipedia.org/wiki/ICalendar for format
				// See http://www.ietf.org/rfc/rfc2445.txt for RFC
				$uid 		  = $event['uid'];
				$type         = $event['type'];
                $startdate    = $event['startdate'];
				$duration	  = $event['duration'];
				$enddate	  = $event['enddate'];
				$summary  	  = $event['summary'];
				$category	  = $event['category'];
                $priority     = $event['priority'];
                $fulldayevent = $event['fulldayevent'];
				$location     = $event['location'];
				$email 		  = $event['email'];
				$url		  = $event['url'];
				$transparency = $event['transparency'];		// OPAQUE (busy) or TRANSPARENT (not busy)
				$description=preg_replace('/<br[\s\/]?>/i',"\n",$event['desc']);
 				$description=dol_string_nohtmltag($description,0);	// Remove html tags
                $created      = $event['created'];
 				$modified     = $event['modified'];

				// Uncomment for tests
				//$summary="Resume";
				//$description="Description";
				//$description="MemberValidatedInDolibarr gd gdf gd gdff\nNom: tgdf g dfgdf gfd r ter\nType: gdfgfdf dfg fd gfd gd gdf gdf gfd gdfg dfg ddf\nAuteur: AD01fg dgdgdfg df gdf gd";

				// Format
				$summary=format_cal($format,$summary);
				$description=format_cal($format,$description);
				$category=format_cal($format,$category);
				$location=format_cal($format,$location);

				// Output the vCard/iCal VEVENT object
				/*
				Example from Google ical export for a 1 hour event:
                BEGIN:VEVENT
                DTSTART:20101103T120000Z
                DTEND:20101103T130000Z
                DTSTAMP:20101121T144902Z
                UID:4eilllcsq8r1p87ncg7vc8dbpk@google.com
                CREATED:20101121T144657Z
                DESCRIPTION:
                LAST-MODIFIED:20101121T144707Z
                LOCATION:
                SEQUENCE:0
                STATUS:CONFIRMED
                SUMMARY:Tâche 1 heure
                TRANSP:OPAQUE
                END:VEVENT

                Example from Google ical export for a 1 day event:
                BEGIN:VEVENT
                DTSTART;VALUE=DATE:20101102
                DTEND;VALUE=DATE:20101103
                DTSTAMP:20101121T144902Z
                UID:d09t43kcf1qgapu9efsmmo1m6k@google.com
                CREATED:20101121T144607Z
                DESCRIPTION:
                LAST-MODIFIED:20101121T144607Z
                LOCATION:
                SEQUENCE:0
                STATUS:CONFIRMED
                SUMMARY:Tâche 1 jour
                TRANSP:TRANSPARENT
                END:VEVENT
                */
				if ($type == 'event')
				{
					fwrite($calfileh,"BEGIN:VEVENT\n");
					fwrite($calfileh,"UID:".$uid."\n");
					if (! empty($email))
					{
						fwrite($calfileh,"ORGANIZER:MAILTO:".$email."\n");
						fwrite($calfileh,"CONTACT:MAILTO:".$email."\n");
					}
					if (! empty($url))
					{
						fwrite($calfileh,"URL:".$url."\n");
					};

                    if ($created)  fwrite($calfileh,"CREATED:".dol_print_date($created,'dayhourxcard',true)."\n");
                    if ($modified) fwrite($calfileh,"LAST-MODIFIED:".dol_print_date($modified,'dayhourxcard',true)."\n");
                    fwrite($calfileh,"SUMMARY:".$encoding.$summary."\n");
					fwrite($calfileh,"DESCRIPTION:".$encoding.$description."\n");

					/* Other keys:
					// Status values for a "VEVENT"
					statvalue  = "TENTATIVE"           ;Indicates event is
				                                        ;tentative.
				                / "CONFIRMED"           ;Indicates event is
				                                        ;definite.
				                / "CANCELLED"           ;Indicates event was
                    // Status values for "VTODO".
                    statvalue  =/ "NEEDS-ACTION"       ;Indicates to-do needs action.
				                / "COMPLETED"           ;Indicates to-do completed.
				                / "IN-PROCESS"          ;Indicates to-do in process of
				                / "CANCELLED"           ;Indicates to-do was cancelled.
                    // Status values for "VJOURNAL".
				    statvalue  =/ "DRAFT"              ;Indicates journal is draft.
				                / "FINAL"               ;Indicates journal is final.
				                / "CANCELLED"           ;Indicates journal is removed.
					*/
					//fwrite($calfileh,"CLASS:PUBLIC\n");				// PUBLIC, PRIVATE, CONFIDENTIAL
                    //fwrite($calfileh,"X-MICROSOFT-CDO-BUSYSTATUS:1\n");
                    //ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Laurent Destailleur;X-NUM-GUESTS=0:mailto:eldy10@gmail.com

                    if (! empty($location)) fwrite($calfileh,"LOCATION:".$encoding.$location."\n");
					if ($fulldayevent) fwrite($calfileh,"X-FUNAMBOL-ALLDAY:1\n");
                    if ($fulldayevent) fwrite($calfileh,"X-MICROSOFT-CDO-ALLDAYEVENT:1\n");

					// Date must be GMT dates
					// Current date
					fwrite($calfileh,"DTSTAMP:".dol_print_date($now,'dayhourxcard',true)."\n");
					// Start date
                    $prefix='';
                    $startdatef = dol_print_date($startdate,'dayhourxcard',true);
                    if ($fulldayevent)
					{
                        $prefix=';VALUE=DATE';
					    $startdatef = dol_print_date($startdate,'dayxcard',false);     // Local time
					}
					fwrite($calfileh,"DTSTART".$prefix.":".$startdatef."\n");
                    // End date
					if ($fulldayevent)
					{
    					if (empty($enddate)) $enddate=dol_time_plus_duree($startdate,1,'d');
					}
					else
					{
                        if (empty($enddate)) $enddate=$startdate+$duration;
					}
                    $prefix='';
					$enddatef = dol_print_date($enddate,'dayhourxcard',true);
					if ($fulldayevent)
					{
                        $prefix=';VALUE=DATE';
					    $enddatef = dol_print_date($enddate+1,'dayxcard',false);
					    //$enddatef .= dol_print_date($enddate+1,'dayhourxcard',false);   // Local time
					}
                    fwrite($calfileh,"DTEND".$prefix.":".$enddatef."\n");
					fwrite($calfileh,'STATUS:CONFIRMED'."\n");
					if (! empty($transparency)) fwrite($calfileh,"TRANSP:".$transparency."\n");
					if (! empty($category)) fwrite($calfileh,"CATEGORIES:".$encoding.$category."\n");
					fwrite($calfileh,"END:VEVENT\n");
				}

				// Output the vCard/iCal VTODO object
				// ...
				//PERCENT-COMPLETE:39

				// Output the vCard/iCal VJOURNAL object
				if ($type == 'journal')
				{
					fwrite($calfileh,"BEGIN:VJOURNAL\n");
					fwrite($calfileh,"UID:".$uid."\n");
					if (! empty($email))
					{
						fwrite($calfileh,"ORGANIZER:MAILTO:".$email."\n");
						fwrite($calfileh,"CONTACT:MAILTO:".$email."\n");
					}
					if (! empty($url))
					{
						fwrite($calfileh,"URL:".$url."\n");
					};

                    if ($created)  fwrite($calfileh,"CREATED:".dol_print_date($created,'dayhourxcard',true)."\n");
                    if ($modified) fwrite($calfileh,"LAST-MODIFIED:".dol_print_date($modified,'dayhourxcard',true)."\n");
					fwrite($calfileh,"SUMMARY:".$encoding.$summary."\n");
					fwrite($calfileh,"DESCRIPTION:".$encoding.$description."\n");
					fwrite($calfileh,'STATUS:CONFIRMED'."\n");
					fwrite($calfileh,"CATEGORIES:".$category."\n");
					fwrite($calfileh,"LOCATION:".$location."\n");
					fwrite($calfileh,"TRANSP:OPAQUE\n");
					fwrite($calfileh,"CLASS:CONFIDENTIAL\n");
					fwrite($calfileh,"DTSTAMP:".dol_print_date($startdatef,'dayhourxcard',true)."\n");

					fwrite($calfileh,"END:VJOURNAL\n");
				}


				// Put other info in comment
				/*
				$comment=array();
				$comment ['eid']			= $eid;
				$comment ['url']			= $linktoevent;
				$comment ['date']			= dol_mktime($evttime,"Ymd");
				$comment ['duration']		= $duration;
				$comment ['startdate']		= $startdate;
				$comment ['enddate']		= $enddate;
				fwrite($calfileh,"COMMENT:" . serialize ($comment) . "\n");
				*/

			}
		}

		// Footer
		fwrite($calfileh,"END:VCALENDAR");

		fclose($calfileh);
		if (! empty($conf->global->MAIN_UMASK))
			@chmod($outputfile, octdec($conf->global->MAIN_UMASK));
	}
	else
	{
		dol_syslog("xcal.lib.php::build_calfile Failed to open file ".$outputfile." for writing");
		return -2;
	}
}

/**
 *	Build a file from an array of events.
 *  All input data must be encoded in $conf->charset_output
 *
 *	@param		string	$format				'rss'
 *	@param		string	$title				Title of export
 *	@param		string	$desc				Description of export
 *	@param		array	$events_array		Array of events ('uid','startdate','summary','url','desc','author','category')
 *	@param		string	$outputfile			Output file
 *	@param		string	$filter				Filter
 *	@return		int							<0 if ko, Nb of events in file if ok
 */
function build_rssfile($format,$title,$desc,$events_array,$outputfile,$filter='')
{
	global $user,$conf,$langs;
	global $dolibarr_main_url_root;

	dol_syslog("xcal.lib.php::build_rssfile Build rss file ".$outputfile." to format ".$format);

	if (empty($outputfile)) return -1;

	$fichier=fopen($outputfile,'w');
	if ($fichier)
	{
		$date=date("r");

		// Print header
		$form='<?xml version="1.0" encoding="'.$langs->charset_output.'"?>';
		fwrite($fichier, $form);
		fwrite($fichier, "\n");
		$form='<rss version="2.0">';
		fwrite($fichier, $form);
		fwrite($fichier, "\n");

		$form="<channel>\n<title>".$title."</title>\n";
		fwrite($fichier, $form);

		$form='<description><![CDATA['.$desc.'.]]></description>'."\n".
//		'<language>fr</language>'."\n".
		'<copyright>Dolibarr</copyright>'."\n".
		'<lastBuildDate>'.$date.'</lastBuildDate>'."\n".
		'<generator>Dolibarr</generator>'."\n";

		// Define $urlwithroot
		$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
		$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;			// This is to use external domain name found into config file
		//$urlwithroot=DOL_MAIN_URL_ROOT;						// This is to use same domain name than current
  		$url=$urlwithroot.'/public/agenda/agendaexport.php?format=rss&exportkey='.urlencode($conf->global->MAIN_AGENDA_XCAL_EXPORTKEY);
		$form.='<link><![CDATA['.$url.']]></link>'."\n";

		//print $form;
		fwrite($fichier, $form);


		foreach ($events_array as $date => $event)
		{
			$eventqualified=true;
			if ($filter)
			{
				// TODO Add a filter

				$eventqualified=false;
			}

			if ($eventqualified)
			{
				$uid		  = $event['uid'];
				$startdate	  = $event['startdate'];
				$summary  	  = $event['summary'];
				$url		  = $event['url'];
				$author		  = $event['author'];
				$category	  = $event['category'];
				/* No place inside a RSS
                $priority     = $event['priority'];
                $fulldayevent = $event['fulldayevent'];
                $location     = $event['location'];
                $email        = $event['email'];
                */
				$description=preg_replace('/<br[\s\/]?>/i',"\n",$event['desc']);
 				$description=dol_string_nohtmltag($description,0);	// Remove html tags

				fwrite($fichier, "<item>\n");
				fwrite($fichier, "<title><![CDATA[".$summary."]]></title>\n");
				fwrite($fichier, "<link><![CDATA[".$url."]]></link>\n");
				fwrite($fichier, "<author><![CDATA[".$author."]]></author>\n");
				fwrite($fichier, "<category><![CDATA[".$category."]]></category>\n");
				fwrite($fichier, "<description><![CDATA[");
				if ($description) fwrite($fichier, $description);
				//else fwrite($fichier, 'NoDesc');
				fwrite($fichier, "]]></description>\n");
				fwrite($fichier, "<pubDate>".date("r", $startdate)."</pubDate>\n");
				fwrite($fichier, "<guid isPermaLink=\"true\"><![CDATA[".$uid."]]></guid>\n");
				fwrite($fichier, "<source><![CDATA[Dolibarr]]></source>\n");
				fwrite($fichier, "</item>\n");
			}
		}

		fwrite($fichier, '</channel>');
		fwrite($fichier, "\n");
		fwrite($fichier, '</rss>');

		fclose($fichier);
		if (! empty($conf->global->MAIN_UMASK))
			@chmod($outputfile, octdec($conf->global->MAIN_UMASK));
	}
}


/**
 * 	Encode for cal export
 *
 * 	@param		string	$format		vcal or ical
 * 	@param 		string	$string		string to encode
 * 	@return		string				string encoded
 */
function format_cal($format,$string)
{
	global $conf;

	$newstring=$string;

	if ($format == 'vcal')
	{
		$newstring=quotedPrintEncode($newstring);
	}
	if ($format == 'ical')
	{
		// Replace new lines chars by '\n'
		$newstring=preg_replace('/'."\r\n".'/i',"\n",$newstring);
		$newstring=preg_replace('/'."\n\r".'/i',"\n",$newstring);
		$newstring=preg_replace('/'."\n".'/i','\n',$newstring);
		// Must not exceed 75 char. Cut with "\r\n"+Space
		$newstring=calEncode($newstring);
	}

	return $newstring;
}

/**
 *	Cut string after 75 chars. Add CRLF+Space.
 *	line must be encoded in UTF-8
 *
 *	@param		string	$line	String to convert
 *	@return		string 			String converted
 */
function calEncode($line)
{
	$out = '';

	$newpara = '';

	// If mb_ functions exists, it's better to use them
	if (function_exists('mb_strlen'))
	{
	    $strlength=mb_strlen($line, 'UTF-8');
		for ($j = 0; $j <= ($strlength - 1); $j++)
		{
			$char = mb_substr($line, $j, 1, 'UTF-8');	// Take char at position $j

			if ((mb_strlen($newpara, 'UTF-8') + mb_strlen($char, 'UTF-8')) >= 75)
			{
				$out .= $newpara . "\r\n ";	// CRLF + Space for cal
				$newpara = '';
			}
			$newpara .= $char;
		}
		$out .= $newpara;
	}
	else
	{
	    $strlength=dol_strlen($line);
		for ($j = 0; $j <= ($strlength - 1); $j++)
		{
			$char = substr($line, $j, 1);	// Take char at position $j

			if ((dol_strlen($newpara) + dol_strlen($char)) >= 75 )
			{
				$out .= $newpara . "\r\n ";	// CRLF + Space for cal
				$newpara = '';
			}
			$newpara .= $char;
		}
		$out .= $newpara;
	}

	return trim($out);
}


/**
 *	Encode into vcal format
 *
 *	@param		string	$str		String to convert
 *	@param		int		$forcal		1=For cal
 *	@return		string 				String converted
 */
function quotedPrintEncode($str,$forcal=0)
{
	$lines = preg_split("/\r\n/", $str);
	$out = '';

	foreach ($lines as $line)
	{
		$newpara = '';

		$strlength=strlen($line);	// Do not use dol_strlen here, we need number of bytes
		for ($j = 0; $j <= ($strlength - 1); $j++)
		{
			$char = substr($line, $j, 1);
			$ascii = ord($char);

			if ( $ascii < 32 || $ascii == 61 || $ascii > 126 )
			$char = '=' . strtoupper(sprintf("%02X", $ascii));

			if ((strlen($newpara) + strlen($char)) >= 76 )	// Do not use dol_strlen here, we need number of bytes
			{
				$out .= $newpara . '=' . "\r\n";	// CRLF
				if ($forcal) $out .= " ";		// + Space for cal
				$newpara = '';
			}
			$newpara .= $char;
		}
		$out .= $newpara;
	}
	return trim($out);
}

/**
 *	Decode vcal format
 *
 *	@param		string	$str		String to convert
 *	@return		string 				String converted
 */
function quotedPrintDecode($str)
{
	$out = preg_replace('/=\r?\n/', '', $str);
	$out = quoted_printable_decode($out);	// Available with PHP 4+
	return trim($out);
}

