<?php

/**
 * Plugin facebookevents: Displays facebook events.
 * 
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @version    1.2
 * @date       September 2016
 * @author     J. Drost-Tenfelde <info@drost-tenfelde.de>
 *
 * This plugin uses Facebook's Graph API v2.7.
 *
 */

// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
 
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');

// Syntax parameters
define( "FB_EVENTS_APPLICATION_ID", "appid" );
define( "FB_EVENTS_SECRET", "secret" );
define( "FB_EVENTS_FAN_PAGE_ID", "fanpageid" );
define( "FB_EVENTS_SHOW_AS", "showAs" );
define( "FB_EVENTS_FROM_DATE", "from" );
define( "FB_EVENTS_TO_DATE", "to" );
define( "FB_EVENTS_NR_ENTRIES", "numberOfEntries" );
define( "FB_EVENTS_SHOW_END_TIMES", "showEndTimes" );
define( "FB_EVENTS_LIMIT", "limit" );

// Configuration parameters
define( "FB_EVENTS_DATE_FORMAT", "dformat" );
define( "FB_EVENTS_TIME_FORMAT", "tformat" );
define( "FB_EVENTS_TEMPLATE", "template" );

/**
 * This plugin retrieves facebook events and displays them in HTML.
 *
 * Usage: {{facebookevents#appid=1234&secret=12345&fanpageid=12345&showAs=default}}
 * 
 */
class syntax_plugin_facebookevents extends DokuWiki_Syntax_Plugin
{
    function getInfo() {
      return array(
        'author' => 'J. Drost-Tenfelde',
        'email'  => 'info@drost-tenfelde.de',
        'date'   => '20162-09-29',
        'name'   => 'facebookevents',
        'desc'   => 'Displays facebook events as HTML',
        'url'    => 'https://www.dokuwiki.org/plugin:facebookevents',
      );
    }
 
    // implement necessary Dokuwiki_Syntax_Plugin methods
    function getType() {
        return 'substition';
    }
    
    function getSort() {
        return 42;
    }
    
    function connectTo($mode) {
        $this->Lexer->addSpecialPattern('\{\{facebookevents.*?\}\}',$mode,'plugin_facebookevents');
    }
    
	function getData($url) {
		$ch = curl_init();
		$timeout = 5;
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		$data = curl_exec($ch);
		curl_close($ch);
		return $data;
	}
	
	/**
	 * parse parameters from the {{facebookevents#...}} tag.
	 * @return an array that will be passed to the renderer function
	 */
	function handle($match, $state, $pos, &$handler) {
        $match = substr($match, 17, -2);
		parse_str($match, $params);
		
		// Make sure the necessary data is set
		if ( !$params[FB_EVENTS_APPLICATION_ID] ) {
		  $this->error = $this->getLang('error_appid_not_set');
        }
        if ( !$params[FB_EVENTS_SECRET] ) {
		  $this->error = $this->getLang('error_secret_not_set');
        }
        if ( !$params[FB_EVENTS_FAN_PAGE_ID] ) {
		  $this->error = $this->getLang('error_fanpageid_not_set');
        }
        if ( !$params[FB_EVENTS_SHOW_AS] ) {
            $params[FB_EVENTS_SHOW_AS] = 'default';
        }
        if ( !$params[FB_EVENTS_LIMIT] ) {
            $params[FB_EVENTS_LIMIT] = 0;        
        }
        
        // Get the appropriate display template
        $template = $this->getConf( $params[FB_EVENTS_SHOW_AS] );
        if ( !isset($template ) || $template == '' ) {
			$template = $this->getConf('default');
		}
        $params[FB_EVENTS_TEMPLATE] = $template;   
		
		// From
		if ($params[FB_EVENTS_FROM_DATE] == 'today') {
			$from = time();
		} else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params[FB_EVENTS_FROM_DATE], $fromDate)) {
			// must be MM/dd/yyyy
			$from = mktime(0, 0, 0, $fromDate[2], $fromDate[1], $fromDate[3]);
		} else if (preg_match('/\d+/', $params[FB_EVENTS_FROM_DATE])) {
			$from = $params[FB_EVENTS_FROM_DATE]; 
		}
		$params[FB_EVENTS_FROM_DATE] = $from;
		
        // Get the to parameter
		if ($params[FB_EVENTS_TO_DATE] == 'today') {
			$to = mktime(24, 0, 0, date("m") , date("d"), date("Y"));

		} else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params[FB_EVENTS_TO_DATE], $toDate)) {
			// must be MM/dd/yyyy
			$to = mktime(0, 0, 0, $toDate[2], $toDate[1], $toDate[3]);
		} else if (preg_match('/\d+/', $params[FB_EVENTS_TO_DATE])) {
			$to = $params[FB_EVENTS_TO_DATE]; 
		}
		$params[FB_EVENTS_TO_DATE] = $to;
		
		// Sorting
		if ( !$params[FB_EVENTS_SORT ] ) {
            $params[FB_EVENTS_SORT ] = 'ASC';
        }
        else {
            if ( $params[FB_EVENTS_SORT] != 'DESC') {
                $params[FB_EVENTS_SORT ] = 'ASC';
            }
        }
      	
		return $params;
	}

	/**
	 * Retrieves the facebook events and parses them to HTML.
	 */
	function render($mode, &$renderer, $data) {
        $info = $this->getInfo();
	
        $content = '';
       
		if ($mode == 'xhtml') {
            // Catch errors
            if ($this->error) {
                $renderer->doc .= 'Error in Plugin '.$info['name'].': '.$this->error;
                return;
            }
			
			// Get the date format
            $date_format = $this->getConf(FB_EVENTS_DATE_FORMAT);
            $time_format = $this->getConf(FB_EVENTS_TIME_FORMAT);
			
			// Get the facebook information
			$fb_app_id = $data[FB_EVENTS_APPLICATION_ID];
			$fb_secret = $data[FB_EVENTS_SECRET];
			$fb_page_id = $data[FB_EVENTS_FAN_PAGE_ID];
			
			// Get the access token using app-id and secret
			$token_url ="https://graph.facebook.com/oauth/access_token?client_id={$fb_app_id}&client_secret={$fb_secret}&grant_type=client_credentials";
			$token_data = $this->getData( $token_url );
			
			$elements = split("=", $token_data );
			if ( count($elements) < 2) {
				$renderer->doc .= 'Access token could not be retrieved for Plugin '.$info['name'].': '.$this->error;
				return;
			}
			$fb_access_token = $elements[1];
			
			// Get the events
			$since_date = $data[FB_EVENTS_FROM_DATE];
			$until_date = $data[FB_EVENTS_TO_DATE];
			
			$fb_fields="id,name,description,place,timezone,start_time,end_time,cover";
			
			$json_link = "https://graph.facebook.com/v2.7/{$fb_page_id}/events/attending/?fields={$fb_fields}&access_token={$fb_access_token}&since={$since_date}&until={$until_date}";
			$json = $this->getData( $json_link);			
			
			//$objects = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
			$objects = json_decode($json, true);
			
			// count the number of events
			$event_count = count($objects['data']);
			$displayed_entries = 0;
			// Loop through the events
			for ($index = $event_count - 1; $index >= 0; $index--){			
				$event = $objects['data'][$index];
				
				date_default_timezone_set($event['timezone']);
				
				$start_date = date( $date_format, strtotime($event['start_time']));			
				$start_time = date( $time_format, strtotime($event['start_time']));
				
				if ( !isset($event['end_time'])) {
					$event['end_time'] = $event['start_time'];
				}			
				$end_date = date( $date_format, strtotime($event['end_time']));
				$end_time = date( $time_format, strtotime($event['end_time']));
				
				$eid = $event['id'];
				$name = $event['name'];
				
				$description = isset($event['description']) ? $event['description'] : "";
				// Limit?
				if ( isset( $data[FB_EVENTS_LIMIT]) && ($data[FB_EVENTS_LIMIT] > 0 ) ) {  
					if ( strlen( $description ) > $data[FB_EVENTS_LIMIT] ) {    
						$description = substr( $description, 0, $data[FB_EVENTS_LIMIT] );
						// Find the first occurance of a space
						$index = strrpos ( $description, ' ' );
						$description = substr( $description, 0, $index ).'...';
					}
				}
				$description = str_replace("\r\n", '<html><br /></html>', $description );
				$description = str_replace("\n", '<html><br /></html>', $description );

				
				$pic = isset($event['cover']['source']) ? $event['cover']['source'] : "https://graph.facebook.com/v2.7/{$fb_page_id}/picture";
				// Add a fix for urls with get parameters
				if ( strpos($pic, '?') > 0 )
				{
					$pic .= '&.png';
				}
				
				// place
				$place_name = isset($event['place']['name']) ? $event['place']['name'] : "";
				$street = isset($event['place']['location']['street']) ? $event['place']['location']['street'] : "";
				$city = isset($event['place']['location']['city']) ? $event['place']['location']['city'] : "";
				$country = isset($event['place']['location']['country']) ? $event['place']['location']['country'] : "";
				$zip = isset($event['place']['location']['zip']) ? $event['place']['location']['zip'] : "";
 
				$location="";
 
				if ( $place_name && $street & $city && $country && $zip){
					$location = "{$place_name}, {$street}, {$zip} {$city}, {$country}";
				}
				else{
					$location = "Location not set or event data is too old.";
				}
				
				// Build the entry
				$entry = $data['template'];
				
				// Replace the values
				$entry = str_replace('{title}', $name, $entry );
				$entry = str_replace('{description}', $description, $entry );
				$entry = str_replace('{location}', $location, $entry );
				$entry = str_replace('{place}', $place_name, $entry );
				$entry = str_replace('{city}', $city, $entry );
				$entry = str_replace('{country}', $country, $entry );
				$entry = str_replace('{zip}', $zip, $entry );
				$entry = str_replace('{image}', $pic, $entry);		
				$entry = str_replace('{image_large}', $pic, $entry);
				$entry = str_replace('{image_small}', $pic, $entry);
				$entry = str_replace('{image_square}', $pic, $entry);
				
				// DateTime
				if ( (!isset( $data[FB_EVENTS_SHOW_END_TIMES])) || $data[FB_EVENTS_SHOW_END_TIMES] == '1' ) {

					// Are they the same date?
					$compare_start_date = date( "Ymd", strtotime($event['start_time']));
					$compare_end_date = date( "Ymd", strtotime($event['end_time']));
					
					if ( $compare_start_date == $compare_end_date ) {
						$datetime_string = $start_date;
						//if ( isset($event['is_date_only']) && (!$event['is_date_only'])) {
							$datetime_string = $datetime_string.' '.$start_time.' - '.$end_time;
							
						//}
						$entry = str_replace('{date}', $date_string, $entry );
						$entry = str_replace('{datetime}', $datetime_string, $entry );
											}
					else {
						$date_string = $start_date.' - '.$end_date;
						$datetime_string = $date_string;
						//if ( isset($event['is_date_only']) && (!$event['is_date_only'])) {
							$datetime_string =  $start_date.' '.$start_time.' - '.$end_date.' '.$end_time;
						//}
						$entry = str_replace('{date}', $date_string, $entry );
						$entry = str_replace('{datetime}', $datetime_string, $entry );                    
					}
				}
				else {                                                
					$entry = str_replace('{date}', $start_date, $entry );
					$entry = str_replace('{datetime}', $start_date.' '.$start_time);
				}

				
				// [[ url | read more ]
                $event_url = "http://www.facebook.com/events/".$eid;
                $entry = str_replace('{url}', $event_url, $entry );
                $entry = str_replace('{more}', '[['.$event_url.'|'.$this->getLang('read_more').']]', $entry );
				
				// Add the entry to the content                                
				$content .= $entry;

				// Only display a maximum number of entries (if set)
				$displayed_entries++;
				if ( isset( $data[FB_EVENTS_NR_ENTRIES] ) && $displayed_entries >= $data[FB_EVENTS_NR_ENTRIES] ) {
					break;
				}
			}
		
			//$renderer->doc .= $ret;
			$html = p_render($mode, p_get_instructions( $content ), $info );
			$renderer->doc .= $html;
			
			// Set the timezone back to the original
			//date_default_timezone_set($origin_timezone);
			
			return true;
		}
		return false;
	}
}

?>