<?php /*

 ocPortal
 Copyright (c) ocProducts, 2004-2012

 See text/EN/licence.txt for full licencing information.


 NOTE TO PROGRAMMERS:
   Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
   **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****

*/

/**
 * @license		http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
 * @copyright	ocProducts Ltd
 * @package		calendar
 */

require_code('aed_module');

/**
 * Module page class.
 */
class Module_cms_calendar extends standard_aed_module
{
	var $lang_type='CALENDAR_EVENT';
	var $select_name='TITLE';
	var $orderer='id';
	var $array_key='id';
	var $title_is_multi_lang=true;
	var $non_integer_id=false;
	var $table='calendar_events';
	var $code_require='calendar';
	var $permissions_require='low';
	var $user_facing=true;
	var $seo_type='event';
	var $award_type='event';
	var $possibly_some_kind_of_upload=true;
	var $menu_label='CALENDAR';
	var $permissions_cat_require='calendar';
	var $permissions_cat_name='type';
	var $posting_field_required=false;

	// These are state-set, for usage by the specialised donext manager
	var $donext_type=NULL;
	var $donext_date=NULL;

	/**
	 * Standard modular entry-point finder function.
	 *
	 * @return ?array	A map of entry points (type-code=>language-code) (NULL: disabled).
	 */
	function get_entry_points()
	{
		return array_merge(array('misc'=>'MANAGE_CALENDARS'),parent::get_entry_points());
	}

	/**
	 * Standard modular privilege-overide finder function.
	 *
	 * @return array	A map of privileges that are overridable; sp to 0 or 1. 0 means "not category overridable". 1 means "category overridable".
	 */
	function get_sp_overrides()
	{
		require_lang('calendar');
		return array(
			'submit_cat_highrange_content'=>array(0,'ADD_EVENT_TYPE'),
			'edit_cat_highrange_content'=>array(0,'EDIT_EVENT_TYPE'),
			'delete_cat_highrange_content'=>array(0,'DELETE_EVENT_TYPE'),
			'submit_lowrange_content'=>array(1,'ADD_CALENDAR_EVENT'),

			'bypass_validation_lowrange_content'=>array(1,'BYPASS_VALIDATION_CALENDAR_EVENT__NON_PUBLIC'),
			'edit_own_lowrange_content'=>array(1,'EDIT_OWN_CALENDAR_EVENT__NON_PUBLIC'),
			'edit_lowrange_content'=>array(1,'EDIT_CALENDAR_EVENT__NON_PUBLIC'),
			'delete_own_lowrange_content'=>array(1,'DELETE_OWN_CALENDAR_EVENT__NON_PUBLIC'),
			'delete_lowrange_content'=>array(1,'DELETE_CALENDAR_EVENT__NON_PUBLIC'),

			'bypass_validation_midrange_content'=>array(1,'BYPASS_VALIDATION_CALENDAR_EVENT'),
			'edit_own_midrange_content'=>array(1,'EDIT_OWN_CALENDAR_EVENT'),
			'edit_midrange_content'=>array(1,'EDIT_CALENDAR_EVENT'),
			'delete_own_midrange_content'=>array(1,'DELETE_OWN_CALENDAR_EVENT'),
			'delete_midrange_content'=>array(1,'DELETE_CALENDAR_EVENT'),

			'mass_import'=>0,
		);
	}

	/**
	 * Standard aed_module run_start.
	 *
	 * @param  ID_TEXT		The type of module execution
	 * @return tempcode		The output of the run
	 */
	function run_start($type)
	{
		$this->cat_aed_module=new Module_cms_calendar_cat();

		$this->javascript="
			var form=document.getElementById('recurrence_pattern').form;

			var start_day=document.getElementById('start_day');
			var start_month=document.getElementById('start_month');
			var start_year=document.getElementById('start_year');
			var start_hour=document.getElementById('start_hour');
			var start_minute=document.getElementById('start_minute');
			var do_timezone_conv=document.getElementById('do_timezone_conv');
			var all_day_event=document.getElementById('all_day_event');

			var crf=function(event) {
				var s=(form.elements['recurrence'][0].checked);
				if (form.elements['recurrence_pattern']) form.elements['recurrence_pattern'].disabled=s;
				if (form.elements['recurrences']) form.elements['recurrences'].disabled=s;
				if (form.elements['seg_recurrences']) form.elements['seg_recurrences'].disabled=s;

				if ((typeof event!='undefined') && (start_day.selectedIndex!=0) && (start_month.selectedIndex!=0) && (start_year.selectedIndex!=0)) // Something changed
				{
					var new_data=load_snippet('calendar_recurrence_suggest&monthly_spec_type='+window.encodeURIComponent(radio_value(form.elements['monthly_spec_type']))+'&day='+window.encodeURIComponent(start_day.options[start_day.selectedIndex].value)+'&month='+window.encodeURIComponent(start_month.options[start_month.selectedIndex].value)+'&year='+window.encodeURIComponent(start_year.options[start_year.selectedIndex].value)+'&hour='+window.encodeURIComponent(start_hour.options[start_hour.selectedIndex].value)+'&minute='+window.encodeURIComponent(start_minute.options[start_minute.selectedIndex].value)+'&do_timezone_conv='+(do_timezone_conv.checked?'1':'0')+'&all_day_event='+(all_day_event.checked?'1':'0'));
					var tr=form.elements['monthly_spec_type'][0];
					while (tr.nodeName.toLowerCase()!='tr')
					{
						tr=tr.parentNode;
					}
					set_inner_html(tr,new_data.replace(/<tr [^>]*>/,'').replace(/<\/tr>/,''));
				}
				var monthly_recurrence=form.elements['recurrence'][3].checked;
				for (var i=0;i<form.elements['monthly_spec_type'].length;i++)
				{
					form.elements['monthly_spec_type'][i].disabled=!monthly_recurrence;
				}
			};
			crf();
			for (var i=0;i<form.elements['recurrence'].length;i++) form.elements['recurrence'][i].onclick=crf;
			start_day.onchange=crf;
			start_month.onchange=crf;
			start_year.onchange=crf;
			start_hour.onchange=crf;
			start_minute.onchange=crf;

			var crf2=function() {
				var s=document.getElementById('all_day_event').checked;
				document.getElementById('start_hour').disabled=s;
				document.getElementById('start_minute').disabled=s;
				document.getElementById('end_hour').disabled=s;
				document.getElementById('end_minute').disabled=s;
			}
			crf2();
			document.getElementById('all_day_event').onclick=crf2;

			form.old_submit=form.onsubmit;
			form.onsubmit=function()
				{
					if (form.elements['end_day'].selectedIndex!=0)
					{
						var start=new Date(form.elements['start_year'].value,form.elements['start_month'].value,form.elements['start_day'].value,form.elements['start_hour'].value,form.elements['start_minute'].value);
						var end=new Date(form.elements['end_year'].value,form.elements['end_month'].value,form.elements['end_day'].value,form.elements['end_hour'].value,form.elements['end_minute'].value);
						if (start>end)
						{
							window.fauxmodal_alert('".php_addslashes(do_lang('EVENT_CANNOT_AROUND'))."');
							return false;
						}
					}
					if (typeof form.old_submit!='undefined' && form.old_submit) return form.old_submit();
					return true;
				};
		";

		$GLOBALS['HELPER_PANEL_PIC']='pagepics/calendar';
		$GLOBALS['HELPER_PANEL_TUTORIAL']='tut_calendar';

		$this->posting_form_title=do_lang_tempcode('EVENT_TEXT');

		require_lang('calendar');
		require_lang('dates');
		require_css('calendar');
		require_code('calendar2');

		// Decide what to do
		if ($type=='misc') return $this->misc();

		// Decide what to do

		if ($type=='import') return $this->import_ical();
		if ($type=='_import_ical') return $this->_import_ical();
		if ($type=='export') 	return 	$this->export_ical();
		if ($type=='_export') 	return 	$this->_export_ical();

		return new ocp_tempcode();
	}

	/**
	 * The do-next manager for before content management.
	 *
	 * @return tempcode		The UI
	 */
	function misc()
	{
		require_code('templates_donext');
		require_code('fields');
		return do_next_manager(get_screen_title('MANAGE_CALENDARS'),comcode_lang_string('DOC_CALENDAR'),
					array_merge(array(
						/*	 type							  page	 params													 zone	  */
						has_specific_permission(get_member(),'submit_cat_highrange_content','cms_calendar')?array('add_one_category',array('_SELF',array('type'=>'ac'),'_SELF'),do_lang('ADD_EVENT_TYPE')):NULL,
						has_specific_permission(get_member(),'edit_own_cat_highrange_content','cms_calendar')?array('edit_one_category',array('_SELF',array('type'=>'ec'),'_SELF'),do_lang('EDIT_EVENT_TYPE')):NULL,
						has_specific_permission(get_member(),'submit_lowrange_content','cms_calendar')?array('add_one',array('_SELF',array('type'=>'ad'),'_SELF'),do_lang('ADD_CALENDAR_EVENT')):NULL,
						has_specific_permission(get_member(),'edit_own_lowrange_content','cms_calendar')?array('edit_one',array('_SELF',array('type'=>'ed'),'_SELF'),do_lang('EDIT_CALENDAR_EVENT')):NULL,
						has_specific_permission(get_member(),'mass_import','cms_calendar')?array('import',array('_SELF',array('type'=>'import'),'_SELF'),do_lang('IMPORT_ICAL')):NULL,
						array('export',array('_SELF',array('type'=>'export'),'_SELF'),do_lang('EXPORT_ICAL')),
					),manage_custom_fields_donext_link('event')),
					do_lang('MANAGE_CALENDARS')
		);
	}


	/**
	 * Standard aed_module table function.
	 *
	 * @param  array			Details to go to build_url for link to the next screen.
	 * @return array			A quartet: The choose table, Whether re-ordering is supported from this screen, Search URL, Archive URL.
	 */
	function nice_get_choose_table($url_map)
	{
		require_code('templates_results_table');

		$current_ordering=get_param('sort','e_title ASC',true);
		if (strpos($current_ordering,' ')===false) warn_exit(do_lang_tempcode('INTERNAL_ERROR'));
		list($sortable,$sort_order)=explode(' ',$current_ordering,2);
		$sortables=array(
			'e_title'=>do_lang_tempcode('TITLE'),
			'e_start_year,e_start_month,e_start_day,e_start_hour,e_start_minute'=>do_lang_tempcode('DATE_TIME'),
			'e_type'=>do_lang_tempcode('TYPE'),
			'validated'=>do_lang_tempcode('VALIDATED'),
		);
		if (($sortable=='e_start_year,e_start_month,e_start_day,e_start_hour,e_start_minute') && ($sort_order=='DESC'))
		{
			$sortable='e_start_year DESC,e_start_month DESC,e_start_day DESC,e_start_hour DESC,e_start_minute';
		} else
		{
			if (((strtoupper($sort_order)!='ASC') && (strtoupper($sort_order)!='DESC')) || (!array_key_exists($sortable,$sortables)))
				log_hack_attack_and_exit('ORDERBY_HACK');
			global $NON_CANONICAL_PARAMS;
			$NON_CANONICAL_PARAMS[]='sort';
		}

		$header_row=results_field_title(array(
			do_lang_tempcode('TITLE'),
			do_lang_tempcode('DATE_TIME'),
			do_lang_tempcode('TYPE'),
			do_lang_tempcode('VALIDATED'),
			do_lang_tempcode('ACTIONS'),
		),$sortables,'sort',$sortable.' '.$sort_order);

		$fields=new ocp_tempcode();

		require_code('form_templates');
		$only_owned=has_specific_permission(get_member(),'edit_lowrange_content','cms_calendar')?NULL:get_member();
		list($rows,$max_rows)=$this->get_entry_rows(false,$current_ordering,(is_null($only_owned)?array():array('e_submitter'=>$only_owned)));
		$types=array();
		foreach ($rows as $row)
		{
			$edit_link=build_url($url_map+array('id'=>$row['id']),'_SELF');

			if (array_key_exists($row['e_type'],$types))
			{
				$type=$types[$row['e_type']];
			} else
			{
				$type=get_translated_text($GLOBALS['SITE_DB']->query_value('calendar_types','t_title',array('id'=>$row['e_type'])));
				$types[$row['e_type']]=$type;
			}

			$start_day_of_month=find_concrete_day_of_month($row['e_start_year'],$row['e_start_month'],$row['e_start_day'],$row['e_start_monthly_spec_type'],is_null($row['e_start_hour'])?find_timezone_start_hour_in_utc($row['e_timezone'],$row['e_start_year'],$row['e_start_month'],$row['e_start_day'],$row['e_start_monthly_spec_type']):$row['e_start_hour'],is_null($row['e_start_minute'])?find_timezone_start_minute_in_utc($row['e_timezone'],$row['e_start_year'],$row['e_start_month'],$row['e_start_day'],$row['e_start_monthly_spec_type']):$row['e_start_minute'],$row['e_timezone'],$row['e_do_timezone_conv']==1);
			$time_raw=mktime($row['e_start_hour'],$row['e_start_minute'],0,$row['e_start_month'],$start_day_of_month,$row['e_start_year']);
			$date=get_timezoned_date($time_raw,!is_null($row['e_start_hour']));

			$fields->attach(results_entry(array(protect_from_escaping(hyperlink(build_url(array('page'=>'calendar','type'=>'view','id'=>$row['id']),get_module_zone('calendar')),get_translated_text($row['e_title']))),$date,$type,($row['validated']==1)?do_lang_tempcode('YES'):do_lang_tempcode('NO'),protect_from_escaping(hyperlink($edit_link,do_lang_tempcode('EDIT'),false,true,'#'.strval($row['id']))))),true);
		}

		$search_url=build_url(array('page'=>'search','id'=>'calendar'),get_module_zone('search'));
		$archive_url=build_url(array('page'=>'calendar'),get_module_zone('calendar'));

		return array(results_table(do_lang($this->menu_label),get_param_integer('start',0),'start',get_param_integer('max',20),'max',$max_rows,$header_row,$fields,$sortables,$sortable,$sort_order),false,$search_url,$archive_url);
	}

	/**
	 * Standard aed_module list function.
	 *
	 * @return tempcode		The selection list
	 */
	function nice_get_entries()
	{
		$only_owned=has_specific_permission(get_member(),'edit_lowrange_content','cms_calendar')?NULL:get_member();
		return nice_get_events($only_owned,NULL,has_specific_permission(get_member(),'edit_midrange_content','cms_calendar'));
	}

	/**
	 * Get the form fields for an event input form.
	 *
	 * @param  ?AUTO_LINK		The event type (NULL: default)
	 * @param  ?integer			The year the event starts at (NULL: default)
	 * @param  ?integer			The month the event starts at (NULL: default)
	 * @param  ?integer			The day the event starts at (NULL: default)
	 * @param  ID_TEXT			In-month specification type for start date
	 * @set day_of_month day_of_month_backwards dow_of_month dow_of_month_backwards
	 * @param  ?integer			The hour the event starts at (NULL: default)
	 * @param  ?integer			The minute the event starts at (NULL: default)
	 * @param  SHORT_TEXT		The title of the event
	 * @param  LONG_TEXT			The full text describing the event
	 * @param  SHORT_TEXT		The recurrence code
	 * @param  ?integer			The number of recurrences (NULL: none/infinite)
	 * @param  BINARY				Whether to segregate the comment-topics/rating/trackbacks per-recurrence
	 * @param  BINARY				Whether it is a public event
	 * @param  integer			The priority
	 * @range  1 5
	 * @param  ?integer			The year the event ends at (NULL: not a multi day event)
	 * @param  ?integer			The month the event ends at (NULL: not a multi day event)
	 * @param  ?integer			The day the event ends at (NULL: not a multi day event)
	 * @param  ID_TEXT			In-month specification type for end date
	 * @set day_of_month day_of_month_backwards dow_of_month dow_of_month_backwards
	 * @param  ?integer			The hour the event ends at (NULL: not a multi day event)
	 * @param  ?integer			The minute the event ends at (NULL: not a multi day event)
	 * @param  ?ID_TEXT			The timezone for the event (NULL: current user's timezone)
	 * @param  BINARY				Whether the time should be presented in the viewer's own timezone
	 * @param  BINARY				Whether the event is validated
 	 * @param  ?BINARY			Whether rating is allowed (NULL: decide statistically, based on existing choices)
 	 * @param  ?SHORT_INTEGER	Whether comments are allowed (0=no, 1=yes, 2=review style) (NULL: decide statistically, based on existing choices)
 	 * @param  ?BINARY			Whether trackbacks are allowed (NULL: decide statistically, based on existing choices)
	 * @param  LONG_TEXT			Notes
	 * @return array				A tuple of: (fields, hidden-fields, delete-fields, edit-text, whether all delete fields are specified, posting form text, more fields)
	 */
	function get_form_fields($type=NULL,$start_year=NULL,$start_month=NULL,$start_day=NULL,$start_monthly_spec_type='day_of_month',$start_hour=NULL,$start_minute=NULL,$title='',$content='',$recurrence='none',$recurrences=NULL,$seg_recurrences=0,$is_public=1,$priority=3,$end_year=NULL,$end_month=NULL,$end_day=NULL,$end_monthly_spec_type='day_of_month',$end_hour=NULL,$end_minute=NULL,$timezone=NULL,$do_timezone_conv=0,$validated=1,$allow_rating=NULL,$allow_comments=NULL,$allow_trackbacks=NULL,$notes='')
	{
		list($allow_rating,$allow_comments,$allow_trackbacks)=$this->choose_feedback_fields_statistically($allow_rating,$allow_comments,$allow_trackbacks);

		unset($content);

		if ((is_null($timezone)) || ($timezone=='')) $timezone=get_users_timezone();

		require_code('form_templates');

		if (is_null($type)) // Adding one
		{
			global $NON_CANONICAL_PARAMS;
			$NON_CANONICAL_PARAMS[]='date';
			$NON_CANONICAL_PARAMS[]='e_type';
			$NON_CANONICAL_PARAMS[]='validated';

			$date=get_param('date','');
			$start_hour=NULL;
			$start_minute=NULL;
			if ($date!='')
			{
				$date2=explode(' ',$date);
				$exploded=explode('-',$date2[0]);
				//if (count($exploded)!=3) warn_exit(do_lang_tempcode('INTERNAL_ERROR'));
				$start_year=intval($exploded[0]);
				$start_month=intval($exploded[1]);
				$start_day=intval($exploded[2]);
				if (array_key_exists(1,$date2))
				{
					$exploded=explode(':',$date2[1]);
					//if (count($exploded)!=2) warn_exit(do_lang_tempcode('INTERNAL_ERROR'));

					$start_hour=intval($exploded[0]);
					$start_minute=intval($exploded[1]);
				}
			} else
			{
				list($start_year,$start_month,$start_day)=array(NULL,NULL,NULL);
			}
			$type=get_param_integer('e_type',-1);
			if ($type==-1) $type=NULL;

			$adding=true;
		} else $adding=false;

		if (is_null($type)) $type=db_get_first_id()+1;
		if (is_null($start_month))
		{
			$start_year=intval(date('Y'));
			$start_month=intval(date('m'));
			$start_day=intval(date('d'));
			$start_hour=NULL;
			$start_minute=NULL;
		}
		if ((is_null($end_year) || is_null($end_month) || is_null($end_day)) && ($adding))
		{
			$end_year=NULL;//$start_year;
			$end_month=NULL;//$start_month;
			$end_day=NULL;//$start_day;
			$end_hour=NULL;
			$end_minute=NULL;
		}

		$fields=new ocp_tempcode();
		$hidden=new ocp_tempcode();

		$fields->attach(form_input_line(do_lang_tempcode('TITLE'),do_lang_tempcode('DESCRIPTION_TITLE'),'title',$title,true));
		//$fields->attach(form_input_text_comcode(do_lang_tempcode('EVENT_TEXT'),do_lang_tempcode('DESCRIPTION_EVENT_TEXT'),'content',$content,false));

		// Type
		$type_list=nice_get_event_types($type);
		$fields->attach(form_input_list(do_lang_tempcode('TYPE'),do_lang_tempcode('DESCRIPTION_EVENT_TYPE'),'type',$type_list));

		// Dates
		$fields->attach(form_input_tick(do_lang_tempcode('ALL_DAY_EVENT'),do_lang_tempcode('DESCRIPTION_ALL_DAY_EVENT'),'all_day_event',is_null($start_hour)));
		$start_day_of_month=find_concrete_day_of_month($start_year,$start_month,$start_day,$start_monthly_spec_type,is_null($start_hour)?find_timezone_start_hour_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_hour,is_null($start_minute)?find_timezone_start_minute_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_minute,$timezone,$do_timezone_conv==1);
		$fields->attach(form_input_date(do_lang_tempcode('DATE_TIME'),'','start',false,false,true,array(is_null($start_minute)?find_timezone_start_minute_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_minute,is_null($start_hour)?find_timezone_start_hour_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_hour,$start_month,$start_day_of_month,$start_year),120,intval(date('Y'))-100,NULL,NULL,true,$timezone,get_param('date','')==''));
		$end_day_of_month=find_concrete_day_of_month($end_year,$end_month,$end_day,$end_monthly_spec_type,is_null($end_hour)?find_timezone_end_hour_in_utc($timezone,$end_year,$end_month,$end_day,$end_monthly_spec_type):$end_hour,is_null($end_minute)?find_timezone_end_minute_in_utc($timezone,$end_year,$end_month,$end_day,$end_monthly_spec_type):$end_minute,$timezone,$do_timezone_conv==1);
		$fields->attach(form_input_date(do_lang_tempcode('END_DATE_AND_TIME'),do_lang_tempcode('DESCRIPTION_END_DATE_AND_TIME'),'end',true,is_null($end_year),true,array(is_null($end_minute)?find_timezone_end_minute_in_utc($timezone,$end_year,$end_month,$end_day,$end_monthly_spec_type):$end_minute,is_null($end_hour)?find_timezone_end_hour_in_utc($timezone,$end_year,$end_month,$end_day,$end_monthly_spec_type):$end_hour,$end_month,$end_day_of_month,$end_year),120,intval(date('Y'))-100,NULL,NULL,true,$timezone));
		//$hidden->attach(form_input_hidden('start_monthly_spec_type',$start_monthly_spec_type));
		//$hidden->attach(form_input_hidden('end_monthly_spec_type',$end_monthly_spec_type));

		// Validation
		if ($validated==0) $validated=get_param_integer('validated',0);
		if (has_some_cat_specific_permission(get_member(),'bypass_validation_'.$this->permissions_require.'range_content',NULL,$this->permissions_cat_require))
			if (addon_installed('unvalidated'))
				$fields->attach(form_input_tick(do_lang_tempcode('VALIDATED'),do_lang_tempcode('DESCRIPTION_VALIDATED'),'validated',$validated==1));

		$fields2=new ocp_tempcode();

		$fields2->attach(do_template('FORM_SCREEN_FIELD_SPACER',array('SECTION_HIDDEN'=>true,'TITLE'=>do_lang_tempcode('ADVANCED'))));

		// More date stuff
		$list='';
		foreach (get_timezone_list() as $_timezone=>$timezone_nice)
		{
			$list.=static_evaluate_tempcode(form_input_list_entry($_timezone,$_timezone==$timezone,$timezone_nice));
		}
		$fields2->attach(form_input_list(do_lang_tempcode('EVENT_TIMEZONE'),do_lang_tempcode('DESCRIPTION_EVENT_TIMEZONE'),'timezone',make_string_tempcode($list)));
		$fields2->attach(form_input_tick(do_lang_tempcode('DO_TIMEZONE_CONV'),do_lang_tempcode('DESCRIPTION_DO_TIMEZONE_CONV'),'do_timezone_conv',$do_timezone_conv==1));

		if (has_specific_permission(get_member(),'add_public_events'))
		{
			$fields2->attach(form_input_tick(do_lang_tempcode('IS_PUBLIC'),do_lang_tempcode('DESCRIPTION_IS_PUBLIC'),'is_public',$is_public==1));
		}

		// Priority
		$priority_list=new ocp_tempcode();
		$priority_list->attach(form_input_list_entry('1',$priority==1,do_lang_tempcode('PRIORITY_1')));
		$priority_list->attach(form_input_list_entry('2',$priority==2,do_lang_tempcode('PRIORITY_2')));
		$priority_list->attach(form_input_list_entry('3',$priority==3,do_lang_tempcode('PRIORITY_3')));
		$priority_list->attach(form_input_list_entry('4',$priority==4,do_lang_tempcode('PRIORITY_4')));
		$priority_list->attach(form_input_list_entry('5',$priority==5,do_lang_tempcode('PRIORITY_5')));
		$fields2->attach(form_input_list(do_lang_tempcode('PRIORITY'),'','priority',$priority_list));

		// Recurrence
		$fields2->attach(do_template('FORM_SCREEN_FIELD_SPACER',array('SECTION_HIDDEN'=>true,'TITLE'=>do_lang_tempcode('RECURRENCE'))));
		if (strpos($recurrence,' ')===false)
		{
			$recurrence_main=$recurrence;
			$recurrence_pattern='';
		} else
		{
			list($recurrence_main,$recurrence_pattern)=explode(' ',$recurrence);
		}
		$radios=form_input_radio_entry('recurrence','none',true,do_lang_tempcode('NA_EM'));
		$radios->attach(form_input_radio_entry('recurrence','daily',$recurrence_main=='daily',do_lang_tempcode('DAILY')));
		$radios->attach(form_input_radio_entry('recurrence','weekly',$recurrence_main=='weekly',do_lang_tempcode('WEEKLY')));
		$radios->attach(form_input_radio_entry('recurrence','monthly',$recurrence_main=='monthly',do_lang_tempcode('MONTHLY')));
		$radios->attach(form_input_radio_entry('recurrence','yearly',$recurrence_main=='yearly',do_lang_tempcode('YEARLY')));
		$fields2->attach(form_input_radio(do_lang_tempcode('RECURRENCE'),do_lang_tempcode('DESCRIPTION_RECURRENCE'),'recurrence',$radios)); // xth_dotw_of_monthly
		$fields2->attach(form_input_line(do_lang_tempcode('RECURRENCE_PATTERN'),do_lang_tempcode('DESCRIPTION_RECURRENCE_PATTERN'),'recurrence_pattern',$recurrence_pattern,false));
		$fields2->attach(form_input_integer(do_lang_tempcode('RECURRENCES'),do_lang_tempcode('DESCRIPTION_RECURRENCES'),'recurrences',$recurrences,false));
		$fields2->attach(form_input_tick(do_lang_tempcode('SEG_RECURRENCES'),do_lang_tempcode('DESCRIPTION_SEG_RECURRENCES'),'seg_recurrences',$seg_recurrences==1));
		$start_time=mktime($start_hour,$start_minute,0,$start_month,$start_day,$start_year);
		$start_time=tz_time($start_time,get_users_timezone());
		$conv_month=intval(date('n',$start_time));
		$conv_day=intval(date('j',$start_time));
		$conv_year=intval(date('Y',$start_time));
		$fields2->attach(monthly_spec_type_chooser($conv_day,$conv_month,$conv_year,$start_monthly_spec_type));

		if (($adding) && (cron_installed()) && (has_specific_permission(get_member(),'set_reminders'))) // Some more stuff only when adding
		{
			$fields2->attach(do_template('FORM_SCREEN_FIELD_SPACER',array('SECTION_HIDDEN'=>true,'TITLE'=>do_lang_tempcode('REMINDERS'))));

			$fields2->attach(form_input_tick(do_lang_tempcode('SIGN_UP_REMINDER'),do_lang_tempcode('DESCRIPTION_SIGN_UP_REMINDER'),'sign_up_reminder',true));
			if (has_specific_permission(get_member(),'add_public_events'))
			{
				$usergroup_list=$GLOBALS['FORUM_DRIVER']->get_usergroup_list(true);
				if (get_forum_type()=='ocf')
					unset($usergroup_list[db_get_first_id()]);
				$t_usergroup_list=new ocp_tempcode();
				foreach ($usergroup_list as $id=>$name)
				{
					$t_usergroup_list->attach(form_input_list_entry(strval($id),false,$name));
				}
				$fields2->attach(form_input_all_and_not(do_lang_tempcode('SIGN_UP_REMINDER_GROUPS'),do_lang_tempcode('DESCRIPTION_SIGN_UP_REMINDER_GROUPS'),'sign_up_reminder_groups',$t_usergroup_list));
			}
			$fields2->attach(form_input_float(do_lang_tempcode('REMINDER_TIME'),do_lang_tempcode('DESCRIPTION_REMINDER_TIME'),'hours_before',1.0,true));
		}

		require_code('feedback2');
		$fields2->attach(feedback_fields($allow_rating==1,$allow_comments==1,$allow_trackbacks==1,false,$notes,$allow_comments==2));

		$fields2->attach(get_syndication_option_fields());

		return array($fields,$hidden,NULL,NULL,true,NULL,$fields2);
	}

	/**
	 * Get the form posted parameters specifying an event.
	 *
	 * @return array			A list of parameters in a certain order (see the return command to see the order)
	 */
	function get_event_parameters()
	{
		$type=post_param_integer('type',INTEGER_MAGIC_NULL);
		if ((!has_actual_page_access(get_member(),'admin_occle')) && ($type==db_get_first_id())) access_denied('I_ERROR');
		$recurrence=post_param('recurrence',STRING_MAGIC_NULL);
		if (($recurrence!='none') && ($recurrence!=STRING_MAGIC_NULL))
		{
			$recurrence_pattern=post_param('recurrence_pattern','');
			if ($recurrence_pattern!='') $recurrence.=' '.$recurrence_pattern;
		}
		$title=post_param('title');
		$content=post_param('post',STRING_MAGIC_NULL);
		$priority=post_param_integer('priority',INTEGER_MAGIC_NULL);
		$is_public=(has_specific_permission(get_member(),'add_public_events'))?post_param_integer('is_public',fractional_edit()?INTEGER_MAGIC_NULL:0):0;
		$recurrences=post_param_integer('recurrences',fractional_edit()?INTEGER_MAGIC_NULL:-1);
		if ($recurrences==-1) $recurrences=NULL;
		$timezone=post_param('timezone',STRING_MAGIC_NULL);
		$do_timezone_conv=post_param_integer('do_timezone_conv',fractional_edit()?INTEGER_MAGIC_NULL:0);

		$start=get_input_date('start');
		if (is_null($start))
		{
			$start_year=INTEGER_MAGIC_NULL;
			$start_month=INTEGER_MAGIC_NULL;
			$start_day=INTEGER_MAGIC_NULL;
			$start_hour=INTEGER_MAGIC_NULL;
			$start_minute=INTEGER_MAGIC_NULL;
			$start_monthly_spec_type=STRING_MAGIC_NULL;
		} else
		{
			$start_year=intval(date('Y',$start));
			$start_month=intval(date('m',$start));
			$start_day=intval(date('d',$start));
			if (post_param_integer('all_day_event',0)==1)
			{
				$start_hour=NULL;
				$start_minute=NULL;
			} else
			{
				$start_hour=intval(date('H',$start));
				$start_minute=intval(date('i',$start));
			}
			$start_monthly_spec_type=post_param('start_monthly_spec_type',post_param('monthly_spec_type','day_of_month')); // We actually don't suppose separate spec-types for the ends and starts in the UI
			if ($start_monthly_spec_type!='day_of_month')
			{
				$start_day=find_abstract_day(post_param_integer('start_year'),post_param_integer('start_month'),post_param_integer('start_day'),$start_monthly_spec_type);
			}
		}
		if (fractional_edit())
		{
			$end_year=INTEGER_MAGIC_NULL;
			$end_month=INTEGER_MAGIC_NULL;
			$end_day=INTEGER_MAGIC_NULL;
			$end_hour=INTEGER_MAGIC_NULL;
			$end_minute=INTEGER_MAGIC_NULL;
			$end_monthly_spec_type=STRING_MAGIC_NULL;
		} else
		{
			$end=get_input_date('end');
			if (!is_null($end))
			{
				$end_year=intval(date('Y',$end));
				$end_month=intval(date('m',$end));
				$end_day=intval(date('d',$end));
				if (post_param_integer('all_day_event',0)==1)
				{
					$end_hour=NULL;
					$end_minute=NULL;
				} else
				{
					$end_hour=intval(date('H',$end));
					$end_minute=intval(date('i',$end));
				}

				$end_monthly_spec_type=post_param('end_monthly_spec_type',$start_monthly_spec_type);
				if ($end_monthly_spec_type!='day_of_month')
				{
					$end_day=find_abstract_day(post_param_integer('end_year'),post_param_integer('end_month'),post_param_integer('end_day'),$end_monthly_spec_type);
				} else
				{
					// Error if wrong way around
					if ($start>$end) warn_exit(do_lang_tempcode('EVENT_CANNOT_AROUND'));
				}
			} else
			{
				$end_year=NULL;
				$end_month=NULL;
				$end_day=NULL;
				$end_hour=NULL;
				$end_minute=NULL;
				$end_monthly_spec_type='day_of_month';
			}
		}

		if ($recurrence!='monthly')
		{
			$start_monthly_spec_type='day_of_month';
			$end_monthly_spec_type='day_of_month';
		}

		return array($type,$recurrence,$recurrences,$title,$content,$priority,$is_public,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,$timezone,$do_timezone_conv);
	}

	/**
	 * Standard aed_module submitter getter.
	 *
	 * @param  ID_TEXT		The entry for which the submitter is sought
	 * @return array			The submitter, and the time of submission (null submission time implies no known submission time)
	 */
	function get_submitter($id)
	{
		$rows=$GLOBALS['SITE_DB']->query_select('calendar_events',array('e_submitter','e_add_date'),array('id'=>intval($id)),'',1);
		if (!array_key_exists(0,$rows)) return array(NULL,NULL);
		return array($rows[0]['e_submitter'],$rows[0]['e_add_date']);
	}

	/**
	 * Standard aed_module cat getter.
	 *
	 * @param  AUTO_LINK		The entry for which the cat is sought
	 * @return mixed			The cat
	 */
	function get_cat($id)
	{
		$temp=$GLOBALS['SITE_DB']->query_value_null_ok('calendar_events','e_type',array('id'=>$id));
		if (is_null($temp)) warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
		return $temp;
	}

	/**
	 * Standard aed_module edit form filler.
	 *
	 * @param  ID_TEXT		The entry being edited
	 * @return array			A tuple of: (fields, hidden-fields, delete-fields, edit-text, whether all delete fields are specified, posting form text, more fields, parsed WYSIWYG editable text)
	 */
	function fill_in_edit_form($id)
	{
		$rows=$GLOBALS['SITE_DB']->query_select('calendar_events',array('*'),array('id'=>intval($id)),'',1);
		if (!array_key_exists(0,$rows))
		{
			warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
		}
		$myrow=$rows[0];

		$parsed=get_translated_tempcode($myrow['e_content']);

		check_edit_permission(($myrow['e_is_public']==1)?'mid':'low',$myrow['e_submitter']);
		$content=get_translated_text($myrow['e_content']);
		$fields=$this->get_form_fields($myrow['e_type'],$myrow['e_start_year'],$myrow['e_start_month'],$myrow['e_start_day'],$myrow['e_start_monthly_spec_type'],$myrow['e_start_hour'],$myrow['e_start_minute'],get_translated_text($myrow['e_title']),$content,$myrow['e_recurrence'],$myrow['e_recurrences'],$myrow['e_seg_recurrences'],$myrow['e_is_public'],$myrow['e_priority'],$myrow['e_end_year'],$myrow['e_end_month'],$myrow['e_end_day'],$myrow['e_end_monthly_spec_type'],$myrow['e_end_hour'],$myrow['e_end_minute'],$myrow['e_timezone'],$myrow['e_do_timezone_conv'],$myrow['validated'],$myrow['allow_rating'],$myrow['allow_comments'],$myrow['allow_trackbacks'],$myrow['notes']);

		if (has_delete_permission('low',get_member(),$myrow['e_submitter'],'cms_calendar'))
		{
			$radios=form_input_radio_entry('delete','0',true,do_lang_tempcode('EDIT'));
			$radios->attach(form_input_radio_entry('delete','3',false,do_lang_tempcode('FIX_PAST_RECURRENCES')));
			$radios->attach(form_input_radio_entry('delete','1',false,do_lang_tempcode('DELETE')));
			$delete_fields=form_input_radio(do_lang_tempcode('ACTION'),do_lang_tempcode('DESCRIPTION_FIX_PAST_RECURRENCES'),'delete',$radios);
		} else $delete_fields=new ocp_tempcode();

		return array($fields[0],$fields[1],$delete_fields,'',true,$content,$fields[6],$parsed);
	}

	/**
	 * Standard aed_module add actualiser.
	 *
	 * @return array			A pair: the entry added, and a description
	 */
	function add_actualisation()
	{
		list($type,$recurrence,$recurrences,$title,$content,$priority,$is_public,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,$timezone,$do_timezone_conv)=$this->get_event_parameters();

		$allow_trackbacks=post_param_integer('allow_trackbacks',0);
		$allow_rating=post_param_integer('allow_rating',0);
		$allow_comments=post_param_integer('allow_comments',0);
		$notes=post_param('notes','');
		$validated=post_param_integer('validated',0);
		$seg_recurrences=post_param_integer('seg_recurrences',0);

		$id=add_calendar_event($type,$recurrence,$recurrences,$seg_recurrences,$title,$content,$priority,$is_public,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,$timezone,$do_timezone_conv,$validated,$allow_rating,$allow_comments,$allow_trackbacks,$notes);

		// Reminders
		if (has_specific_permission(get_member(),'set_reminders'))
		{
			if (function_exists('set_time_limit')) @set_time_limit(0);
			$rem_groups=array();
			if ((has_specific_permission(get_member(),'add_public_events')) && (array_key_exists('sign_up_reminder_groups',$_POST)))
			{
				$all_groups=$GLOBALS['FORUM_DRIVER']->get_usergroup_list(true);
				$multi_code=read_multi_code('sign_up_reminder_groups'); // Usergroups signed up
				require_code('ocfiltering');
				if ((substr($multi_code,0,1)=='-') || (substr($multi_code,0,1)=='*'))
				{
					$rem_groups=$all_groups;
					if (get_forum_type()=='ocf')
						unset($rem_groups[db_get_first_id()]);
				}
				foreach (explode(',',substr($multi_code,1)) as $m)
				{
					if (substr($multi_code,0,1)=='-')
					{
						unset($rem_groups[intval($m)]);
					} elseif (substr($multi_code,0,1)=='+')
					{
						$rem_groups[intval($m)]=$all_groups[intval($m)];
					}
				}
				$rem_groups=array_keys($rem_groups);
			}
			$start=0;
			do
			{
				$members=array();
				if (count($rem_groups)!=0)
				{
					$members=array_keys($GLOBALS['FORUM_DRIVER']->member_group_query($rem_groups,300,$start));
					$members=array_diff($members,array(get_member(),$GLOBALS['FORUM_DRIVER']->get_guest_id()));
				}
				if (($start==0) && (post_param_integer('sign_up_reminder',0)==1)) // If this member is signing up
					$members[]=get_member();
				if (count($members)!=0) // Now add their reminders
				{
					$secs_before=floatval(post_param('hours_before','1.0'))*3600.0;

					$filled1=array();
					for ($i=0;$i<count($members);$i++) $filled1[]=$id;
					$filled2=array();
					for ($i=0;$i<count($members);$i++) $filled2[]=intval($secs_before);
					$GLOBALS['SITE_DB']->query_insert('calendar_reminders',array(
						'e_id'=>$filled1,
						'n_member_id'=>array_values($members),
						'n_seconds_before'=>$filled2
					));
				}
				$start+=300;
			}
			while (array_key_exists(0,$members));
			if ($is_public==1)
			{
				$start=0;
				do
				{
					$members=array();
					$interested=$GLOBALS['SITE_DB']->query_select('calendar_interests',array('i_member_id'),array('t_type'=>$type),'',300,$start);
					foreach ($interested as $int) // Members with declarations of interest
					{
						if (!in_array($int['i_member_id'],$members)) $members[]=$int['i_member_id'];
					}
					$members=array_diff($members,array(get_member(),$GLOBALS['FORUM_DRIVER']->get_guest_id()));
					foreach ($members as $member) // Now add their reminders. Can't do this as multi-insert as there may be dupes, so we need to skip over errors individually
					{
						$secs_before=floatval(post_param('hours_before','1.0'))*3600.0;
						$GLOBALS['SITE_DB']->query_insert('calendar_reminders',array(
							'e_id'=>$id,
							'n_member_id'=>$member,
							'n_seconds_before'=>intval($secs_before),
						),false,true);
					}
					$start+=300;
				}
				while (array_key_exists(0,$members));
			}
		}

		regenerate_event_reminder_jobs($id);

		$conflicts=detect_conflicts(get_member(),$id,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$start_monthly_spec_type,$end_hour,$end_minute,$recurrence,$recurrences);
		$_description=is_null($conflicts)?paragraph(do_lang_tempcode('SUBMIT_THANKYOU')):$conflicts;

		$this->donext_type=$type;
		$start_day_of_month=find_concrete_day_of_month($start_year,$start_month,$start_day,$start_monthly_spec_type,is_null($start_hour)?find_timezone_start_hour_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_hour,is_null($start_minute)?find_timezone_start_minute_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_minute,$timezone,$do_timezone_conv==1);
		$this->donext_date=strval($start_year).'-'.strval($start_month).'-'.strval($start_day_of_month);

		if ($validated==1)
		{
			if ((has_actual_page_access($GLOBALS['FORUM_DRIVER']->get_guest_id(),'calendar')) && (has_category_access($GLOBALS['FORUM_DRIVER']->get_guest_id(),'calendar',strval($type))))
			{
				$_from=cal_get_start_utctime_for_event($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,true);
				$from=cal_utctime_to_usertime($_from,$timezone,false);
				$to=mixed();
				if (!is_null($end_year) && !is_null($end_month) && !is_null($end_day))
				{
					$_to=cal_get_end_utctime_for_event($timezone,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,true);
					$to=cal_utctime_to_usertime($_to,$timezone,false);
				}

				syndicate_described_activity('calendar:ACTIVITY_CALENDAR_EVENT',$title,date_range($from,$to,!is_null($start_hour)),'','_SEARCH:calendar:view:'.strval($id),'','','calendar',1,NULL,true);
			}
		}

		return array(strval($id),$_description);
	}

	/**
	 * Standard aed_module edit actualiser.
	 *
	 * @param  ID_TEXT		The entry being edited
	 * @return tempcode		Description shown after editing
	 */
	function edit_actualisation($_id)
	{
		$id=intval($_id);

		$rows=$GLOBALS['SITE_DB']->query_select('calendar_events',array('*'),array('id'=>$id),'',1);
		if (!array_key_exists(0,$rows))
			warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
		$event=$rows[0];

		check_edit_permission(($event['e_is_public']==1)?'mid':'low',$event['e_submitter']);

		$delete_status=post_param('delete','0');

		list($type,$recurrence,$_recurrences,$title,$content,$priority,$is_public,$_start_year,$_start_month,$_start_day,$start_monthly_spec_type,$_start_hour,$_start_minute,$_end_year,$_end_month,$_end_day,$end_monthly_spec_type,$_end_hour,$_end_minute,$timezone,$do_timezone_conv)=$this->get_event_parameters();
		if ($delete_status!='3')
		{
			$start_year=$_start_year;
			$start_month=$_start_month;
			$start_day=$_start_day;
			$start_hour=$_start_hour;
			$start_minute=$_start_minute;
			$end_year=$_end_year;
			$end_month=$_end_month;
			$end_day=$_end_day;
			$end_hour=$_end_hour;
			$end_minute=$_end_minute;

			$recurrences=$_recurrences;
		}

		$allow_trackbacks=post_param_integer('allow_trackbacks',fractional_edit()?INTEGER_MAGIC_NULL:0);
		$allow_rating=post_param_integer('allow_rating',fractional_edit()?INTEGER_MAGIC_NULL:0);
		$allow_comments=post_param_integer('allow_comments',fractional_edit()?INTEGER_MAGIC_NULL:0);
		$notes=post_param('notes',STRING_MAGIC_NULL);
		$validated=post_param_integer('validated',fractional_edit()?INTEGER_MAGIC_NULL:0);
		$seg_recurrences=post_param_integer('seg_recurrences',fractional_edit()?INTEGER_MAGIC_NULL:0);

		if (($delete_status=='3') && (!fractional_edit()))
		{
			// Fix past occurences
			$past_times=find_periods_recurrence($event['e_timezone'],1,$event['e_start_year'],$event['e_start_month'],$event['e_start_day'],$event['e_start_monthly_spec_type'],$event['e_start_hour'],$event['e_start_minute'],$event['e_end_year'],$event['e_end_month'],$event['e_end_day'],$event['e_end_monthly_spec_type'],$event['e_end_hour'],$event['e_end_minute'],$event['e_recurrence'],$event['e_recurrences'],utctime_to_usertime(mktime($event['e_start_hour'],$event['e_start_minute'],0,$event['e_start_month'],$event['e_start_day'],$event['e_start_year'])),utctime_to_usertime(time()));
			foreach ($past_times as $past_time)
			{
				list($start_year,$start_month,$start_day,$start_hour,$start_minute)=explode('-',date('Y-m-d-h-i',usertime_to_utctime($past_time[0])));
				if (is_null($past_time[1]))
				{
					list($end_year,$end_month,$end_day,$end_hour,$end_minute)=array(NULL,NULL,NULL,NULL,NULL);
				} else
				{
					$explode=explode('-',date('Y-m-d-h-i',usertime_to_utctime($past_time[1])));
					$end_year=intval($explode[0]);
					$end_month=intval($explode[1]);
					$end_day=intval($explode[2]);
					$end_hour=intval($explode[3]);
					$end_minute=intval($explode[4]);
				}
				add_calendar_event($event['e_type'],'none',NULL,0,get_translated_text($event['e_title']),get_translated_text($event['e_content']),$event['e_priority'],$event['e_is_public'],intval($start_year),intval($start_month),intval($start_day),'day_of_month',intval($start_hour),intval($start_minute),$end_year,$end_month,$end_day,'day_of_month',$end_hour,$end_minute,$timezone,$do_timezone_conv,$validated,$allow_rating,$allow_comments,$allow_trackbacks,$notes);
			}
			if (is_null($_recurrences))
			{
				$recurrences=NULL;
			} else
			{
				$recurrences=max(0,$_recurrences-count($past_times));
			}

			// Find next occurence in future
			if (count($past_times)==0)
			{
				$start_year=$_start_year;
				$start_month=$_start_month;
				$start_day=$_start_day;
				$start_hour=$_start_hour;
				$start_minute=$_start_minute;
				$end_year=$_end_year;
				$end_month=$_end_month;
				$end_day=$_end_day;
				$end_hour=$_end_hour;
				$end_minute=$_end_minute;
			}
			$past_times=find_periods_recurrence($event['e_timezone'],1,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,$event['e_recurrence'],1,time());
			if (array_key_exists(0,$past_times))
			{
				$past_time=$past_times[0];
				$explode=explode('-',date('Y-m-d-h-i',$past_time[0]));
				$start_year=intval($explode[0]);
				$start_month=intval($explode[1]);
				$start_day=intval($explode[2]);
				$start_hour=intval($explode[3]);
				$start_minute=intval($explode[4]);

				if (is_null($past_time[1]))
				{
					list($end_year,$end_month,$end_day,$end_hour,$end_minute)=array(NULL,NULL,NULL,NULL,NULL);
				} else
				{
					$explode=explode('-',date('Y-m-d-h-i',$past_time[1]));
					$end_year=intval($explode[0]);
					$end_month=intval($explode[1]);
					$end_day=intval($explode[2]);
					$end_hour=intval($explode[3]);
					$end_minute=intval($explode[4]);
				}
			} else
			{
				$recurrences=0;
			}
		}

		if (($validated==1) && ($GLOBALS['SITE_DB']->query_value('calendar_events','validated',array('id'=>$id))==0)) // Just became validated, syndicate as just added
		{
			if ((has_actual_page_access($GLOBALS['FORUM_DRIVER']->get_guest_id(),'calendar')) && (has_category_access($GLOBALS['FORUM_DRIVER']->get_guest_id(),'calendar',strval($type))))
			{
				$_from=cal_get_start_utctime_for_event($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,true);
				$from=cal_utctime_to_usertime($_from,$timezone,false);
				$to=mixed();
				if (!is_null($end_year) && !is_null($end_month) && !is_null($end_day))
				{
					$_to=cal_get_end_utctime_for_event($timezone,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,true);
					$to=cal_utctime_to_usertime($_to,$timezone,false);
				}

				$submitter=$GLOBALS['SITE_DB']->query_value('calendar_events','submitter',array('id'=>$id));

				syndicate_described_activity(($submitter!=get_member())?'calendar:ACTIVITY_VALIDATE_CALENDAR_EVENT':'calendar:ACTIVITY_CALENDAR_EVENT',$title,date_range($from,$to,!is_null($start_hour)),'','_SEARCH:calendar:view:'.strval($id),'','','calendar',1,$submitter,true);
			}
		}

		edit_calendar_event($id,$type,$recurrence,$recurrences,$seg_recurrences,$title,$content,$priority,$is_public,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,$timezone,$do_timezone_conv,post_param('meta_keywords',STRING_MAGIC_NULL),post_param('meta_description',STRING_MAGIC_NULL),$validated,$allow_rating,$allow_comments,$allow_trackbacks,$notes);

		if (!fractional_edit())
		{
			$conflicts=detect_conflicts(get_member(),$id,$start_year,$start_month,$start_day,$start_monthly_spec_type,$start_hour,$start_minute,$end_year,$end_month,$end_day,$end_monthly_spec_type,$end_hour,$end_minute,$recurrence,$recurrences);
			$_description=is_null($conflicts)?paragraph(do_lang_tempcode('SUCCESS')):$conflicts;

			regenerate_event_reminder_jobs($id);
		} else $_description=do_lang_tempcode('SUCCESS');

		$this->donext_type=$type;
		$start_day_of_month=find_concrete_day_of_month($start_year,$start_month,$start_day,$start_monthly_spec_type,is_null($start_hour)?find_timezone_start_hour_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_hour,is_null($start_minute)?find_timezone_start_minute_in_utc($timezone,$start_year,$start_month,$start_day,$start_monthly_spec_type):$start_minute,$timezone,$do_timezone_conv==1);
		$this->donext_date=strval($start_year).'-'.strval($start_month).'-'.strval($start_day_of_month);

		return $_description;
	}

	/**
	 * Standard aed_module delete actualiser.
	 *
	 * @param  ID_TEXT		The entry being deleted
	 */
	function delete_actualisation($_id)
	{
		$id=intval($_id);

		$rows=$GLOBALS['SITE_DB']->query_select('calendar_events',array('*'),array('id'=>$id),'',1);
		if (!array_key_exists(0,$rows))
			warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
		$event=$rows[0];
		check_delete_permission(($event['e_is_public']==1)?'mid':'low',$event['e_submitter']);

		delete_calendar_event($id);
	}

	/**
	 * The do-next manager for after calendar content management (events only).
	 *
	 * @param  tempcode		The title (output of get_screen_title)
	 * @param  tempcode		Some description to show, saying what happened
	 * @param  ?AUTO_LINK	The ID of whatever was just handled (NULL: N/A)
	 * @return tempcode		The UI
	 */
	function do_next_manager($title,$description,$id)
	{
		return $this->cat_aed_module->_do_next_manager($title,$description,is_null($id)?NULL:intval($id),$this->donext_type,$this->donext_date);
	}

	/**
	 * The UI to import ical for calendar
	 *
	 * @return tempcode		The UI
	 */
	function import_ical()
	{
		check_specific_permission('mass_import');

		$lang=post_param('lang',user_lang());

		require_code('calendar_ical');

		$title=get_screen_title('IMPORT_ICAL');

		$post_url=build_url(array('page'=>'_SELF','type'=>'_import_ical','old_type'=>get_param('type','')),'_SELF');
		$submit_name=do_lang_tempcode('IMPORT_ICAL');

		// Build up form
		$fields=new ocp_tempcode();
		require_code('form_templates');

		$fields->attach(form_input_upload(do_lang_tempcode('UPLOAD'),do_lang_tempcode('DESCRIPTION_ICAL'),'file_novalidate',false,NULL,NULL,true,'ics,ical'));

		$hidden=new ocp_tempcode();
		$hidden->attach(form_input_hidden('lang',$lang));
		handle_max_file_size($hidden);

		return do_template('FORM_SCREEN',array('_GUID'=>'5a970cd3766a6d32b64015b4dfd4b25e','TITLE'=>$title,'TEXT'=>do_lang_tempcode('IMPORT_ICAL_TEXT'),'HIDDEN'=>$hidden,'FIELDS'=>$fields,'SUBMIT_NAME'=>$submit_name,'URL'=>$post_url));
	}

	/**
	 * The actualiser to import ical for calendar
	 *
	 * @return tempcode		The UI
	 */
	function _import_ical()
	{
		check_specific_permission('mass_import');

		$title=get_screen_title('IMPORT_ICAL');

		require_code('calendar_ical');

		$ical_url=post_param('ical_feed_url',NULL);

		require_code('uploads');
		if (((is_swf_upload(true)) && (array_key_exists('file_novalidate',$_FILES))) || ((array_key_exists('file_novalidate',$_FILES)) && (is_uploaded_file($_FILES['file_novalidate']['tmp_name']))))
			$ical_url=$_FILES['file_novalidate']['tmp_name'];

		if (is_null($ical_url))
			warn_exit(do_lang_tempcode('IMPROPERLY_FILLED_IN'));

		ical_import($ical_url);

		breadcrumb_set_parents(array(array('_SELF:_SELF:misc',do_lang_tempcode('MANAGE_CALENDARS')),array('_SELF:_SELF:import',do_lang_tempcode('IMPORT_ICAL'))));
		breadcrumb_set_self(do_lang_tempcode('DONE'));

		return inform_screen($title,do_lang_tempcode('IMPORT_ICAL_DONE'));
	}

	/**
	 * UI to display export screen fields
	 *
	 * @return tempcode		The UI
	 */
	function export_ical()
	{
		$title=get_screen_title('EXPORT_ICAL');

		$fields=new ocp_tempcode();
		$type_list=nice_get_event_types();

		//Add all cal option
		$type_list->attach(form_input_list_entry('0',true,'All types'));

		$fields->attach(form_input_list(do_lang_tempcode('TYPE'),do_lang_tempcode('DESCRIPTION_EVENT_TYPE'),'type_filter',$type_list));
		$post_url=build_url(array('page'=>'_SELF','type'=>'_export'),'_SELF');
		$submit_name=do_lang_tempcode('EXPORT_ICAL');

		return do_template('FORM_SCREEN',array('_GUID'=>'fa308cb6dd4f82f5ed2dd2fab45b0fef','TITLE'=>$title,'TEXT'=>do_lang_tempcode('EXPORT_ICAL_TEXT'),'HIDDEN'=>'','FIELDS'=>$fields,'SUBMIT_NAME'=>$submit_name,'URL'=>$post_url,'GET'=>true));
	}

	/**
	 * The actualiser to export ical
	 */
	function _export_ical()
	{
		$title=get_screen_title('EXPORT_ICAL');
		require_code('calendar_ical');
		output_ical();
	}
}

/**
 * Module page class.
 */
class Module_cms_calendar_cat extends standard_aed_module
{
	var $lang_type='EVENT_TYPE';
	var $select_name='EVENT_TYPE';
	var $select_name_description='DESCRIPTION_EVENT_TYPE';
	var $orderer='t_title';
	var $array_key='id';
	var $title_is_multi_lang=true;
	var $non_integer_id=false;
	var $protect_first=2;
	var $table='calendar_types';
	var $permissions_require='cat_high';
	var $permission_module='calendar';
	var $menu_label='CALENDAR';

	/**
	 * Get tempcode for a post template adding/editing form.
	 *
	 * @param  ?AUTO_LINK	ID of category (NULL: new category)
	 * @param  SHORT_TEXT	The title
	 * @param  SHORT_TEXT	The theme image code
	 * @param  URLPATH		URL to external feed to associate with this event type
	 * @return array			A pair: The input fields, Hidden fields
	 */
	function get_form_fields($id=NULL,$title='',$logo='',$external_feed='')
	{
		$fields=new ocp_tempcode();
		$hidden=new ocp_tempcode();

		$fields->attach(form_input_line(do_lang_tempcode('TITLE'),do_lang_tempcode('DESCRIPTION_TITLE'),'title',$title,true));

		require_code('themes2');
		$ids=get_all_image_ids_type('calendar');

		$set_name='image';
		$required=true;
		$set_title=do_lang_tempcode('IMAGE');
		$field_set=(count($ids)==0)?new ocp_tempcode():alternate_fields_set__start($set_name);

		$field_set->attach(form_input_upload(do_lang_tempcode('UPLOAD'),'','file',$required,NULL,NULL,true,str_replace(' ','',get_option('valid_images'))));

		$field_set->attach(form_input_theme_image(do_lang_tempcode('STOCK'),'','theme_img_code',$ids,NULL,$logo,NULL,false));

		$fields->attach(alternate_fields_set__end($set_name,$set_title,'',$field_set,$required));

		handle_max_file_size($hidden,'image');

		if (addon_installed('syndication_blocks'))
		{
			$fields->attach(form_input_line(do_lang_tempcode('EXTERNAL_FEED'),do_lang_tempcode('DESCRIPTION_EXTERNAL_FEED'),'external_feed',$external_feed,false));
		} else
		{
			$hidden->attach(form_input_hidden('external_feed',$external_feed));
		}

		// Permissions
		$fields->attach($this->get_permission_fields(is_null($id)?NULL:strval($id),NULL,($title=='')));

		return array($fields,$hidden);
	}

	/**
	 * Standard aed_module table function.
	 *
	 * @param  array			Details to go to build_url for link to the next screen.
	 * @return array			A quartet: The choose table, Whether re-ordering is supported from this screen, Search URL, Archive URL.
	 */
	function nice_get_choose_table($url_map)
	{
		require_code('templates_results_table');

		$current_ordering=get_param('sort','t_title ASC',true);
		if (strpos($current_ordering,' ')===false) warn_exit(do_lang_tempcode('INTERNAL_ERROR'));
		list($sortable,$sort_order)=explode(' ',$current_ordering,2);
		$sortables=array(
			't_title'=>do_lang_tempcode('TITLE'),
		);
		if (((strtoupper($sort_order)!='ASC') && (strtoupper($sort_order)!='DESC')) || (!array_key_exists($sortable,$sortables)))
			log_hack_attack_and_exit('ORDERBY_HACK');
		global $NON_CANONICAL_PARAMS;
		$NON_CANONICAL_PARAMS[]='sort';

		$header_row=results_field_title(array(
			do_lang_tempcode('TITLE'),
			do_lang_tempcode('COUNT_TOTAL'),
			do_lang_tempcode('ACTIONS'),
		),$sortables,'sort',$sortable.' '.$sort_order);

		$fields=new ocp_tempcode();

		require_code('form_templates');
		list($rows,$max_rows)=$this->get_entry_rows(false,$current_ordering);
		foreach ($rows as $row)
		{
			$edit_link=build_url($url_map+array('id'=>$row['id']),'_SELF');

			$total=$GLOBALS['SITE_DB']->query_value('calendar_events','COUNT(*)',array('e_type'=>$row['id']));

			$fields->attach(results_entry(array(get_translated_text($row['t_title']),integer_format($total),protect_from_escaping(hyperlink($edit_link,do_lang_tempcode('EDIT'),false,true,'#'.strval($row['id']))))),true);
		}

		$search_url=NULL;
		$archive_url=NULL;

		return array(results_table(do_lang($this->menu_label),get_param_integer('start',0),'start',get_param_integer('max',20),'max',$max_rows,$header_row,$fields,$sortables,$sortable,$sort_order),false,$search_url,$archive_url);
	}

	/**
	 * Standard aed_module edit form filler.
	 *
	 * @param  ID_TEXT		The entry being edited
	 * @return array			A pair: The input fields, Hidden fields
	 */
	function fill_in_edit_form($id)
	{
		$m=$GLOBALS['SITE_DB']->query_select('calendar_types',array('*'),array('id'=>intval($id)),'',1);
		if (!array_key_exists(0,$m)) warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
		$r=$m[0];

		$ret=$this->get_form_fields(intval($id),get_translated_text($r['t_title']),$r['t_logo'],$r['t_external_feed']);

		return $ret;
	}

	/**
	 * Standard aed_module add actualiser.
	 *
	 * @return ID_TEXT		The entry added
	 */
	function add_actualisation()
	{
		require_code('themes2');

		$id=add_event_type(post_param('title'),get_theme_img_code('calendar'),post_param('external_feed'));
		$this->set_permissions(strval($id));
		return strval($id);
	}

	/**
	 * Standard aed_module edit actualiser.
	 *
	 * @param  ID_TEXT		The entry being edited
	 */
	function edit_actualisation($id)
	{
		require_code('themes2');

		edit_event_type(intval($id),post_param('title'),get_theme_img_code('calendar'),post_param('external_feed'));
		if (!fractional_edit())
		{
			$this->set_permissions(strval($id));
		}
	}

	/**
	 * Standard aed_module delete actualiser.
	 *
	 * @param  ID_TEXT		The entry being deleted
	 */
	function delete_actualisation($id)
	{
		delete_event_type(intval($id));
	}

	/**
	 * The do-next manager for after calendar content management (event types only).
	 *
	 * @param  tempcode		The title (output of get_screen_title)
	 * @param  tempcode		Some description to show, saying what happened
	 * @param  ?AUTO_LINK	The ID of whatever was just handled (NULL: N/A)
	 * @return tempcode		The UI
	 */
	function do_next_manager($title,$description,$id)
	{
		return $this->_do_next_manager($title,$description,NULL,is_null($id)?NULL:intval($id),'');
	}

	/**
	 * The do-next manager for after calendar content management.
	 *
	 * @param  tempcode		The title (output of get_screen_title)
	 * @param  tempcode		Some description to show, saying what happened
	 * @param  ?AUTO_LINK	The ID of whatever was just handled (NULL: N/A)
	 * @param  ?AUTO_LINK	The category ID we were working in (NULL: N/A)
	 * @param  string			The Y-m-d of the added/edited event (first occurence) (blank: whatever)
	 * @return tempcode		The UI
	 */
	function _do_next_manager($title,$description,$id,$type,$date)
	{
		$archive_map=array('type'=>'misc','view'=>'day');
		if ($date!='') $archive_map['id']=$date;

		require_code('templates_donext');

		breadcrumb_set_self(do_lang_tempcode('DONE'));

		if ((is_null($id)) && (is_null($type)))
		{
			return do_next_manager($title,$description,
						NULL,
						NULL,
						/*		TYPED-ORDERED LIST OF 'LINKS'		*/
						/*	 page	 params				  zone	  */
						array('_SELF',array('type'=>'ad'),'_SELF',do_lang_tempcode('ADD_CALENDAR_EVENT')),							// Add one
						NULL,							 // Edit this
						has_specific_permission(get_member(),'edit_own_lowrange_content','cms_calendar')?array('_SELF',array('type'=>'ed'),'_SELF',do_lang_tempcode('EDIT_CALENDAR_EVENT')):NULL,											// Edit one
						NULL,							// View this
						array('calendar',$archive_map,get_module_zone('calendar'),do_lang('CALENDAR')),				// View archive
						NULL,	  // Add to category
						has_specific_permission(get_member(),'submit_cat_highrange_content','cms_calendar')?array('_SELF',array('type'=>'ac'),'_SELF',do_lang_tempcode('ADD_EVENT_TYPE')):NULL,					  // Add one category
						has_specific_permission(get_member(),'edit_own_cat_highrange_content','cms_calendar')?array('_SELF',array('type'=>'ec'),'_SELF',do_lang_tempcode('EDIT_EVENT_TYPE')):NULL,					  // Edit one category
						NULL,			 // Edit this category
						NULL,																						 // View this category
						NULL,
						NULL,
						NULL,
						NULL,
						NULL,
						NULL,
						do_lang_tempcode('EVENT_TYPES')
			);
		}

		return do_next_manager($title,$description,
					NULL,
					NULL,
					/*		TYPED-ORDERED LIST OF 'LINKS'		*/
					/*	 page	 params				  zone	  */
					array('_SELF',array('type'=>'ad','e_type'=>$type),'_SELF',do_lang_tempcode('ADD_CALENDAR_EVENT')),											// Add one
					(is_null($id) || (!has_specific_permission(get_member(),'edit_own_lowrange_content','cms_calendar',array('calendar','type'))))?NULL:array('_SELF',array('type'=>'_ed','id'=>$id),'_SELF',do_lang_tempcode('EDIT_THIS_CALENDAR_EVENT')),							 // Edit this
					has_specific_permission(get_member(),'edit_own_lowrange_content','cms_calendar')?array('_SELF',array('type'=>'ed'),'_SELF',do_lang_tempcode('EDIT_CALENDAR_EVENT')):NULL,											// Edit one
					is_null($id)?NULL:array('calendar',array('type'=>'view','id'=>$id),get_module_zone('calendar')),						  // View this
					array('calendar',$archive_map,get_module_zone('calendar'),do_lang('CALENDAR')),				// View archive
					NULL,																						// Add to category
					has_specific_permission(get_member(),'submit_cat_highrange_content','cms_calendar')?array('_SELF',array('type'=>'ac'),'_SELF',do_lang_tempcode('ADD_EVENT_TYPE')):NULL,				// Add one category
					has_specific_permission(get_member(),'edit_own_cat_highrange_content','cms_calendar')?array('_SELF',array('type'=>'ec'),'_SELF',do_lang_tempcode('EDIT_EVENT_TYPE')):NULL,				// Edit one category
					has_specific_permission(get_member(),'edit_own_cat_highrange_content','cms_calendar',array('calendar','type'))?array('_SELF',array('type'=>'_ec','id'=>$type),'_SELF',do_lang_tempcode('EDIT_THIS_EVENT_TYPE')):NULL,			  // Edit this category
					NULL,																						// View this category
					NULL,
					NULL,
					NULL,
					NULL,
					NULL,
					NULL,
					do_lang_tempcode('EVENT_TYPES')
		);
	}

}


