<?php
/**
 * Plug-in to render fileupload element
 * @package fabrikar
 * @author Rob Clayburn
 * @copyright (C) Rob Clayburn
 * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
 */

// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die();

require_once(JPATH_SITE.DS.'components'.DS.'com_fabrik'.DS.'models'.DS.'element.php');

require_once(COM_FABRIK_FRONTEND.DS.'helpers'.DS.'image.php');

define( "FU_DOWNLOAD_SCRIPT_NONE", '0');
define( "FU_DOWNLOAD_SCRIPT_TABLE", '1');
define( "FU_DOWNLOAD_SCRIPT_DETAIL", '2');
define( "FU_DOWNLOAD_SCRIPT_BOTH", '3');

class FabrikModelFabrikFileupload  extends FabrikModelElement {

	var $_pluginName = 'fileupload';

	/**@var object storage method adaptor object (filesystem/amazon s3) */
	var $storage = null;

	/**
	 * Constructor
	 */

	function __construct()
	{
		parent::__construct();
		$this->_is_upload = true;
	}

	/**
	 * decide whether to ingore data when updating a record
	 *
	 * @param string $val
	 * @return bol true if you shouldnt update the data
	 */

	function ignoreOnUpdate($val)
	{
		//check if its a CSV import if it is allow the val to be inserted
		if (JRequest::getCmd('task') === 'makeTableFromCSV' || $this->getTableModel()->_importingCSV) {
			return false;
		}
		$fullName = $this->getFullName(true, true, false);
		$params =& $this->getParams();
		$groupModel =& $this->_group;
		$return = false;
		if ($groupModel->canRepeat()) {
			//$$$rob could be the case that we aren't uploading an element by have removed
			//a repeat group (no join) with a file upload element, in this case processUpload has the correct
			//file path settings.
			return false;

			/*$return = true;
			 foreach ($_FILES[$fullName]['name'] as $n) {
			 if ($n != '') {
			 $return = false;
			 }
			 }*/
		} else {

			if ($groupModel->isJoin()) {
				$name 		= $this->getFullName(false, true, false);
				$joinid = $groupModel->getGroup()->join_id;
				$fdata = $_FILES['join']['name'][$joinid][$name];
			} else {
				$fdata = @$_FILES[$fullName]['name'];
			}
			if ($fdata == '') {
				if ($params->get('fileupload_crop') == false) {
					return true;
				} else {
					//if we can crop we need to store the cropped coordinated in the field data
					// @see onStoreRow();
					return false;
				}
			} else {
				return false;
			}
		}
		return $return;
	}

	/**
	 * run in ajax submit mode (e.g. fancy upload file uploader)
	 *  @return bol true if the element type forces the form to
	 */

	function requiresAJAXSubmit()
	{
		return ($this->getParams()->get('fu_fancy_upload')) ? true : false;
	}

	/**
	 * return tehe javascript to create an instance of the class defined in formJavascriptClass
	 * @return string javascript to create instance. Instance name must be 'el'
	 */

	function elementJavascript($repeatCounter)
	{
		$element =& $this->getElement();
		$params =& $this->getParams();
		$id = $this->getHTMLId($repeatCounter);
		$opts =& $this->getElementJSOptions($repeatCounter);
		$opts->liveSite = COM_FABRIK_LIVESITE;
		$opts->id = $this->_id;
		$opts->defaultImage = $params->get('default_image');
		$opts->folderSelect = $params->get('upload_allow_folderselect', 0);
		$opts->dir		= JPATH_SITE . DS .  $params->get('ul_directory');
		$opts->ds = DS;
		$opts = FastJSON::encode($opts);
		return "new FbFileUpload('$id', $opts)";
	}

	/**
	 * load the javascript class that manages interaction with the form element
	 * should only be called once
	 * @return string javascript class file
	 */

	function formJavascriptClass()
	{
		FabrikHelperHTML::script('javascript.js', 'components/com_fabrik/plugins/element/fabrikfileupload/', false);
	}

	/**
	 * shows the data formatted for the table view
	 * @param string data
	 * @param object all the data in the tables current row
	 * @return string formatted value
	 */

	function renderTableData($data, $oAllRowsData)
	{
		$data = explode(GROUPSPLITTER, $data);
		$params =& $this->getParams();
		for ($i=0; $i <count($data); $i++) {
			$data[$i] = $this->_renderTableData($data[$i], $oAllRowsData, $i);
		}
		$data = implode(GROUPSPLITTER, $data);
		return parent::renderTableData($data, $oAllRowsData);
	}
	/**
	 * shows the data formatted for the CSV export view
	 * @param string data
	 * @param string element name
	 * @param object all the data in the tables current row
	 * @return string formatted value
	 */

	function renderTableData_csv($data, $rows)
	{
		$params =& $this->getParams();
		$format = $params->get('ul_export_encode_csv', 'base64');
		return $this->encodeFile( $data, $format);
	}

	/**
	 * shows the data formatted for the JSON export view
	 * @param string data
	 * @param string element name
	 * @param object all the data in the tables current row
	 * @return string formatted value
	 */

	function renderTableData_json($data, $rows)
	{
		$params =& $this->getParams();
		$format = $params->get('ul_export_encode_json', 'base64');
		return $this->encodeFile($data, $format);
	}

	/**
	 * encodes the file
	 * @param string $file relative file path
	 * @param mixed format to encode the file full|url|base64|raw|relative
	 * @return string encoded file for export
	 */

	protected function encodeFile($file, $format = 'relative')
	{
		$path = JPATH_SITE.DS.$file;
		if (!JFile::exists($path)) {
			return $file;
		}

		switch ($format) {
			case 'full':
				return $path;
				break;
			case 'url':
				return COM_FABRIK_LIVESITE . str_replace('\\', '/', $file);
				break;
			case 'base64':
				return base64_encode(JFile::read($path));
				break;
			case 'raw':
				return JFile::read($path);
				break;
			case 'relative':
				return $file;
				break;
		}
	}

	/**
	 * examine the file being displayed and load in the corresponding
	 * class that deals with its display
	 * @param string file
	 */

	function loadElement($file)
	{
		$ext = strtolower(JFile::getExt($file));
		if (JFile::exists(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'element'.DS.'custom'.DS.$ext.'.php')) {
			require(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'element'.DS.'custom'.DS.$ext.'.php');
		}
		else if (JFile::exists(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'element'.DS.$ext.'.php')) {
			require(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'element'.DS.$ext.'.php');
		} else {
			//default down to allvideos content plugin
			if (in_array($ext, array('flv', '3gp', 'divx'))) {
				require(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'element'.DS.'allvideos.php');
			} else {
				require(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'element'.DS.'default.php');
			}
		}
		return $render;
	}

	/**
	 * Display the file in the table
	 *
	 * @param strng $data
	 * @param array $oAllRowsData
	 * @param int repeat group count
	 * @return string
	 */

	function _renderTableData($data, $oAllRowsData, $i = 0)
	{
		// $$$ hugh - if no file, bail out
		// $$$ rob - you cant do this as the default image wont get rendered
		// $$$ hugh - OOOOPS!!
		/*if (empty($data) || !JFile::exists(COM_FABRIK_BASE.DS.$data)) {
		 return '';
		 }*/
		$this->_repeatGroupCounter = $i;
		$element =& $this->getElement();
		$params =& $this->getParams();
		if (strstr($data, GROUPSPLITTER2)) {
			//crop stuff needs to be removed from data to get correct file path
			$data = explode(GROUPSPLITTER2, $data);
			$data = $data[0];
		}

		$storage =& $this->getStorage();

		$use_download_script = $params->get('fu_use_download_script', '0');
		if ($use_download_script == FU_DOWNLOAD_SCRIPT_TABLE || $use_download_script == FU_DOWNLOAD_SCRIPT_BOTH) {
			if (empty($data) || !$storage->exists(COM_FABRIK_BASE.DS.$data)) {
				return "";
			}
			$aclEl = str_replace('.', '___', $params->get('fu_download_acl', ''));
			if (!empty($aclEl)) {
				$canDownload = FabrikWorker::getACL($oAllRowsData->$aclEl, 'filedownload');
				if (!$canDownload) {
					$img = $params->get('fu_download_noaccess_image');
					return $img == '' ? '' : "<img src=\"images/stories/$img\" alt=\"".JText::_('DOWNLOAD NO PERMISSION')."\" />";
				}
			}
			$formModel = $this->getForm();
			$formid = $formModel->_id;
			$rowid = $oAllRowsData->__pk_val;
			$elementid = $this->_id;
			$title = basename( $data);
			if ($params->get('fu_title_element') == '') {
				$title_name = $this->getFullName(true, true, false ) . '__title';
			} else {
				$title_name = str_replace('.', '___', $params->get('fu_title_element'));
			}
			$title_name .= '_raw';
			if (array_key_exists($title_name, $oAllRowsData)) {
				if (!empty($oAllRowsData->$title_name)) {
					$title = $oAllRowsData->$title_name;
					$title = explode(GROUPSPLITTER,$title);
					$title = $title[$i];
				}
			}
			if ($params->get('fu_download_access_image') !== '') {
				$title = "<img src=\"images/stories/".$params->get('fu_download_access_image')."\" alt=\"$title\" />";
			}
			//$link = "&format=raw&Itemid=undefined&controller=plugin&task=pluginAjax&plugin=fabrikcascadingdropdown&method=ajax_getOptions&element_id=588"
			$link = COM_FABRIK_LIVESITE . "index.php?option=com_fabrik&amp;controller=plugin&amp;task=pluginAjax&amp;plugin=fabrikfileupload&amp;method=ajax_download&amp;element_id=$elementid&amp;formid=$formid&amp;rowid=$rowid&amp;repeatcount=$i";
			$url = "<a href=\"$link\">$title</a>";
			return $url;
		}

		if ($params->get('fu_show_image_in_table')  == '0') {
			$render =& $this->loadElement('default');
		} else {
			$render =& $this->loadElement($data);
		}

		if (empty($data) || !$storage->exists(COM_FABRIK_BASE.DS.$data)) { //@TODO use adaptor
			$render->output = '';
		} else {
			$render->renderTableData($this, $params, $data, $oAllRowsData);
		}
		if ($render->output == '' && $params->get('default_image') != '') {
			$render->output = "<img src=\"{$params->get('default_image')}\" alt=\"image\" />";
		}
		return $render->output;
	}

	/**
	 * do we need to include the lighbox js code
	 *
	 * @return bol
	 */

	function requiresLightBox()
	{
		$params =& $this->getParams();
		if (JRequest::getVar('view') == 'table') {
			if ($params->get('fu_show_image_in_table')  == '0') {
				return false;
			}
		}
		return true;
	}

	/**
	 * DEPREICATED - SHOULD USE storage->_getThumb();
	 * get the thumbnail file for the file given
	 *
	 * @param string $file
	 * @return string thumbnail
	 */

	function _getThumb($file)
	{
		$params =& $this->getParams();
		$w = new FabrikWorker();

		$ulDir = JPath::clean($params->get('ul_directory'));
		$ulDir = str_replace("\\", "/", $ulDir);

		//replace things like $my->id may barf on other stuff
		$afile = str_replace(JURI::root(), '', $file);
		$afile = ltrim($afile, "/");
		$ulDir = ltrim($ulDir, "/");

		$ulDirbits = explode('/', $ulDir);
		$filebits = explode('/', $afile);

		$match = array();
		$replace = array();
		for ($i=0; $i < count($filebits); $i++) {
			if (array_key_exists($i, $ulDirbits) && $filebits[$i] != $ulDirbits[$i]) {
				$match[] = $ulDirbits[$i];
				$replace[] = $filebits[$i];
			}
		}
		$ulDir = str_replace($match, $replace, $ulDir);
		$thumbdir = str_replace($match, $replace, $params->get('thumb_dir'));

		$ulDir = $w->parseMessageForPlaceHolder($ulDir);
		$thumbdir = $w->parseMessageForPlaceHolder($thumbdir);
		$file = str_replace($ulDir, $thumbdir , $file);
		$file = $w->parseMessageForPlaceHolder($file);
		$f = basename($file);
		$dir = dirname($file);
		$file = $dir . '/' . $params->get('thumb_prefix') .  $f;
		return $file;
	}

	function _getCropped( $file )
	{
		$params =& $this->getParams();
		$w = new FabrikWorker();

		$ulDir = JPath::clean($params->get('ul_directory'));
		$ulDir = str_replace("\\", "/", $ulDir);

		//replace things like $my->id may barf on other stuff
		$afile = str_replace(JURI::root(), '', $file);
		$afile = ltrim($afile, "/");
		$ulDir = ltrim($ulDir, "/");

		$ulDirbits = explode('/', $ulDir);
		$filebits = explode('/', $afile);

		$match = array();
		$replace = array();
		for ($i=0; $i < count($filebits); $i++) {
			if (array_key_exists($i, $ulDirbits) && $filebits[$i] != $ulDirbits[$i]) {
				$match[] = $ulDirbits[$i];
				$replace[] = $filebits[$i];
			}
		}
		$ulDir = str_replace($match, $replace, $ulDir);
		$thumbdir = str_replace($match, $replace, $params->get('fileupload_crop_dir'));

		$ulDir = $w->parseMessageForPlaceHolder($ulDir);
		$thumbdir = $w->parseMessageForPlaceHolder($thumbdir);
		$file = str_replace($ulDir, $thumbdir , $file);
		$file = $w->parseMessageForPlaceHolder($file);
		$f = basename($file);
		$dir = dirname($file);
		$file = $dir . '/'  .  $f;
		//@todo apply JPath::clean to file name
		return $file;
	}

	/**
	 * formats the posted data for insertion into the database
	 * @param mixed thie elements posted form data
	 * @param array posted form data
	 */

	function storeDatabaseFormat($val, $data)
	{
		//val already contains group splitter from processUpload() code
		return $val;
	}

	/**
	 * checks the posted form data against elements INTERNAL validataion rule - e.g. file upload size / type
	 * @param string elements data
	 * @param int repeat group counter
	 * @return bol true if passes / false if falise validation
	 */

	function validate( $data, $repeatCounter = 0)
	{
		$params 		=& $this->getParams();
		$groupModel =& $this->_group;
		$group 			=& $groupModel->getGroup();
		$this->_validationErr = '';
		$errors = array();
		$elName = $this->getFullName();
		$elName = str_replace('[]', '', $elName); //remove any repeat group labels
		if ($groupModel->isJoin()) {
			// $$$ hugh - kinda screws things up if 'join' is used in the element name!
			/*
			$elTempName = str_replace('join', '', $elName);
			$elTempName = str_replace('[', '', $elTempName);
			$joinArray = explode(']', $elTempName);
			*/
			$joinArray = array();
			if (!preg_match('#join\[(\d+)\]\[(\S+)\]#', $elName, $joinArray)) {
				return true;
			}
			if (!array_key_exists('join', $_FILES)) {
				return true;
			}
			$aFile 	=  $_FILES['join'];
			$myFileName = $aFile['name'][$joinArray[1]][$joinArray[2]];
			$myFileSize = $aFile['size'][$joinArray[1]][$joinArray[2]];
			if (is_array($myFileSize)) {
				$myFileSize = $myFileSize[$repeatCounter];
			}
			if (is_array($myFileName)) {
				$myFileName = $myFileName[$repeatCounter];
			}
		} else {
			if (!array_key_exists($elName, $_FILES)) {
				return true;
			}
			$aFile 	=  $_FILES[$elName];
			if ($groupModel->canRepeat()) {
				$myFileName = $aFile['name'][$repeatCounter];
				$myFileSize = $aFile['size'][$repeatCounter];
			} else {
				$myFileName = $aFile['name'];
				$myFileSize = $aFile['size'];
			}
		}
		$ok = true;

		if (!$this->_fileUploadFileTypeOK( $myFileName)) {
			$errors[] = JText::_('PLG_ELEMENT_FILEUPLOAD_FILE_TYPE_NOT_ALLOWED');
			$ok = false;
		}
		if (!$this->_fileUploadSizeOK( $myFileSize)) {
			$ok = false;
			$mySize = $myFileSize / 1000;
			$errors[] = JText::sprintf('PLG_ELEMENT_FILEUPLOAD_FILE_TOO_LARGE',  $params->get('ul_max_file_size'), $mySize);
		}
		$filepath = $this->_getFilePath( $repeatCounter);
		jimport('joomla.filesystem.file');
		if (JFile::exists($filepath)) {
			if ($params->get('ul_file_increment', 0) == 0) {
				$errors[] = JText::_('PLG_ELEMENT_FILEUPLOAD_EXITING_FILE_NAME');
				$ok = false;
			}
		}
		$this->_validationErr = implode('<br />', $errors);
		return $ok;
	}

	function _getAllowedExtension()
	{
		$params =& $this->getParams();
		$allowedFiles = $params->get('ul_file_types');
		if ($allowedFiles != '') {
			// $$$ hugh - strip spaces, as folk often do ".foo, .bar"
			preg_replace('#\s+#', '', $allowedFiles);
			$aFileTypes = explode(",", $allowedFiles);
		} else {
			$mediaparams =& JComponentHelper::getParams('com_media');
			$aFileTypes = explode(',', $mediaparams->get('upload_extensions'));
		}
		return $aFileTypes;
	}

	/**
	 * This checks the uploaded file type against the csv specified in the upload
	 * element
	 * @access PRIVATE
	 * @param string filename
	 * @return bol true if upload file type ok
	 */

	function _fileUploadFileTypeOK( $myFileName )
	{
		$aFileTypes = $this->_getAllowedExtension();
		if ($myFileName == '') {
			return true;
		}
		$curr_f_ext = strtolower(JFile::getExt($myFileName));
		array_walk($aFileTypes, create_function('&$v', '$v = strtolower($v);'));
		if (in_array($curr_f_ext, $aFileTypes) || in_array(".".$curr_f_ext, $aFileTypes)) {
			return true;
		}

		return false;
	}

	/**
	 * This checks that thte fileupload size is not greater than that specified in
	 * the upload element
	 * @access PRIVATE
	 * @param string file size
	 * @return bol true if upload file type ok
	 */

	function _fileUploadSizeOK( $myFileSize )
	{
		$params =& $this->getParams();
		$max_size = $params->get('ul_max_file_size') * 1000;
		if ($myFileSize <= $max_size) {
			return true;
		}
		return false;
	}

	/**
	 * OPTIONAL
	 */

	function processUpload()
	{
		//@TODO: test in joins
		$params =& $this->getParams();
		$request =& JRequest::get('request');
		$groupModel =& $this->getGroup();
		$isjoin = $groupModel->isJoin();
		$origData = $this->_form->getOrigData();

		if ($isjoin) {
			$name = $this->getFullName(false, true, false);
			$joinid = $groupModel->getGroup()->join_id;
		} else {
			$name = $this->getFullName(true, true, false);
		}

		$files = array();
		$deletedImages = JRequest::getVar('fabrik_fileupload_deletedfile', array(), 'request', 'array');
		$gid = $groupModel->getGroup()->id;

		$deletedImages = JArrayHelper::getValue($deletedImages, $gid, array());
		$imagesToKeep = array();

		for ($j = 0; $j < count($origData); $j++) {
			foreach ($origData[$j] as $key => $val) {
				if ($key == $name) {
					if ($groupModel->canRepeat() && !$isjoin) {
						foreach (explode(GROUPSPLITTER, $val) as $subval) {
							if (!in_array($subval,$deletedImages)) {
								$imagesToKeep[] = $subval;
							}
						}
						if (empty($imagesToKeep)) {
							unset($origData[$j]->$key);
						}
						else {
							$origData[$j]->$key = implode(GROUPSPLITTER, $imagesToKeep);
						}
					}
					else {
						if (in_array($val, $deletedImages)) {
							unset($origData[$j]->$key);
						} else {
							$imagesToKeep[] = $origData[$j]->$key;
						}
					}
					continue;
				}
			}
		}

		if ($groupModel->canRepeat()) {
			if ($isjoin) {
				$fdata = $_FILES['join']['name'][$joinid][$name];
			} else {
				$fdata = $_FILES[$name]['name'];
			}

			foreach ($fdata as $i => $f) {
				if ($isjoin) {
					$myFileDir = (is_array($request['join'][$joinid][$name]) && array_key_exists($i, $request['join'][$joinid][$name])) ? $request['join'][$joinid][$name][$i] : '';
				} else {
					$myFileDir = (is_array($request[$name]) && array_key_exists($i, $request[$name])) ? $request[$name][$i] : '';
				}

				$file = array(
					'name' 			=> $isjoin ? $_FILES['join']['name'][$joinid][$name][$i] : $_FILES[$name]['name'][$i],
					'type' 			=> $isjoin ? $_FILES['join']['type'][$joinid][$name][$i] : $_FILES[$name]['type'][$i],
					'tmp_name' 	=> $isjoin ? $_FILES['join']['tmp_name'][$joinid][$name][$i] : $_FILES[$name]['tmp_name'][$i],
					'error' 		=> $isjoin ? $_FILES['join']['error'][$joinid][$name][$i] : $_FILES[$name]['error'][$i],
					'size' 			=> $isjoin ? $_FILES['join']['size'][$joinid][$name][$i] : $_FILES[$name]['size'][$i]
				);
				if ($file['name'] != '') {
					$files[$i] = $this->_processIndUpload($file, $myFileDir, $i);
				} else {
					$files[$i] = $imagesToKeep[$i];;//$origData[$i]->$name;
				}
			}
			foreach($imagesToKeep as $k => $v) {
				if (!array_key_exists($k, $files)) {
					$files[$k] = $v;
				}
			}
		} else {
			if ($isjoin) {
				$myFileDir = $request['join'][$joinid][$name];
			} else {
				$myFileDir = JArrayHelper::getValue($request, $name);
			}

			$file = array(
					'name' 			=> $isjoin ? $_FILES['join']['name'][$joinid][$name] : $_FILES[$name]['name'],
					'type' 			=> $isjoin ? $_FILES['join']['type'][$joinid][$name] : $_FILES[$name]['type'],
					'tmp_name' 	=> $isjoin ? $_FILES['join']['tmp_name'][$joinid][$name] : $_FILES[$name]['tmp_name'],
					'error' 		=> $isjoin ? $_FILES['join']['error'][$joinid][$name] : $_FILES[$name]['error'],
					'size' 			=> $isjoin ? $_FILES['join']['size'][$joinid][$name] : $_FILES[$name]['size']
			);

			if ($file['name'] != '') {
				$files[] = $this->_processIndUpload($file, $myFileDir);
			} else {
				$files[] = $imagesToKeep[0];//$origData[0]->$name;
			}
		}
		$files = array_flip(array_flip($files));
		if ($params->get('upload_delete_image')) {
			foreach ($deletedImages as $filename) {
				$this->deleteFile( $filename);
			}
		}
		// $$$ rob dont alter the request array as we should be inserting into the form models
		// ->_formData array using updateFormData();

		if ($isjoin) {
			if (!$groupModel->canRepeat()) {
				$files = $files[0];
			}
			$this->_form->updateFormData("join.{$joinid}.{$name}", $files);
			$this->_form->updateFormData("join.{$joinid}.{$name}_raw", $files);
		} else {
			$strfiles = implode(GROUPSPLITTER, $files);
			$this->_form->updateFormData($name . "_raw", $strfiles);
			$this->_form->updateFormData($name, $strfiles);
		}

	}

	/**
	 * delete the file
	 * @param $filename string file name (not including JPATH)
	 */

	function deleteFile( $filename )
	{
		$storage =& $this->getStorage();
		$file =  $storage->clean(JPATH_SITE . DS . $filename);
		$thumb =  $storage->clean($storage->_getThumb($file));
		if ($storage->exists($file)) {
			$storage->delete($file);
		}
		if ($storage->exists($thumb)) {
			$storage->delete($thumb);
		}
	}

	/**
	 * used in notempty validation rule
	 */

	function dataConsideredEmpty($data, $repeatCounter)
	{
		if ((int)JRequest::getVar('rowid', 0) != 0) {
			if (JRequest::getVar('task') == '') {
				$r= parent::dataConsideredEmpty( $data, $repeatCounter);
				return $r;
			}
			// editing an existing record so consider that the file was tested and added for
			// when the original record was added. (cant test $_FILES on edit)
			return false;
		}
		$groupModel = $this->getGroup();
		if ($groupModel->isJoin()) {
			$name 		= $this->getFullName(false, true, false);
			$joinid = $groupModel->getGroup()->join_id;
			$joindata = JRequest::getVar('join', '', 'files', 'array', array());
			if (!array_key_exists('name', $joindata)) {
				return true;
			}
			$file = (array)$joindata['name'][$joinid][$name];
			return JArrayHelper::getValue($file, $repeatCounter, '') == '' ? true : false;
		} else {
			$name 		= $this->getFullName(true, true, false);
			$file = JRequest::getVar($name, '', 'files', 'array', array());
			if ($groupModel->canRepeat()) {
				return JArrayHelper::getValue($file['name'], $repeatCounter, '') == '' ? true : false;
			}
		}

		if (!array_key_exists('name', $file)) {
			$file = JRequest::getVar($name);
			return $file == '' ? true : false;//ajax test - nothing in files
		}
		// no files selected?
		return $file['name'] == '' ? true : false;
	}

	/**
	 * it parameters set so we make a cropped image
	 * (non-PHPdoc)
	 * @see components/com_fabrik/models/FabrikModelElement#onStoreRow($data)
	 */

	function onStoreRow(&$tmpdata)
	{
		//@TODO make code in here react to storage settings

		$params =& $this->getParams();
		$storage =& $this->getStorage();
		if ($params->get('fileupload_crop') == false) {
			return;
		}
		$toploc = explode(",", JRequest::getVar($this->getFullName() . "_cropcoords", array(0,0), 'default', 'array'));
		$k = $this->getElement()->name . "_raw";

		if (array_key_exists($k, $tmpdata) && $tmpdata[$k] !== '') {
			$file = COM_FABRIK_BASE .$tmpdata[$k];
		} else {
			$file = str_replace(COM_FABRIK_LIVESITE, COM_FABRIK_BASE, JRequest::getVar($this->getFullName() . "_dragger_thumb"));
		}
		if (!JFile::exists($file)) {
			return;
		}

		$newwidth = $params->get('fileupload_crop_width', 50);
		$newheight = $params->get('fileupload_crop_height', 50);

		list($sourcewidth, $sourceheight) = getimagesize($file);

		$cropped = imagecreatetruecolor($newwidth, $newheight);
		$source = imagecreatefromjpeg( $file);
		$cropLeft =  (int)$toploc[0];
		$cropTop = $toploc[1];
		$destx= 0;
		$desty = 0;

		$dest = $params->get('fileupload_crop_dir');
		$w = new FabrikWorker();
		$destfolder = $w->parseMessageForPlaceHolder(COM_FABRIK_BASE . DS.$dest);

		if (!$storage->exists($destfolder)) {
			$storage->createFolder( $destfolder);
		}
		$dest = $destfolder . DS. basename($file);
		$dest = $storage->clean($dest);

		$ok = imagecopy( $cropped, $source, $destx, $desty, $cropLeft, $cropTop, $newwidth, $newheight);
		if (!$ok) {
			JError::raiseWarning(21, "could not make cropped image - $dest, source = $file");
		}


		$ext = JFile::getExt($file);

		if ($ext == "jpeg" || $ext == 'jpg') {
			if (!imagejpeg( $cropped, $dest)) {
				//go figure sometimes this returns false but the image is saved??
				JError::raiseWarning(21, "could not create image - $dest");
			}
			ob_start();
			imagejpeg( $cropped, "", 100);
			$image = ob_get_contents();
			ob_end_clean();
			JFile::write( $dest, $image);
		} else {
			if ($ext == "png") {
				ob_start();
				imagepng( $cropped, "", 100);
				$image = ob_get_contents();
				ob_end_clean();
				$storage->write( $dest, $image);
			} else {
				if (function_exists("imagegif")) {
					ob_start();
					imagegif( $cropped, "", 100);
					$image = ob_get_contents();
					ob_end_clean();
					$storage->write( $dest, $image);
				} else {
					/* try using imagemagick to convert gif to png:*/
					$image_file = imageHelper::imgkConvertImage($image_file, $baseDir, $destDir, ".png");
				}
			}
		}
		$file = str_replace(COM_FABRIK_BASE, '', $file) . GROUPSPLITTER2 . implode(',', $toploc);
		if (!array_key_exists($k, $tmpdata) || $tmpdata[$k] == '') {

			$tmpdata[$this->getElement()->name] = $file;
			$tmpdata[$this->getElement()->name . "_raw"] = $file;
		}
		$dest = str_replace(COM_FABRIK_BASE, '', $dest);
	}

	/**
	 * process the upload
	 * @access private
	 *
	 * @param array $file info
	 * @param string user selected upload folder
	 * @param int repeat group counter
	 * @return string location of uploaded file
	 */

	function _processIndUpload(&$file, $myFileDir = '', $repeatGroupCounter = 0)
	{
		$params 		=& $this->getParams();

		$storage =& $this->getStorage();
		// $$$ hugh - check if we need to blow away the cached filepath, set in validation
		$myFileName = $storage->cleanName($file['name'], $repeatGroupCounter);
		if ($myFileName != $file['name']) {
			$file['name'] = $myFileName;
			unset($this->_filePaths[$repeatGroupCounter]);
		}
		$tmpFile 		= $file['tmp_name'];
		$uploader 	=& $this->_form->getUploader();

		if ($params->get('ul_file_types') == '') {
			$params->set('ul_file_types', implode(',', $this->_getAllowedExtension()));
		}
		$err		= null;
		// Set FTP credentials, if given
		jimport('joomla.client.helper');
		JClientHelper::setCredentialsFromRequest('ftp');
		if ($myFileName == '') {
			return;
		}
		$filepath = $this->_getFilePath( $repeatGroupCounter);
		if (!uploader::canUpload($file, $err, $params)) {
			JError::raiseNotice(100, $file['name'] .': '. JText::_($err));
		}

		if ($storage->exists($filepath)) {
			switch( $params->get('ul_file_increment', 0)) {
				case 0:
					break;
				case 1:
					$filepath = uploader::incrementFileName($filepath, $filepath, 1);
					break;
				case 2:
					$storage->delete($filepath);
					break;
			}
		}
		if (!$storage->upload($tmpFile, $filepath)) {
			$uploader->moveError = true;
			JError::raiseWarning(100, JText::_("Error. Unable to upload file (from $tmpFile to $filepath)"));
			return;
		}
		$filepath = $storage->getUploadedFilePath();
		jimport('joomla.filesystem.path');
		$storage->setPermissions($filepath);

		// $$$ hugh @TODO - shouldn't we check to see if it's actually an image before we do any of this stuff???

		//resize main image
		$oImage 		= imageHelper::loadLib( $params->get('image_library'));
		$oImage->setStorage($storage);
		// $$$ hugh - removing default of 200, otherwise we ALWAYS resize, whereas
		// tooltip on these options say 'leave blank for no resizing'
		$mainWidth 		= $params->get('fu_main_max_width', '');
		$mainHeight 	= $params->get('fu_main_max_height', '');

		if ($mainWidth != '' || $mainHeight != '') {
			// $$$ rob ensure that both values are integers otherwise resize fails
			if ($mainHeight == '') {
				$mainHeight = (int)$mainWidth;
			}
			if ($mainWidth == '') {
				$mainWidth = (int)$mainHeight;
			}
			$oImage->resize($mainWidth, $mainHeight, $filepath, $filepath);
		}
		// $$$ hugh - if it's a PDF, make sure option is set to attempt PDF thumb
		$make_thumbnail = $params->get('make_thumbnail') == '1' ? true : false;
		$fileinfo = pathinfo($filepath);
		if (strtolower($fileinfo['extension']) == 'pdf' && $params->get('fu_make_pdf_thumb', '0') == '0') {
			$make_thumbnail = false;
		}
		if ($make_thumbnail) {
			$thumbPath 		=  $storage->clean(JPATH_SITE.DS.$params->get('thumb_dir').DS.$myFileDir.DS, false);
			$w = new FabrikWorker();
			$thumbPath = $w->parseMessageForPlaceHolder($thumbPath);
			$thumbPrefix 	= $params->get('thumb_prefix');
			$maxWidth 		= $params->get('thumb_max_width', 125);
			$maxHeight 		= $params->get('thumb_max_height', 125);

			if ($thumbPath != '') {
				if (!$storage->folderExists($thumbPath)) {
					if (!$storage->createFolder($thumbPath)) {
						JError::raiseError(21, "Could not make dir $thumbPath ");
					}
				}
			}
			$fileURL = $storage->getFileUrl(str_replace(COM_FABRIK_BASE, '', $filepath));
			$destThumbFile = $storage->_getThumb($fileURL);
			$destThumbFile = $storage->urlToPath($destThumbFile);
			$oImage->resize($maxWidth, $maxHeight, $filepath, $destThumbFile);
			$storage->setPermissions($destThumbFile);
		}
		$storage->setPermissions($filepath);
		$storage->finalFilePathParse($filepath);
		return $filepath;
	}

	function getStorage()
	{
		if (!isset($this->storage)) {
			$params =& $this->getParams();
			$storageType = JFilterInput::clean($params->get('fileupload_storage_type', 'filesystemstorage'), 'CMD');
			require_once(COM_FABRIK_FRONTEND.DS.'plugins'.DS.'element'.DS.'fabrikfileupload'.DS.'adaptors'.DS.$storageType.'.php');
			$this->storage = new $storageType( $params);
		}
		return $this->storage;
	}

	/**
	 * get the full server file path for the upload, including the file name i
	 * @param int repeat group counter
	 * @return string path
	 */

	function _getFilePath( $repeatCounter = 0)
	{
		if (!isset($this->_filePaths)) {
			$this->_filePaths = array();
		}
		if (array_key_exists($repeatCounter, $this->_filePaths)) {
			return $this->_filePaths[$repeatCounter];
		}
		$aData   =& JRequest::get('post');
		$elName   = $this->getFullName(true, true, false);
		$elNameRaw = $elName . '_raw';
		$params   =& $this->getParams();
		//@TODO test with fileuploads in join groups

		$groupModel =& $this->getGroup();
		// $$$ hugh - for some reason we need $elName for repeat groups, and $elNameRaw for onesies
		/*		if ($groupModel->canRepeat()) {
			if ($groupModel->isJoin()) {
			$joinid = $groupModel->getGroup()->join_id;

			$elNameNoJoinstr   = $this->getFullName(false, true, false);
			$myFileName = $_FILES['join']['name'][$joinid][$elNameNoJoinstr][$repeatCounter];
			$myFileDir = $aData['join'][$joinid][$elNameNoJoinstr]['ul_end_dir'][$repeatCounter];
			} else {
			$myFileDir = (array_key_exists($elName, $aData) && array_key_exists($repeatCounter, $aData[$elName])) ? @$aData[$elName][$repeatCounter] : '';
			$myFileName   = @$_FILES[$elName]['name'][$repeatCounter];
			}

			} else {

			}*/


		if ($groupModel->isJoin()) {
			$joinid = $groupModel->getGroup()->join_id;

			$elNameNoJoinstr   = $this->getFullName(false, true, false);
			if ($groupModel->canRepeat()) {
				$myFileName = $_FILES['join']['name'][$joinid][$elNameNoJoinstr][$repeatCounter];
				$myFileDir = JArrayHelper::getValue($aData['join'][$joinid][$elNameNoJoinstr], 'ul_end_dir', array());
				$myFileDir = JArrayHelper::getValue($myFileDir, $repeatCounter, '');
			} else {
				$myFileName = $_FILES['join']['name'][$joinid][$elNameNoJoinstr];
				$myFileDir = JArrayHelper::getValue($aData['join'][$joinid][$elNameNoJoinstr], 'ul_end_dir', '');
			}
		} else {
			if ($groupModel->canRepeat()) {
				$myFileName   = @$_FILES[$elName]['name'][$repeatCounter];
				$myFileDir    = array_key_exists($elNameRaw, $aData) && is_array($aData[$elNameRaw] ) ? @$aData[$elNameRaw]['ul_end_dir'][$repeatCounter] : '';
			} else {
				$myFileName   = @$_FILES[$elName]['name'];
				$myFileDir    = array_key_exists($elNameRaw, $aData) && is_array($aData[$elNameRaw] ) ? @$aData[$elNameRaw]['ul_end_dir'] : '';

			}
		}

		$storage =& $this->getStorage();
		// $$$ hugh - check if we need to blow away the cached filepath, set in validation
		$myFileName = $storage->cleanName($myFileName, $repeatCounter);

		$folder = $params->get('ul_directory');
		$folder  = $folder . DS . $myFileDir;
		$folder = JPath::clean(JPATH_SITE . DS . $folder);
		$w = new FabrikWorker();
		$folder = $w->parseMessageForPlaceHolder($folder);

		JPath::check($folder);
		$storage->makeRecursiveFolders($folder);
		$p = $folder . DS . $myFileName;
		$this->_filePaths[$repeatCounter] = JPath::clean($p);
		return $this->_filePaths[$repeatCounter];
	}

	/**
	 * draws the form element
	 * @param array data
	 * @param int repeat group counter
	 * @return string returns element html
	 */

	function render($data, $repeatCounter = 0)
	{
		$this->_repeatGroupCounter = $repeatCounter;
		$id 			= $this->getHTMLId($repeatCounter);
		$name 		= $this->getHTMLName($repeatCounter);
		$groupModel =& $this->getGroup();
		$element 	=& $this->getElement();
		$params 	=& $this->getParams();
		if ($element->hidden == '1') {
			return $this->getHiddenField($name, $data[$name], $id);
		}

		$str = '';
		$value = $this->getValue($data, $repeatCounter);
		$imagedata = array();
		if (strstr($value, GROUPSPLITTER2)) {
			//crop stuff needs to be removed from data to get correct file path
			$imagedata = explode(GROUPSPLITTER2, $value);
			$value = $imagedata[0];
		}
		if (array_key_exists(1, $imagedata)) {
			$this->_cropCoords = explode(",", $imagedata[1]);
		}else{
			$this->_cropCoords = array(0,0);
		}

		$ulDir = $params->get('ul_directory');
		$storage =& $this->getStorage();

		$use_download_script = $params->get('fu_use_download_script', '0');
		if (!$this->_editable && ($use_download_script == FU_DOWNLOAD_SCRIPT_DETAIL || $use_download_script == FU_DOWNLOAD_SCRIPT_BOTH)) {
			if (empty($value) || !$storage->exists(COM_FABRIK_BASE.DS.$value)) {
				return "";
			}
			$aclEl = str_replace('.', '___', $params->get('fu_download_acl', ''));
			if (!empty($aclEl)) {
				$canDownload = FabrikWorker::getACL($data[$aclEl], 'filedownload');
				if (!$canDownload) {
					$img = $params->get('fu_download_noaccess_image');
					return $img == '' ? '' : "<img src=\"images/stories/$img\" alt=\"".JText::_('DOWNLOAD NO PERMISSION')."\" />";
				}
			}
			$formModel = $this->getForm();
			$formid = $formModel->_id;
			$rowid = JRequest::getVar('rowid', '0');
			$elementid = $this->_id;
			$title = basename($value);
			if ($params->get('fu_title_element') == '') {
				$title_name = $this->getFullName(true, true, false ) . '__title';
			} else {
				$title_name = str_replace('.', '___', $params->get('fu_title_element'));
			}
			$title_name .= '_raw';
			if (is_array($formModel->_data)) {
				if (array_key_exists($title_name, $formModel->_data)) {
					if (!empty($formModel->_data[$title_name])) {
						$title = $formModel->_data[$title_name];
						$title = explode(GROUPSPLITTER, $title);
						$title = $title[$repeatCounter];
					}
				}
			}
			if ($params->get('fu_download_access_image') !== '') {
				$title = "<img src=\"images/stories/".$params->get('fu_download_access_image')."\" alt=\"$title\" />";
			}
			//$link = "&format=raw&Itemid=undefined&controller=plugin&task=pluginAjax&plugin=fabrikcascadingdropdown&method=ajax_getOptions&element_id=588"
			$link = COM_FABRIK_LIVESITE . "index.php?option=com_fabrik&controller=plugin&task=pluginAjax&plugin=fabrikfileupload&method=ajax_download&element_id=$elementid&formid=$formid&rowid=$rowid&repeatcount=$repeatCounter";
			$url = "<a href=\"$link\">$title</a>";
			return $url;
		}

		$render =& $this->loadElement($value);
		if ($params->get('fu_show_image')  != '0') {

			if ($value != '' && $storage->exists(COM_FABRIK_BASE.DS.$value)) {
				$render->render($this, $params, $value);
			}

		}
		if ($render->output == '' && $params->get('default_image') != '') {
			$render->output = "<img src=\"{$params->get('default_image')}\" alt=\"image\" />";
		}
		if ($render->output != '') {
			$str .= $render->output . "<br />";
		}

		if (!$this->_editable) {
			//return $str . "</div>";
			return $str;
		} else {
			// $$$ rob dont wrap readonly in subElementContainer as it stops dataConsideredEmpty() working when testing ro values
			$str 	= "<div class=\"fabrikSubElementContainer\">$str";
		}
		$str .= '<input class="fabrikinput" name="'.$name.'" type="file" id="'.$id.'" />'."\n";
		if ($params->get('upload_allow_folderselect', 0) == '1') {
			$rDir		= JPATH_SITE . DS . $params->get('ul_directory');
			$folders = JFolder::folders($rDir);
			$str .= FabrikHelperHTML::folderAjaxSelect($folders);
			if ($groupModel->canRepeat()) {
				$ulname = FabrikString::rtrimword( $name, "[$repeatCounter]") . "[ul_end_dir][$repeatCounter]";
			} else {
				$ulname = $name.'[ul_end_dir]';
			}
			$str .= "<input name=\"$ulname\" type=\"hidden\" class=\"folderpath\"/>";
		}

		if ($params->get('fu_fancy_upload')) {
			$str .= "<span id=\"{$id}upload-clear\"></span>";

			$str .= "<ul class='upload-queue' id='{$id}upload-queue'>
			<li style='display: none' />
			</ul>";
			FabrikHelperHTML::script('swf.js');
			FabrikHelperHTML::script('uploader.js');

			static $uploaders;

			if (!isset($uploaders)) {
				$uploaders = array();
			}

			/*if (isset($uploaders[$id]) && ($uploaders[$id])) {
			 return;
			 }*/

			// Setup options object
			$opt['url']					=  null;
			$opt['swf']					=  JURI::root(true).'/media/system/swf/uploader.swf';
			$opt['multiple']			=  '\\true';
			$opt['queued']				= '\\true';
			$opt['queueList']			=  $id.'upload-queue';
			$opt['instantStart']		=  '\\false';
			$opt['allowDuplicates']		= '\\true';
			$opt['limitSize']			=  null;
			$opt['limitFiles']			=  null;
			$opt['optionFxDuration']	=  null;
			$opt['container']			=  '\\$(\''.$id.'\').getParent()';
			$opt['types']				=  '\\{\'All Files (*.*)\': \'*.*\'}';


			// Optional functions
			$opt['createReplacement']	=  null;
			$opt['onComplete']			=  null;
			$opt['onAllComplete']		=  null;

			/*  types: Object with (description: extension) pairs, default: Images (*.jpg; *.jpeg; *.gif; *.png)
			 */

			$options = JHTMLBehavior::_getJSObject($opt);

			// Attach tooltips to document
			$document =& JFactory::getDocument();
			$document->addStyleSheet('administrator/components/com_media/assets/mediamanager.css');

			$uploaderInit = 'sBrowseCaption=\''.JText::_('Browse Files', true).'\';
				sRemoveToolTip=\''.JText::_('Remove from queue', true).'\';
				window.addEvent(\'load\', function() {
				Uploader = new FancyUpload($(\''.$id.'\'), '.$options.');
				$(\''.$id.'upload-clear\').adopt(new Element(\'input\', { type: \'button\', events: { click: Uploader.clearList.bind(Uploader, [false])}, value: \''.JText::_('Clear Completed').'\' }));				});';
			FabrikHelperHTML::addScriptDeclaration($uploaderInit);

			// Set static array
			$uploaders[$id] = true;
		}
		$str .= "</div>";
		return $str;
	}

	function getFieldDescription()
	{
		$p = $this->getParams();
		if ($this->encryptMe()) {
			return 'BLOB';
		}
		return "TEXT";
	}

	function renderAdminSettings(&$lists)
	{
		$params =& $this->getParams();
		$pluginParams =& $this->getPluginParams();
		// $$$ hugh - not sure what the maxUpload is doing in there?
		?>
<div id="page-<?php echo $this->_name;?>" class="elementSettings"
	style="display: none"><?php $this->maxUpload(); ?> <?php echo $pluginParams->render();?>
<fieldset><legend> <?php echo JText::_('Display');?> </legend> <?php echo $pluginParams->render('params', 'display');?>
</fieldset>
<fieldset><legend> <?php echo JText::_('Thumbnail');?> </legend> <?php echo $pluginParams->render('params', 'thumbnail');?>
</fieldset>
<fieldset><legend> <?php echo JText::_('CROP');?> </legend> <?php echo $pluginParams->render('params', 'crop');?>
</fieldset>
<fieldset><legend> <?php echo JText::_('PLG_ELEMENT_FILEUPLOAD_DOWNLOADS');?> </legend> <?php echo $pluginParams->render('params', 'downloads');?>
</fieldset>
<fieldset><legend> <?php echo JText::_('STORAGE');?> </legend> <?php echo $pluginParams->render('params', 'storage');?>
</fieldset>
<fieldset><legend> <?php echo JText::_('EXPORT');?> </legend> <?php echo $pluginParams->render('params', 'export');?>
</fieldset>

</div>
		<?php
	}

	function getAdminJS()
	{
		FabrikHelperHTML::script('admin.js', 'components/com_fabrik/plugins/element/fabrikfileupload/', true);
		$lang = new stdClass();
		$lang->error_thumb = JText::_('FILEUPLOAD_WARNING_THUMB', true);
		$lang->error_crop = JText::_('FILEUPLOAD_WARNING_CROP', true);
		$lang = FastJSON::encode($lang);
		$script = "\tvar fabrikfileupload = new fabrikAdminFileupload($lang);\n".
		"\tpluginControllers.push({element:'fabrikfileupload', controller:fabrikfileupload});\n";
		return $script;
	}

	/**
	 * attach documents to the email
	 * @param string data
	 * @return string formatted value
	 */

	function addEmailAttachement($data)
	{
		/// @TODO: check what happens here with open base_dir in effect //
		$params =& $this->getParams();

		if ($params->get('ul_email_file')) {
			$config	=& JFactory::getConfig();
			if (empty($data)) {
				$data = $params->get('default_image');
			}
			if (strstr($data, JPATH_SITE)) {
				$p = str_replace(COM_FABRIK_LIVESITE , JPATH_SITE, $data);
			} else {
				$p = JPATH_SITE . DS . $data;
			}
			return $p;
		}
		return false;
	}

	/**
	 * If a database join element's value field points to the same db field as this element
	 * then this element can, within modifyJoinQuery, update the query.
	 * E.g. if the database join element points to a file upload element then you can replace
	 * the file path that is the standard $val with the html to create the image
	 *
	 * @param string $val
	 * @param string view form or table
	 * @return string modified val
	 * @TODO: base the returned string completely on the params specified for the element
	 * e.g. thumbnail, show image, link etc
	 */

	function modifyJoinQuery($val, $view='form')
	{
		$params =& $this->getParams();
		if( !$params->get('fu_show_image', 0) && $view == 'form') {
			return $val;
		}
		if ($params->get('make_thumbnail')) {
			$ulDir = JPath::clean($params->get('ul_directory')) . DS;
			$ulDir = str_replace("\\", "\\\\", $ulDir);
			$thumbDir = $params->get('thumb_dir');
			$thumbDir = JPath::clean($params->get('thumb_dir')) . DS;
			$w = new FabrikWorker();
			$thumbDir = $w->parseMessageForPlaceHolder($thumbDir);
			$thumbDir = str_replace("\\", "\\\\", $thumbDir);

			$w = new FabrikWorker();
			$thumbDir = $w->parseMessageForPlaceHolder($thumbDir);

			$thumbDir .= $params->get('thumb_prefix');

			$str = "CONCAT('<img src=\"".COM_FABRIK_LIVESITE."',".
			"REPLACE(".
 			"REPLACE($val, '$ulDir', '".$thumbDir."')".	//replace the main image dir with thumb dir
			", '\\\', '/')".														//replace the backslashes with forward slashes
			", '\" alt=\"database join image\" />')";

		} else {
			$str = " REPLACE(CONCAT('<img src=\"".COM_FABRIK_LIVESITE. "' , $val, '\" alt=\"database join image\"/>'), '\\\', '/') ";
		}
		return $str;
	}

	/**
	 * trigger called when a row is deleted
	 *
	 */
	function onDeleteRows($groups )
	{
		//cant delete files from unpublished elements
		if (!$this->canUse()) {
			return;
		}
		$storage =& $this->getStorage();
		require_once(COM_FABRIK_FRONTEND.DS.'helpers'.DS.'uploader.php');
		$params =& $this->getParams();
		if ($params->get('upload_delete_image')) {
			jimport('joomla.filesystem.file');
			$elName = $this->getFullName(false, true, false);

			foreach ($groups as $rows) {
				foreach ($rows as $row) {
					if (array_key_exists($elName."_raw", $row)) {
						$files = explode(GROUPSPLITTER, $row->{$elName."_raw"});
						foreach ($files as $filename) {
							$this->deleteFile( trim($filename));
						}
					}
				}
			}
		}
	}

	function _return_bytes($val)
	{
		$val = trim($val);
		$last = strtolower(substr($val, -1));

		if($last == 'g')
		$val = $val*1024*1024*1024;
		if($last == 'm')
		$val = $val*1024*1024;
		if($last == 'k')
		$val = $val*1024;

		return $val;
	}

	/**
	 * get the max upload size allowed by the server.
	 * @return int kilobyte upload size
	 */

	function maxUpload()
	{
		$post_value 	= $this->_return_bytes( ini_get('post_max_size'));
		$upload_value 	= $this->_return_bytes( ini_get('upload_max_filesize'));
		$value = min( $post_value, $upload_value);
		$value = $value / 1024;
		return $value;
	}

	/**
	 * used to format the data when shown in the form's email
	 * @param string
	 * @return string formatted value
	 */

	protected function _getEmailValue($value, $data = array(), $repeatCounter = 0)
	{
		$params =& $this->getParams();
		if ($params->get('fu_show_image_in_email', false)) {
			$storage =& $this->getStorage();
			$render =& $this->loadElement($value);
			if ($params->get('fu_show_image')  != '0') {

				if ($value != '' && $storage->exists(COM_FABRIK_BASE.DS.$value)) {
					$render->render($this, $params, $value);
				}

			}
			if ($render->output == '' && $params->get('default_image') != '') {
				$render->output = "<img src=\"{$params->get('default_image')}\" alt=\"image\" />";
			}
			return $render->output;
		} else {
			return $value;
		}
	}

	function getROValue($data, $repeatCounter = 0)
	{
		$v = $this->getValue($data, $repeatCounter);
		$storage =& $this->getStorage();
		return $storage->pathToURL($v);
	}

	/* not really an AJAX call, we just use the pluginAjax method so we can run this
	 * method for handling scripted downloads.
	 */
	function ajax_download()
	{
		$app =& JFactory::getApplication();
		$url = JRequest::getVar('HTTP_REFERER', '', 'server');
		$lang = &JFactory::getLanguage();
		$lang->load('com_fabrik.plg.element.fabrikfileupload', JPATH_ADMINISTRATOR);
		$params =& $this->getParams();
		$aclEl = str_replace('.', '___', $params->get('fu_download_acl', ''));
		if (!empty($aclEl)) {
			$canDownload = FabrikWorker::getACL($data[$aclEl], 'filedownload');
			if (!$canDownload) {
				$app->enqueueMessage(JText::_('DOWNLOAD NO PERMISSION'));
				$app->redirect($url);
			}
		}
		if (!$this->canView()) {
			$app->enqueueMessage(JText::_('DOWNLOAD NO PERMISSION'));
			$app->redirect($url);
			exit;
		}
		$rowid = JRequest::getInt('rowid', 0);
		if (empty($rowid)) {
			$app->enqueueMessage(JText::_('DOWNLOAD NO SUCH FILE'));
			$app->redirect($url);
			exit;
		}
		$repeatcount = JRequest::getInt('repeatcount', 0);
		$tableModel = $this->getTableModel();
		$row = $tableModel->getRow($rowid, false);
		if (empty($row)) {
			$app->enqueueMessage(JText::_('DOWNLOAD NO SUCH FILE'));
			$app->redirect($url);
			exit;
		}
		//$element = $this->getElement();
		$storage =& $this->getStorage();
		$elName = $this->getFullName(true, true, false);
		$elName .= '_raw';
		$filepath = $row->$elName;
		$filepath = explode(GROUPSPLITTER,$filepath);
		$filepath = $filepath[$repeatcount];
		$filepath = $storage->getFullPath($filepath);
		$filecontent = $storage->read($filepath);
		if ($filecontent !== false) {
			/*
			// $$$ hugh - turn of E_DEPRECATED to avoid warnings about eregi() in getid3
			$current_level = error_reporting();
    		error_reporting($current_level & ~E_DEPRECATED);
    		
			require_once(COM_FABRIK_FRONTEND.DS.'libs'.DS.'getid3'.DS.'getid3'.DS.'getid3.php');
			require_once(COM_FABRIK_FRONTEND.DS.'libs'.DS.'getid3'.DS.'getid3'.DS.'getid3.lib.php');

			getid3_lib::IncludeDependency(COM_FABRIK_FRONTEND.DS.'libs'.DS.'getid3'.DS.'getid3'.DS.'extension.cache.mysql.php', __FILE__, true);
			$config =& JFactory::getConfig();
			$host =  $config->getValue('host');
			$database = $config->getValue('db');
			$username = $config->getValue('user');
			$password = $config->getValue('password');
			$getID3 = new getID3_cached_mysql($host, $database, $username, $password);
			// Analyze file and store returned data in $ThisFileInfo
			$thisFileInfo = $getID3->analyze($filepath);
			*/
			$thisFileInfo = $storage->getFileInfo($filepath);
			if ($thisFileInfo === false) {
				$app->enqueueMessage( JText::_('DOWNLOAD NO SUCH FILE'));
				$app->redirect($url);
				exit;
			}

			header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
			header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
			header("Cache-Control: no-store, no-cache, must-revalidate");
			header("Cache-Control: post-check=0, pre-check=0", false);
			header("Pragma: no-cache");
			header('Accept-Ranges: bytes');
			header('Content-Length: ' . $thisFileInfo['filesize']);
			header('Content-Type: ' . $thisFileInfo['mime_type']);
			header('Content-Disposition: attachment; filename=' . $thisFileInfo['filename']);

			// ... serve up the image ...
			echo $filecontent;

			$this->downloadEmail($row, $filepath);
			$this->downloadHit($rowid, $repeatcount);
			$this->downloadLog($filepath);
			// ... and we're done.
			exit();
		}
		else {
			$app->enqueueMessage( JText::_('DOWNLOAD NO SUCH FILE'));
			$app->redirect($url);
			exit;
		}
	}

	function downloadHit($rowid, $repeatCount = 0)
	{
		// $$$ hugh @TODO - make this work for repeats and/or joins!
		$params =& $this->getParams();
		if ($hit_counter = $params->get('fu_download_hit_counter','')) {
			JError::setErrorHandling(E_ALL, 'ignore');
			$tableModel =& $this->getTableModel();
			$pk = $tableModel->getTable()->db_primary_key;
			$fabrikDb   =& $tableModel->getDb();
			list($table_name,$element_name) = explode('.',$hit_counter);
			$sql = "UPDATE $table_name SET $element_name = COALESCE($element_name,0) + 1 WHERE $pk = '$rowid'";
			$fabrikDb->setQuery($sql);
			$fabrikDb->query();
		}
	}

	function downloadEmail(&$row, $filepath)
	{
		$params =& $this->getParams();
		$email_to = $params->get('fu_download_email', '');
		if (!empty($email_to)) {
			JError::setErrorHandling(E_ALL, 'ignore');
			jimport('joomla.mail.helper');
			$w = new FabrikWorker();
			$email_to = $w->parseMessageForPlaceholder($email_to, JArrayHelper::fromObject($row), false);
			$config =& JFactory::getConfig();
			$from = $config->getValue('mailfrom');
			$fromname = $config->getValue('fromname');
			$msg = JText::_(DOWNLOAD_EMAIL_MSG) . "<br />\n";
			$msg .= JText::_(FILENAME) . ': ' . $filepath . "<br />\n";
			$user =& JFactory::getUser();
			$msg .= JText::_(BY) . ': ' . ($user->get('id') == 0 ? 'guest' : $user->get('username')) . "<br />\n";
			$msg .= JText::_(FROM) . ': ' . JRequest::getVar('REMOTE_ADDR','','server') . "<br />\n";
			$msg .= JText::_(ON) . ': ' . date(DATE_RFC822) . "<br />\n";
			$subject = JText::_(DOWNLOAD_EMAIL_SUBJECT) . ' :: ' . $config->getValue('sitename');
			foreach (explode(',', $email_to) as $to) {
				$res = JUtility::sendMail($from, $fromname, $to, $subject, $msg, true);
			}
		}
	}

	/**
	 * log the download
	 * @since 2.0.5
	 * @param string $filepath
	 */

	function downloadLog(&$row, $filepath)
	{
		$params =& $this->getParams();
		if ((int)$params->get('fu_download_log', 0)) {
			JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_fabrik'.DS.'tables');
			$log =& JTable::getInstance('log', 'Table');
			$log->message_type = 'fabrik.fileupload.download';
			$user = JFactory::getUser();
			$msg = new stdClass();
			$msg->file = $filepath;
			$msg->userid = $user->get('id');
			$msg->username = $user->get('username');
			$msg->email = $user->get('email');
			$log->referring_url = JRequest::getVar('REMOTE_ADDR','','server');
			$log->message = FastJSON::encode($msg);
			$log->store();
		}
	}

}
?>