<?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		galleries
 */

/**
 * Module page class.
 */
class Module_galleries
{

	/**
	 * Standard modular info function.
	 *
	 * @return ?array	Map of module info (NULL: module is disabled).
	 */
	function info()
	{
		$info=array();
		$info['author']='Chris Graham';
		$info['organisation']='ocProducts';
		$info['hacked_by']=NULL;
		$info['hack_version']=NULL;
		$info['version']=8;
		$info['update_require_upgrade']=1;
		$info['locked']=false;
		return $info;
	}
	
	/**
	 * Standard modular uninstall function.
	 */
	function uninstall()
	{
		$GLOBALS['SITE_DB']->drop_if_exists('galleries');
		$GLOBALS['SITE_DB']->drop_if_exists('images');
		$GLOBALS['SITE_DB']->drop_if_exists('videos');
		$GLOBALS['SITE_DB']->drop_if_exists('video_transcoding');

		delete_config_option('default_video_width');
		delete_config_option('default_video_height');
		delete_config_option('maximum_image_size');
		delete_config_option('max_personal_gallery_images_low');
		delete_config_option('max_personal_gallery_images_high');
		delete_config_option('max_personal_gallery_videos_low');
		delete_config_option('max_personal_gallery_videos_high');
		delete_config_option('points_ADD_IMAGE');
		delete_config_option('points_ADD_VIDEO');
		delete_config_option('galleries_show_stats_count_galleries');
		delete_config_option('galleries_show_stats_count_images');
		delete_config_option('galleries_show_stats_count_videos');
		delete_config_option('show_empty_galleries');
		delete_config_option('gallery_name_order');
		delete_config_option('gallery_selectors');
		delete_config_option('reverse_thumb_order');
		delete_config_option('show_gallery_counts');
		delete_config_option('video_bitrate');
		delete_config_option('audio_bitrate');
		delete_config_option('ffmpeg_path');
		delete_config_option('transcoding_server');
		delete_config_option('transcoding_zencoder_api_key');
		delete_config_option('transcoding_zencoder_ftp_path');
		delete_config_option('video_width_setting');
		delete_config_option('video_height_setting');
		delete_config_option('galleries_subcat_narrowin');

		delete_specific_permission('may_download_gallery');
		delete_specific_permission('high_personal_gallery_limit');
		delete_specific_permission('no_personal_gallery_limit');

		$GLOBALS['SITE_DB']->query_delete('group_category_access',array('module_the_name'=>'galleries'));
	
		$GLOBALS['SITE_DB']->query_delete('trackbacks',array('trackback_for_type'=>'galleries'));

		deldir_contents(get_custom_file_base().'/uploads/galleries',true,true);

		deldir_contents(get_custom_file_base().'/uploads/galleries_thumbs',true);

		delete_menu_item_simple('_SEARCH:galleries:type=misc');
	}

	/**
	 * Standard modular install function.
	 *
	 * @param  ?integer	What version we're upgrading from (NULL: new install)
	 * @param  ?integer	What hack version we're upgrading from (NULL: new-install/not-upgrading-from-a-hacked-version)
	 */
	function install($upgrade_from=NULL,$upgrade_from_hack=NULL)
	{
		require_code('galleries');
		require_lang('galleries');
		require_code('galleries2');

		if (is_null($upgrade_from))
		{
			$GLOBALS['SITE_DB']->create_table('galleries',array(
				'name'=>'*ID_TEXT',
				'description'=>'LONG_TRANS',	// Comcode
				'teaser'=>'SHORT_TRANS',
				'fullname'=>'SHORT_TRANS',
				'add_date'=>'TIME',
				'rep_image'=>'URLPATH',
				'parent_id'=>'ID_TEXT',
				'watermark_top_left'=>'URLPATH',
				'watermark_top_right'=>'URLPATH',
				'watermark_bottom_left'=>'URLPATH',
				'watermark_bottom_right'=>'URLPATH',
				'accept_images'=>'BINARY',
				'accept_videos'=>'BINARY',
				'allow_rating'=>'BINARY',
				'allow_comments'=>'SHORT_INTEGER',
				'notes'=>'LONG_TEXT',
				'is_member_synched'=>'BINARY',
				'flow_mode_interface'=>'BINARY',
				'gallery_views'=>'INTEGER',
				'g_owner'=>'?AUTO_LINK',
			));
			$GLOBALS['SITE_DB']->create_index('galleries','watermark_top_left',array('watermark_top_left'));
			$GLOBALS['SITE_DB']->create_index('galleries','watermark_top_right',array('watermark_top_right'));
			$GLOBALS['SITE_DB']->create_index('galleries','watermark_bottom_left',array('watermark_bottom_left'));
			$GLOBALS['SITE_DB']->create_index('galleries','watermark_bottom_right',array('watermark_bottom_right'));
			$GLOBALS['SITE_DB']->create_index('galleries','gadd_date',array('add_date'));
			$GLOBALS['SITE_DB']->create_index('galleries','parent_id',array('parent_id'));
	
			$GLOBALS['SITE_DB']->create_table('images',array(
				'id'=>'*AUTO',
				'cat'=>'ID_TEXT',
				'url'=>'URLPATH',
				'thumb_url'=>'URLPATH',
				'comments'=>'LONG_TRANS',	// Comcode
				'allow_rating'=>'BINARY',
				'allow_comments'=>'SHORT_INTEGER',
				'allow_trackbacks'=>'BINARY',
				'notes'=>'LONG_TEXT',
				'submitter'=>'USER',
				'validated'=>'BINARY',
				'add_date'=>'TIME',
				'edit_date'=>'?TIME',
				'image_views'=>'INTEGER',
				'title'=>'SHORT_TRANS',
			));
	
			$GLOBALS['SITE_DB']->create_index('images','image_views',array('image_views'));
			$GLOBALS['SITE_DB']->create_index('images','category_list',array('cat'));
			$GLOBALS['SITE_DB']->create_index('images','i_validated',array('validated'));
			$GLOBALS['SITE_DB']->create_index('images','xis',array('submitter'));
			$GLOBALS['SITE_DB']->create_index('images','iadd_date',array('add_date'));

			add_config_option('ADD_IMAGE','points_ADD_IMAGE','integer','return addon_installed(\'points\')?\'100\':NULL;','POINTS','COUNT_POINTS_GIVEN');
			add_config_option('ADD_VIDEO','points_ADD_VIDEO','integer','return addon_installed(\'points\')?\'100\':NULL;','POINTS','COUNT_POINTS_GIVEN');

			require_lang('galleries');
			add_menu_item_simple('main_content',NULL,'GALLERIES','_SEARCH:galleries:type=misc');
		}
	
		if ((!is_null($upgrade_from)) && ($upgrade_from<3))
		{
			$GLOBALS['SITE_DB']->add_table_field('galleries','teaser','SHORT_TRANS',2);
			$GLOBALS['SITE_DB']->add_table_field('galleries','rep_image','URLPATH');
			$GLOBALS['SITE_DB']->add_table_field('galleries','parent_id','ID_TEXT','root');
			$GLOBALS['SITE_DB']->add_table_field('galleries','accept_images','BINARY',1);
			$GLOBALS['SITE_DB']->add_table_field('galleries','accept_videos','BINARY',1);
			$GLOBALS['SITE_DB']->add_table_field('galleries','watermark_top_left','URLPATH');
			$GLOBALS['SITE_DB']->add_table_field('galleries','watermark_top_right','URLPATH');
			$GLOBALS['SITE_DB']->add_table_field('galleries','watermark_bottom_left','URLPATH');
			$GLOBALS['SITE_DB']->add_table_field('galleries','watermark_bottom_right','URLPATH');
			$GLOBALS['SITE_DB']->add_table_field('galleries','is_member_synched','BINARY');
			$GLOBALS['SITE_DB']->add_table_field('galleries','flow_mode_interface','BINARY');
			$GLOBALS['SITE_DB']->add_table_field('galleries','allow_rating','BINARY',1);
			$GLOBALS['SITE_DB']->add_table_field('galleries','allow_comments','SHORT_INTEGER',1);
	
			$GLOBALS['SITE_DB']->add_table_field('images','allow_trackbacks','BINARY',1);
		}

		if ((is_null($upgrade_from)) || ($upgrade_from<3))
		{
			add_specific_permission('GALLERIES','may_download_gallery',false);

			$GLOBALS['SITE_DB']->create_table('videos',array(
				'id'=>'*AUTO',
				'cat'=>'ID_TEXT',
				'url'=>'URLPATH',
				'thumb_url'=>'URLPATH',
				'comments'=>'LONG_TRANS',
				'allow_rating'=>'BINARY',
				'allow_comments'=>'SHORT_INTEGER',
				'allow_trackbacks'=>'BINARY',
				'notes'=>'LONG_TEXT',
				'submitter'=>'USER',
				'validated'=>'BINARY',
				'add_date'=>'TIME',
				'edit_date'=>'?TIME',
				'video_views'=>'INTEGER',
				'video_width'=>'INTEGER',
				'video_height'=>'INTEGER',
				'video_length'=>'INTEGER',
				'title'=>'SHORT_TRANS',
			));
	
			$GLOBALS['SITE_DB']->create_index('videos','video_views',array('video_views'));
			$GLOBALS['SITE_DB']->create_index('videos','vs',array('submitter'));
			$GLOBALS['SITE_DB']->create_index('videos','v_validated',array('validated'));
			$GLOBALS['SITE_DB']->create_index('videos','category_list',array('cat'));
			$GLOBALS['SITE_DB']->create_index('videos','vadd_date',array('add_date'));
	
			add_config_option('DEFAULT_VIDEO_WIDTH','default_video_width','integer','return \'320\';','FEATURE','GALLERIES');
			add_config_option('DEFAULT_VIDEO_HEIGHT','default_video_height','integer','return \'240\';','FEATURE','GALLERIES');
			add_config_option('MAXIMUM_IMAGE_SIZE','maximum_image_size','integer','return \'1024\';','FEATURE','GALLERIES');
			add_config_option('GALLERY_IMAGE_LIMIT_LOW','max_personal_gallery_images_low','integer','return \'5\';','FEATURE','GALLERIES');
			add_config_option('GALLERY_IMAGE_LIMIT_HIGH','max_personal_gallery_images_high','integer','return \'10\';','FEATURE','GALLERIES');
			add_config_option('GALLERY_VIDEO_LIMIT_LOW','max_personal_gallery_videos_low','integer','return \'2\';','FEATURE','GALLERIES');
			add_config_option('GALLERY_VIDEO_LIMIT_HIGH','max_personal_gallery_videos_high','integer','return \'5\';','FEATURE','GALLERIES');
			add_specific_permission('GALLERIES','high_personal_gallery_limit',false);
			add_specific_permission('GALLERIES','no_personal_gallery_limit',false);

			// Add root gallery
			add_gallery('root',do_lang('GALLERIES_HOME'),'','','','',1,1,0,1);
			$groups=$GLOBALS['FORUM_DRIVER']->get_usergroup_list(false,true);
			foreach (array_keys($groups) as $group_id)
				$GLOBALS['SITE_DB']->query_insert('group_category_access',array('module_the_name'=>'galleries','category_name'=>'root','group_id'=>$group_id));
		}

		if ((is_null($upgrade_from)) || ($upgrade_from<4))
		{
			add_config_option('GALLERIES','galleries_show_stats_count_galleries','tick','return addon_installed(\'stats_block\')?\'0\':NULL;','BLOCKS','STATISTICS');
			add_config_option('IMAGES','galleries_show_stats_count_images','tick','return addon_installed(\'stats_block\')?\'0\':NULL;','BLOCKS','STATISTICS');
			add_config_option('VIDEOS','galleries_show_stats_count_videos','tick','return addon_installed(\'stats_block\')?\'0\':NULL;','BLOCKS','STATISTICS');
			add_config_option('SHOW_EMPTY_GALLERIES','show_empty_galleries','tick','return \'1\';','FEATURE','GALLERIES');
			add_config_option('GALLERY_NAME_ORDER','gallery_name_order','tick','return \'0\';','FEATURE','GALLERIES');
		}

		if ((is_null($upgrade_from)) || ($upgrade_from<5))
		{
			add_config_option('GALLERY_SELECTORS','gallery_selectors','line','return is_null($old=get_value(\'gallery_selectors\'))?\'12,24,36,64,128\':$old;','FEATURE','GALLERIES');
			add_config_option('REVERSE_THUMB_ORDER','reverse_thumb_order','tick','return is_null($old=get_value(\'reverse_thumb_order\'))?\'0\':$old;','FEATURE','GALLERIES');
			add_config_option('SHOW_GALLERY_COUNTS','show_gallery_counts','tick','return is_null($old=get_value(\'show_gallery_counts\'))?((get_forum_type()==\'ocf\')?\'0\':NULL):$old;','FEATURE','GALLERIES');
		}

		if ((is_null($upgrade_from)) || ($upgrade_from<6))
		{
			add_config_option('VIDEO_BITRATE','video_bitrate','integer','return \'1000\';','FEATURE','TRANSCODING');
			add_config_option('AUDIO_BITRATE','audio_bitrate','integer','return \'192\';','FEATURE','TRANSCODING');
			add_config_option('VIDEO_WIDTH_SETTING','video_width_setting','integer','return \'720\';','FEATURE','TRANSCODING');
			add_config_option('VIDEO_HEIGHT_SETTING','video_height_setting','integer','return \'480\';','FEATURE','TRANSCODING');
			$GLOBALS['SITE_DB']->create_index('videos','ftjoin_vcomments',array('comments'));
			$GLOBALS['SITE_DB']->create_index('images','ftjoin_icomments',array('comments'));
			$GLOBALS['SITE_DB']->create_index('galleries','ftjoin_gfullname',array('fullname'));
			$GLOBALS['SITE_DB']->create_index('galleries','ftjoin_gdescrip',array('description'));
		}

		if ((is_null($upgrade_from)) || ($upgrade_from<7))
		{
			$old_option=get_option('ffmpeg_path',true);
			if (is_null($old_option)) $old_option='';
			delete_config_option('ffmpeg_path');
			add_config_option('TRANSCODING_ZENCODER_API_KEY','transcoding_zencoder_api_key','line','return \'\';','FEATURE','TRANSCODING');
			add_config_option('TRANSCODING_ZENCODER_FTP_PATH','transcoding_zencoder_ftp_path','line','return \'\';','FEATURE','TRANSCODING');
			add_config_option('TRANSCODING_SERVER','transcoding_server','line','return \'\';','FEATURE','TRANSCODING');
			add_config_option('FFMPEG_PATH','ffmpeg_path','line','return \''.addslashes($old_option).'\';','FEATURE','TRANSCODING');

			$GLOBALS['SITE_DB']->create_table('video_transcoding',array(
				't_id'=>'*ID_TEXT',
				't_error'=>'LONG_TEXT',
				't_url'=>'URLPATH',
				't_table'=>'ID_TEXT',
				't_url_field'=>'ID_TEXT',
				't_orig_filename_field'=>'ID_TEXT',
				't_width_field'=>'ID_TEXT',
				't_height_field'=>'ID_TEXT',
				't_output_filename'=>'ID_TEXT',
			));
		}

		if ((!is_null($upgrade_from)) && ($upgrade_from<7))
		{
			$GLOBALS['SITE_DB']->add_table_field('videos','title','SHORT_TRANS');
			$GLOBALS['SITE_DB']->add_table_field('images','title','SHORT_TRANS');
			$GLOBALS['SITE_DB']->add_table_field('galleries','gallery_views','INTEGER');
			$GLOBALS['SITE_DB']->add_table_field('galleries','g_owner','?USER');
		}

		if ((is_null($upgrade_from)) || ($upgrade_from<8))
		{
			add_config_option('GALLERIES_SUBCAT_NARROWIN','galleries_subcat_narrowin','tick','return \'1\';','FEATURE','SECTION_GALLERIES');
		}
	}
	
	/**
	 * 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('list'=>'LIST_OF_GALLERIES','misc'=>'GALLERIES_HOME');
	}

	/**
	 * Standard modular page-link finder function (does not return the main entry-points that are not inside the tree).
	 *
	 * @param  ?integer  The number of tree levels to computer (NULL: no limit)
	 * @param  boolean	Whether to not return stuff that does not support permissions (unless it is underneath something that does).
	 * @param  ?string	Position to start at in the tree. Does not need to be respected. (NULL: from root)
	 * @param  boolean	Whether to avoid returning categories.
	 * @return ?array	 	A tuple: 1) full tree structure [made up of (pagelink, permission-module, permissions-id, title, children, ?entry point for the children, ?children permission module, ?whether there are children) OR a list of maps from a get_* function] 2) permissions-page 3) optional base entry-point for the tree 4) optional permission-module 5) optional permissions-id (NULL: disabled).
	 */
	function get_page_links($max_depth=NULL,$require_permission_support=false,$start_at=NULL,$dont_care_about_categories=false)
	{
		unset($require_permission_support);

		$permission_page='cms_galleries';

		$category_data_count=$GLOBALS['SITE_DB']->query_value('galleries','COUNT(*)');
		if ($category_data_count>2000) $dont_care_about_categories=true;

		require_code('galleries');
		$category_id=NULL;
		if (!is_null($start_at))
		{
			$matches=array();
			if (preg_match('#[^:]*:galleries:type=misc:id=(.*)#',$start_at,$matches)!=0) $category_id=$matches[1];
		}
		$adjusted_max_depth=is_null($max_depth)?NULL:(is_null($category_id)?($max_depth-1):$max_depth);
		return array($dont_care_about_categories?array():get_gallery_tree($category_id,'',NULL,true,NULL,false,false,true,false,$adjusted_max_depth,NULL,false),$permission_page,'_SELF:_SELF:type=misc:id=!','galleries');
	}

	/**
	 * Standard modular new-style deep page-link finder function (does not return the main entry-points).
	 *
	 * @param  string  	Callback function to send discovered page-links to.
	 * @param  MEMBER		The member we are finding stuff for (we only find what the member can view).
	 * @param  integer	Code for how deep we are tunnelling down, in terms of whether we are getting entries as well as categories.
	 * @param  string		Stub used to create page-links. This is passed in because we don't want to assume a zone or page name within this function.
	 * @param  ?string	Where we're looking under (NULL: root of tree). We typically will NOT show a root node as there's often already an entry-point representing it.
	 * @param  integer	Our recursion depth (used to calculate importance of page-link, used for instance by Google sitemap). Deeper is typically less important.
	 * @param  ?array		Non-standard for API [extra parameter tacked on] (NULL: yet unknown). Contents of database table for performance.
	 * @param  ?array		Non-standard for API [extra parameter tacked on] (NULL: yet unknown). Contents of database table for performance.
	 * @param  ?array		Non-standard for API [extra parameter tacked on] (NULL: yet unknown). Contents of database table for performance.
	 */
	function get_sitemap_pagelinks($callback,$member_id,$depth,$pagelink_stub,$parent_pagelink=NULL,$recurse_level=0,$category_data=NULL,$image_data=NULL,$video_data=NULL)
	{
		// This is where we start
		if (is_null($parent_pagelink))
		{
			$parent_pagelink=$pagelink_stub.':misc'; // This is the entry-point we're under
			$parent_attributes=array('id'=>'root');
		} else
		{
			list(,$parent_attributes,)=page_link_decode($parent_pagelink);
		}

		// We read in all data for efficiency
		if (is_null($category_data))
		{
			$category_data_count=$GLOBALS['SITE_DB']->query_value('galleries','COUNT(*)');
			if ($category_data_count>2000)
			{
				$category_data=$GLOBALS['SITE_DB']->query('SELECT name AS id,name AS title,parent_id,add_date FROM '.get_table_prefix().'galleries WHERE name NOT LIKE \''.db_encode_like('member\_%').'\'');
			} else
			{
				$category_data=$GLOBALS['SITE_DB']->query_select('galleries',array('name AS id','name AS title','parent_id','add_date'));
			}
		}
		if (is_null($image_data))
		{
			$image_data_count=$GLOBALS['SITE_DB']->query_value('images','COUNT(*)');
			$image_data=($image_data_count>2000)?array():$GLOBALS['SITE_DB']->query_select('images d LEFT JOIN '.get_table_prefix().'translate t ON '.db_string_equal_to('language',user_lang()).' AND t.id=d.comments',array('d.comments','d.id','t.text_original AS title','cat AS category_id','add_date','edit_date'));
		}
		if (is_null($video_data))
		{
			$video_data_count=$GLOBALS['SITE_DB']->query_value('videos','COUNT(*)');
			$video_data=($video_data_count>2000)?array():$GLOBALS['SITE_DB']->query_select('videos d LEFT JOIN '.get_table_prefix().'translate t ON '.db_string_equal_to('language',user_lang()).' AND t.id=d.comments',array('d.comments','d.id','t.text_original AS title','cat AS category_id','add_date','edit_date'));
		}

		// Subcategories
		foreach ($category_data as $row)
		{
			if (($row['parent_id']!='') && ($row['parent_id']==$parent_attributes['id']))
			{
				$pagelink=$pagelink_stub.'misc:'.$row['id'];
				if (__CLASS__!='')
				{
					$this->get_sitemap_pagelinks($callback,$member_id,$depth,$pagelink_stub,$pagelink,$recurse_level+1,$category_data,$image_data,$video_data); // Recurse
				} else
				{
					call_user_func_array(__FUNCTION__,array($callback,$member_id,$depth,$pagelink_stub,$pagelink,$recurse_level+1,$category_data,$image_data,$video_data)); // Recurse
				}
				if (has_category_access($member_id,'galleries',$row['id']))
				{
					call_user_func_array($callback,array($pagelink,$parent_pagelink,$row['add_date'],NULL,max(0.7-$recurse_level*0.1,0.3),$row['title'])); // Callback
				} else // Not accessible: we need to copy the node through, but we will flag it 'Unknown' and say it's not accessible.
				{
					call_user_func_array($callback,array($pagelink,$parent_pagelink,$row['add_date'],NULL,max(0.7-$recurse_level*0.1,0.3),do_lang('UNKNOWN'),false)); // Callback
				}
			}
		}

		// Entries
		if (($depth>=DEPTH__ENTRIES) && (has_category_access($member_id,'galleries',$parent_attributes['id'])))
		{
			foreach ($image_data as $row)
			{
				if ($row['category_id']==$parent_attributes['id'])
				{
					$pagelink=$pagelink_stub.'image:'.strval($row['id']);
					if (is_null($row['title'])) $row['title']=get_translated_text($row['comments']);
					call_user_func_array($callback,array($pagelink,$parent_pagelink,$row['add_date'],$row['edit_date'],0.2,$row['title'])); // Callback
				}
			}
			foreach ($video_data as $row)
			{
				if ($row['category_id']==$parent_attributes['id'])
				{
					$pagelink=$pagelink_stub.'video:'.strval($row['id']);
					if (is_null($row['title'])) $row['title']=get_translated_text($row['comments']);
					call_user_func_array($callback,array($pagelink,$parent_pagelink,$row['add_date'],$row['edit_date'],0.2,$row['title'])); // Callback
				}
			}
		}
	}

	/**
	 * Convert a page link to a category ID and category permission module type.
	 *
	 * @param  string	The page link
	 * @return array	The pair
	 */
	function extract_page_link_permissions($page_link)
	{
		$matches=array();
		preg_match('#^([^:]*):([^:]*):type=misc:id=(.*)$#',$page_link,$matches);
		return array($matches[3],'galleries');
	}

	/**
	 * Standard modular run function.
	 *
	 * @return tempcode	The result of execution.
	 */
	function run()
	{
		require_code('galleries');
		require_lang('galleries');
		require_code('feedback');
		require_css('galleries');

		global $NON_CANONICAL_PARAMS;
		$NON_CANONICAL_PARAMS[]='max';
		$NON_CANONICAL_PARAMS[]='start';
		$NON_CANONICAL_PARAMS[]='days';

		// What are we doing?
		$type=get_param('type','misc');
		if ($type=='image') return $this->show_image();
		if ($type=='video') return $this->show_video();
		if ($type=='misc') return $this->do_gallery();
		if ($type=='list') return $this->list_galleries();

		return new ocp_tempcode();
	}
	
	/**
	 * The UI to list all galleries for browsing.
	 *
	 * @return tempcode		The UI
	 */
	function list_galleries()
	{
		$title=get_page_title('LIST_OF_GALLERIES');

		$GLOBALS['FEED_URL']=find_script('backend').'?mode=galleries&filter=';

		$count=$GLOBALS['SITE_DB']->query_value('galleries','COUNT(*)');
		if ($count>500) warn_exit(do_lang_tempcode('TOO_MANY_TO_CHOOSE_FROM'));
		$rows=$GLOBALS['SITE_DB']->query_select('galleries',array('*'));
		$out=new ocp_tempcode();
		foreach ($rows as $myrow)
		{
			if (substr($myrow['name'],0,9)=='download_') continue;

			if (get_option('show_empty_galleries')!='1')
			{
				$count=$GLOBALS['SITE_DB']->query_value('images','COUNT(*)',array('cat'=>$myrow['name']));
				if ($count==0)
				{
					$count2=$GLOBALS['SITE_DB']->query_value('videos','COUNT(*)',array('cat'=>$myrow['name']));
					if ($count2==0) continue;
				}
			}

			if (!has_category_access(get_member(),'galleries',$myrow['name'])) continue;

			$url=build_url(array('page'=>'_SELF','id'=>$myrow['name'],'type'=>'misc'),'_SELF');
			$name=get_translated_text($myrow['fullname']);
			if ($name=='') $name=$myrow['name'];
	
			$out->attach(do_template('INDEX_SCREEN_ENTRY',array('_GUID'=>'8a98d6e306a71398b57aa28b92f9cc01','NAME'=>$name,'URL'=>$url)));
		}

		return do_template('INDEX_SCREEN',array('_GUID'=>'76b23ef79ede9908a8664cf82bea7568','TITLE'=>$title,'PRE'=>'','POST'=>'','CONTENT'=>$out));
	}

	/**
	 * The UI to show a gallery.
	 *
	 * @return tempcode		The UI
	 */
	function do_gallery()
	{
		require_code('images');

		$cat=get_param('id','root');
		$GLOBALS['FEED_URL']=find_script('backend').'?mode=galleries&filter='.$cat;
		$root=get_param('root','root');
	
		if (!has_category_access(get_member(),'galleries',$cat)) access_denied('CATEGORY_ACCESS');

		// Info on our gallery
		$gallery_rows=$GLOBALS['SITE_DB']->query_select('galleries',array('*'),array('name'=>$cat),'',1);
		$implied_existence=false;
		if (!array_key_exists(0,$gallery_rows))
		{
			// Possibly we will 'imply' it's existence if this is a member gallery; allows normal rendering to finish, with add links
			$matches=array();
			if (preg_match('#^member\_(\d+)\_(.*)$#',$cat,$matches)!=0)
			{
				$username=$GLOBALS['FORUM_DRIVER']->get_username(intval($matches[1]));
				if (!is_null($username))
					$gallery_rows=$GLOBALS['SITE_DB']->query_select('galleries',array('*'),array('name'=>$matches[2]),'',1);
			}
			if (!array_key_exists(0,$gallery_rows))
				return warn_screen(get_page_title('ERROR_OCCURRED'),do_lang_tempcode('MISSING_RESOURCE'));
			$myrow=$gallery_rows[0];
			$myrow['is_member_synched']=0;
			$fullname=do_lang('PERSONAL_GALLERY_OF',$username,get_translated_text($myrow['fullname']));
			$myrow['parent_id']=$matches[2];
			$implied_existence=true;
		} else
		{
			$myrow=$gallery_rows[0];
			$fullname=get_translated_text($myrow['fullname']);
		}
		if ($fullname=='') $fullname=$cat;

		$description=get_translated_tempcode($myrow['description']);
	
		if ((has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_submit_permission('mid',get_member(),get_ip_address(),'cms_galleries',array('galleries',$cat))))
		{
			$submit_cat=($myrow['is_member_synched']==1)?('member_'.strval(get_member()).'_'.$cat):$cat;
			$submit_image_url=($myrow['accept_images']==0)?new ocp_tempcode():build_url(array('page'=>'cms_galleries','type'=>'ad','cat'=>$submit_cat),get_module_zone('cms_galleries'));
			$submit_video_url=($myrow['accept_videos']==0)?new ocp_tempcode():build_url(array('page'=>'cms_galleries','type'=>'av','cat'=>$submit_cat),get_module_zone('cms_galleries'));
		} else
		{
			$submit_image_url=new ocp_tempcode();
			$submit_video_url=new ocp_tempcode();
		}

		if ((!$implied_existence) && (has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_edit_permission('cat_mid',get_member(),get_member_id_from_gallery_name($cat),'cms_galleries',array('galleries',$cat))))
		{
			$edit_url=build_url(array('page'=>'cms_galleries','type'=>'_ec','id'=>$cat),get_module_zone('cms_galleries'));
		} else $edit_url=new ocp_tempcode();

		if ((!$implied_existence) && (has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_submit_permission('cat_mid',get_member(),get_ip_address(),'cms_galleries')))
		{
			$add_gallery_url=build_url(array('page'=>'cms_galleries','type'=>'ac','cat'=>$cat),get_module_zone('cms_galleries'));
		} else $add_gallery_url=new ocp_tempcode();

		$may_download_gallery=has_specific_permission(get_member(),'may_download_gallery','galleries',array('galleries',$cat));

		$tree=gallery_breadcrumbs($cat,$root,true,get_module_zone('galleries'));
		if (!$tree->is_empty())
			$tree->attach(do_template('BREADCRUMB_ESCAPED'));
		if (has_specific_permission(get_member(),'open_virtual_roots'))
		{
			$url=get_self_url(false,false,array('root'=>$cat));
			$tree->attach(hyperlink($url,escape_html($fullname),false,false,do_lang_tempcode('VIRTUAL_ROOT')));
		} else $tree->attach('<span>'.escape_html($fullname).'</span>');

		$myrow['flow_mode_interface']=get_param_integer('flow_mode_interface',$myrow['flow_mode_interface']); // Allow override via URL

		// Flow mode puts emphasis on subgalleries, rather than entries; it is subgalleries that there are a lot of, rather than entries
		if ($myrow['flow_mode_interface']==1)
		{
			$max=get_param_integer('max',get_default_gallery_max());
			if ($max<1) $max=1;
			$start=get_param_integer('start',0);
		} else
		{
			$max=NULL;
			$start=NULL;
		}

		// Subgalleries
		$order='add_date DESC';
		if (get_option('gallery_name_order')=='1')
		{
			$order='name ASC';
		}

		$rows_children=$GLOBALS['SITE_DB']->query_select('galleries',array('*'),array('parent_id'=>$cat),'ORDER BY '.$order,200/*reasonable limit*/);
		$children=new ocp_tempcode();
		$num_galleries=0;
		if (count($rows_children)==200) $rows_children=array(); // Lots of personal galleries. Will need to be reached via member profiles
		foreach ($rows_children as $child)
		{
			if (substr($child['name'],0,9)=='download_') continue;
			if (!has_category_access(get_member(),'galleries',$child['name'])) continue;

			if ((get_option('show_empty_galleries')=='1') || (gallery_has_content($child['name'])))
			{
				if ((is_null($max)) || (($num_galleries>=$start) && ($num_galleries<$start+$max)))
				{
					$content=show_gallery_box($child,$root,true,get_zone_name(),get_option('show_empty_galleries')!='1');
					if (!$content->is_empty())
						$children->attach(do_template('GALLERY_SUBGALLERY_WRAP',array('CONTENT'=>$content)));
				}
				$num_galleries++;
			}
		}
		// Views
		if (get_db_type()!='xml')
		{
			$myrow['gallery_views']++;
			$GLOBALS['SITE_DB']->query_update('galleries',array('gallery_views'=>$myrow['gallery_views']),array('name'=>$cat),'',1,NULL,false,true);
		}

		// Page title
		if (addon_installed('awards'))
		{
			require_code('awards');
			$awards=find_awards_for('gallery',$cat);
		} else $awards=array();
		$title_to_use=do_lang_tempcode('_GALLERY',escape_html($fullname));
		$title_to_use_2=do_lang('_GALLERY',$fullname);
		$title=get_page_title($title_to_use,false,NULL,NULL,$awards);

		seo_meta_load_for('gallery',$cat,$title_to_use_2);

		$rep_image=$myrow['rep_image'];

		if (post_param_integer('rating_'.$cat,-1)!=-1) decache('main_top_galleries');

		list($rating_details,$comment_details,$trackback_details)=embed_feedback_systems(
			get_page_name(),
			$cat,
			$myrow['allow_rating'],
			$myrow['allow_comments'],
			0,
			1,
			NULL,
			build_url(array('page'=>'_SELF'),'_SELF',NULL,true,false,true),
			$title_to_use_2,
			get_value('comment_forum__galleries')
		);

		breadcrumb_add_segment($tree);

		$GLOBALS['META_DATA']+=array(
			'created'=>date('Y-m-d',$myrow['add_date']),
			'creator'=>is_null($myrow['g_owner'])?'':$GLOBALS['FORUM_DRIVER']->get_username($myrow['g_owner']),
			'publisher'=>'', // blank means same as creator
			'modified'=>'',
			'type'=>'Gallery',
			'title'=>$fullname,
			'identifier'=>'_SEARCH:galleries:misc:'.$cat,
			'description'=>get_translated_text($myrow['description']),
		);
		if ($rep_image!='')
		{
			$GLOBALS['META_DATA']+=array(
				'image'=>(url_is_local($rep_image)?(get_custom_base_url().'/'):'').$rep_image,
			);
		}

		// Sorting
		list($sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos)=$this->get_sort_order();
		$_selectors=array(
			'compound_rating DESC'=>'POPULARITY',
			'url ASC'=>'FILENAME',
			'add_date ASC'=>'OLDEST_FIRST',
			'add_date DESC'=>'NEWEST_FIRST'
		);
		$selectors=new ocp_tempcode();
		foreach ($_selectors as $selector_value=>$selector_name)
		{
			$selected=($sort==$selector_value);
			$selectors->attach(do_template('RESULTS_BROWSER_SORTER',array('SELECTED'=>$selected,'NAME'=>do_lang_tempcode($selector_name),'VALUE'=>$selector_value)));
		}
		$sort_url=get_self_url(false,false,array('sort'=>NULL),false,true);
		$sorting=do_template('RESULTS_BROWSER_SORT',array('SORT'=>'sort','RAND'=>uniqid(''),'URL'=>$sort_url,'SELECTORS'=>$selectors));

		if ($myrow['flow_mode_interface']==1)
			return $this->do_gallery_flow_mode($rating_details,$comment_details,$cat,$root,$description,$children,$may_download_gallery,$edit_url,$add_gallery_url,$submit_image_url,$submit_video_url,$title,$rep_image,$start,$max,$num_galleries,$fullname,$sorting);
		else return $this->do_gallery_regular_mode($rating_details,$comment_details,$cat,$root,$description,$children,$may_download_gallery,$edit_url,$add_gallery_url,$submit_image_url,$submit_video_url,$title,$fullname,$sorting);
	}

	/**
	 * The UI for a "flow mode" gallery.
	 *
	 * @param  tempcode		Rating area
	 * @param  tempcode		Commenting area
	 * @param  ID_TEXT		Our gallery ID
	 * @param  ID_TEXT		Virtual root gallery
	 * @param  tempcode		The description of the gallery
	 * @param  tempcode		The tempcode for our visible child galleries
	 * @param  boolean		Whether may "download this gallery"
	 * @param  tempcode		The URL to "edit this gallery"
	 * @param  tempcode		The URL to "add a gallery"
	 * @param  tempcode		The URL to "submit an image to this gallery"
	 * @param  tempcode		The URL to "submit a video to this gallery"
	 * @param  tempcode		The title of the page (our of get_page_title)
	 * @param  URLPATH		The representative image for the gallery
	 * @param  integer		The start position we are in browsing through child galleries
	 * @param  integer		The maximum number of child galleries we can display per page
	 * @param  integer		The number of child galleries we have
	 * @param  string			The gallery title
	 * @param  tempcode		Sorting UI
	 * @return tempcode		The UI
	 */
	function do_gallery_flow_mode($rating_details,$comment_details,$cat,$root,$description,$children,$may_download,$edit_url,$add_gallery_url,$submit_image_url,$submit_video_url,$title,$rep_image,$start,$max,$num_galleries,$fullname,$sorting)
	{
		list($sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos)=$this->get_sort_order();
		
		$page_num=intval(floor(floatval($start)/floatval($max)))+1;
		$num_pages=intval(ceil(floatval($num_galleries)/floatval($max)));
		$image_select=get_param('select','*');
		$video_select=get_param('video_select','*');
		$previous=($page_num==1)?new ocp_tempcode():build_url(array('page'=>'_SELF','start'=>(max($start-$max,0)==0)?NULL:max($start-$max,0),'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select),'_SELF',NULL,true);
		$next=($page_num==$num_pages)?new ocp_tempcode():build_url(array('page'=>'_SELF','start'=>$start+$max,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select),'_SELF',NULL,true);
		if ($num_pages<2)
		{
			$browse=new ocp_tempcode();
		} else
		{
			$browse=do_template('NEXT_BROWSER_BROWSE_NEXT',array('_GUID'=>'5a01713ab670f1eb1dd17bde663e6e9f','PREVIOUS_LINK'=>$previous,'NEXT_LINK'=>$next,'PAGE_NUM'=>integer_format($page_num),'NUM_PAGES'=>integer_format($num_pages)));
		}

		// View current entry
		$row=NULL;
		$current_entry=new ocp_tempcode();
		$view_url=new ocp_tempcode();
		$full_url='';
		$entry_edit_url=new ocp_tempcode();
		$entry_rating_details=new ocp_tempcode();
		$entry_comment_details=new ocp_tempcode();
		$entry_trackback_details=new ocp_tempcode();
		$entry_add_date_raw='';
		$entry_edit_date_raw='';
		$entry_views='';
		$entry_title='';
		$entry_submitter=NULL;
		$entry_description=new ocp_tempcode();
		$probe_type=get_param('probe_type','first');
		$probe_id=get_param_integer('probe_id',0);
		if ($probe_type=='first')
		{
			$where=db_string_equal_to('cat',$cat);
			if (!has_specific_permission(get_member(),'see_unvalidated')) $where.=' AND validated=1';
			if (get_param('days','')!='') $where.=' AND add_date>'.strval(time()-get_param_integer('days')*60*60*24);
			$first_video=$GLOBALS['SITE_DB']->query('SELECT *'.$sql_suffix_videos.' FROM '.get_table_prefix().'videos e WHERE '.$where.' ORDER BY '.$sort,1);
			if (array_key_exists(0,$first_video))
			{
				$row=$first_video[0];
				$probe_type='video';
				$probe_id=$row['id'];
			} else
			{
				$where=db_string_equal_to('cat',$cat);
				if (!has_specific_permission(get_member(),'see_unvalidated')) $where.=' AND validated=1';
				if (get_param('days','')!='') $where.=' AND add_date>'.strval(time()-get_param_integer('days')*60*60*24);
				$first_image=$GLOBALS['SITE_DB']->query('SELECT *'.$sql_suffix_images.' FROM '.get_table_prefix().'images e WHERE '.$where.' ORDER BY '.$sort,1);
				if (array_key_exists(0,$first_image))
				{
					$row=$first_image[0];
					$probe_type='image';
					$probe_id=$row['id'];
				} // If else, then we have no probe_type, and thus won't be able to show anything
			}
		}
		if ((!is_null($row)) && ($row['validated']==0))
		{
			if (!has_specific_permission(get_member(),'jump_to_unvalidated'))
				access_denied('SPECIFIC_PERMISSION','jump_to_unvalidated');

			$warning_details=do_template('WARNING_TABLE',array('WARNING'=>do_lang_tempcode((get_param_integer('redirected',0)==1)?'UNVALIDATED_TEXT_NON_DIRECT':'UNVALIDATED_TEXT')));
		} else $warning_details=new ocp_tempcode();
		switch ($probe_type)
		{
			case 'video':
				if (is_null($row))
				{
					$map=array('cat'=>$cat,'id'=>$probe_id);
					if (!has_specific_permission(get_member(),'see_unvalidated')) $map['validated']=1;
					$rows=$GLOBALS['SITE_DB']->query_select('videos',array('*'),$map,'',1);
					if (!array_key_exists(0,$rows))
					{
						attach_message(do_lang_tempcode('MISSING_RESOURCE','warn'));
						break;
					}
					$row=$rows[0];
				}
	
				if ((has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_edit_permission('mid',get_member(),$row['submitter'],'cms_galleries',array('galleries',$cat))))
				{
					$entry_edit_url=build_url(array('page'=>'cms_galleries','type'=>'_ev','id'=>$row['id']),get_module_zone('cms_galleries'));
				}

				/*$view_url=build_url(array('page'=>'_SELF','type'=>'video','root'=>($root=='root')?NULL:$root,'wide'=>1,'id'=>$row['id']),'_SELF');
				$thumb_url=$row['thumb_url'];
				if (($thumb_url!='') && (url_is_local($thumb_url))) $thumb_url=get_custom_base_url().'/'.$thumb_url;
				if ($thumb_url=='') $thumb_url=find_theme_image('na');
				$thumb=do_image_thumb($thumb_url,'');*/

				// Video HTML
				$thumb_url=$row['thumb_url'];
				$url=$row['url'];
				$video_player=show_gallery_media($url,$thumb_url,$row['video_width'],$row['video_height'],$row['video_length']);
				$view_url=build_url(array('page'=>'_SELF','type'=>'video','id'=>$row['id'],'wide'=>1,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select),'_SELF');

				// Some extra variables relating to the currently selected entry
				$entry_title=get_translated_text($row['title']);
				$entry_rating_details=get_rating_box(get_self_url(true),$entry_title,'videos',strval($row['id']),$row['allow_rating']==1,$row['submitter']);
				$entry_comment_details=get_comments('videos',$row['allow_comments']==1,strval($row['id']),false,get_value('comment_forum__videos'),NULL,NULL,false,false,$row['submitter'],$row['allow_comments']==2);
				$entry_trackback_details=get_trackbacks('videos',strval($row['id']),$row['allow_trackbacks']==1);
				$entry_add_date_raw=is_null($row['add_date'])?'':strval($row['add_date']);
				$entry_edit_date_raw=is_null($row['edit_date'])?'':strval($row['edit_date']);
				$entry_views=integer_format($row['video_views']);
				$current_entry=do_template('GALLERY_FLOWMODE_VIDEO',array('_GUID'=>'b6a795dc3853789df2a2951293d0fb26','_TITLE'=>get_translated_tempcode($row['title']),'EDIT_URL'=>$entry_edit_url,'MAIN'=>true,'RATING_DETAILS'=>$entry_rating_details,'DESCRIPTION'=>get_translated_tempcode($row['comments']),'CAT'=>$cat,'THUMB_URL'=>$url,'FULL_URL'=>$full_url,'ID'=>strval($row['id']),'VIEWS'=>strval($row['video_views']),'ADD_DATE_RAW'=>strval($row['add_date']),'EDIT_DATE_RAW'=>is_null($row['edit_date'])?'':strval($row['edit_date']),'SUBMITTER'=>strval($row['submitter']),'VIDEO_PLAYER'=>$video_player,'VIEW_URL'=>$view_url,'VIDEO_DETAILS'=>show_video_details($row)));

				$GLOBALS['SITE_DB']->query_update('videos',array('video_views'=>$row['video_views']+1),array('id'=>$row['id']),'',1,NULL,false,true);

				break;
			case 'image':
				if (is_null($row))
				{
					$map=array('cat'=>$cat,'id'=>$probe_id);
					if (!has_specific_permission(get_member(),'see_unvalidated')) $map['validated']=1;
					$rows=$GLOBALS['SITE_DB']->query_select('images',array('*'),$map,'',1);
					if (!array_key_exists(0,$rows))
					{
						attach_message(do_lang_tempcode('MISSING_RESOURCE','warn'));
						break;
					}
					$row=$rows[0];
				}

				if ((has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_edit_permission('mid',get_member(),$row['submitter'],'cms_galleries',array('galleries',$cat))))
				{
					$entry_edit_url=build_url(array('page'=>'cms_galleries','type'=>'_ed','id'=>$row['id']),get_module_zone('cms_galleries'));
				}

				/*$view_url=build_url(array('page'=>'_SELF','type'=>'image','root'=>($root=='root')?NULL:$root,'wide'=>1,'id'=>$row['id']),'_SELF');
				$thumb_url=ensure_thumbnail($row['url'],$row['thumb_url'],'galleries','images',$row['id']);
				$thumb=do_image_thumb($thumb_url,'');*/
				$thumb_url=$row['url'];//do_image_thumb($row['url'],'');
				if (url_is_local($thumb_url))
				{
					$file_size=file_exists(get_custom_file_base().'/'.rawurldecode($thumb_url))?strval(filesize(get_custom_file_base().'/'.rawurldecode($thumb_url))):'';
					$thumb_url=get_custom_base_url().'/'.$thumb_url;
				} else $file_size='';
				$full_url=$thumb_url;
				$view_url=build_url(array('page'=>'_SELF','type'=>'image','id'=>$row['id'],'wide'=>1,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select),'_SELF');

				// Some extra variables relatin to the currently selected entry
				$entry_title=get_translated_text($row['title']);
				$entry_rating_details=get_rating_box(get_self_url(true),$entry_title,'images',strval($row['id']),$row['allow_rating']==1,$row['submitter']);
				$entry_comment_details=get_comments('images',$row['allow_comments']==1,strval($row['id']),false,get_value('comment_forum__images'),NULL,NULL,false,false,$row['submitter'],$row['allow_comments']==2);
				$entry_trackback_details=get_trackbacks('images',strval($row['id']),$row['allow_trackbacks']==1);
				$entry_add_date_raw=is_null($row['add_date'])?'':strval($row['add_date']);
				$entry_edit_date_raw=is_null($row['edit_date'])?'':strval($row['edit_date']);
				$entry_views=integer_format($row['image_views']);

				$current_entry=do_template('GALLERY_FLOWMODE_IMAGE',array('_GUID'=>'fd486cf9a3338bc277a7170a1961089b','_TITLE'=>get_translated_tempcode($row['title']),'EDIT_URL'=>$entry_edit_url,'MAIN'=>true,'RATING_DETAILS'=>$entry_rating_details,'DESCRIPTION'=>get_translated_tempcode($row['comments']),'FILE_SIZE'=>$file_size,'CAT'=>$cat,'THUMB_URL'=>$thumb_url,'FULL_URL'=>$full_url,'ID'=>strval($row['id']),'VIEWS'=>strval($row['image_views']),'ADD_DATE_RAW'=>strval($row['add_date']),'EDIT_DATE_RAW'=>is_null($row['edit_date'])?'':strval($row['edit_date']),'SUBMITTER'=>strval($row['submitter']),'THUMB'=>$thumb_url,'VIEW_URL'=>$view_url));

				$GLOBALS['SITE_DB']->query_update('images',array('image_views'=>$row['image_views']+1),array('id'=>$row['id']),'',1,NULL,false,true);

				break;
		}

		$entries=new ocp_tempcode();

		// Display entries
		$where=db_string_equal_to('cat',$cat);
		if (!has_specific_permission(get_member(),'see_unvalidated')) $where.=' AND validated=1';
		if (get_param('days','')!='') $where.=' AND add_date>'.strval(time()-get_param_integer('days')*60*60*24);
		$_max_entries=get_value('flow_mode_max');
		if (is_null($_max_entries)) $max_entries=50; else $max_entries=intval($_max_entries);
		$query_rows_videos=$GLOBALS['SITE_DB']->query('SELECT *'.$sql_suffix_videos.' FROM '.get_table_prefix().'videos e WHERE '.$where.' ORDER BY '.$sort,$max_entries);
		$query_rows_images=$GLOBALS['SITE_DB']->query('SELECT *'.$sql_suffix_images.' FROM '.get_table_prefix().'images e WHERE '.$where.' ORDER BY '.$sort,$max_entries);

		// See if there is a numbering system to sort by
		$all_are=NULL;
		foreach ($query_rows_images as $q)
		{
			$this_are=strtolower(preg_replace('#\d#','',$q['url']));
			if (is_null($all_are)) $all_are=$this_are;
			if ($all_are!=$this_are)
			{
				$all_are=NULL;
				break;
			}
		}
		if (!is_null($all_are))
		{
			global $M_SORT_KEY;
			$M_SORT_KEY=mixed();
			$M_SORT_KEY='url';
			usort($query_rows_images,'multi_sort');
		}

		$query_rows=array_merge($query_rows_images,$query_rows_videos);
		foreach ($query_rows as $row)
		{
			$type=array_key_exists('video_length',$row)?'video':'image';

			if (($type==$probe_type) && ($row['id']==$probe_id)) continue;

			$caption=get_translated_tempcode($row['comments']);

			$probe_url=build_url(array('page'=>'_SELF','type'=>'misc','root'=>($root=='root')?NULL:$root,'id'=>$cat,'flow_mode_interface'=>get_param_integer('flow_mode_interface',NULL),'probe_type'=>$type,'probe_id'=>$row['id'],'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select),'_SELF');
			$view_url_2=build_url(array('page'=>'_SELF','wide'=>1,'type'=>$type,'root'=>($root=='root')?NULL:$root,'id'=>$row['id'],'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select),'_SELF');
			if (array_key_exists('url',$row))
			{
				$thumb_url=ensure_thumbnail($row['url'],$row['thumb_url'],'galleries','images',$row['id']);
			} else
			{
				$thumb_url=$row['thumb_url'];
				if ($thumb_url=='') $thumb_url=find_theme_image('na');
				if (url_is_local($thumb_url)) $thumb_url=get_custom_base_url().'/'.$thumb_url;
			}

			$class=(($type==$probe_type) && ($row['id']==$probe_id))?'currentimage':'';
			$thumb=do_image_thumb($thumb_url,$caption);
			$entries->attach(do_template('GALLERY_FLOW_ENTRY',array('_GUID'=>'ff75c904ba7fe857484874483ed65f5a','DESCRIPTION'=>get_translated_tempcode($row['comments']),'_TITLE'=>get_translated_tempcode($row['title']),'TYPE'=>$type,'ID'=>strval($row['id']),'VIEWS'=>strval($row[$type.'_views']),'ADD_DATE_RAW'=>strval($row['add_date']),'EDIT_DATE_RAW'=>is_null($row['edit_date'])?'':strval($row['edit_date']),'SUBMITTER'=>strval($row['submitter']),'CLASS'=>$class,'THUMB'=>$thumb,'VIEW_URL'=>$probe_url,'VIEW_URL_2'=>$view_url_2)));
		}

		$member_id=get_member_id_from_gallery_name($cat);
		if (get_forum_type()=='ocf')
		{
			require_code('ocf_members');
			require_code('ocf_members2');
		}
		$member_details=((is_null($member_id)) || (get_forum_type()!='ocf'))?new ocp_tempcode():ocf_show_member_box($member_id);

		$rep_image_url='';
		if (($rep_image!='') && (url_is_local($rep_image)))
		{
			$rep_image_url=get_custom_base_url().'/'.$rep_image;
		} elseif ($rep_image!='') $rep_image_url=$rep_image;

		list(,,,$first_entry_id,,,$first_type)=$this->build_set_navigation(db_string_equal_to('cat',$cat),'','',$probe_id,$root,$probe_type,get_param_integer('slideshow',0),get_param_integer('wide_high',0),$start,$max,$cat,$sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos,get_param('select','*'),get_param('video_select','*'));

		return do_template('GALLERY_FLOW_MODE_SCREEN',array('_GUID'=>'73728cb94579f06ab487627101011d43','FIRST_ENTRY_ID'=>is_null($first_entry_id)?'':($first_type.':'.strval($first_entry_id)),'SORTING'=>$sorting,'_TITLE'=>$fullname,'MEMBER_ID'=>is_null($member_id)?'':strval($member_id),'VIEW_URL'=>$view_url,'FULL_URL'=>$full_url,'PROBE_TYPE'=>$probe_type,'PROBE_ID'=>strval($probe_id),'ENTRY_TITLE'=>$entry_title,'ENTRY_DESCRIPTION'=>$entry_description,'ENTRY_SUBMITTER'=>strval($entry_submitter),'ENTRY_VIEWS'=>$entry_views,'ENTRY_ADD_DATE_RAW'=>$entry_add_date_raw,'ENTRY_EDIT_DATE_RAW'=>$entry_edit_date_raw,'ENTRY_TRACKBACK_DETAILS'=>$entry_trackback_details,'ENTRY_RATING_DETAILS'=>$entry_rating_details,'ENTRY_COMMENT_DETAILS'=>$entry_comment_details,'ENTRY_EDIT_URL'=>$entry_edit_url,'WARNING_DETAILS'=>$warning_details,'TAGS'=>get_loaded_tags('galleries'),'RATING_DETAILS'=>$rating_details,'COMMENT_DETAILS'=>$comment_details,'BROWSE'=>$browse,'REP_IMAGE_URL'=>$rep_image_url,'TITLE'=>$title,'MEMBER_DETAILS'=>$member_details,'DESCRIPTION'=>$description,'CHILDREN'=>$children,'CURRENT_ENTRY'=>$current_entry,'ENTRIES'=>$entries,'ADD_GALLERY_URL'=>$add_gallery_url,'EDIT_URL'=>$edit_url,'IMAGE_URL'=>$submit_image_url,'VIDEO_URL'=>$submit_video_url,'MAY_DOWNLOAD'=>$may_download,'CAT'=>$cat));
	}

	/**
	 * The UI for an "regular mode" gallery.
	 *
	 * @param  tempcode		Rating area
	 * @param  tempcode		Commenting area
	 * @param  ID_TEXT		Our gallery ID
	 * @param  ID_TEXT		Virtual root gallery
	 * @param  tempcode		The description of the gallery
	 * @param  tempcode		The tempcode for our visible child galleries
	 * @param  boolean		Whether may "download this gallery"
	 * @param  tempcode		The URL to "edit this gallery"
	 * @param  tempcode		The URL to "add a gallery"
	 * @param  tempcode		The URL to "submit an image to this gallery"
	 * @param  tempcode		The URL to "submit a video to this gallery"
	 * @param  tempcode		The title of the page (our of get_page_title)
	 * @param  string			The gallery title
	 * @param  tempcode		Sorting UI
	 * @return tempcode		The UI
	 */
	function do_gallery_regular_mode($rating_details,$comment_details,$cat,$root,$description,$children,$may_download,$edit_url,$add_gallery_url,$submit_image_url,$submit_video_url,$title,$fullname,$sorting)
	{
		$max=get_param_integer('max',get_default_gallery_max());
		$start=get_param_integer('start',0);
		if ($max<1) $max=1;
		$page_num=($max==0)?0:(intval(floor(floatval($start)/floatval($max)))+1);

		// WHERE clause
		if (get_option('galleries_subcat_narrowin')=='1')
		{
			require_code('ocfiltering');
			$where=ocfilter_to_sqlfragment($cat.'*','id','galleries','parent_id','cat','name',true,false);
		} else
		{
			$where=db_string_equal_to('cat',$cat);
		}
		if (!has_specific_permission(get_member(),'see_unvalidated')) $where.=' AND validated=1';
		if (get_param('days','')!='') $where.=' AND add_date>'.strval(time()-get_param_integer('days')*60*60*24);

		// ocSelect
		$ocselect=either_param('active_filter','');
		if ($ocselect!='')
		{
			require_code('ocselect');

			$content_type='image';
			list($ocselect_extra_select_images,$ocselect_extra_join_images,$ocselect_extra_where_images)=ocselect_to_sql($GLOBALS['SITE_DB'],parse_ocselect($ocselect),$content_type,'');
			$extra_select_sql_images=implode('',$ocselect_extra_select_images);
			$extra_join_sql_images=implode('',$ocselect_extra_join_images);

			$content_type='video';
			list($ocselect_extra_select_videos,$ocselect_extra_join_videos,$ocselect_extra_where_videos)=ocselect_to_sql($GLOBALS['SITE_DB'],parse_ocselect($ocselect),$content_type,'');
			$extra_select_sql_videos=implode('',$ocselect_extra_select_videos);
			$extra_join_sql_videos=implode('',$ocselect_extra_join_videos);
		} else
		{
			$extra_select_sql_images='';
			$extra_join_sql_images='';
			$ocselect_extra_where_images='';
			$extra_select_sql_videos='';
			$extra_join_sql_videos='';
			$ocselect_extra_where_videos='';
		}

		// Work out totals
		$num_images=$GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) FROM '.get_table_prefix().'images r'.$extra_join_sql_images.' WHERE '.$where.$ocselect_extra_where_images);
		$num_videos=$GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) FROM '.get_table_prefix().'videos r'.$extra_join_sql_videos.' WHERE '.$where.$ocselect_extra_where_videos);
		$total_rows=$num_images+$num_videos;
		$total_pages=($max==0)?1:intval(ceil(floatval($total_rows)/floatval($max)));
		if ($total_pages==0) $total_pages=1;

		list($sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos)=$this->get_sort_order();

		$rows=$GLOBALS['SITE_DB']->query('SELECT r.*'.$sql_suffix_videos.$extra_select_sql_videos.' FROM '.get_table_prefix().'videos r'.$extra_join_sql_videos.' WHERE '.$where.$ocselect_extra_where_videos.' ORDER BY '.$sort,$max,$start);
		if (count($rows)<$max)
		{
			$rows2=$GLOBALS['SITE_DB']->query('SELECT r.*'.$sql_suffix_images.$extra_select_sql_images.' FROM '.get_table_prefix().'images r'.$extra_join_sql_images.' WHERE '.$where.$ocselect_extra_where_images.' ORDER BY '.$sort,$max-count($rows),max(0,$start-$num_videos));
		} else $rows2=array();

		$entries=new ocp_tempcode();

		$image_select=get_param('select','*');
		$video_select=get_param('video_select','*');

		// Display videos
		foreach ($rows as $row_video)
		{
			$view_url=build_url(array('page'=>'_SELF','type'=>'video','root'=>($root=='root')?NULL:$root,'wide'=>1,'id'=>$row_video['id'],'start'=>($start==0)?NULL:$start,'max'=>($start==get_default_gallery_max())?NULL:$max,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF');
			$thumb_url=ensure_thumbnail($row_video['url'],$row_video['thumb_url'],'galleries','videos',$row_video['id']);
			if ($thumb_url=='') $thumb_url=find_theme_image('na');
			$thumb=do_image_thumb($thumb_url,'',true);
			$this_full_url=$row_video['url'];
			if (url_is_local($this_full_url)) $this_full_url=get_custom_base_url().'/'.$this_full_url;

			$entry_rating_details=($row_video['allow_rating']==1)?display_rating(get_self_url(true),get_translated_text($row_video['title']),'videos',strval($row_video['id']),'RATING_INLINE_STATIC',$row_video['submitter']):NULL;

			$map=array('_GUID'=>'395f0aa1212e69da5752d228a6efe54d','RATING_DETAILS'=>$entry_rating_details,'DESCRIPTION'=>get_translated_tempcode($row_video['comments']),'CAT'=>$cat,'THUMB_URL'=>$thumb_url,'FULL_URL'=>$this_full_url,'ID'=>strval($row_video['id']),'VIEWS'=>strval($row_video['video_views']),'ADD_DATE_RAW'=>strval($row_video['add_date']),'EDIT_DATE_RAW'=>is_null($row_video['edit_date'])?'':strval($row_video['edit_date']),'SUBMITTER'=>strval($row_video['submitter']),'THUMB'=>$thumb,'VIEW_URL'=>$view_url,'VIDEO_DETAILS'=>show_video_details($row_video));
			$entry=do_template('GALLERY_VIDEO',$map);
			$entries->attach(do_template('GALLERY_ENTRY_WRAP',array('_GUID'=>'bc0d3de5d0160b00e3250d78658888c1','ENTRY'=>$entry)+$map));
		}

		// Display images
		foreach ($rows2 as $row_image)
		{
			$view_url=build_url(array('page'=>'_SELF','type'=>'image','root'=>($root=='root')?NULL:$root,'wide'=>1,'id'=>$row_image['id'],'start'=>($start==0)?NULL:$start,'max'=>($max==get_default_gallery_max())?NULL:$max,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF');
			$thumb_url=ensure_thumbnail($row_image['url'],$row_image['thumb_url'],'galleries','images',$row_image['id']);
			$thumb=do_image_thumb($thumb_url,'',true);
			$this_full_url=$row_image['url'];
			if (url_is_local($this_full_url))
			{
				$file_size=file_exists(get_custom_file_base().'/'.rawurldecode($this_full_url))?strval(filesize(get_custom_file_base().'/'.rawurldecode($this_full_url))):'';
				$this_full_url=get_custom_base_url().'/'.$this_full_url;
			} else $file_size='';

			$entry_rating_details=($row_image['allow_rating']==1)?display_rating(get_self_url(true),get_translated_text($row_image['title']),'images',strval($row_image['id']),'RATING_INLINE_STATIC',$row_image['submitter']):NULL;

			$map=array('_GUID'=>'aa70f543297e25379c49fa25d6dbcac0','RATING_DETAILS'=>$entry_rating_details,'DESCRIPTION'=>get_translated_tempcode($row_image['comments']),'FILE_SIZE'=>$file_size,'CAT'=>$cat,'THUMB_URL'=>$thumb_url,'FULL_URL'=>$this_full_url,'ID'=>strval($row_image['id']),'VIEWS'=>strval($row_image['image_views']),'ADD_DATE_RAW'=>strval($row_image['add_date']),'EDIT_DATE_RAW'=>is_null($row_image['edit_date'])?'':strval($row_image['edit_date']),'SUBMITTER'=>strval($row_image['submitter']),'THUMB'=>$thumb,'VIEW_URL'=>$view_url);
			$entry=do_template('GALLERY_IMAGE',$map);
			$entries->attach(do_template('GALLERY_ENTRY_WRAP',array('_GUID'=>'ea12d7acf47eab493b6fb4658b3c0346','ENTRY'=>$entry)+$map));
		}

		// Member gallery?
		$member_id=get_member_id_from_gallery_name($cat);
		if (get_forum_type()=='ocf')
		{
			require_code('ocf_members');
			require_code('ocf_members2');
		}
		$member_details=((is_null($member_id)) || (get_forum_type()!='ocf'))?new ocp_tempcode():ocf_show_member_box($member_id);

		// Results browser
		require_code('templates_results_browser');
		$_selectors=array_map('intval',explode(',',get_option('gallery_selectors')));
		$results_browser=results_browser(do_lang('ENTRY'),$cat,$start,'start',$max,'max',$total_rows,$root,'misc',true,false,10,$_selectors);

		return do_template('GALLERY_REGULAR_MODE_SCREEN',array('_GUID'=>'cec405597f47f5079b7c7f581fa6b5c2','SORTING'=>$sorting,'_TITLE'=>$fullname,'MEMBER_ID'=>is_null($member_id)?'':strval($member_id),'RESULTS_BROWSER'=>$results_browser,'TAGS'=>get_loaded_tags('galleries'),'CAT'=>$cat,'MEMBER_DETAILS'=>$member_details,'RATING_DETAILS'=>$rating_details,'COMMENT_DETAILS'=>$comment_details,'ADD_GALLERY_URL'=>$add_gallery_url,'EDIT_URL'=>$edit_url,'CHILDREN'=>$children,'TITLE'=>$title,'DESCRIPTION'=>$description,'IMAGE_URL'=>$submit_image_url,'VIDEO_URL'=>$submit_video_url,'MAY_DOWNLOAD'=>$may_download,'ENTRIES'=>$entries));
	}

	/**
	 * The UI to show an image.
	 *
	 * @param  ?string		Alternate category name to use (NULL: use standard one). This is useful if you are overriding this code to show images in virtual galleries.
	 * @param  ?tempcode		Breadcrumbs (NULL: derive in this function).
	 * @return tempcode		The UI
	 */
	function show_image($category_name=NULL,$tree=NULL)
	{
		$id=get_param_integer('id');

		list($sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos)=$this->get_sort_order();

		if (addon_installed('awards'))
		{
			require_code('awards');
			$awards=find_awards_for('image',strval($id));
		} else $awards=array();

		// Pic up some info
		$rows=$GLOBALS['SITE_DB']->query_select('images',array('*'),array('id'=>$id),'',1);
		if (!array_key_exists(0,$rows))
		{
			return warn_screen(get_page_title('ERROR_OCCURRED'),do_lang_tempcode('MISSING_RESOURCE'));
		}
		$myrow=$rows[0];
		$url=$myrow['url'];
		if (url_is_local($url)) $url=get_custom_base_url().'/'.$url;
		$cat=$myrow['cat'];
		$GLOBALS['FEED_URL']=find_script('backend').'?mode=galleries&filter='.$cat;

		if ((get_value('no_individual_gallery_view')==='1') && ($GLOBALS['SITE_DB']->query_value('galleries','flow_mode_interface',array('name'=>$cat))=='1'))
		{
			require_code('site2');
			assign_refresh(build_url(array('page'=>'_SELF','type'=>'misc','id'=>$cat,'probe_id'=>$id,'probe_type'=>'video'),'_SELF'),0.0);
		}

		if (!has_category_access(get_member(),'galleries',$cat)) access_denied('CATEGORY_ACCESS');

		$true_category_name=get_translated_text($GLOBALS['SITE_DB']->query_value('galleries','fullname',array('name'=>$cat)));
		if (is_null($category_name))
			$category_name=$true_category_name;

		if (get_param_integer('slideshow',0)==1)
		{
			$title=get_page_title('VIEW_SLIDESHOW',true,array($category_name));

			global $EXTRA_HEAD;
			$EXTRA_HEAD->attach('<meta name="robots" content="noindex" />'); // XHTMLXHTML
		} else
		{
			$title=get_page_title((get_translated_text($myrow['title'])=='')?'VIEW_IMAGE':'_VIEW_IMAGE',true,array(get_translated_tempcode($myrow['title'])),NULL,$awards);
		}
	
		$root=get_param('root','root');
	
		seo_meta_load_for('image',strval($id));
	
		// Views
		if (get_db_type()!='xml')
		{
			$myrow['image_views']++;
			$GLOBALS['SITE_DB']->query_update('images',array('image_views'=>$myrow['image_views']),array('id'=>$id),'',1,NULL,false,true);
		}

		list($rating_details,$comment_details,$trackback_details)=embed_feedback_systems(
			'images',
			strval($id),
			$myrow['allow_rating'],
			$myrow['allow_comments'],
			$myrow['allow_trackbacks'],
			$myrow['validated'],
			$myrow['submitter'],
			build_url(array('page'=>'_SELF','type'=>'image','id'=>$id),'_SELF',NULL,false,false,true),
			(get_translated_text($myrow['title'])=='')?do_lang('VIEW_IMAGE_IN',$true_category_name):get_translated_text($myrow['title']),
			get_value('comment_forum__images')
		);

		// Comments
		$comments=get_translated_tempcode($myrow['comments']);

		// Validation
		if ($myrow['validated']==0)
		{
			if (!has_specific_permission(get_member(),'jump_to_unvalidated'))
				access_denied('SPECIFIC_PERMISSION','jump_to_unvalidated');

			$warning_details=do_template('WARNING_TABLE',array('_GUID'=>'c32faacba974e648a67e5e91ffd3d8e5','WARNING'=>do_lang_tempcode((get_param_integer('redirected',0)==1)?'UNVALIDATED_TEXT_NON_DIRECT':'UNVALIDATED_TEXT')));
		} else $warning_details=new ocp_tempcode();

		if ((has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_edit_permission('mid',get_member(),$myrow['submitter'],'cms_galleries',array('galleries',$cat))))
		{
			$edit_url=build_url(array('page'=>'cms_galleries','type'=>'_ed','id'=>$id),get_module_zone('cms_galleries'));
		} else $edit_url=new ocp_tempcode();

		$add_date=get_timezoned_date($myrow['add_date']);
		$edit_date=is_null($myrow['edit_date'])?'':get_timezoned_date($myrow['edit_date']);

		list($n,$x,$nav)=$this->build_set_navigation(db_string_equal_to('cat',$cat),'',$category_name,$id,$root,'image',get_param_integer('slideshow',0),get_param_integer('wide_high',0),get_param_integer('start',0),get_param_integer('max',get_default_gallery_max()),$cat,$sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos,get_param('select','*'),get_param('video_select','*'));

		$member_id=get_member_id_from_gallery_name($cat);
		if (get_forum_type()=='ocf')
		{
			require_code('ocf_members');
			require_code('ocf_members2');
		}
		$member_details=((is_null($member_id)) || (get_forum_type()!='ocf'))?new ocp_tempcode():ocf_show_member_box($member_id);

		if (is_null($tree)) $tree=gallery_breadcrumbs($cat,$root,false,get_module_zone('galleries'));
		breadcrumb_add_segment($tree,do_lang_tempcode('VIEW_IMAGE'));

		$GLOBALS['META_DATA']+=array(
			'created'=>date('Y-m-d',$myrow['add_date']),
			'creator'=>$GLOBALS['FORUM_DRIVER']->get_username($myrow['submitter']),
			'publisher'=>'', // blank means same as creator
			'modified'=>is_null($myrow['edit_date'])?'':date('Y-m-d',$myrow['edit_date']),
			'type'=>'Image',
			'title'=>get_translated_text($myrow['title']),
			'identifier'=>'_SEARCH:galleries:image:'.strval($id),
			'description'=>get_translated_text($myrow['comments']),
			'image'=>$url,
		);

		return do_template('GALLERY_ENTRY_SCREEN',array('_GUID'=>'332a19b6a72505f8e1eb4d288df247ce','MEDIA_TYPE'=>'image','E_TITLE'=>get_translated_tempcode($myrow['title']),'CAT'=>$cat,'SLIDESHOW'=>(get_param_integer('slideshow',0)==1),'TRUE_GALLERY_TITLE'=>$true_category_name,'GALLERY_TITLE'=>$category_name,'MEMBER_ID'=>is_null($member_id)?'':strval($member_id),'ID'=>strval($id),'TAGS'=>get_loaded_tags('images'),'TITLE'=>$title,'SUBMITTER'=>strval($myrow['submitter']),'MEMBER_DETAILS'=>$member_details,'X'=>integer_format($x),'N'=>integer_format($n),'VIEWS'=>integer_format($myrow['image_views']),'ADD_DATE_RAW'=>strval($myrow['add_date']),'EDIT_DATE_RAW'=>is_null($myrow['edit_date'])?'':strval($myrow['edit_date']),'ADD_DATE'=>$add_date,'EDIT_DATE'=>$edit_date,'TRACKBACK_DETAILS'=>$trackback_details,'RATING_DETAILS'=>$rating_details,'COMMENT_DETAILS'=>$comment_details,'EDIT_URL'=>$edit_url,'NAV'=>$nav,'COMMENTS'=>$comments,'URL'=>$url,'WARNING_DETAILS'=>$warning_details));
	}

	/**
	 * The UI to show a video.
	 *
	 * @param  ?string		Alternate category name to use (NULL: use standard one). This is useful if you are overriding this code to show images in virtual galleries.
	 * @param  ?tempcode		Breadcrumbs (NULL: derive in this function).
	 * @return tempcode		The UI
	 */
	function show_video($category_name=NULL,$tree=NULL)
	{
		$id=get_param_integer('id');

		list($sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos)=$this->get_sort_order();

		if (addon_installed('awards'))
		{
			require_code('awards');
			$awards=find_awards_for('video',strval($id));
		} else $awards=array();

		// Pic up some info
		$rows=$GLOBALS['SITE_DB']->query_select('videos',array('*'),array('id'=>$id),'',1);
		if (!array_key_exists(0,$rows))
		{
			return warn_screen(get_page_title('ERROR_OCCURRED'),do_lang_tempcode('MISSING_RESOURCE'));
		}
		$myrow=$rows[0];
		$url=$myrow['url'];
		if (url_is_local($url)) $url=get_custom_base_url().'/'.$url;
		$cat=$myrow['cat'];
		$GLOBALS['FEED_URL']=find_script('backend').'?mode=galleries&filter='.urlencode($cat);

		if ((get_value('no_individual_gallery_view')==='1') && ($GLOBALS['SITE_DB']->query_value('galleries','flow_mode_interface',array('name'=>$cat))=='1'))
		{
			require_code('site2');
			assign_refresh(build_url(array('page'=>'_SELF','type'=>'misc','id'=>$cat,'probe_id'=>$id,'probe_type'=>'image'),'_SELF'),0.0);
		}

		$true_category_name=get_translated_text($GLOBALS['SITE_DB']->query_value('galleries','fullname',array('name'=>$cat)));
		if (is_null($category_name))
			$category_name=$true_category_name;

		if (get_param_integer('slideshow',0)==1)
		{
			$title=get_page_title('VIEW_SLIDESHOW',true,array($category_name));

			global $EXTRA_HEAD;
			$EXTRA_HEAD->attach('<meta name="robots" content="noindex" />'); // XHTMLXHTML
		} else
		{
			$title=get_page_title((get_translated_text($myrow['title'])=='')?'VIEW_VIDEO':'_VIEW_VIDEO',true,array(get_translated_tempcode($myrow['title'])),NULL,$awards);
		}

		$root=get_param('root','root');

		seo_meta_load_for('video',strval($id));

		$thumb_url=$myrow['thumb_url'];
		if (url_is_local($thumb_url)) $thumb_url=get_custom_base_url().'/'.$thumb_url;

		if (!has_category_access(get_member(),'galleries',$cat)) access_denied('CATEGORY_ACCESS');

		// Views
		if (get_db_type()!='xml')
		{
			$myrow['video_views']++;
			$GLOBALS['SITE_DB']->query_update('videos',array('video_views'=>$myrow['video_views']),array('id'=>$id),'',1,NULL,false,true);
		}

		list($rating_details,$comment_details,$trackback_details)=embed_feedback_systems(
			'videos',
			strval($id),
			$myrow['allow_rating'],
			$myrow['allow_comments'],
			$myrow['allow_trackbacks'],
			$myrow['validated'],
			$myrow['submitter'],
			build_url(array('page'=>'_SELF','type'=>'video','id'=>$id),'_SELF',NULL,false,false,true),
			(get_translated_text($myrow['title'])=='')?do_lang('VIEW_VIDEO_IN',$true_category_name):get_translated_text($myrow['title']),
			get_value('comment_forum__videos')
		);

		// Validation
		if ($myrow['validated']==0)
		{
			if (!has_specific_permission(get_member(),'jump_to_unvalidated'))
				access_denied('SPECIFIC_PERMISSION','jump_to_unvalidated');

			$warning_details=do_template('WARNING_TABLE',array('_GUID'=>'b32faacba974e648a67e5e91ffd3d8e5','WARNING'=>do_lang_tempcode((get_param_integer('redirected',0)==1)?'UNVALIDATED_TEXT_NON_DIRECT':'UNVALIDATED_TEXT')));
		} else $warning_details=new ocp_tempcode();

		// Comments
		$comments=get_translated_tempcode($myrow['comments']);

		if ((has_actual_page_access(NULL,'cms_galleries',NULL,NULL)) && (has_edit_permission('mid',get_member(),$myrow['submitter'],'cms_galleries',array('galleries',$cat))))
		{
			$edit_url=build_url(array('page'=>'cms_galleries','type'=>'_ev','id'=>$id),get_module_zone('cms_galleries'));
		} else $edit_url=new ocp_tempcode();

		$add_date=get_timezoned_date($myrow['add_date']);
		$edit_date=is_null($myrow['edit_date'])?'':get_timezoned_date($myrow['edit_date']);

		// Video HTML
		$video=show_gallery_media($url,$thumb_url,$myrow['video_width'],$myrow['video_height'],$myrow['video_length']);

		$extension=get_file_extension($url);
		require_code('mime_types');
		$mime_type=get_mime_type($extension);

		list($n,$x,$nav)=$this->build_set_navigation(db_string_equal_to('cat',$cat),'',$category_name,$id,$root,'video',get_param_integer('slideshow',0),get_param_integer('wide_high',0),get_param_integer('start',0),get_param_integer('max',get_default_gallery_max()),$cat,$sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos,get_param('select','*'),get_param('video_select','*'));

		$member_id=get_member_id_from_gallery_name($cat);
		if (get_forum_type()=='ocf')
		{
			require_code('ocf_members');
			require_code('ocf_members2');
		}
		$member_details=((is_null($member_id)) || (get_forum_type()!='ocf'))?new ocp_tempcode():ocf_show_member_box($member_id);

		$video_details=show_video_details($myrow);

		if (is_null($tree)) $tree=gallery_breadcrumbs($cat,$root,false,get_module_zone('galleries'));
		breadcrumb_add_segment($tree,do_lang_tempcode('VIEW_VIDEO'));

		$GLOBALS['META_DATA']+=array(
			'created'=>date('Y-m-d',$myrow['add_date']),
			'creator'=>$GLOBALS['FORUM_DRIVER']->get_username($myrow['submitter']),
			'publisher'=>'', // blank means same as creator
			'modified'=>is_null($myrow['edit_date'])?'':date('Y-m-d',$myrow['edit_date']),
			'type'=>'Video',
			'title'=>get_translated_text($myrow['title']),
			'identifier'=>'_SEARCH:galleries:video:'.strval($id),
			'description'=>get_translated_text($myrow['comments']),
			'image'=>$thumb_url,
			'video'=>$url,
			'video:height'=>strval($myrow['video_height']),
			'video:width'=>strval($myrow['video_width']),
			'video:type'=>$mime_type,
		);

		return do_template('GALLERY_ENTRY_SCREEN',array('_GUID'=>'91e231906ed899513ec2db8a2974dddf','MEDIA_TYPE'=>'video','E_TITLE'=>get_translated_tempcode($myrow['title']),'CAT'=>$cat,'SLIDESHOW'=>(get_param_integer('slideshow',0)==1),'TRUE_GALLERY_TITLE'=>$true_category_name,'GALLERY_TITLE'=>$category_name,'MEMBER_ID'=>is_null($member_id)?'':strval($member_id),'ID'=>strval($id),'TAGS'=>get_loaded_tags('videos'),'TITLE'=>$title,'SUBMITTER'=>strval($myrow['submitter']),'URL'=>$url,'VIDEO_DETAILS'=>$video_details,'MEMBER_DETAILS'=>$member_details,'X'=>integer_format($x),'N'=>integer_format($n),'VIEWS'=>integer_format($myrow['video_views']),'ADD_DATE_RAW'=>strval($myrow['add_date']),'EDIT_DATE_RAW'=>is_null($myrow['edit_date'])?'':strval($myrow['edit_date']),'ADD_DATE'=>$add_date,'EDIT_DATE'=>$edit_date,'RATING_DETAILS'=>$rating_details,'TRACKBACK_DETAILS'=>$trackback_details,'COMMENT_DETAILS'=>$comment_details,'EDIT_URL'=>$edit_url,'NAV'=>$nav,'COMMENTS'=>$comments,'VIDEO'=>$video,'WARNING_DETAILS'=>$warning_details));
	}

	/**
	 * Sort out gallery back/next navigation.
	 *
	 * @param  string			Where clause for doing set query
	 * @param  string			Join clause for doing set query
	 * @param  tempcode		The actual title for the gallery we are using
	 * @param  ?AUTO_LINK	The ID of the current entry of the type we are browsing in the gallery we are using (NULL: assume first)
	 * @param  ID_TEXT		The root gallery (the gallery we are considering as an adhoc root, to allow gallery splitting-up)
	 * @param  ?ID_TEXT		The current type being browsed (NULL: assume first)
	 * @set image video
	 * @param  BINARY			If in slideshow
	 * @param  BINARY			If panels hidden
	 * @param  integer		Start position when returning to category
	 * @param  integer		Max to show when returning to category
	 * @param  ID_TEXT		Category
	 * @param  ID_TEXT		Sort order
	 * @param  ID_TEXT		Sort order for reverse sorting
	 * @param  string			Select clause query suffix for images
	 * @param  string			Select clause query suffix for videos
	 * @param  string			ocFilter for limiting images displayed
	 * @param  string			ocFilter for limiting videos displayed
	 * @return array			A tuple of the navigation bits
	 */
	function build_set_navigation($where,$join,$category_name,$current_id,$root,$current_type,$slideshow,$wide_high,$start,$max,$cat,$sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos,$image_select,$video_select)
	{
		$our_table=$current_type.'s';

		$sv=has_specific_permission(get_member(),'see_unvalidated');
		if (!$sv) $where.=' AND validated=1';

		$days=get_param('days','');
		$where_sup='';
		if ($days!='') $where.=' AND add_date>='.strval(time()-intval($days)*60*60*24);

		require_code('ocfiltering');
		$image_select_sql=ocfilter_to_sqlfragment($image_select,'e.id');
		$where_images=$where.' AND '.$image_select_sql;
		$video_select_sql=ocfilter_to_sqlfragment($video_select,'e.id');
		$where_videos=$where.' AND '.$video_select_sql;

		$total_images=$GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) FROM '.get_table_prefix().'images e'.$join.' WHERE '.$where_images);
		$total_videos=$GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) FROM '.get_table_prefix().'videos e'.$join.' WHERE '.$where_videos);

		// These will hopefully be replaced with proper values
		$position=1;
		$back_id=NULL;
		$back_type=$current_type;
		$next_id=NULL;
		$next_type=$current_type;
		$first_id=$current_id;
		$first_type=$current_type;

		$total=$total_videos+$total_images;
		if ($total<500) // Not too many to navigate through
		{
			$rows_images=$GLOBALS['SITE_DB']->query('SELECT e.id,add_date,url'.$sql_suffix_images.' FROM '.get_table_prefix().'images e'.$join.' WHERE '.$where_images.' ORDER BY '.$sort);
			$rows_videos=$GLOBALS['SITE_DB']->query('SELECT e.id,add_date,url'.$sql_suffix_videos.' FROM '.get_table_prefix().'videos e'.$join.' WHERE '.$where_videos.' ORDER BY '.$sort);

			list($_sort,$_dir)=explode(' ',$sort,2);

			// Sort
			$combined=array();
			foreach ($rows_images as $row_image) $combined[]=array($row_image,'image',$row_image[$_sort]);
			foreach ($rows_videos as $row_video) $combined[]=array($row_video,'video',$row_video[$_sort]);
			global $M_SORT_KEY;
			$M_SORT_KEY=2;
			usort($combined,'multi_sort');
			if ($_dir=='DESC')
				$combined=array_reverse($combined);

			// Find current position in navigation set, and neighbour positions
			foreach ($combined as $position=>$c)
			{
				if ($position==0)
				{
					$first_id=$c[0]['id'];
					$first_type=$c[1];
				}
				
				if ((is_null($current_id)) || (($c[1]==$current_type) && ($c[0]['id']==$current_id)))
				{
					if ($position!=0)
					{
						$back_id=$combined[$position-1][0]['id'];
						$back_type=$combined[$position-1][1];
					}

					if ($position!=count($combined)-1)
					{
						$next_id=$combined[$position+1][0]['id'];
						$next_type=$combined[$position+1][1];
					}

					$position++; // We're not counting from zero

					break;
				}
			}
		}

		// UI for navigating all this
		$nav_ui=is_null($first_id)?new ocp_tempcode():$this->show_nav($category_name,$where,$join,$current_id,$first_id,$back_id,$next_id,$root,$position,$total,$current_type,$first_type,$back_type,$next_type,$slideshow,$wide_high,$start,$max,$cat,$sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos,$image_select,$video_select);

		return array($total/*aka $n*/,$position/*aka $x*/,$nav_ui,$first_id,$back_id,$next_id,$first_type,$back_type,$next_type);
	}

	/**
	 * Show gallery navigation bits used when viewing images/videos.
	 *
	 * @param  tempcode		The actual title for the gallery we are using
	 * @param  string			Where clause for doing set query
	 * @param  string			Join clause for doing set query
	 * @param  AUTO_LINK		The ID of the current entry of the type we are browsing in the gallery we are using
	 * @param  AUTO_LINK		The ID of the first entry of the type we are browsing in the gallery we are using (NULL: no previous)
	 * @param  ?AUTO_LINK	The ID of the previous entry of the type we are browsing in the gallery we are using (NULL: no previous)
	 * @param  ?AUTO_LINK	As above, except next entry (NULL: no next)
	 * @param  ID_TEXT		The root gallery (the gallery we are considering as an adhoc root, to allow gallery splitting-up)
	 * @param  integer		Position in collection
	 * @param  integer		Total in collection
	 * @param  ID_TEXT		The first type being browsed
	 * @set image video
	 * @param  ID_TEXT		The current type being browsed
	 * @set image video
	 * @param  ID_TEXT		The type for the back link
	 * @set image video
	 * @param  ID_TEXT		The type for the next link
	 * @set image video
	 * @param  BINARY			If in slideshow
	 * @param  BINARY			If panels hidden
	 * @param  integer		Start position when returning to category
	 * @param  integer		Max to show when returning to category
	 * @param  ?ID_TEXT		Category (NULL: not in a category)
	 * @param  ID_TEXT		Sort order
	 * @param  ID_TEXT		Sort order for reverse sorting
	 * @param  string			Select clause query suffix for images
	 * @param  string			Select clause query suffix for videos
	 * @param  string			ocFilter for limiting images displayed
	 * @param  string			ocFilter for limiting videos displayed
	 * @return tempcode		The navigation bits
	 */
	function show_nav($category_name,$where,$join,$current_id,$first_id,$back_id,$next_id,$root,$x,$n,$current_type,$first_type,$back_type,$next_type,$slideshow,$wide_high,$start,$max,$cat,$sort,$sort_backwards,$sql_suffix_images,$sql_suffix_videos,$image_select,$video_select)
	{
		if (!is_null($back_id))
		{
			$slideshow_previous_url=build_url(array('page'=>'_SELF','type'=>$back_type,'root'=>($root=='root')?NULL:$root,'wide_high'=>1,'id'=>$back_id,'slideshow'=>1,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF',NULL,true); // Continues, but as slideshow
			$back_url=build_url(array('page'=>'_SELF','type'=>$back_type,'root'=>($root=='root')?NULL:$root,'wide'=>1,'id'=>$back_id,'slideshow'=>($slideshow==0)?NULL:$slideshow,'wide_high'=>($wide_high==0)?NULL:$wide_high,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF',NULL,true);
		} else
		{
			$slideshow_previous_url=new ocp_tempcode();
			$back_url=new ocp_tempcode();
		}
		if (!is_null($next_id))
		{
			$slideshow_next_url=build_url(array('page'=>'_SELF','type'=>$next_type,'root'=>($root=='root')?NULL:$root,'wide_high'=>1,'id'=>$next_id,'slideshow'=>1,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF',NULL,true); // Continues, but as slideshow
			$next_url=build_url(array('page'=>'_SELF','type'=>$next_type,'root'=>($root=='root')?NULL:$root,'wide'=>1,'id'=>$next_id,'slideshow'=>($slideshow==0)?NULL:$slideshow,'wide_high'=>($wide_high==0)?NULL:$wide_high,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF',NULL,true);
		} else
		{
			$slideshow_next_url=new ocp_tempcode();
			$next_url=new ocp_tempcode();
		}

		// Link to show more. Preserve info about where we were
		$slideshow_url=build_url(array('page'=>'_SELF','type'=>$first_type,'root'=>($root=='root')?NULL:$root,'wide_high'=>1,'id'=>$first_id,'slideshow'=>1,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF',NULL,true);
		$more_url=is_null($cat)?NULL:build_url(array('page'=>'_SELF','type'=>'misc','id'=>$cat,'root'=>($root=='root')?NULL:$root,'start'=>($start==0)?NULL:$start,'max'=>($max==get_default_gallery_max())?NULL:$max,'days'=>(get_param('days','')=='')?NULL:get_param('days'),'sort'=>($sort=='add_date DESC')?NULL:$sort,'select'=>($image_select=='*')?NULL:$image_select,'video_select'=>($video_select=='*')?NULL:$video_select)+propagate_ocselect(),'_SELF');

		// Only one entry?
		if ($n==1)
		{
			$slideshow_url=new ocp_tempcode();
		}

		return do_template('GALLERY_NAV',array(
			'_GUID'=>'efd58f97d9c6254bd727125dfabb5a95',
			'X'=>integer_format($x),
			'N'=>integer_format($n),
			'_X'=>strval($x),
			'_N'=>strval($n),
			'SLIDESHOW_URL'=>$slideshow_url,
			'SLIDESHOW_NEXT_URL'=>$slideshow_next_url,
			'SLIDESHOW_PREVIOUS_URL'=>$slideshow_previous_url,
			'BACK_URL'=>$back_url,
			'NEXT_URL'=>$next_url,
			'MORE_URL'=>$more_url,
			'CATEGORY_NAME'=>$category_name,
			'SLIDESHOW'=>($slideshow==1),
		));
	}

	/**
	 * Read in the sort order currently active, and a suffix to the select statement to allow it to work. Apply security.
	 *
	 * @return array			A quarter: The sort order, The sort order (for backwards sorting), SQL suffix for select statement for images, SQL suffix for select statement for videos
	 */
	function get_sort_order()
	{
		global $NON_CANONICAL_PARAMS;
		$NON_CANONICAL_PARAMS[]='sort';
		$NON_CANONICAL_PARAMS[]='select';
		$NON_CANONICAL_PARAMS[]='video_select';

		$sort=get_param('sort','add_date DESC');
		if ($sort=='random ASC') $sort='add_date ASC';
		if (($sort!='fixed_random ASC') && ($sort!='compound_rating DESC') && ($sort!='compound_rating ASC') && ($sort!='add_date DESC') && ($sort!='add_date ASC') && ($sort!='url DESC') && ($sort!='url ASC'))
			log_hack_attack_and_exit('ORDERBY_HACK');
		list($_sort,$_dir)=explode(' ',$sort,2);
		$sort_backwards=$_sort.' '.(($_dir=='ASC')?'DESC':'ASC');
		if (($sort=='compound_rating ASC') || ($sort=='compound_rating DESC'))
		{
			$suffix_images=',(SELECT AVG(rating) FROM '.get_table_prefix().'rating WHERE '.db_string_equal_to('rating_for_type','images').' AND rating_for_id=e.id) AS compound_rating';
			$suffix_videos=',(SELECT AVG(rating) FROM '.get_table_prefix().'rating WHERE '.db_string_equal_to('rating_for_type','videos').' AND rating_for_id=e.id) AS compound_rating';
		} elseif ($sort=='fixed_random ASC')
		{
			$suffix_images=',(MOD(id,3.142)) AS fixed_random';
			$suffix_videos=',(MOD(id,3.142)) AS fixed_random';
		} else
		{
			$suffix_images='';
			$suffix_videos='';
		}
		return array($sort,$sort_backwards,$suffix_images,$suffix_videos);
	}

}


