HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/modules/gallery/module.gallery.php
<?php

/**
 * This implements the 'Gallery' functionality.
 *
 * @version $Id$
 
 *
 * @package IWP_Modules
 * @subpackage Gallery_Module
 */


/**
 * Class iwp_module_gallery
 *
 */
class iwp_module_gallery extends iwp_module
{

	/**
	 * This static variable contains permissions that are available to be chosen for setting module permissions on a per-content-type basis.
	 *
	 * @var Array
	 */
	public static $ContentPermissionOptions;

	/**
	 * This static variable contains permissions that are available to be chosen for setting module permissions on a site-wide basis.
	 *
	 * @var Array
	 */
	public static $SitePermissionOptions;

	/**
	 * The name of the module. This should correspond with the directory name and the name of this class.
	 *
	 * @var string
	 */

	public $moduleName = 'gallery';

	/**
	* An array of the cache directories that this module uses.
	*
	* @var array
	*/

	public $cacheDirs = array('module_gallery'	=> array('expires' => 172800, 'extension' => 'html')); // expires in 48 hours

	/**
	 * This variable specifies that this module does have blocks that can be added to the website on the site layout page of the control panel
	 *
	 * @var boolean
	 */
	public $hasBlocks = true;

	/**
	 * This variable specifies that this module has a layout that can be changed on the site layout page.
	 *
	 * @var boolean
	 */
	public $hasLayout = true;

	/**
	 * This is a list of the blocks that can be dragged onto the site layout page.
	 * @var unknown_type
	 */
	protected $layoutBlocks = array(
		array(
			'id'	=>'GalleryList',
			'name'	=>'',
			'icon'	=>'field_icon.png',
		),
		array(
			'id'	=>'LatestGallery',
			'name'	=>'',
			'icon'	=>'field_icon_latest.png',
		),
		array(
			'id'		=>'SelectedGallery',
			'name'		=>'',
			'icon'		=>'field_icon_preview.png',
			'hasPopup' 	=> true,
			'hasJS' 	=> true,
		),
		array(
			'id'		=>'SlideShow',
			'name'		=>'',
			'icon'		=>'field_icon_slideshow.png',
			'hasPopup' 	=> true,
			'hasJS' 	=> true,
		),
	);

	/**
	 * This is a list of all the image directories that this module uses
	 *
	 * @var array
	 */

	protected $imageDirectories = array('gallery');

	/**
	 * An array of all the database tables that this module uses. These names will be appended with the module table prefix.
	 *
	 * @var array
	 */

	protected $dbTables = array(
		'galleries',
		'galleryimages'
	);

	/**
	 * This is the name of the primary key column used in the primary table
	 *
	 * @var string
	 */

	protected $contentIdColumn = 'id';

	/**
	 * This is an array which holds a list of any errors that occur during the 'delete a gallery' process.
	 *
	 * @var array
	 */

	private $DeleteErrors = array();

	/**
	 * These are the fields that are to be displayed on the 'View' galleries page
	 *
	 * @var array
	 */

	public $DisplayFields = array(
		array(
			'name'		=> 'Name',
			'dbfield'	=> 'name',
			'sortable'	=> true,
			'display'	=> true,
			'default'	=> '[None]',
			'UseLang'	=> true,
		),
		array(
			'name'		=> 'NumImages',
			'dbfield'	=> 'numimages',
			'subquery' 	=> 'select count(*) from [table.galleryimages] as gi where g.id=gi.galleryid',
			'sortable'	=> true,
			'display'	=> true,
			'default'	=> '[None]',
			'UseLang'	=> true,
		),
		array(
			'name'		=> 'DateCreated',
			'dbfield'	=> 'date_created',
			'sortable'	=> true,
			'display'	=> true,
			'default'	=> '[None]',
			'UseLang'	=> true,
		),
		array(
			'name'		=> 'DateModified',
			'dbfield'	=> 'date_updated',
			'sortable'	=> true,
			'display'	=> true,
			'default'	=> '[None]',
			'UseLang'	=> true,
		),

	);

	/**
	 * Instance
	 * This static variable holds the current instance of this object being loaded.
	 * So using the getInstance function anywhere will return the very same instance.
	 *
	 * @var object Instance
	 */

	public static $Instance;

	/**
	 * getInstance
	 * This is a static function that sets up the class instance and stores it to the static variable. It will then return that instantiation in the future.
	 *
	 * @return iwp_module_comments Returns the instantiated object
	 **/

	public static function getInstance(){
		if(!isset(self::$Instance)){
			self::$Instance = new self();
		}
		return self::$Instance;
	}

	/**
	 * This is the class constructor. It calls the parent constructor that may complete some default actions.
	 * It also sets the UploadPath and UploadDir variables for this module using the current installation's path information.
	 *
	 * @return void
	 */
	public function __construct(){
		parent::__construct();
		$this->UploadPath = IWP_IMAGES_PATH . '/gallery';
		$this->UploadDir  = IWP_IMAGES_URI . '/gallery';
	}
	/**
	 * Private storage for the control panel view data
	 *
	 * @var array
	 */

	private $ViewList;

	/**
	 * Set up the event listeners for the module.
	 * For this module, it wants to hook into the control panel's drop down meny system and add a menu item for managing galleries.
	 *
	 * @var array
	 */
	protected $eventListeners = array(
		'iwp_event_admin_navigation_dropdownmenucreated' => array(
			'iwp_module_gallery', 'OnDropdownMenuCreated'
		),
		'iwp_event_admin_content_urlbrowser' => array(
			'iwp_module_gallery', 'URLBrowserHook'
		),
		'iwp_event_content_afterdbload' => array(
			'iwp_module_gallery', 'ViewContentHook'
		),
		'iwp_event_admin_content_tinymceplugin' => array(
			'iwp_module_gallery', 'TinyMCEPluginHook'
		),
		'iwp_event_categories_beforeshowtemplate' => array(
			'iwp_module_gallery', 'onCategoriesBeforeShowTemplate'
		),
		'iwp_event_template_outputblockbeforeparsesection' => array(
			'iwp_module_gallery', 'onTemplateOutputBlockBeforeParseSection'
		),
		'iwp_event_users_beforeprofiledisplay' => array(
			'iwp_module_gallery', 'onUserProfileDisplay'
		),
	);

	/**
	 * Returns whether or not this module implements content functionality.
	 *
	 * @return boolean
	 */

	public function IsContentModule () { return false; }

	/**
	 * Returns whether or not this module implements a configuration screen
	 *
	 * @return boolean
	 */

	public function HasConfigurationScreen () { return false; }

	/**
	 * This function shows a page based on a match found in on of its URL patterns
	 *
	 * @param string $url The matched URL
	 * @return void This function outputs a page of HTML
	 */
	public function ShowPageByIniUri($url){
		$uriList	= $this->urls->GetModuleUrls($this->moduleName);
		$matchedUri = $this->urls->GetCurrentModulePage();
		$uriBits	= $this->urls->GetCurrentMatches();

		if (in_string('{idnumber}', $uriList[$matchedUri]) && (!isset($uriBits['idnumber']) || !iwp_IsId($uriBits['idnumber']))) {
			iwp_controller::getInstance()->ShowPage('NotFound');
		}

		switch(iwp_strtolower($matchedUri)) {
			case 'getpicture':
				$this->RemoteGetPicture($uriBits);
				break;

			case 'getgallery':
				die($this->RemoteGetGallery($uriBits));
				break;

			case 'tinymceplaceholder':
				$this->GetPlaceholderImg();
				break;

			case 'viewimage':
				$this->RemoteGetImagePage($uriBits);
				break;

			case 'allgalleries':
			case 'allgalleries2':
				$this->GetAllGalleriesPage($uriBits);
				break;
		}
		die();
	}

	/**
	* This function displays the front end page that lists all the visible galleries to website visitors.
	*
	* @return void
	*/

	private function GetAllGalleriesPage() {
		// Load the module language variables
		$this->LoadLanguageVariables();

		$requestPage 	= max((int)@$_GET['page'], 1);
		$perpage 		= 5;
		$limit 			= (($requestPage*$perpage)-$perpage) . ', '.$perpage;

		$imagesQuery = $this->db->Query('select SQL_CALC_FOUND_ROWS * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where assoctype="module" and modulename="gallery" and (select count(*) from  ' . $this->getTable('galleryimages') . ' where galleryid=id)>0 order by date_created desc LIMIT ' . $limit);

		$foundRows = $this->db->FetchQuery('select found_rows() as found');
		$foundRows = $foundRows['found'];

		$OutputList = array();
		$OutputList = $this->db->FetchQueryAll($imagesQuery);

		$this->paging = new iwp_paging();
		$this->paging->SetPaging($foundRows, $perpage, $requestPage, iwp_config::Get('siteURL') . '/galleries/?page=%d', 5);

		$paging = array();
		$paging['PageCount']	= $this->paging->PageCount;
		$paging['currentPage']	= $this->paging->CurrentPage;
		$paging['prevPageLink']	= $this->paging->PreviousURL;
		$paging['nextPageLink']	= $this->paging->NextURL;
		$paging['links']		= $this->paging->PageList;
		$paging['firstPageLink']= $this->paging->FirstURL;
		$paging['lastPageLink']	= $this->paging->LastURL;

		$this->template->Assign('paging', $paging);
		$this->template->Assign('galleryPaging', $this->template->ParseSection('paginglinks_standard'), false);

		$breadCrumbTrailLinks = array();
		$breadCrumbTrailLinks[] = array('Url' => iwp_config::Get('siteURL') .'/', 'Title' => $this->lang->Get('HomePage'));
		$breadCrumbTrailLinks[] = array('Title' => $this->lang->Get('gGalleries'));

		$this->template->Assign(array('breadcrumbtrail', 'links'), $breadCrumbTrailLinks);
		$this->template->Assign('galleryBreadcrumb', $this->template->ParseSection('breadcrumbtrail_standard'), false);
		$this->template->Assign('galleryList', 		 $OutputList);

		$this->controller->SetContent($this->template->ParseTemplate('gallery.viewgalleries', true, 'gallery'));
		$this->controller->ShowTemplate('module_gallery');
	}

	/**
	* This is a function that is called through an ajax request when the user drags a certain block onto the site layout.
	* This function outputs a HTML form with a select box containing the list of available galleries.
	*
	* @return void
	*/

	public function RemoteGetSelectGallery () {
		// Load the module language variables
		$this->LoadLanguageVariables();

		if(isset($_GET['selectedgallery']) && (int)$_GET['selectedgallery'] > 0) {
			$this->template->Assign('galleryOptions', $this->GetGalleriesList((int)$_GET['selectedgallery']));
		}else{
			$this->template->Assign('galleryOptions', $this->GetGalleriesList());
		}

		die($this->template->ParseTemplate('block.select', true, 'gallery'));
	}

	/**
	* This function is called through an ajax request when a user drags a 'Gallery SlideShow' onto their site layout.
	*
	* @return void
	*/

	public function RemoteGetSlideShow () {
		// Load the module language variables
		$this->LoadLanguageVariables();

		$this->template->Assign('galleryOptions', $this->GetGalleriesList());

		$this->template->Assign('SelectedImages_20', $this->output->Selected());
		$this->template->Assign('DisplayTypeSelected_first', $this->output->Selected());

		die($this->template->ParseTemplate('block.select.slideshow', true, 'gallery'));
	}

	/**
	* Implements conversion of request data into data insertable to the template_data table for this module
	*
	* @param array $request
	* @param array $insert
	* @return boolean
	*/
	public function getSavedBlockInsert ($request, &$insert) {

		// the name of the block is the gallery name
		$insert['name'] = $this->db->FetchOne('select name from ' . $this->getTable('galleries') . ' where id=' . (int)$request['galleryid']);

		$request['numimages'] = (int)$request['numimages'];
		if($request['numimages'] < 5 || $request['numimages'] > 100) {
			$request['numimages'] = 20;
		}

		if(!in_array($request['displaytype'], array('newest', 'oldest', 'first', 'last', 'random'))) {
			$request['displaytype'] = 'first';
		}

		$data = array(
			'numimages'		=> $request['numimages'],
			'displaytype'	=> $request['displaytype'],
			'galleryid'		=> $request['galleryid'],
		);

		$insert['content'] = serialize($data);

		// This associates the saved block to the layoutBlocks array in this module,
		// it then allows the right icon to be added to the block
		$insert['title'] = 'SlideShow';

		return true;
	}

	/**
	* Implements output of an edit saved block template for this module. See parent function for more info.
	*
	* @param int $blockId
	* @param array $data
	* @return mixed
	*/
	public function getEditSavedBlockTemplate ($blockId, $data) {
		// Load the module language variables
		$this->LoadLanguageVariables();

		$options = unserialize($data['content']);

		if(isset($options['galleryid']) && (int)$options['galleryid'] > 0) {
			$this->template->Assign('galleryOptions', $this->GetGalleriesList((int)$options['galleryid']));
		}else{
			$this->template->Assign('galleryOptions', $this->GetGalleriesList());
		}

		$options['numimages'] = (int)$options['numimages'];

		if(in_array($options['numimages'], array(5,10,15,20,25,30,40,50,75,100))) {
			$this->template->Assign('SelectedImages_'.$options['numimages'], $this->output->Selected());
		}else{
			$this->template->Assign('SelectedImages_20', $this->output->Selected());
		}

		if(in_array($options['displaytype'], array('newest', 'oldest', 'first', 'last', 'random'))) {
			$this->template->Assign('DisplayTypeSelected_'.$options['displaytype'], $this->output->Selected());
		}else{
			$this->template->Assign('DisplayTypeSelected_first', $this->output->Selected());
		}

		return $this->template->ParseTemplate('block.select.slideshow', true, 'gallery');
	}

	/**
	* This function sets the album cover id for the current gallery. It expects the ID numbers for the image and gallery in a GET request.
	*
	* @return void This function outputs its result in JSON
	*/

	public function RemoteSetAlbumCover () {
		$imageId = (int)$_GET['imageid'];
		$galleryId = (int)$_GET['galleryid'];

		if ($imageId < 0 || $galleryId < 0) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidIDNumber'),
			)));
		}

		// permissions check
		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', $galleryId)) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		$update = array(
			'albumcoverid' => $imageId,
		);

		if ($this->db->UpdateQuery($this->getTable('galleries'), $update, 'id=' . $galleryId)) {

			$this->GenerateCoverImages($imageId);

			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gAlbumCoverSelectionSuccessful'),
			)));
		}

		$this->cache->SetDir('module_gallery');
		$this->cache->ClearCacheDir();

		die(json_encode(array(
			'success' => false,
			'message' => sprintf($this->lang->Get('gAlbumCoverMySQLError'), $this->db->GetErrorMsg()) ,
		)));

	}


	/**
	 * This function displays a page for a single image in a gallery, including the header and footer.
	 *
	 * @param array $uriBits An array of sections matched in the URL.
	 * @return void This function outputs its results.
	 */

	private function RemoteGetImagePage($uriBits) {
		$this->cache->SetDir('module_gallery');

		$this->template->AddRequiredJS(IWP_BASE_URI . '/modules/gallery/javascript/gallery.js');
		$this->template->Assign('onViewGalleryPage', '0');

		$cacheId = 'image_' . (int)$uriBits['idnumber'];

		$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . (int)$uriBits['idnumber']);
		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where assoctype="module" and modulename="gallery" and id=' . (int)$imageInfo['galleryid']);


		if(!$this->cache->HasExpired($cacheId)){
			$imageOutput = $this->cache->ReadCache($cacheId);
		}else{

			$nextImageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']+1));

			if(!$nextImageInfo) {
				// if there is no next image, get the first in the gallery
				$imgQuery = $this->db->Query('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder asc limit 2');
				$nextImageInfo = $this->db->Fetch($imgQuery);
				$navLastImageInfo = $this->db->Fetch($imgQuery);
			}else{
				$navLastImageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']+2));

				if(!$navLastImageInfo) {
					// if there is no next image, get the first in the gallery
					$navLastImageInfo = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder asc limit 1');
				}
			}

			$prevImageInfo = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']-1));

			if(!$prevImageInfo) {
				// if there is no previous image, get the last image in the gallery
				$imgQuery = $this->db->Query('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder desc limit 2');
				$prevImageInfo = $this->db->Fetch($imgQuery);
				$navFirstImageInfo = $this->db->Fetch($imgQuery);
			}else{
				$navFirstImageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']-2));

				if(!$navFirstImageInfo) {
					// if there is no next image, get the first in the gallery
					$navFirstImageInfo = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder desc limit 1');
				}
			}

			if(!is_array($imageInfo) || sizeof($imageInfo) < 1){
				iwp_controller::getInstance()->ShowPage('NotFound');
			}

			list($width, $height) = getimagesize($this->UploadPath . '/' . $imageInfo['galleryid'] . '/' . $imageInfo['imageid'] .'_album.' . $imageInfo['extension']);

			$imageNumber = (int)($this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where sortorder < ' . $imageInfo['sortorder'] . ' and galleryid=' . $imageInfo['galleryid'])+1);
			$totalImages = (int)$this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid']);

			$imageInfo['width'] = $width;
			$imageInfo['overlayPrevWidth'] =  floor($width/2);
			$imageInfo['overlayNextWidth'] =  ceil($width/2);
			$imageInfo['height'] = $height;

			$imageNav = array(
				'first' => array(
					'src' => $this->UploadDir . '/'. $navFirstImageInfo['galleryid'] . '/' . $navFirstImageInfo['imageid']  . '_nav.' . $navFirstImageInfo['extension'],
					'url' => '#viewimage-' . $navFirstImageInfo['imageid'],
					'title' => $navFirstImageInfo['title'],
				),
				'second' => array(
					'src' => $this->UploadDir . '/'. $prevImageInfo['galleryid'] . '/' . $prevImageInfo['imageid']  . '_nav.' . $prevImageInfo['extension'],
					'url' => '#viewimage-' . $prevImageInfo['imageid'],
					'title' => $prevImageInfo['title'],
				),
				'third' => array(
					'src' => $this->UploadDir . '/'. $imageInfo['galleryid'] . '/' . $imageInfo['imageid']  . '_nav.' . $imageInfo['extension'],
					'url' => '#viewimage-' . $imageInfo['imageid'],
					'title' => $imageInfo['title'],
				),
				'fourth' => array(
					'src' => $this->UploadDir . '/'. $nextImageInfo['galleryid'] . '/' . $nextImageInfo['imageid']  . '_nav.' . $nextImageInfo['extension'],
					'url' => '#viewimage-' . $nextImageInfo['imageid'],
					'title' => $nextImageInfo['title'],
				),
				'fifth' => array(
					'src' => $this->UploadDir . '/'. $navLastImageInfo['galleryid'] . '/' . $navLastImageInfo['imageid']  . '_nav.' . $navLastImageInfo['extension'],
					'url' => '#viewimage-' . $navLastImageInfo['imageid'],
					'title' => $navLastImageInfo['title'],
				),
			);

			$jsonData = array(
				'prevurl' 	=> '#viewimage-' . $prevImageInfo['imageid'],
				'nexturl' 	=> '#viewimage-' . $nextImageInfo['imageid'],
				'imagenum' 	=> sprintf($this->lang->Get('gViewImageNumber'), $imageNumber, $totalImages),
				'title' 	=> iwp_htmlspecialchars($imageInfo['title']),
				'caption' 	=> $imageInfo['caption'],
				'width'		=> $width,
				'height'		=> $height,
				'originalurl' 	=> $this->UploadDir . '/'. $imageInfo['galleryid'] . '/' . $imageInfo['imageid']  . '_original.' . $imageInfo['extension'],
				'viewimagesrc' 	=> $this->UploadDir . '/'. $imageInfo['galleryid'] . '/' . $imageInfo['imageid']  . '_album.' . $imageInfo['extension'],
				'imagenav'		=> $imageNav,
			);

			$breadCrumbTrailLinks = array();
			$breadCrumbTrailLinks[] = array('Url' => iwp_config::Get('siteURL') .'/', 'Title' => $this->lang->Get('HomePage'));
			$breadCrumbTrailLinks[] = array('Url' =>  iwp_config::Get('siteURL') .'/galleries/', 'Title' => $this->lang->Get('gGalleries'));
			$breadCrumbTrailLinks[] = array('Url' =>  iwp_config::Get('siteURL') . $galleryInfo['urlpath'], 'Title' => $galleryInfo['name']);
			$breadCrumbTrailLinks[] = array('Title' => $imageInfo['title']);

			$this->template->Assign(array('breadcrumbtrail', 'links'), $breadCrumbTrailLinks);

			$jsonData['breadcrumb'] = $this->template->ParseSection('breadcrumbtrail_standard');

				$this->template->Assign('image', $imageInfo);
				$this->template->Assign('next', $nextImageInfo);
				$this->template->Assign('prev', $prevImageInfo);
				$this->template->Assign('imageNav', $imageNav);
				$this->template->Assign('imageNumber', ($this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where sortorder < ' . $imageInfo['sortorder'] . ' and galleryid=' . $imageInfo['galleryid'])+1));
				$this->template->Assign('totalImages', $this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid']));

				$output = $this->template->ParseTemplate('gallery.viewimage', true, 'gallery');

			$imageOutput = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where imageid=' . (int)$uriBits['idnumber']);

			$imageOutput =  $this->template->ParseTemplate('gallery.viewimage', true, 'gallery');
			$this->cache->WriteCache($cacheId, $imageOutput);
		}

		$this->template->Assign('gallery',   $galleryInfo);
		$this->template->Assign('galleryId', $imageInfo['galleryid']);

		$this->template->Assign('galleryPageContent', $imageOutput, false);

		$this->controller->SetContent($this->template->ParseTemplate('gallery.view', true, 'gallery'));
		$this->controller->ShowTemplate('module_gallery');
	}

	/**
	 * This function displays the HTML for a single image. It displays only the HTMl for the image and not the whole page.
	 *
	 * @param array $uriBits An array of the section matches specified by the uri patterns.
	 * @return void
	 */

	private function RemoteGetPicture($uriBits) {
		$this->cache->SetDir('module_gallery');

		$cacheId = 'image_json_' . (int)$uriBits['idnumber'];

		$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . (int)$uriBits['idnumber']);
		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where assoctype="module" and modulename="gallery" and id=' . (int)$imageInfo['galleryid']);

		$nextImageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']+1));

		if(!$nextImageInfo) {
			// if there is no next image, get the first in the gallery
			$imgQuery = $this->db->Query('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder asc limit 2');
			$nextImageInfo = $this->db->Fetch($imgQuery);
			$navLastImageInfo = $this->db->Fetch($imgQuery);
		}else{
			$navLastImageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']+2));

			if(!$navLastImageInfo) {
				// if there is no next image, get the first in the gallery
				$navLastImageInfo = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder asc limit 1');
			}
		}

		$prevImageInfo = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']-1));

		if(!$prevImageInfo) {
			// if there is no previous image, get the last image in the gallery
			$imgQuery = $this->db->Query('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder desc limit 2');
			$prevImageInfo = $this->db->Fetch($imgQuery);
			$navFirstImageInfo = $this->db->Fetch($imgQuery);
		}else{
			$navFirstImageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid'] . ' AND sortorder='. ($imageInfo['sortorder']-2));

			if(!$navFirstImageInfo) {
				// if there is no next image, get the first in the gallery
				$navFirstImageInfo = $this->db->FetchQuery('select * from '. $this->getTable('galleryimages'). ' where galleryid=' . $imageInfo['galleryid'] . ' order by sortorder desc limit 1');
			}
		}

		if(!is_array($imageInfo) || sizeof($imageInfo) < 1){
			iwp_controller::getInstance()->ShowPage('NotFound');
		}

		list($width, $height) = getimagesize($this->UploadPath . '/' . $imageInfo['galleryid'] . '/' . $imageInfo['imageid'] .'_album.' . $imageInfo['extension']);

		$imageNumber = (int)($this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where sortorder < ' . $imageInfo['sortorder'] . ' and galleryid=' . $imageInfo['galleryid'])+1);
		$totalImages = (int)$this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid']);

		$imageInfo['width'] = $width;
		$imageInfo['overlayPrevWidth'] =  floor($width/2);
		$imageInfo['overlayNextWidth'] =  ceil($width/2);
		$imageInfo['height'] = $height;

		$imageNav = array(
			'first' => array(
				'src' => $this->UploadDir . '/'. $navFirstImageInfo['galleryid'] . '/' . $navFirstImageInfo['imageid']  . '_nav.' . $navFirstImageInfo['extension'],
				'url' => '#viewimage-' . $navFirstImageInfo['imageid'],
				'title' => $navFirstImageInfo['title'],
			),
			'second' => array(
				'src' => $this->UploadDir . '/'. $prevImageInfo['galleryid'] . '/' . $prevImageInfo['imageid']  . '_nav.' . $prevImageInfo['extension'],
				'url' => '#viewimage-' . $prevImageInfo['imageid'],
				'title' => $prevImageInfo['title'],
			),
			'third' => array(
				'src' => $this->UploadDir . '/'. $imageInfo['galleryid'] . '/' . $imageInfo['imageid']  . '_nav.' . $imageInfo['extension'],
				'url' => '#viewimage-' . $imageInfo['imageid'],
				'title' => $imageInfo['title'],
			),
			'fourth' => array(
				'src' => $this->UploadDir . '/'. $nextImageInfo['galleryid'] . '/' . $nextImageInfo['imageid']  . '_nav.' . $nextImageInfo['extension'],
				'url' => '#viewimage-' . $nextImageInfo['imageid'],
				'title' => $nextImageInfo['title'],
			),
			'fifth' => array(
				'src' => $this->UploadDir . '/'. $navLastImageInfo['galleryid'] . '/' . $navLastImageInfo['imageid']  . '_nav.' . $navLastImageInfo['extension'],
				'url' => '#viewimage-' . $navLastImageInfo['imageid'],
				'title' => $navLastImageInfo['title'],
			),
		);

		$jsonData = array(
			'prevurl' 	=> '#viewimage-' . $prevImageInfo['imageid'],
			'nexturl' 	=> '#viewimage-' . $nextImageInfo['imageid'],
			'imagenum' 	=> sprintf($this->lang->Get('gViewImageNumber'), $imageNumber, $totalImages),
			'title' 	=> iwp_htmlspecialchars($imageInfo['title']),
			'caption' 	=> $imageInfo['caption'],
			'width'		=> $width,
			'overlayPrevWidth' =>  floor($width/2),
			'overlayNextWidth' =>  ceil($width/2),
			'height'		=> $height,
			'originalurl' 	=> $this->UploadDir . '/'. $imageInfo['galleryid'] . '/' . $imageInfo['imageid']  . '_original.' . $imageInfo['extension'],
			'viewimagesrc' 	=> $this->UploadDir . '/'. $imageInfo['galleryid'] . '/' . $imageInfo['imageid']  . '_album.' . $imageInfo['extension'],
			'imagenav'		=> $imageNav,
		);

		$breadCrumbTrailLinks = array();
		$breadCrumbTrailLinks[] = array('Url' => iwp_config::Get('siteURL') .'/', 'Title' => $this->lang->Get('HomePage'));
		$breadCrumbTrailLinks[] = array('Url' =>  iwp_config::Get('siteURL') .'/galleries/', 'Title' => $this->lang->Get('gGalleries'));
		$breadCrumbTrailLinks[] = array('Url' =>  iwp_config::Get('siteURL') . $galleryInfo['urlpath'], 'Title' => $galleryInfo['name']);
		$breadCrumbTrailLinks[] = array('Title' => $imageInfo['title']);

		$this->template->Assign(array('breadcrumbtrail', 'links'), $breadCrumbTrailLinks);

		$jsonData['breadcrumb'] = $this->template->ParseSection('breadcrumbtrail_standard');

		if(isset($_GET['h']) && $_GET['h'] == 'y') { // do we need to include the HTML structure? This is if they've clicked on an image from the gallery.
			$this->template->Assign('image', $imageInfo);
			$this->template->Assign('next', $nextImageInfo);
			$this->template->Assign('prev', $prevImageInfo);
			$this->template->Assign('imageNav', $imageNav);
			$this->template->Assign('imageNumber', ($this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where sortorder < ' . $imageInfo['sortorder'] . ' and galleryid=' . $imageInfo['galleryid'])+1));
			$this->template->Assign('totalImages', $this->db->FetchOne('select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=' . $imageInfo['galleryid']));

			$output = $this->template->ParseTemplate('gallery.viewimage', true, 'gallery');
			$jsonData['output'] = $output;
			$jsonData['hasOutput'] = true;
		}else {
			$jsonData['output'] = false;
			$jsonData['hasOutput'] = false;
		}

		$result = json_encode($jsonData);
		$this->cache->WriteCache($cacheId, $result);
		die($result);
	}

	/**
	 * This function outputs the HTML for the image thumbnails for a gallery.
	 *
	 * @param array $uriBits An array of the section matches specified by the uri patterns.
	 * @return void This function outputs its HTML.
	 */

	private function RemoteGetGallery($uriBits, $galleryInfo=null) {
		$urlId = (int)$uriBits['idnumber'];

		if(is_null($galleryInfo)) {
			$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where assoctype="module" and modulename="gallery" and id=' . $urlId);
		}

		$this->template->Assign("gallery", $galleryInfo);

		$requestPage 	= max((int)@$_GET['page'], 1);
		$perpage 		= 21;
		$limit 			= (($requestPage*$perpage)-$perpage) . ', '.$perpage;

		$imagesQuery = $this->db->Query('select SQL_CALC_FOUND_ROWS * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $urlId . ' order by sortorder asc LIMIT ' . $limit);
		$foundRows = $this->db->FetchQuery('select found_rows() as found');
		$foundRows = $foundRows['found'];

		$OutputList = array();

		while($row = $this->db->Fetch($imagesQuery)) {
			$OutputList[] = $row;
		}

		$this->paging = new iwp_paging();
		$this->paging->SetPaging($foundRows, $perpage, $requestPage, iwp_config::Get('siteURL') . $galleryInfo['urlpath'] . '?page=%d', 5);

		$paging = array();
		$paging['PageCount']	= $this->paging->PageCount;
		$paging['currentPage']	= $this->paging->CurrentPage;
		$paging['prevPageLink']	= $this->paging->PreviousURL;
		$paging['nextPageLink']	= $this->paging->NextURL;
		$paging['links']		= $this->paging->PageList;
		$paging['firstPageLink']= $this->paging->FirstURL;
		$paging['lastPageLink']	= $this->paging->LastURL;

		$this->template->Assign('OutputList', $OutputList);
		$this->template->AddRequiredJS(IWP_BASE_URI . '/modules/gallery/javascript/gallery.js');

		$this->template->Assign('paging', $paging);
		$pagingHTML = $this->template->ParseSection('paginglinks_standard');
		$this->template->Assign('galleryPaging', $pagingHTML, false);

		return $this->template->ParseTemplate('gallery.albumview', true, 'gallery');
	}


	/**
	 * This function returns the array of module blocks with any modifications or additions that need to be made.
	 *
	 * @return array The array of blocks for the site layout page in the control panel
	 */
	public function GetLayoutBlocks(){
		$blocks = $this->layoutBlocks;

		foreach($blocks as $key=>$block){
			$blocks[$key]['icon'] = IWP_MODULES_URI . '/' . $this->moduleName . '/images/' .$blocks[$key]['icon'];
			$blocks[$key]['name'] = $this->lang->Get('gLayoutBlock_' . $blocks[$key]['id']);
		}

		$this->template->AddLanguageForJS('galleryPleaseChooseSlideShowGallery', $this->lang);

		return $blocks;
	}

	/**
	* This is the primary handler function for displaying on the frontend any blocks placed on the site layout page.
	*
	* @param mixed $blockName The unique name for this block type
	* @param mixed $position The position of the block on the page; top, middle, left, right, bottom
	* @param mixed $id The ID number of the gallery for this particular block.(if any)
	*
	* @return string This function returns HTML or a blank string depending on whether the requested block is valid and should be displayed or not.
	*/

	public function OutputBlock($blockName, $position, $id=null) {
		$blocks = $this->GetLayoutBlocks();

		$data = array();
		$data['lang'] = $this->lang->GetLangVars();
		$this->template->Assign($this->moduleName, $data, false);

		$this->cache->SetDir('module_gallery');

		if(is_null($id)) {
			$cacheId = $blockName . '_' . $position;
		}else{
			$cacheId = $blockName . '_' . $position . '_' . $id;
		}

		if(!$this->cache->HasExpired($cacheId)){
			return $this->cache->ReadCache($cacheId);
		}

		switch($blockName) {
			case 'GalleryList':
				return $this->GetGalleryListBlock($position);
			case 'LatestGallery':
				return $this->GetLatestGalleryBlock($position);
			case 'SelectedGallery':
				return $this->GetGalleryPreviewBlock($id, $position);
		}

		return '';
	}

	/**
	* Outputs a block for this module which is saved in the template_data table
	*
	* @param int $blockId The block id to output
	* @param int $position The section of the page this block is displayed in; left, middle, right, top, bottom
	* @return string The resulting output HTML
	*/
	public function OutputSavedBlock($blockId, $position) {
		$data = $this->db->FetchQuery('select * from ' . IWP_TABLE_TEMPLATE_DATA . ' where blockid=' . (int)$blockId);

		if($data['title'] == "SlideShow") {
			$options = @unserialize($data['content']);
			if(!is_array($options) || empty($options) || !isset($options['galleryid']) || !isset($options['numimages'])  || !isset($options['displaytype'])) {
				return '';
			}

			return $this->GetSlideShowBlock($options['galleryid'], $position, $options['numimages'], $options['displaytype']);
		}

		return '';
	}

	/**
	* This is a handler/hook function that is called upon when loading the website layout page.
	* The call allows modules define any javascript code they need for the page.
	* This particular function loads the list of avaialble galleries that is used if the user drags a 'Slideshow' or 'Preview' gallery block onto the site layout.
	*
	* @param string $block
	*/

	public function LayoutPageJavascript($block) {
		if($block == "SelectedGallery") {
			return 'GalleryModuleBlocksHelper.galleryNames = ' . $this->GetGalleriesJSON() . ';' . "\n";
		}
	}

	/**
	* This function returns the HTML for a 'Gallery Preview' block on the front end based on its ID number and position on the page.
	*
	* @param integer $id The ID number of the gallery to display the preview for.
	* @param string $position The position of the block on the page; top, middle, left, right, bottom
	*
	* @return string The HTML for the Gallery Preview block, or a blank string if the ID was not valid.
	*/

	private function GetGalleryPreviewBlock($id, $position) {
		$id = (int)$id;

		if($id < 1) {
			return '';
		}

		$OutputList = array();

		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where assoctype="module" and modulename="gallery" and id=' . $id);

		if(sizeof($galleryInfo) < 1 || !isset($galleryInfo['id']) || (int)$galleryInfo['id']<1) {
			return '';
		}

		$this->template->Assign('galleryInfo', $galleryInfo);

		if($position == "middle") {
			$return = $this->template->ParseTemplate('gallery.preview.middle', true, 'gallery');
		}else{
			$return = $this->template->ParseTemplate('gallery.preview', true, 'gallery');
		}

		$this->cache->WriteCache('SelectedGallery_' . $position . '_' . $id, $return);

		return $return;

	}

	/**
	* This function returns the HTML for the 'Gallery List' block that displays a list of the 10 latest galleries on the front end.
	*
	* @return string The HTML for the Gallery Preview block, or a blank string if there are no galleries.
	*/

	private function GetGalleryListBlock($position) {

		$OutputList = array();

		$listQuery = $this->db->Query('select * from ' . $this->getTable('galleries') . ' as g inner join ' . IWP_TABLE_URLS .' as u on u.associd=g.id inner join ' . $this->getTable('galleryimages') . ' as gi on g.albumcoverid=gi.imageid where (select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=id)>0 and u.assoctype="module" and u.modulename="gallery" order by g.date_created desc limit 10');

		$OutputList = $this->db->FetchQueryAll($listQuery);

		if(sizeof($OutputList) < 1) {
			return '';
		}


		$this->template->Assign('blockTitle', $this->lang->Get('imageGalleries'));
		$this->template->Assign('OutputList', $OutputList, false);

		if($position == "middle") {
			$return = $this->template->ParseTemplate('gallery.list.middle', true, 'gallery');
		}else{
			$return = $this->template->ParseTemplate('gallery.list', true, 'gallery');
		}

		$this->cache->WriteCache('GalleryList_' . $position, $return);

		return $return;
	}

	/**
	* This function returns the HTML for the 'Latest Gallery' block which displays a gallery preview for the most recently added gallery.
	*
	* @return string The HTML for the Latest Gallery block, or a blank string if there are no galleries.
	*/

	private function GetLatestGalleryBlock ($position) {
		$OutputList = array();

		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' as g inner join ' . IWP_TABLE_URLS .' as u on u.associd=g.id inner join ' . $this->getTable('galleryimages') . ' as gi on g.albumcoverid=gi.imageid where (select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=id)>0 and u.assoctype="module" and u.modulename="gallery" order by g.date_created desc limit 1');

		if(sizeof($galleryInfo) < 1 || !isset($galleryInfo['id']) || (int)$galleryInfo['id'] < 1) {
			return '';
		}

		$this->template->Assign('galleryInfo', $galleryInfo);

		if($position == "middle") {
			$return = $this->template->ParseTemplate('gallery.latest.middle', true, 'gallery');
		}else{
			$return = $this->template->ParseTemplate('gallery.latest', true, 'gallery');
		}

		$this->cache->WriteCache('LatestGallery_' . $position, $return);

		return $return;
	}


	/**
	* This function returns the HTML for a 'Gallery Slideshow' block on the front end based on its ID number and position on the page.
	*
	* @param integer $id The ID number of the gallery to display the slideshow for.
	* @param string $position The position of the block on the page; top, middle, left, right, bottom
	*
	* @return string The HTML for the Gallery Slideshow block, or a blank string if the ID was not valid.
	*/

	private function GetSlideShowBlock ($id, $position, $numimages=50, $displaytype='first') {
		$OutputList = array();
		$orderby = "ORDER BY ";

		switch($displaytype) {
			case 'random':
				$orderby .= " rand()";
				break;

			case 'last':
				$orderby .= " sortorder desc";
				break;
			case 'newest':
				$orderby .= " date_created desc";
				break;
			case 'oldest':
				$orderby .= " date_created asc";
				break;

			case 'first':
			default:
				$orderby .= " sortorder asc";
				break;
		}

		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where (select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=id)>0 and assoctype="module" and modulename="gallery" and id=' . (int)$id . ' limit 1');

		if(sizeof($galleryInfo) < 1 || !isset($galleryInfo['id']) || (int)$galleryInfo['id'] < 1) {
			return '';
		}

		$galleryImages = $this->db->FetchQueryAll('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . (int)$id  . ' ' . $orderby .' limit ' . (int)$numimages);

		foreach($galleryImages as $key => $thisImage) {
			$imagePath = IWP_IMAGES_PATH . '/gallery/' . $galleryInfo['id'] . '/' . $thisImage['imageid'] . '_album.' . $thisImage['extension'];
			list($width, $height) = getimagesize($imagePath);
			$galleryImages[$key]['height'] = $height;
			$galleryImages[$key]['width']  = $width;
		}

		$this->template->Assign('galleryInfo', $galleryInfo);
		$this->template->Assign('galleryImages', $galleryImages);
		$this->template->Assign('totalImageCount', count($galleryImages));
		$this->template->Assign('randomId', rand(1000,1000000));

		if($position == 'middle'){
			$return = $this->template->ParseTemplate('gallery.slideshow.middle', true, 'gallery');
		}else{
			$return = $this->template->ParseTemplate('gallery.slideshow', true, 'gallery');
		}

		$this->cache->SetDir('module_gallery');
		$this->cache->WriteCache('SlideShow_' . $position . '_' . $id, $return);

		$this->template->AddRequiredJS(IWP_BASE_URI . '/modules/gallery/javascript/galleryview/jquery.galleryview-2.0-pack.js');
		$this->template->AddRequiredCSS(IWP_BASE_URI . '/modules/gallery/javascript/galleryview/galleryview.css');

		return $return;
	}

	/**
	 * This function displays a page on the frontend based on a URL that is stored in the database.
	 *
	 * @return void
	 */

	public function ShowPageByDbUri($data) {
		$urlId = (int)$data['associd'];
		$uriBits = array('idnumber'=>$urlId);

		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where  assoctype="module" and modulename="gallery" and id=' . $urlId);

		$breadCrumbTrailLinks = array();
		$breadCrumbTrailLinks[] = array('Url' => iwp_config::Get('siteURL') .'/', 'Title' => $this->lang->Get('HomePage'));
		$breadCrumbTrailLinks[] = array('Url' =>  iwp_config::Get('siteURL') .'/galleries/', 'Title' => $this->lang->Get('gGalleries'));
		$breadCrumbTrailLinks[] = array('Title' => $galleryInfo['name']);

		$this->template->Assign(array('breadcrumbtrail', 'links'), $breadCrumbTrailLinks);
		$this->template->Assign('galleryBreadcrumb', $this->template->ParseSection('breadcrumbtrail_standard'), false);

		$this->template->Assign('onViewGalleryPage', '1');
		$this->template->Assign('galleryPageContent', $this->RemoteGetGallery($uriBits, $galleryInfo), false);

		$this->controller->SetContent($this->template->ParseTemplate('gallery.view', true, 'gallery'));
		$this->controller->ShowTemplate('module_gallery');
	}

	/**
	 * This is the routing function for the control panel for the module. It handles all the views of the module.
	 *
	 *  @return void
	 */
	public function AdminCustom() {

		$moduleAction = @$_GET['moduleaction'];
		$this->template->Assign('module', 'gallery');

		switch (iwp_strtolower($moduleAction)) {
			case 'create':
				if (!$this->auth->HasPerm('sitemodules', 'gallery', 'create')) {
					$this->template->Assign('MessageText', $this->lang->Get('gNoPermissionToCreateGallery'), false);
					$this->template->Assign('MessageType', MSG_ERROR);
					$this->AdminView();
				}else{
					$this->template->Assign('moduleaction', $moduleAction);
					$this->AdminCreate();
				}

			break;

			case 'deletesinglegallery':
				if (!$this->auth->HasPerm('sitemodules', 'gallery', 'delete', (int)$_GET['galleryid'])) {
					$this->template->Assign('MessageText', $this->lang->Get('gNoPermissionToDeleteGallery'), false);
					$this->template->Assign('MessageType', MSG_ERROR);
					$this->AdminView();
				}else {
					$this->template->Assign('moduleaction', $moduleAction);
					$this->DeleteSingleGallery();
				}
			break;

			case 'edit':
				if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$_GET['galleryid'])) {
					$this->template->Assign('MessageText', $this->lang->Get('gNoPermissionToEditGallery'), false);
					$this->template->Assign('MessageType', MSG_ERROR);
					$this->AdminView();
				}else {
					$this->template->Assign('moduleaction', $moduleAction);
					$this->EditGallery();
				}
			break;

			case 'deletegalleries':
				// permission checking takes place on a per gallery level inside the DeleteGallery() function
				$this->template->Assign('moduleaction', $moduleAction);
				$this->DeleteGalleries();
			break;

			default:
				$this->template->Assign('moduleaction', 'view');
				$this->AdminView();
			break;
		}
	}

	/**
	 * This function returns the member array variable ViewList
	 *
	 * @return array The $ViewList variable'
	 *
	 * @see $ViewList
	 */

	public function GetViewList ()
	{
		return $this->ViewList;
	}

	/**
	 * This function loads the manage 'view' for the lists and puts it into the member variable $ViewList which is then used by the template system to loop over.
	 *
	 * @return void Doesn't return anything
	 *
	 * @see $ViewList
	 */

	public function LoadViewList($status = null)
	{
		// set the default sort order information
		$sortField = 'date_created';
		$sortDir   = 'desc';

		// initialize variables
		$searchQuery 	= $searchField 	= '';
		$requestPage 	= 1;
		$pagingStart 	= 0;
		$where 			= array();
		$pagingPerPage	= 20;

		// do we have user requested sort direction information ?
		if(isset($_GET['sortdir'])) {
			if(iwp_strtolower($_GET['sortdir']) == "asc"){
				$sortDir = "asc";
			}

			if(iwp_strtolower($_GET['sortdir']) == "desc"){
				$sortDir = "desc";
			}
		}

		// do we have user requested sort field information?
		if(isset($_GET['field'])){
			foreach($this->DisplayFields as $_key=>$v) {
				if($v['dbfield'] == $_GET['field']){
					$sortField = $v['dbfield'];
					$this->template->Assign('SortField', $sortField);
					$this->template->Assign('SortDir', $sortDir);
					break;
				}
			}
		}

		// checking the page number, defaulting to page one
		if(isset($_GET['page'])) {
			$requestPage = (int)$_GET['page'];
			if($requestPage < 1) {
				$requestPage = 1;
			}
		}

		// check for a search term
		if (isset($_GET['searchQuery'])) {
			$searchQuery = $_GET['searchQuery'];
		}

		if (isset($_GET['searchField'])) {
			$searchField = $_GET['searchField'];
			if ($searchField) {
				$this->template->Assign('SearchField_'. $searchField .'_selected', ' selected="selected"');
			}
		}

		// define a boolean variable to determine if we are performing a search based on whether there is a search term
		$isSearching = ($searchQuery != '');

		// assign template variables
		$this->template->Assign('searchQuery', $searchQuery, true);
		$this->template->Assign('searchField', $searchField, true);
		$this->template->Assign('isSearching', $isSearching, false);

		// determine our starting position
		$pagingStart = ($requestPage * $pagingPerPage) - $pagingPerPage;

		// if there is not a query preset, we need to create one
		if(is_null($this->ViewQuery) || !$this->ViewQuery) {
			$subQueries = array();
			$tableList = $this->getTables(true);
			// add in any subqueries that are needed to get the data into the table
			foreach($this->DisplayFields as $_key=>$field) {
				if(isset($field['subquery'])) {
					foreach($tableList as $tableName) {
						$field['subquery'] = str_replace('[table.' . $tableName . ']', IWP_MODULE_DB_PREFIX . $tableName, $field['subquery']);
					}
					$subQueries[] = '('. $field['subquery'] .') AS `'. $field['dbfield'] .'`';
				}
			}

			if (count($subQueries)) {
				$subQueries = ', ' . implode(', ', array_unique($subQueries));
			} else {
				$subQueries = '';
			}


			if(sizeof($where) > 0){
				$where =  array_unique($where);
				$queryWhere = ' where ('.implode(' and ', $where).') and assoctype="module" and modulename="gallery"';
			} else {
				$queryWhere = ' where assoctype="module" and modulename="gallery"';
			}

			$query = 'select SQL_CALC_FOUND_ROWS *' . $subQueries .' from ' . $this->getTable() . ' as g inner join ' . IWP_TABLE_URLS .' as u on g.id=u.associd left join '. $this->getTable('galleryimages'). ' as gi on g.albumcoverid=gi.imageid ' . $queryWhere. ' order by g.`' . $sortField . '` ' . $sortDir . ' limit ' . $pagingStart . ', ' . $pagingPerPage;
			$this->ViewQuery = $this->db->Query($query);
		}

		$TotalResults = $this->db->FetchOne('select found_rows()');

		while (($row = $this->db->Fetch($this->ViewQuery))) {
			$row['deletePermission'] = $this->auth->HasPerm('sitemodules', 'gallery', 'delete', (int)$row['id']);
			$row['editPermission'] = $this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$row['id']);
			$this->ViewList[] = $row;
		}

		// set up the paging object
		$this->paging = new iwp_paging();
		$this->paging->SetPaging($TotalResults, $pagingPerPage, $requestPage, 'index.php?section=module&action=custom&module=gallery&moduleaction=' . urlencode($_GET['moduleaction']) . '&searchQuery='. urlencode($searchQuery) .'&searchField='. urlencode($searchField) .'&sortdir='. urlencode($sortDir) .'&field='. urlencode($sortField) .'&page=%d', 10);

		$paging['PageCount']	= $this->paging->PageCount;
		$paging['CurrentPage']	= $this->paging->CurrentPage;
		$paging['PreviousURL']	= $this->paging->PreviousURL;
		$paging['PageList']		= $this->paging->PageList;
		$paging['NextURL']		= $this->paging->NextURL;
		$paging['FirstURL']		= $this->paging->FirstURL;
		$paging['LastURL']		= $this->paging->LastURL;

		// parse the paging template to get the links
		$this->template->Assign('paging', $paging);
		$paging = $this->template->ParseTemplate('paging', true);

		// set the paging template variable to false if there are no paging links
		if(!empty($paging)) {
			$this->template->Assign('paging', $paging );
		}else{
			$this->template->Assign('paging', false);
		}

		// set up the variables that can be accessed by the template system
		$this->template->Assign('DisplayFields', 	$this->GetDisplayFields());
		$this->template->Assign('ViewList', 		$this->GetViewList());
		$this->template->Assign('ViewListCount', 	count($this->GetViewList()));
	}

	/**
	 * Returns a list of database tables for this module.
	 *
	 * @param boolean $withoutPrefix A boolean for whether or not to include the prefix for the table.
	 *
	 * @return string
	 */
	public function getTables($withoutPrefix=false) {
		if($withoutPrefix) {
			return $this->dbTables;
		}

		$tables = $this->dbTables;

		foreach($tables as $k=>$table ){
			$tables[$k] = IWP_MODULE_DB_PREFIX . $table;
		}

		return $tables;
	}

	/**
	 * This function builds the SQL for the database tables used by this module. It uses the iwp_tablecreator to do so.
	 * It sets the member variables table and tableSchema with the objects and final SQL.
	 * @return void
	 *
	 * @see iwp_tablecreator
	 */
	public function CreateModuleTable ()
	{
		//	create statements should match a SHOW CREATE result, with cr/lf chars stripped out
		$settingsTableName = $this->getTable('galleries');
		$dataTableName = $this->getTable('galleryimages');

		// primary table, "iwp_module_galleries"
		$settingsTable = new iwp_tablecreator($settingsTableName);

		$settingsTable->AddField('id')->SetAsPrimaryKey();
		$settingsTable->AddField('name')->SetAsVarChar('255');
		$settingsTable->AddField('description')->SetAsText()->Set('default', '');
		$settingsTable->AddField('albumcoverid')->SetAsInt();
		$settingsTable->AddField('date_created')->Set('type', 'timestamp')->Set('default', '2000-01-01 01:00:00'); // mysql won't let us use the CURRENT_TIMESTAMP twice ;(
		$settingsTable->AddField('date_updated')->Set('type', 'timestamp')->Set('default', 'CURRENT_TIMESTAMP')->SetOnUpdateTimeStamp();

		// data table, "iwp_module_galleryimages"
		$dataTable = new iwp_tablecreator($dataTableName);

		$dataTable->AddField('imageid')->SetAsPrimaryKey();
		$dataTable->AddField('galleryid')->SetAsInt();
		$dataTable->AddField('title')->SetAsVarChar();
		$dataTable->AddField('caption')->Set('type', 'longtext')->Set('hasFullText', true);
		$dataTable->AddField('sortorder')->SetAsInt();
		$dataTable->AddField('date_created')->Set('type', 'timestamp')->Set('default', '2000-01-01 01:00:00'); // mysql won't let us use the CURRENT_TIMESTAMP twice
		$dataTable->AddField('date_updated')->Set('type', 'timestamp')->Set('default', 'CURRENT_TIMESTAMP')->SetOnUpdateTimeStamp();
		$dataTable->AddField('extension')->SetAsVarChar('10')->Set('default', 'jpg');

		$this->table = array(&$settingsTable, &$dataTable);
		$this->tableSchema = array(
			$settingsTableName => $settingsTable->GetCreateTable(),
			$dataTableName => $dataTable->GetCreateTable(),
		);
	}

	/**
	 * This function checks to see if there is a success or error message stored in the session.
	 * If there is, it will set them to template variables and clear the message from the session.
	 *
	 * @return void
	 */
	public function CheckSessionMessage () {
		if (iwp_session::Exists('GalleryModuleSuccessMessage')) {
			$this->template->Assign('MessageText', iwp_session::Get('GalleryModuleSuccessMessage'), false);
			$this->template->Assign('MessageType', MSG_SUCCESS);
			iwp_session::Kill('GalleryModuleSuccessMessage');

		}elseif(iwp_session::Exists('GalleryModuleErrorMessage')) {
			$this->template->Assign('MessageText', iwp_session::Get('GalleryModuleErrorMessage'), false);
			$this->template->Assign('MessageType', MSG_ERROR);
			iwp_session::Kill('GalleryModuleErrorMessage');
		}
	}

	/**
	 * This function displays the 'view' page for the module. It displays all current galleries. They can then be ordered by different fields, or deleted in a bulk action.
	 *
	 * @return void
	 */
	public function AdminView() {

		if (!$this->auth->HasPerm('sitemodules', 'gallery', '*')) {
			iwp_admin_home::getInstance()->ShowDashboard(GetLang('GenericAccessNoPermission'), MSG_ERROR);
			die();
		}

		// If there was some bulk action taken, the message should be stored in the session
		$this->CheckSessionMessage();

		// Load the module language variables
		$this->LoadLanguageVariables();

		iwp_language::getInstance()->Set('module_custom_breadcrumb', $this->lang->Get('module_custom_breadcrumb'));

		// permissions
		$this->template->Assign('createPermission', $this->auth->HasPerm('sitemodules', 'gallery', 'create'));
		$this->template->Assign('anyDeletePermission', $this->auth->HasPerm('sitemodules', 'gallery', 'delete', '*'));

		// set up the template variables
		$this->template->Assign('PageTitle', $this->lang->Get('ViewGalleries'));
		$this->template->Assign('CustomIntro', $this->lang->Get('ViewGalleriesIntro'));
		$this->template->Assign('hasCustomIntro', true);
		$this->template->Assign('BreadCrumbSection', $this->lang->Get('BreadCrumbSection'));
		$this->template->Assign('CustomButtons', $this->template->ParseTemplate('gallery.view.buttons', true, 'gallery'));

		// load the list of galleries to display, takes into account searching and paging
		$this->LoadViewList();

		// output the templates
		$this->template->ParseTemplate('header');
		$this->template->ParseTemplate('common.view.top');
		$this->template->ParseTemplate('gallery.view', false, 'gallery');
		$this->template->ParseTemplate('footer');
	}

	/**
	 * This is a private function to delete a single gallery. Called from DeleteGalleries()
	 * Any errors that occurr are accessible via the $this->DeleteErrors private member variable.
	 *
	 * @param integer $galleryId The ID number of the gallery to delete
	 * @return boolean True if the delete was successful, false if there was an error.
	 */
	private function DeleteGallery($galleryId) {
		$galleryId = (int)$galleryId;

		if($galleryId < 1) {
			return false;
		}

		$deleteGalleryDbResult = $deleteImageFilesResult = $deleteImagesDbResult = true;

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'delete', $galleryId)) {
			$this->DeleteErrors[] = $this->lang->Get('gNoPermissionToDeleteGallery');
			$deleteImagesDbResult = false;
			return false;
		}

		// delete all images
		if(!$this->db->Query('delete from ' . $this->getTable('galleryimages') . ' where galleryid=' . $galleryId)) {
			$this->DeleteErrors[] = sprintf($this->lang->Get('gMySQLDeleteImagesError'), $this->db->GetErrorMsg());
			$deleteImagesDbResult = false;
		}

		// delete gallery images folder and all images
		$deleteImageFilesResult = rmdirr($this->UploadPath . DIRECTORY_SEPARATOR . $galleryId);
		if(!$deleteImageFilesResult) {
			$this->DeleteErrors[] = sprintf($this->lang->Get('gCantDeleteFiles'), $this->UploadPath . DIRECTORY_SEPARATOR . $galleryId);
		}

		// delete database
		if(!$this->db->Query('delete from ' . $this->getTable('galleries') . ' where id=' . $galleryId)) {
			$this->DeleteErrors[] = sprintf($this->lang->Get('gMySQLDeleteGalleryError'), $this->db->GetErrorMsg());
			$deleteGalleryDbResult = false;
		}

		// delete any blocks from the site layout
		$layoutResource = $this->db->Query('select * from ' . IWP_TABLE_TEMPLATE_SETTINGS . ' where value LIKE "%module_gallery_SlideShow_' . $galleryId . '%" OR value LIKE "%module_gallery_SelectedGallery_' . $galleryId . '%"');
		while($layoutRow = $this->db->Fetch($layoutResource)) {
			$layoutBlocks = explode(',', $layoutRow['value']);

			if(!in_array('module_gallery_SlideShow_' . $galleryId, $layoutBlocks) && !in_array('module_gallery_SelectedGallery_' . $galleryId, $layoutBlocks)) {
				continue;
			}

			$newBlockArray = array();
			foreach($layoutBlocks as $blockName) {
				if(!in_array($blockName, array('module_gallery_SlideShow_' . $galleryId, 'module_gallery_SelectedGallery_' . $galleryId))) {
					$newBlockArray[] = $blockName;
				}
			}

			$Update = array(
				'value' => implode(',', $newBlockArray),
			);

			$this->db->UpdateQuery(IWP_TABLE_TEMPLATE_SETTINGS, $Update, 'settingid=' . $layoutRow['settingid']);

		}

		// delete any placeholders from content on the site
		$contentResource = $this->db->Query('select * from ' . IWP_TABLE_CONTENT . ' where content LIKE "%<!-- gallery:preview:' . $galleryId . '-->%" OR content LIKE "%<!-- gallery:slideshow:' . $galleryId . '-->%"');

		while($contentRow = $this->db->Fetch($contentResource)) {

			$contentRow['content'] = str_replace('<!-- gallery:preview:' . $galleryId . '-->', '', $contentRow['content']);
			$contentRow['content'] = str_replace('<!-- gallery:slideshow:' . $galleryId . '-->', '', $contentRow['content']);

			$contentRow['summary'] = str_replace('<!-- gallery:preview:' . $galleryId . '-->', '', $contentRow['summary']);
			$contentRow['summary'] = str_replace('<!-- gallery:slideshow:' . $galleryId . '-->', '', $contentRow['summary']);

			$Update = array(
				'summary' => $contentRow['summary'],
				'content' => $contentRow['content'],
			);

			$this->db->UpdateQuery(IWP_TABLE_CONTENT, $Update, 'contentid=' . $contentRow['contentid']);

		}

		return ($deleteGalleryDbResult && $deleteImageFilesResult && $deleteImagesDbResult);
	}

	/**
	 * This function deletes a single gallery based on the GET request with a gallery ID
	 *
	 * @return void
	 */

	public function DeleteSingleGallery () {
		$galleryId = (int)$_GET['galleryid'];
		$this->DeleteGalleries($galleryId);
	}

	/**
	 * This function deletes multiple galleries based on the ID numbers sent in the POST request.
	 * This function stores the result of the operation into a session variable and redirects the user back to the galleries view page.
	 *
	 * @return void
	 */
	public function DeleteGalleries($galleryId=null) {

		if(!is_null($galleryId)) {
			$_POST['items'] = array($galleryId);
		}

		if(!isset($_POST['items'])) {
			iwp_session::Set('GalleryModuleErrorMessage', $this->lang->Get('gNoGalleriesSelectedDelete'));
			// Redirect back to the views page to display the result of the operation.
			// This stops them hitting 'back' and attempting the POST again.
			header('Location: index.php?section=module&action=custom&module=gallery&moduleaction=view');
			die();
		}

		$deleteResults		= array();
		$deleteGalleries 	= array_map('intval', $_POST['items']);

		if(sizeof($deleteGalleries) < 1) {
			iwp_session::Set('GalleryModuleErrorMessage', $this->lang->Get('gNoGalleriesSelectedDelete'));
			// Redirect back to the views page to display the result of the operation.
			// This stops them hitting 'back' and attempting the POST again.
			header('Location: index.php?section=module&action=custom&module=gallery&moduleaction=view');
			die();
		}

		foreach ($deleteGalleries as $galleryId) {
			$deleteResults[] = $this->DeleteGallery($galleryId);
		}

		if(in_array(false, $deleteResults, true)) {
			iwp_session::Set('GalleryModuleErrorMessage', sprintf($this->lang->Get('gErrorDeletingGalleries'), $this->output->ArrayToList($this->DeleteErrors)));
		}else{
			iwp_session::Set('GalleryModuleSuccessMessage', $this->lang->Get('gDeleteGallerySuccess'));
		}

		// Redirect back to the views page to display the result of the operation.
		// This stops them hitting 'back' and attempting the POST again.
		header('Location: index.php?section=module&action=custom&module=gallery&moduleaction=view');
		die();
	}

	/**
	 * This function takes a file submission and adds it to a gallery specified in the POST.
	 *
	 * @return void
	 */
	public function RemoteUploadImage(){
		// Simulate a upload that takes around 3 seconds
		// for($i=0; $i<100000; $i++){ for($i=0; $i<5000000; $i++){}}

		$error 		= true;
		$galleryId 	= (int)$_REQUEST['galleryid'];
		$tmp_name 	= $_FILES["Filedata"]["tmp_name"];
		$name 		= $_FILES["Filedata"]["name"];

		unset($_FILES['Filedata']['tmp_name']);

		if($galleryId == 0) {
			if (!$this->auth->HasPerm('sitemodules', 'gallery', 'create')) {
				$error = true;
				$_FILES['Filedata']['message'] = $this->lang->Get('gNoPermissionToCreateGallery');
				$_FILES['Filedata']['error'] = true;
				die(json_encode($_FILES['Filedata']));
			}
		}else{
			if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', $galleryId)) {
				$error = true;
				$_FILES['Filedata']['message'] = $this->lang->Get('gNoPermissionToEditGallery');
				$_FILES['Filedata']['error'] = true;
				die(json_encode($_FILES['Filedata']));
			}
		}

		// verify file upload is valid image
		switch($_FILES['Filedata']['error']) {
			case UPLOAD_ERR_OK:
				if(!$this->IsValidImageFile($tmp_name, $_FILES['Filedata']['type'])){
					$error = true;
					$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gBadFileType'), iwp_htmlentities($name));

				}elseif (!$this->IsImageFile(iwp_strtolower($name))){
					$error = true;
					$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gBadFileType'), iwp_htmlentities($name));

				}else{
					$error = false;
				}
				break;

			case UPLOAD_ERR_INI_SIZE:
			case UPLOAD_ERR_FORM_SIZE:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gBadFileSize'), iwp_htmlentities($name), getMaxUploadSize());
				break;

			case UPLOAD_ERR_PARTIAL:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gPartialUpload'), iwp_htmlentities($name));
				break;

			case UPLOAD_ERR_NO_FILE:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gNoFileUpload'), iwp_htmlentities($name));
				break;

			case UPLOAD_ERR_NO_FILE:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gNoFileUpload'), iwp_htmlentities($name));
				break;

			case UPLOAD_ERR_NO_TMP_DIR:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gNoPHPTmpDirectory'), iwp_htmlentities($name));
				break;

			case UPLOAD_ERR_CANT_WRITE:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gCantWrite'), iwp_htmlentities($name));
				break;
			default:
				$error = true;
				$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gUnknownUploadError'), iwp_htmlentities($name));
				break;
		}

		if ($error) {
			// PHP had a problem with this file, it shall not pass
			$_FILES['Filedata']['error'] = true;
			die(json_encode($_FILES['Filedata']));
		}

		// If the gallery's image directory doesn't already exist, attempt to create it
		if(!is_dir($this->UploadPath)) {
			mkdir($this->UploadPath, 0777);
			@chmod($this->UploadPath, 0777);
		}
		if(!is_dir($this->UploadPath . '/' . $galleryId)) {
			mkdir($this->UploadPath . '/' . $galleryId, 0777);
			@chmod($this->UploadPath . '/' . $galleryId, 0777);
		}

		// SWF Upload is putting slashes in ;(
		$name = stripslashes($name);

		$pathInfo = pathinfo($name);

		if(!isset($pathInfo['filename'])) {
			// PHP 5.2.0 and above has this value set
			$pathInfo['filename'] = substr($name, 0, strrpos($name,'.'));
		}

		$Insert = array(
			'galleryid' 	=> $galleryId,
			'title' 		=> $pathInfo['filename'],
			'caption' 		=> '',
			'date_created' 	=> 'NOW()',
			'extension' 	=> iwp_strtolower($pathInfo['extension']),
		);

		$imageId = $this->db->InsertQuery($this->getTable('galleryimages'), $Insert);

		if ((int)$imageId < 1) {
			// The image didn't save in the database
			$_FILES['Filedata']['error'] = true;
			$_FILES['Filedata']['message'] = sprintf($this->lang->Get('gDatabaseError'), iwp_htmlentities($name), $this->db->GetErrorMsg());
			die(json_encode($_FILES['Filedata']));
		}

		$pathInfo['extension'] = iwp_strtolower($pathInfo['extension']);

		$albumImagePath 	= $this->UploadPath . '/' . $galleryId . '/' . $imageId . '_album.' . $pathInfo['extension'];
		$squareImagePath 	= $this->UploadPath . '/' . $galleryId . '/' . $imageId . '_square.' . $pathInfo['extension'];
		$originalImagePath 	= $this->UploadPath . '/' . $galleryId . '/' . $imageId . '_original.' . $pathInfo['extension'];
		$thumbnailImagePath = $this->UploadPath . '/' . $galleryId . '/' . $imageId . '_thumbnail.' . $pathInfo['extension'];
		$smallSquareImagePath = $this->UploadPath . '/' . $galleryId . '/' . $imageId . '_nav.' . $pathInfo['extension'];

		move_uploaded_file($tmp_name, $originalImagePath);
		@chmod($originalImagePath, 0666);

		// create thumbnail versions
		ResizeGDImagesExact($originalImagePath, $squareImagePath, 130, 130);
		ResizeGDImagesExact($originalImagePath, $smallSquareImagePath, 50, 50);
		ResizeGDImages($originalImagePath, $albumImagePath, 500, 490);
		ResizeGDImages($originalImagePath, $thumbnailImagePath, 130, 130);

		@chmod($squareImagePath, 0666);
		@chmod($smallSquareImagePath, 0666);
		@chmod($albumImagePath, 0666);
		@chmod($thumbnailImagePath, 0666);

		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' where id=' . (int)$galleryId);

		// return all file names and any errors
		$returnData = $_FILES['Filedata'];
		$returnData['filesize'] = NiceSize($_FILES['Filedata']['size']);
		$returnData['id'] = substr(md5($_FILES['Filedata']['name']), 0, 10);
		$returnData['errorfile'] = false;

		$returnData['image'] = array(
			'album' 	=> $this->UploadDir . '/' . $galleryId . '/' . $imageId . '_album.' . $pathInfo['extension'],
			'square' 	=> $this->UploadDir . '/' . $galleryId . '/' . $imageId . '_square.' . $pathInfo['extension'],
			'original' 	=> $this->UploadDir . '/' . $galleryId . '/' . $imageId . '_original.' . $pathInfo['extension'],
			'thumbnail' => $this->UploadDir . '/' . $galleryId . '/' . $imageId . '_thumbnail.' . $pathInfo['extension'],
			'id' 		=> $imageId,
			'title' 	=> iwp_htmlspecialchars($pathInfo['filename']),
		);

		$additionalSet = '';

		if($galleryInfo['albumcoverid'] < 1) {
			$additionalSet = ', albumcoverid=' . $imageId;
			$returnData['gallery'] = array('albumcoverid' => $imageId);
			$this->GenerateCoverImages($imageId);
		}else {
			$returnData['gallery'] = array('albumcoverid' => $galleryInfo['albumcoverid']);
		}

		$updateGallery = $this->db->Query('update '. $this->getTable('galleries'). ' set date_updated=CURRENT_TIMESTAMP ' . $additionalSet .' where id=' . (int)$galleryId);

		die(json_encode($returnData));
	}

	/**
	 * This function sets up the AdminCreate function to edit a gallery
	 *
	 * @return void
	 */

	private function EditGallery () {
		$galleryId = (int)$_GET['galleryid'];
		if($galleryId > 0) {
			$this->AdminCreate($galleryId);
		}
	}

	/**
	 * This function sets up the page to create or edit a gallery.
	 *
	 * @param integer $galleryId If this is passed in, the gallery is edited. If it is null or zero a new gallery is created.
	 * @return void
	 */

	private function AdminCreate($galleryId=null) {

		if(!is_null($galleryId)) {
			$galleryId = (int)$galleryId;
		}

		// Load and display the template
		if (iwp_session::Exists('GallerySuccessMessage')) {
			$this->template->Assign('MessageText', iwp_session::Get('GallerySuccessMessage'));
			$this->template->Assign('MessageType', MSG_SUCCESS);
			iwp_session::Kill('GallerySuccessMessage');
		}

		if(is_null($galleryId) || !is_int($galleryId) || $galleryId < 1) {
			$this->template->Assign('PageTitle', $this->lang->Get('CreateNewGallery'));
			$this->template->Assign('PageIntro', $this->lang->Get('CreateNewGalleryIntro'));
			$this->template->Assign('galleryId', '0');
			$this->template->Assign('GalleryCoverId', '0');
		} else {
			$this->template->Assign('PageTitle', $this->lang->Get('EditNewGallery'));
			$this->template->Assign('PageIntro', $this->lang->Get('EditNewGalleryIntro'));
			$this->template->Assign('galleryId', $galleryId);


			$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' where id=' . $galleryId);
			$this->template->Assign('GalleryCoverId', $galleryInfo['albumcoverid'], true);
			$this->template->Assign('galleryDesc', $galleryInfo['description'], true);
			$this->template->Assign('galleryName', $galleryInfo['name'], true);
		}

		$this->template->Assign('BreadCrumbSection', $this->lang->Get('BreadCrumbSection'));
		$this->template->Assign('BreadCrumbAction', $this->lang->Get('BreadCrumbAction_CreateGallery'));

		$this->template->Assign('existingGalleries', $this->GetGalleriesList());
		$this->template->Assign('sessionid', $_COOKIE['PHPSESSID']);

		$this->LoadLanguageVariables();
		$this->template->AddLanguageForJS(array('CreateNewGalleryIntro', 'gSkip', 'gConfirmDeleteImage', 'gClickCoverImage', 'gMakeCover', 'gImageEditTitleCaption', 'gEditCaption',  'gIntroUploadPhotos', 'gUploadingFirstImage', 'gConfirmDeleteImageSingle', 'gDeleteMultiImages','gEnterGalleryName','gDragInstructions', 'gDeletePhoto', 'Cancel', 'Save', 'SaveOnly', 'gUploadingFile', 'gUploadingImageCount', 'gSWFFileEmpty', 'gSWFFileTooBig','gSWFNotValidImages','gGalleryNotSaved', 'Cancel', 'gSaveImage', 'gSWFImageUploaded', 'gSWFImagesUploaded', 'gUploadingImagesError', ), $this->lang);

		$this->template->AddRequiredJS('../lib/imodal/imodal.js');
		$this->template->AddRequiredJS('../javascript/detect.flash.js');
		$this->template->AddRequiredJS('../javascript/swfupload.js');
		$this->template->AddRequiredJS(IWP_MODULES_URI . '/' . $this->moduleName . '/javascript/admin.' . $this->moduleName . '.js');
		$this->template->AddRequiredCSS(IWP_MODULES_URI . '/' . $this->moduleName . '/templates/admin.styles.css');

		$this->template->Assign('step', 1);

		$this->template->ParseTemplate('header');
		$this->template->ParseTemplate('gallery.breadcrumb', false, 'gallery');
		$this->template->ParseTemplate('common.form.top');
		$this->template->ParseTemplate('gallery.create', false, 'gallery');
		$this->template->ParseTemplate('footer');
	}

	/**
	 * This function caters to those without flash installed. It displays an alternative uploading form.
	 * @return void
	 */
	public function RemoteNoFlashUpload() {

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'create')) {
				echo $this->lang->Get('gNoPermissionToCreateGallery');
				die();
		}

		$this->LoadLanguageVariables();
		$this->template->ParseTemplate('gallery.multiupload', false, 'gallery');
	}


	/**
	 * This function gets information from the database for a specific image based on its image ID. It outputs the data in JSON.
	 *
	 * @return void
	 */

	public function RemoteGetImageInfo () {
		$imageId = (int)$_GET['imageid'];

		if($imageId < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidImage'),
			)));
		}

		$imageDetails = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);

		die(json_encode(array(
			'success' => true,
			'caption' => iwp_htmlspecialchars($imageDetails['caption']),
			'title' => iwp_htmlspecialchars($imageDetails['title']),
		)));
	}

	/**
	 * This function takes in an array of image IDs in the specific order that they should be saved in.
	 * It outputs the result of the operation in JSON.
	 *
	 * @return void
	 */
	public function RemoteSaveSortOrder () {

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$_GET['galleryid'])) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		if(!isset($_GET['img'])) {
			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gImageSortOrderSuccess'),
			)));
		}

		$sortOrder = 0;
		$firstImage = null;

		foreach ($_GET['img'] as $imageId) {
			$imageId = (int)$imageId;

			if($imageId < 1) {
				continue;
			}

			if(is_null($firstImage)) {
				$firstImage = $imageId;
			}

			$Update = array(
				'sortorder' => $sortOrder
			);

			if(!$this->db->UpdateQuery($this->getTable('galleryimages'), $Update, 'imageid=' . $imageId)){
				die(json_encode(array(
					'success' => false,
					'message' => sprintf($this->lang->Get('gImageSortOrderError'), $this->db->GetErrorMsg()),
				)));
			}

			++$sortOrder;
		}

		die(json_encode(array(
			'success' => true,
			'message' => $this->lang->Get('gImageSortOrderSuccess'),
		)));
	}

	/**
	* This function takes an image ID and generates the cover images required for it.
	*
	* @param mixed $imageId This is the ID of the image that should be used for the thumbnails of the album cover
	*/
	public function GenerateCoverImages ($imageId) {
		$imageDetails = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);

		if(is_array($imageDetails)) {
			$originalImagePath 	= $this->UploadPath . DIRECTORY_SEPARATOR . $imageDetails['galleryid'] . DIRECTORY_SEPARATOR . $imageId . '_original.' . $imageDetails['extension'];
			$squareImagePath = $this->UploadPath . DIRECTORY_SEPARATOR . $imageDetails['galleryid'] . DIRECTORY_SEPARATOR .'gallerythumb_small.' . $imageDetails['extension'];
			$smallPreviewImagePath = $this->UploadPath . DIRECTORY_SEPARATOR . $imageDetails['galleryid'] . DIRECTORY_SEPARATOR .'gallerythumb_album.' . $imageDetails['extension'];
			$previewImagePath = $this->UploadPath . DIRECTORY_SEPARATOR . $imageDetails['galleryid'] . DIRECTORY_SEPARATOR .'gallerythumb_medium.' . $imageDetails['extension'];

			if(file_exists($squareImagePath)) {
				@unlink($squareImagePath);
			}

			if(file_exists($originalImagePath)) {
				ResizeGDImagesExact($originalImagePath, $squareImagePath, 50, 50);
				@chmod($squareImagePath, 0666);
			}

			if(file_exists($originalImagePath)) {
				ResizeGDImagesExact($originalImagePath, $smallPreviewImagePath, 100, 100);
				@chmod($smallPreviewImagePath, 0666);
			}

			if(file_exists($previewImagePath)) {
				@unlink($previewImagePath);
			}

			if(file_exists($originalImagePath)) {
				ResizeGDImagesExact($originalImagePath, $previewImagePath, 175, 175);
				@chmod($previewImagePath, 0666);
			}
		}
	}

	/**
	* This function takes a gallery ID number and resets the album cover image to the first in the gallery.
	*
	* @param mixed $galleryId
	*/

	private function ResetAlbumCover ($galleryId) {
		$Update 	= array();
		$galleryId 	= (int)$galleryId;

		$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $galleryId .' order by sortorder asc');

		if(is_array($imageInfo) && isset($imageInfo['imageid'])  && $imageInfo['imageid'] > 0){
			$Update['albumcoverid'] = $imageInfo['imageid'];
			$this->db->UpdateQuery($this->getTable('galleries'), $Update, 'id=' . $galleryId);
			$this->GenerateCoverImages($imageInfo['imageid']);
		}
	}

	/**
	 * This function deletes a single image based upon the ID number sent in the GET request.
	 * It outputs the result of the operation in JSON.
	 *
	 * @return void
	 */

	public function RemoteDeleteImage() {

		$imageId = (int)$_GET['imageid'];

		if($imageId < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidImage'),
			)));
		}

		$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$imageInfo['galleryid'])) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		if($this->db->Query('delete from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId)){
			if($this->DeleteImageFiles($imageId, $imageInfo['galleryid'])) {
				die(json_encode(array(
					'success' => true,
					'message' => $this->lang->Get('gImageDeleteSuccess'),
				)));
			}

			die(json_encode(array(
				'success' => false,
				'message' => sprintf($this->lang->Get('gImageFileDeleteError'), $this->db->GetErrorMsg()) ,
			)));


		}

		die(json_encode(array(
			'success' => false,
			'message' => sprintf($this->lang->Get('gImageDeleteError'), $this->db->GetErrorMsg()) ,
		)));
	}

	/**
	* This function deletes all image files based on an image id. Each image in a gallery has multiple thumbnails generated.
	*
	* @param integer $imageId
	* @param integer $galleryId
	*
	* @return boolean True if deleting all images was successful, false otherwise
	*/

	private function DeleteImageFiles($imageId, $galleryId) {
		$imageId = (int)$imageId;
		$galleryId = (int)$galleryId;

		if($galleryId < 1 || $imageId < 1) {
			return false;
		}

		$deleteImageResult = true;

		$idStr = (string)$imageId;

		$dirObject = new DirectoryIterator($this->UploadPath . DIRECTORY_SEPARATOR . $galleryId);

		foreach($dirObject as $fileName=>$objFile){
			if($objFile->isFile() && substr($objFile->getFilename(), 0, strlen($idStr)) == $imageId){
				if(!@unlink($objFile->getPath() . DIRECTORY_SEPARATOR . $objFile->getFilename())) {
					$deleteImageResult = false;
				}
			}
		}

		$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' where id=' . $galleryId);

		if($imageId == $galleryInfo['albumcoverid']) {
			$this->ResetAlbumCover($galleryId);
		}

		return $deleteImageResult;
	}

	/**
	 * This function updates the information for a specific image based on data sent through a GET request.
	 * It outputs the result of the operation in JSON.
	 *
	 * @return void
	 */

	public function RemoteSaveImage () {

		$imageId = (int)$_GET['imageid'];
		$caption = $_GET['imagecaption'];
		$title   = $_GET['imagetitle'];

		if($imageId < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidImage'),
			)));
		}

		$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$imageInfo['galleryid'])) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		$Update = array(
			'caption' => $caption,
			'title'   => $title,
		);

		if($this->db->UpdateQuery($this->getTable('galleryimages'), $Update, 'imageid=' . $imageId)){
			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gImageSaveSuccess'),
			)));
		}

		die(json_encode(array(
			'success' => false,
			'message' => sprintf($this->lang->Get('gImageSaveError'), $this->db->GetErrorMsg()) ,
		)));
	}

	/**
	 * This function updates the title of a specified image.
	 * This function is to be called through an AJAX request, it takes a title and image id.
	 *
	 * @return void
	 */

	public function RemoteSaveTitle () {

		$imageId = (int)$_GET['imageid'];
		$title   = $_GET['imagetitle'];

		if($imageId < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidImage'),
			)));
		}

		$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$imageInfo['galleryid'])) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		$Update = array(
			'title'   => $title,
		);

		if($this->db->UpdateQuery($this->getTable('galleryimages'), $Update, 'imageid=' . $imageId)){
			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gImageSaveSuccess'),
			)));
		}

		die(json_encode(array(
			'success' => false,
			'message' => sprintf($this->lang->Get('gImageSaveError'), $this->db->GetErrorMsg()) ,
		)));
	}

	/**
	 * This function retieves the information for a gallery based on the gallery ID sent through a GET request.
	 * It outputs the result of the operation in JSON.
	 *
	 * @return void
	 */
	public function RemoteGetAlbumInfo () {
		$info = array();
		if((int)$_GET['galleryid'] > 0) {
			$info = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where  assoctype="module" and modulename="gallery" and id=' . (int)$_GET['galleryid']);
			$info['success'] = true;
			$info['images'] = array();
			$info['message'] = '';
			$maxSize = 130;

			$query = $this->db->Query('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . (int)$_GET['galleryid'] . ' order by sortorder asc');
			while(($row = $this->db->Fetch($query))) {

				$thisImage = getimagesize($this->UploadPath . '/' . (int)$_GET['galleryid'] . '/' . $row['imageid'] . '_album.' . $row['extension']);
				$thisImage['origwidth'] = $thisImage[0];
				$thisImage['origheight'] = $thisImage[1];

				$width = $thisImage['origwidth'];
				$height = $thisImage['origheight'];

				$info['images'][] = array(
										'square' 	=> $this->UploadDir . '/' . (int)$_GET['galleryid'] . '/' . $row['imageid'] . '_square.' . $row['extension'],
										'id' 		=> (int)$row['imageid'],
										'title' 	=> iwp_htmlspecialchars($row['title']),
										'origwidth'		=> $thisImage['origwidth'],
										'origheight'	=> $thisImage['origheight'],
									);
			}
			die(json_encode($info));
		}else{
			die(json_encode(array('success'=>false, 'message'=>$this->lang->Get('gInvalidGallery'))));
		}

	}

	/**
	* This function outputs JSON encoded data representing the images in a gallery, which is used by the image manager and link manager in TinyMCE.
	*
	* @return void
	*/

	public function RemoteGetInsertAlbumInfo () {
		$info = array();
		if((int)$_GET['galleryid'] > 0) {
			$this->RemoteGetAlbumInfo();
		}
	}

	/**
	 * This function retieves a list of galleries and returns a string of HTML containing an option list that can be used in a HTML <select>.
	 *
	 * @return string HTML containing a list of option tags with the gallery IDs as the values and the gallery names as the text.
	 */
	public function GetGalleriesList($galleryId=null) {
		$array = array();
		$resource = $this->db->Query('select * from ' . $this->getTable() . ' order by name asc');
		while($row = $this->db->Fetch($resource)) {
			$array[$row['id']] = $row['name'];
		}

		if(!is_null($galleryId) && (int)$galleryId > 0) {
			return $this->output->ArrayToOptions($array, array($galleryId));
		}

		return $this->output->ArrayToOptions($array);
	}

	/**
	 * This function retieves a list of galleries and returns a string of HTML containing an option list that can be used in a HTML <select>.
	 *
	 * @return string HTML containing a list of option tags with the gallery IDs as the values and the gallery names as the text.
	 */
	public function GetGalleriesJSON() {
		$array = array();
		$resource = $this->db->Query('select * from ' . $this->getTable() . ' order by name asc');
		while($row = $this->db->Fetch($resource)) {
			$array[$row['id']] = $row['name'];
		}
		return json_encode($array);
	}

	/**
	 * This function takes a GET request with a gallery ID and outputs the information in JSON.
	 *
	 * @return void
	 */

	public function RemoteGetAllImagesInfo() {
		$galleryId = (int)$_GET['galleryid'];

		if($galleryId < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidGallery'),
			)));
		}

		$query = $this->db->Query('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . $galleryId . ' order by sortorder asc');
		$return = array();
		$return['images'] = array();

		while(($row = $this->db->Fetch($query))) {
			$return['images'][] = $row;
		}


		die(json_encode(array(
				'success' => true,
				'message' => '',
				'images' => $return['images']
		)));
	}

	/**
	 * This function deletes any number of images based on a GET array of image IDs. The result is ouput in JSON
	 *
	 * @return void
	 */

	public function RemoteDeleteSelectedImages() {
		$galleryId = (int)$_GET['galleryid'];

		if(isset($_GET['deleteimg'])) {
			$_GET['deleteimg'] = array_map('intval', $_GET['deleteimg']);
		}

		if($galleryId < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gInvalidGallery'),
			)));
		}

		if(!isset($_GET['deleteimg']) || sizeof($_GET['deleteimg']) < 1) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoImagesToDelete'),
			)));
		}

		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', $galleryId)) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		$imagesDeleted = true;

		foreach($_GET['deleteimg'] as $imageId) {
			$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);

			if(!$this->DeleteImageFiles($imageId, $imageInfo['galleryid'])) {
				$imagesDeleted = false;
			} else {
				$this->db->Query('delete from ' . $this->getTable('galleryimages') . ' where imageid=' . $imageId);
			}
		}

		if($imagesDeleted) {
			$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' where id=' . $galleryId);

			if(in_array($galleryInfo['albumcoverid'], $_GET['deleteimg'])) {
				$this->ResetAlbumCover($galleryId);
			}

			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gImagesDeletedSuccess'),
			)));
		}else{
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gImagesFilesDeletedError'),
			)));
		}

		die(json_encode(array(
			'success' => false,
			'message' => sprintf($this->lang->Get('gImagesDeletedError'), $this->db->GetErrorMsg()),
		)));
	}

	/**
	 * This function saves the title and caption information for multiple images in a gallery.
	 * It outputs the result in JSON.
	 *
	 * @return void
	 */

	public function RemoteSaveMultiImages () {
		if(!isset($_POST['caption']) || !isset($_POST['title'])) {
			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gMultiInvalidData'),
			)));
		}

		$galleryIds = $imageIds = array();
		$galleryId = $imageId = 0;

		// grab all the image id's
		foreach ($_POST['title'] as $imageId=>$title) {
			if($imageId < 1) {
				continue;
			}

			if(!in_array($imageId, $imageIds)) {
				$imageIds[] = $imageId;
			}
		}

		// grab the gallery id's for all the images, make sure they're all in the same gallery
		$imagesInfo = $this->db->Query('select * from ' . $this->getTable('galleryimages') . ' where imageid IN (' . implode(',', $imageIds) . ')');

		while($imageRow = $this->db->Fetch($imagesInfo)) {
			if(!in_array($imageRow['galleryid'], $galleryIds)) {
				$galleryIds[] = $imageRow['galleryid'];
				$galleryId = (int)$imageRow['galleryid'];
			}
		}

		// if the images aren't in the same gallery, return an error
		if(sizeof($galleryIds) > 1 || $galleryId < 1){
			die(json_encode(array(
				'success' => true,
				'message' => $this->lang->Get('gMultiInvalidData'),
			)));
		}

		// make sure the user has access to edit the images in this gallery
		if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', $galleryId)) {
			die(json_encode(array(
				'success' => false,
				'message' => $this->lang->Get('gNoPermissionToEditGallery'),
			)));
		}

		foreach ($_POST['title'] as $imageId=>$title) {
			$imageId = (int)$imageId;

			if($imageId < 1) {
				continue;
			}

			$caption = $_POST['caption'][$imageId];

			$Update = array(
				'title'   => $title,
				'caption' => $caption,
			);

			if(!$this->db->UpdateQuery($this->getTable('galleryimages'), $Update, 'imageid=' . $imageId)){
				die(json_encode(array(
					'success' => false,
					'message' => sprintf($this->lang->Get('gMultiImageSaveError'), $this->db->GetErrorMsg()),
				)));
			}
		}

		die(json_encode(array(
			'success' => true,
			'message' => $this->lang->Get('gMultiImageUpdateSuccess'),
		)));
	}

	/**
	 * This function saves a new gallery based on POST data. It outputs the result in JSON format.
	 *
	 * @return void
	 */

	public function RemoteSaveGallery(){

		$errors 	= array();
		$galleryid 	= 0;

		// if there is no valid post data at all, let them know its invalid!
		if(!isset($_POST['name']) || !isset($_POST['description'])) {
			die(json_encode(array(
				'success'=>false,
				'message'=>$this->lang->Get('gInvalidFormSubmission')
			)));
		}

		// we don't want any names with spaces around them
		$_POST['name'] = trim($_POST['name']);

		// if there is no name for the gallery, add an error to the list
		if(empty($_POST['name'])) {
			$errors[] = $this->lang->Get('gNoName');
		}

		if(!empty($errors)) {
			echo json_encode(array(
				'success'=>false,
				'message'=>$this->lang->Get('gErrorsOccurred') . $this->output->ArrayToList($errors)
			));
			die();
		}

		$Insert = array();
		$Insert['name'] = $_POST['name'];
		$Insert['description'] = $_POST['description'];

		if((int)$_POST['galleryid'] < 1) {
			$Insert['date_created'] = GetMysqlDateTime();
		}

		if(isset($_POST['galleryid']) && (int)$_POST['galleryid'] > 0) {
			if (!$this->auth->HasPerm('sitemodules', 'gallery', 'edit', (int)$_POST['galleryid'])) {
				die(json_encode(array(
					'success' => false,
					'message' => $this->lang->Get('gNoPermissionToEditGallery'),
				)));
			}

			$galleryInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleries') . ' where id=' . (int)$_POST['galleryid']);

			if($galleryInfo['albumcoverid'] == 0) {
				$imageInfo = $this->db->FetchQuery('select * from ' . $this->getTable('galleryimages') . ' where galleryid=' . (int)$_POST['galleryid'] .' order by sortorder asc');

				if(is_array($imageInfo) && isset($imageInfo['imageid'])  && $imageInfo['imageid'] > 0){
					$Insert['albumcoverid'] = $imageInfo['imageid'];
				}
			}

			if(!$this->db->UpdateQuery($this->getTable(), $Insert, 'id=' . (int)$_POST['galleryid'])) {
				die(json_encode(array('success'=>false, 'message'=>$this->lang->Get('gErrorsOccurred') . $this->output->ArrayToList(array($this->db->GetErrorMsg())))));
			}

			$galleryid = (int)$_POST['galleryid'];

		}else{

			if (!$this->auth->HasPerm('sitemodules', 'gallery', 'create')) {
				die(json_encode(array(
					'success' => false,
					'message' => $this->lang->Get('gNoPermissionToCreateGallery'),
				)));
			}

			if(!$this->db->InsertQuery($this->getTable(), $Insert)) {
				die(json_encode(array('success'=>false, 'message'=>$this->lang->Get('gErrorsOccurred') . $this->output->ArrayToList(array($this->db->GetErrorMsg())))));
			}

			$galleryid = $this->db->LastId();
		}

		$this->cache->SetDir('module_gallery');
		$this->cache->ClearCacheDir();

		$this->SaveGalleryURL($Insert['name'], $galleryid);

		echo json_encode(array(
			'success'	=> true,
			'message'	=> $this->lang->Get('GallerySavedSuccessfully'),
			'galleryid' => $galleryid,
		));
	}

	/**
	 * This function saves the URL of the gallery. If the URL is already taken, it increments a number on the end of the name and tries again.
	 *
	 * @param string $galleryName The name of the gallery to check/save the URL for.
	 * @param integer $galleryId The ID number of the gallery.
	 * @return unknown_type
	 */

	private function SaveGalleryURL($galleryName, $galleryId) {

		$url = $this->GetGalleryURL($galleryName, $galleryId);

		$checkQuery = $this->db->Query('select * from ' . IWP_TABLE_URLS . ' where urlpath="' . $this->db->Quote($url) . '" and assoctype="module" and modulename="gallery" and associd=' . $galleryId);

		if($this->db->CountResult($checkQuery) > 0) {
			return true;
		}

		$checkQuery = $this->db->Query('select * from ' . IWP_TABLE_URLS . ' where urlpath="' . $this->db->Quote($url) . '"');

		$count 	= 2;
		$max 	= 100;

		while($this->db->CountResult($checkQuery) > 0 && $max > 0) {
			$url = $this->GetGalleryURL($galleryName . '-' . $count, $galleryId);
			$checkQuery = $this->db->Query('select * from ' . IWP_TABLE_URLS . ' where urlpath="' . $this->db->Quote($url) . '"');
			++$count;
			--$max;
		}

		$Insert = array(
			'urlpath' => $url,
			'assoctype' => 'module',
			'modulename' => 'gallery',
			'associd' => $galleryId,
		);

		$urlId = $this->db->InsertQuery(IWP_TABLE_URLS, $Insert);

		if((int)$urlId < 1) {
			return false;
		}


		$Update = array(
			'assoctype' => 'redirect',
			'redirecttype' => 'module',
		);

		$this->db->UpdateQuery(IWP_TABLE_URLS, $Update, 'associd=' . $galleryId .' and assoctype="module" and modulename="gallery" and urlid!='. $urlId);
	}

	/**
	 * This function generates a URL for a gallery based on its name
	 *
	 * @param string $galleryName The name of the gallery
	 * @param integer $galleryId The ID of the gallery, used as a backup when the name is blank
	 *
	 * @return string The URL for the gallery
	 */

	private function GetGalleryURL($galleryName, $galleryId) {
		$urlname = iwp_strtolower(trim($galleryName));
		$urlname = str_replace(' ', '-', $urlname);
		$urlname = str_replace(array('?', '#', '/', '&', '>', '<', '"', "'"), '', $urlname);

		if(empty($urlname)) {
			$urlname = $galleryId;
		}

		$url = '/galleries/' . $urlname . '/';

		return $url;
	}

	/**
	* This function returns an array of all the galleries with their URLs selected from the URLs table.
	*
	* @return array Returns an array of database result rows for the selected galleries.
	*/

	private function GetGalleryArray() {
		$listQuery = $this->db->Query('select * from ' . $this->getTable('galleries') . ' inner join ' . IWP_TABLE_URLS .' on associd=id where (select count(*) from ' . $this->getTable('galleryimages') . ' where galleryid=id)>0 and assoctype="module" and modulename="gallery" order by date_created desc');

		return $this->db->FetchQueryAll($listQuery);
	}

	/**
	* Listener for the iwp_event_admin_content_urlbrowser event
	*
	* @param iwp_event_content_afterdbload $data
	*/
	public static function ViewContentHook (iwp_event_content_afterdbload $data)
	{
		$thisClass = self::getInstance();
		$content = iwp_content::getInstance();

		$content->Set('content', $thisClass->ReplaceContentPlaceholders($content->Get('content')));
		$content->Set('summary', $thisClass->ReplaceContentPlaceholders($content->Get('summary')));
	}

	/**
	* Listener for the iwp_event_categories_beforeshowtemplate event which adjusts template output to make slideshows and gallery previews appear on front end category descriptions
	*
	* @param iwp_event_categories_beforeshowtemplate $data
	*/
	public static function onCategoriesBeforeShowTemplate (iwp_event_categories_beforeshowtemplate $data) {
		$data->template->Assign('categoryDescription', self::getInstance()->ReplaceContentPlaceholders($data->template->Get('categoryDescription')), false);
	}

	/**
	* Listener for the iwp_event_template_outputblockbeforeparsesection event which adjusts custom block output to make slideshows and gallery previews appear on front end custom blocks
	*
	* @param iwp_event_template_outputblockbeforeparsesection $data
	*/
	public static function onTemplateOutputBlockBeforeParseSection (iwp_event_template_outputblockbeforeparsesection $data) {
		switch (strtolower($data->type)) {
			case 'customcontent':
				$data->template->Assign('blockContent', self::getInstance()->ReplaceContentPlaceholders($data->template->Get('blockContent')), false);
				break;
		}
	}
	/**
	* Listener for the iwp_event_users_beforeprofiledisplay event which adjusts user biography output to make slideshows and gallery previews appear on front end custom blocks
	*
	* @param iwp_event_users_beforeprofiledisplay $data
	*/
	public static function onUserProfileDisplay (iwp_event_users_beforeprofiledisplay $event) {
		$thisClass = self::getInstance();
		$event->user->Set('biography', $thisClass->ReplaceContentPlaceholders($event->user->Get('biography')));
	}

	/**
	* This function searches the passed in string and checks for any gallery specific comments that are placeholders for gallery previews or gallery slideshows.
	*
	* @param string $content The string of HTML that should be searched for gallery placeholders
	*
	* @return string The parsed string with any gallery placeholders replaced with the appropriate HTML
	*/

	private function ReplaceContentPlaceholders ($content) {
		preg_match_all('#(?:<p>)?\s*'. preg_quote('<!-- ', '#') . 'gallery\:(preview|slideshow):([0-9]+)' . preg_quote(' -->', '#') . '\s*(?:<p>)?#ism', $content, $matches);

		if(sizeof($matches[0]) > 0) {
			$data = array();
			$data['lang'] = $this->lang->GetLangVars();
			$this->template->Assign($this->moduleName, $data, false);

			$this->cache->SetDir('module_gallery');

			foreach($matches[0] as $key=>$matchedString) {
				$galleryId = $matches[2][$key];
				if((int)$galleryId > 0) {

					if($matches[1][$key] == 'preview') {
						$insertGallery =  $this->GetGalleryPreviewBlock($galleryId, 'middle');
					}else {
						$insertGallery =  $this->GetSlideShowBlock($galleryId, 'middle');
					}

					$content = str_replace($matchedString, $insertGallery, $content);
				}
			}
		}

		return $content;
	}

	/**
	* Listener for the iwp_event_admin_content_urlbrowser event
	*
	* @param iwp_event_admin_content_urlbrowser $data
	*/
	public static function URLBrowserHook (iwp_event_admin_content_urlbrowser $data)
	{
		$thisClass = self::getInstance();
		$thisClass->LoadLanguageVariables();
		$thisClass->template->Assign('GalleryList', $thisClass->GetGalleryArray());

		$data->insertImageActionList[] 	= $thisClass->template->ParseTemplate('gallery.urlbrowser.actionlist', true, 'gallery');
		$data->insertImageActions[] 	= $thisClass->template->ParseTemplate('gallery.urlbrowser.insertimageaction', true, 'gallery');
		$data->checkImagePathMatched[] 	= $thisClass->template->ParseTemplate('gallery.urlbrowser.matchpath', true, 'gallery');
	}

	/**
	* Listener for the iwp_event_admin_content_tinymceplugin event. This adds a tinymce plugin for the gallery module.
	*
	* @param iwp_event_admin_content_tinymceplugin $data
	*/
	public static function TinyMCEPluginHook (iwp_event_admin_content_tinymceplugin $data)
	{
		$thisClass = self::getInstance();
		$data->code .= $thisClass->template->ParseTemplate('gallery.tinymce.plugin', true, 'gallery');
	}

	/**
	* Listener for the iwp_event_admin_navigation_dropdownmenucreated event
	*
	* @param iwp_event_admin_navigation_dropdownmenucreated $data
	*/
	public static function OnDropdownMenuCreated (iwp_event_admin_navigation_dropdownmenucreated $data)
	{
		$auth = iwp_admin_auth::getInstance();

		if ($auth->HasPerm('sitemodules', 'gallery', '*')) {

			$module = iwp_module_gallery::getInstance();
			// image paths are taken from the admin images folder, but they can be relative so to use a module image you'll need to go up a few directories first
			$menu = array(
				array(
					'text' => $module->lang->Get('menuManageGalleries'),
					'link' => 'index.php?section=module&action=custom&module=gallery&moduleaction=view',
					'show' => $auth->HasPerm('sitemodules', 'gallery', '*'),
					'help' => $module->lang->Get('menuManagealleriesHelp'),
					'icon' => '../../modules/gallery/images/gallery.png',
				),
				array(
					'text' => $module->lang->Get('menuCreateGallery'),
					'link' => 'index.php?section=module&action=custom&module=gallery&moduleaction=create',
					'show' => $auth->HasPerm('sitemodules', 'gallery', 'create'),
					'help' => $module->lang->Get('menuCreateGalleryHelp'),
					'icon' => '../../modules/gallery/images/gallery.png',
				),
			);

			$contentMenuIndex = array_search('mnuContent', array_keys($data->menuItems));

			if ($contentMenuIndex === false || $contentMenuIndex == count($data->menuItems) - 1) {
				//	content menu not found or content menu is at end of tab list, insert at end of tab list
				$data->menuItems['module_gallery'] = $menu;
			} else {
				//	otherwise insert after the content tab
				iwp_module_gallery::ArrayInsert($data->menuItems, $contentMenuIndex + 1, array('module_gallery' => $menu));
			}
		}

		if (@$_GET['section'] == 'module' && @$_GET['action'] == 'custom' && @$_GET['module'] == 'gallery') {
			$data->currentMenu = 'mnuGallery';
		}
	}

	/**
	 * This function checks the extension of a filename to make sure it is one of the allowed extensions. This stops a faked MIME type attack which uploads a .php (or similar) file.
	 *
	 * @param $fileName string This is the name of the file to check the extension for
	 *
	 * @return boolean True if the filename is
	 */

	public function IsImageFile($fileName){
		$validImages = array('png', 'jpg', 'gif', 'jpeg', 'tiff', 'bmp', 'jpe');
		foreach($validImages as $image) {
			if(substr(iwp_strtolower($fileName), (int)-(strlen($image)+1)) === '.' . $image){
				return true;
			}
		}
		return false;
	}

	/**
	 * This checks the image using getImageSize to ensure it is a valid image file. It is deleteed if its not.
	 *
	 * @param string $filePath The path to the file that needs to be checked.
	 *
	 * @return boolean
	 */

	public function IsValidImageFile($filePath){
		// Check a list of known MIME types to establish the type of image we're uploading
		$imageTypes = array();
		$imageTypes[] = IMAGETYPE_GIF;
		$imageTypes[] = IMAGETYPE_JPEG;
		$imageTypes[] = IMAGETYPE_PNG;
		$imageTypes[] = IMAGETYPE_BMP;
		$imageTypes[] = IMAGETYPE_TIFF_II;

		$imageDimensions = getimagesize($filePath);
		if(!is_array($imageDimensions) || !in_array($imageDimensions[2], $imageTypes, true)) {
			@unlink($filePath);
			return false;
		}
		return true;
	}


	/**
	* ArrayInsert
	* Inserts one array into another at a given position.
	*
	* @param array $array The recipient array to be inserted into, passed by reference and will have it's pointer reset
	* @param mixed $position The index (numeric) position at which to insert
	* @param mixed $insert_array The array to be inserted
	*/
	private static function ArrayInsert (&$array, $position, $insert_array) {
		$first_array = array_splice ($array, 0, $position);
		$array = array_merge ($first_array, $insert_array, $array);
	}

	/**
	 * GetFileType
	 * Takes the image file path and checks the extension to determine the file
	 * type then saves it to the class variable $FileType
	 *
	 * @return void Doesn't return anything.
	 */
	public function GetFileTypeFromFile($image)
	{
		// if there is no image defined, set the error and return false
		if(empty($image)) {
			return false;
		}
		// grabs the extension of the file
		$type = strtolower(substr(strrchr($image, "."), 1));

		if($type == 'png' || $type == 'jpg' || $type == 'gif') {
			// supported types only
			return $type;

		}elseif($type == 'jpeg') {
			// if the extension is jpeg, we want our type value to be 'jpg'
			return 'jpg';

		} else {
			// nfi what this file is, lets not try and use it
			return 'unknown';
		}
	}


	/**
	* This function generates and outputs a placeholder image for use in the WYSIWYG editor to represent a gallery preview or slideshow.
	*
	* @return void Doesn't return anything.The image content is directly output after an image/png header.
	*/

	private function GetPlaceholderImg() {

		$imageWidth = 460;
		$imageHeight = 200;
		$im = imagecreatetruecolor($imageWidth, $imageHeight);
		$white = imagecolorallocate($im, 255, 255, 255);
		$black = imagecolorallocate($im, 0x00, 0x00, 0x00);

		// Make the background white
		imagefilledrectangle($im, 0, 0, $imageWidth, $imageHeight, $black);
		imagefilledrectangle($im, 1, 1, $imageWidth-2, $imageHeight-2, $white);

		// Path to our ttf font file
		$font_file = IWP_BASE_PATH . '/lib/fonts/arial.ttf';

		$galleryName = $this->db->FetchOne('select name from '. $this->getTable('galleries'). ' where id=' . (int)$_GET['galleryid']);
		$albumCoverExtension = $this->db->FetchOne('select extension from '. $this->getTable('galleries'). ' as g inner join '. $this->getTable('galleryimages'). ' as gi on g.albumcoverid=gi.imageid limit 1');
		$albumCover = $this->UploadPath . DIRECTORY_SEPARATOR . (int)$_GET['galleryid'] . DIRECTORY_SEPARATOR . 'gallerythumb_medium.' . $albumCoverExtension;

		if($_GET['type'] == 'preview') {
			$aPlaceholderFor = $this->lang->Get('aGalleryPreviewFor');
		}else{
			$aPlaceholderFor = $this->lang->Get('aSlideshowFor');
		}

		switch($this->GetFileTypeFromFile($albumCover)) {
			case 'png':
				$InsertHandle =  imagecreatefrompng($albumCover);
			break;

			case 'jpg':
				$InsertHandle =  imagecreatefromjpeg($albumCover);
			break;

			case 'gif':
				$InsertHandle =  imagecreatefromgif($albumCover);
			break;
		}

		imagealphablending($InsertHandle, true);
		$insert_x = imagesx($InsertHandle);
		$insert_y = imagesy($InsertHandle);
		imagecopy($im, $InsertHandle, 12, 12, 0, 0, $insert_x, $insert_y);

		$box = imagettfbbox(13, 0, $font_file, $aPlaceholderFor);
		imagettftext  ($im, 13, 0, (($imageWidth-175-$box[4])/2)+175, 50, $black, $font_file, $aPlaceholderFor);

		$box = imagettfbbox(13, 0, $font_file, '"' . $galleryName .'"');
		imagettftext  ($im, 13, 0, (($imageWidth-175-$box[4])/2)+175, 75, $black, $font_file, '"' . $galleryName .'"');

		$box = imagettfbbox(13, 0, $font_file, $this->lang->Get('willDisplayHere'));
		imagettftext  ($im, 13, 0, (($imageWidth-175-$box[4])/2)+175, 100, $black, $font_file, $this->lang->Get('willDisplayHere'));

		// Output image to the browser
		header('Content-Type: image/png');
		imagepng($im);

		die();
	}

	/**
	 * Returns this module's site-wide permission options
	 *
	 * @return array
	 */
	public static function GetSitePermissionOptions () {
		return iwp_module_gallery::$SitePermissionOptions;
	}

	/**
	 * Returns this module's content-type-specific permission options
	 *
	 * @return array
	 */
	public static function GetContentPermissionOptions () {
		return iwp_module_gallery::$ContentPermissionOptions;
	}


	/**
	 * Returns a granularity list for this class to be displayed on the group permissions page
	 *
	 * @param Integer $total Total will be populated with number of rows found in query (by reference)
	 * @param String $filter Filter string, optional
	 * @param Integer $page Page number of records to return, optional
	 * @return Array List of value/text pairs
	 */
	public static function getGranularityList (&$total, &$page, $filter = '') {
		$module = iwp_module_gallery::getInstance();

		$limitStart = ($page * IWP_PERMISSIONGRANULARITEMS_PER_PAGE) - IWP_PERMISSIONGRANULARITEMS_PER_PAGE;
		$where = '';
		if ($filter) {
			$filter = '%'. $module->db->Quote($filter) .'%';
			$where = sprintf("WHERE (`summary` LIKE '%s')", $filter);
		}

		$result = $module->db->Query(sprintf("SELECT SQL_CALC_FOUND_ROWS `id` AS `value`, `name` AS `text` FROM %s %s ORDER BY `name` LIMIT %d, %d", $module->getTable('galleries'), $where, $limitStart, IWP_PERMISSIONGRANULARITEMS_PER_PAGE));

		$total = $module->db->FetchOne('SELECT found_rows()');
		$list = array();
		if ($result) {
			while ($row = $module->db->Fetch($result)) {
				$row['value'] = (int)$row['value'];
				array_push($list, $row);
			}
			$module->db->FreeResult($result);
		}

		return $list;
	}
}

/**
 * @see iwp_module::$SitePermissionOptions
 */
iwp_module_gallery::$SitePermissionOptions = array(
	'full'		=> new iwp_permissionoption(true,  false, false),
	'create'	=> new iwp_permissionoption(false, false, false),
	'edit'		=> new iwp_permissionoption(true,  false, false),
	'delete'	=> new iwp_permissionoption(true,  false, false),
);

/**
 * So long, and thanks for all the fish
 */