Your IP : 216.73.216.43


Current Path : /home/cbequiperp/www/administrator/components/com_flexicontent/models/
Upload File :
Current File : /home/cbequiperp/www/administrator/components/com_flexicontent/models/flexicontent.php

<?php
/**
 * @package         FLEXIcontent
 * @version         3.3
 *
 * @author          Emmanuel Danan, Georgios Papadakis, Yannick Berges, others, see contributor page
 * @link            https://flexicontent.org
 * @copyright       Copyright © 2018, FLEXIcontent team, All Rights Reserved
 * @license         http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('legacy.model.legacy');
jimport('joomla.access.rules');
use Joomla\String\StringHelper;

/**
 * FLEXIcontent Component Dashboard Model
 *
 */
class FlexicontentModelFlexicontent extends JModelLegacy
{
	/**
	 * Constructor
	 *
	 * @since 1.0
	 */
	public function __construct($config = array())
	{
		parent::__construct($config);
	}

	/**
	 * Method to get items in pending state, waiting for publication approval
	 *
	 * @access public
	 * @return array
	 */
	function getPending(&$total=null)
	{
		$user = JFactory::getUser();
		$permission = FlexicontentHelperPerm::getPerm();
		$allitems	= $permission->DisplayAllItems;

		$use_tmp = true;
		$query_select_ids = 'SELECT SQL_CALC_FOUND_ROWS c.id';
		$query_select_data = 'SELECT c.id, c.title, c.catid, c.created, cr.name as creator, c.created_by, c.modified, c.modified_by, mr.name as modifier, c.checked_out';

		$query_from_join = ''
				. ' FROM '.($use_tmp ? '#__flexicontent_items_tmp' : '#__content').' as c'
				. ' LEFT JOIN #__users AS cr ON cr.id = c.created_by'
				. ' LEFT JOIN #__users AS mr ON mr.id = c.modified_by'
				;
		$query_where_orderby_having = ''
				. ' WHERE state = -3'
				. (!FLEXI_J16GE ? ' AND c.sectionid = ' . (int)FLEXI_SECTION : '')
				. ($allitems ? '' : ' AND c.created_by = '.$user->id)
				. ' ORDER BY c.created DESC'
				;

		$query = $query_select_ids . $query_from_join . $query_where_orderby_having;
		$this->_db->SetQuery($query, 0, 5);
		$ids = $this->_db->loadColumn();

		// Get total
		$this->_db->setQuery("SELECT FOUND_ROWS()");
		$total = $this->_db->loadResult();

		$genstats = array();

		if (!empty($ids))
		{
			$query = $query_select_data . str_replace('#__flexicontent_items_tmp', '#__content', $query_from_join) . ' WHERE c.id IN ('.implode(',',$ids).')';
			$this->_db->SetQuery($query, 0, 5);
			$_data = $this->_db->loadObjectList('id');

			foreach($ids as $id) $genstats[] = $_data[$id];
			unset($_data);
		}
		return $genstats;
	}

	/**
	 * Method to get items revised, having unapproved version, waiting to be reviewed and approved
	 *
	 * @access public
	 * @return array
	 */
	function getRevised(&$total=null)
	{
		$user = JFactory::getUser();
		$permission = FlexicontentHelperPerm::getPerm();
		$allitems	= $permission->DisplayAllItems;

		$use_tmp = true;
		$query_select_ids = 'SELECT SQL_CALC_FOUND_ROWS c.id'.', c.version, MAX(fv.version_id)';
		$query_select_data = 'SELECT c.id, c.title, c.catid, c.created, cr.name as creator, c.created_by, c.modified, c.modified_by, mr.name as modifier, c.checked_out'
			.', c.version, MAX(fv.version_id)';

		$query_from_join = ''
				. ' FROM '.($use_tmp ? '#__flexicontent_items_tmp' : '#__content').' as c'
				. ' LEFT JOIN #__flexicontent_versions AS fv ON c.id=fv.item_id'
				. ' LEFT JOIN #__users AS cr ON cr.id = c.created_by'
				. ' LEFT JOIN #__users AS mr ON mr.id = c.modified_by'
				;
		$query_where_orderby_having = ''
				. ' WHERE c.state = -5 OR c.state = 1'
				. (!FLEXI_J16GE ? ' AND c.sectionid = ' . (int)FLEXI_SECTION : '')
				. ($allitems ? '' : ' AND c.created_by = '.$user->id)
				. ' GROUP BY fv.item_id '
				. ' HAVING c.version<>MAX(fv.version_id) '
				. ' ORDER BY c.modified DESC'
				;

		$query = $query_select_ids . $query_from_join . $query_where_orderby_having;
		$this->_db->SetQuery($query, 0, 5);
		$ids = $this->_db->loadColumn();

		// Get total
		$this->_db->setQuery("SELECT FOUND_ROWS()");
		$total = $this->_db->loadResult();

		$genstats = array();

		if (!empty($ids))
		{
			$query = $query_select_data . str_replace('#__flexicontent_items_tmp', '#__content', $query_from_join) . ' WHERE c.id IN ('.implode(',',$ids).')'
				.' GROUP BY fv.item_id ';
			$this->_db->SetQuery($query, 0, 5);
			$_data = $this->_db->loadObjectList('id');

			foreach($ids as $id) $genstats[] = $_data[$id];
			unset($_data);
		}
		return $genstats;
	}

	/**
	 * Method to get items in draft state, waiting to be written (and published)
	 *
	 * @access public
	 * @return array
	 */
	function getDraft(&$total=null)
	{
		$user = JFactory::getUser();
		$permission = FlexicontentHelperPerm::getPerm();
		$allitems	= $permission->DisplayAllItems;
		$requestApproval = @ $permission->RequestApproval;

		$use_tmp = true;
		$query_select_ids = 'SELECT SQL_CALC_FOUND_ROWS c.id';
		$query_select_data = 'SELECT c.id, c.title, c.catid, c.created, cr.name as creator, c.created_by, c.modified, c.modified_by, mr.name as modifier, c.checked_out';

		$query_from_join = ''
				. ' FROM '.($use_tmp ? '#__flexicontent_items_tmp' : '#__content').' as c'
				. ' LEFT JOIN #__users AS cr ON cr.id = c.created_by'
				. ' LEFT JOIN #__users AS mr ON mr.id = c.modified_by'
				;
		$query_where_orderby_having = ''
				. ' WHERE state = -4'
				. (!FLEXI_J16GE ? ' AND c.sectionid = ' . (int)FLEXI_SECTION : '')
				. (($allitems || $requestApproval) ? '' : ' AND c.created_by = '.$user->id)
				. ' ORDER BY c.created DESC'
				;

		$query = $query_select_ids . $query_from_join . $query_where_orderby_having;
		$this->_db->SetQuery($query, 0, 5);
		$ids = $this->_db->loadColumn();

		// Get total
		$this->_db->setQuery("SELECT FOUND_ROWS()");
		$total = $this->_db->loadResult();

		$genstats = array();

		if (!empty($ids))
		{
			$query = $query_select_data . str_replace('#__flexicontent_items_tmp', '#__content', $query_from_join) . ' WHERE c.id IN ('.implode(',',$ids).')';
			$this->_db->SetQuery($query, 0, 5);
			$_data = $this->_db->loadObjectList('id');

			foreach($ids as $id) $genstats[] = $_data[$id];
			unset($_data);
		}
		return $genstats;
	}

	/**
	 * Method to get items in progress state, (published but) waiting to be completed
	 *
	 * @access public
	 * @return array
	 */
	function getInprogress(&$total=null)
	{
		$user = JFactory::getUser();
		$permission = FlexicontentHelperPerm::getPerm();
		$allitems	= $permission->DisplayAllItems;

		$use_tmp = true;
		$query_select_ids = 'SELECT SQL_CALC_FOUND_ROWS c.id';
		$query_select_data = 'SELECT c.id, c.title, c.catid, c.created, cr.name as creator, c.created_by, c.modified, c.modified_by, mr.name as modifier, c.checked_out';

		$query_from_join = ''
				. ' FROM '.($use_tmp ? '#__flexicontent_items_tmp' : '#__content').' as c'
				. ' LEFT JOIN #__users AS cr ON cr.id = c.created_by'
				. ' LEFT JOIN #__users AS mr ON mr.id = c.modified_by'
				;
		$query_where_orderby_having = ''
				. ' WHERE c.state = -5'
				. (!FLEXI_J16GE ? ' AND c.sectionid = ' . (int)FLEXI_SECTION : '')
				. ($allitems ? '' : ' AND c.created_by = '.$user->id)
				. ' ORDER BY c.created DESC'
				;

		$query = $query_select_ids . $query_from_join . $query_where_orderby_having;
		$this->_db->SetQuery($query, 0, 5);
		$ids = $this->_db->loadColumn();

		// Get total
		$this->_db->setQuery("SELECT FOUND_ROWS()");
		$total = $this->_db->loadResult();

		$genstats = array();

		if (!empty($ids))
		{
			$query = $query_select_data . str_replace('#__flexicontent_items_tmp', '#__content', $query_from_join) . ' WHERE c.id IN ('.implode(',',$ids).')';
			$this->_db->SetQuery($query, 0, 5);
			$_data = $this->_db->loadObjectList('id');

			foreach($ids as $id) $genstats[] = $_data[$id];
			unset($_data);
		}
		return $genstats;
	}


	/**
	 * Method to check if default Flexi Menu Items exist
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistMenuItems()
	{
		static $return;
		if ($return !== null) return $return;
		$return = false;

		$app = JFactory::getApplication();

		// Get 'default_menu_itemid' parameter
		$params = JComponentHelper::getParams('com_flexicontent');
		$default_menu_itemid = $params->get('default_menu_itemid', false);

		// Load the default menu item
		$menus = $app->getMenu('site', array());
		$menu = $menus->getItem($default_menu_itemid);

		$public_acclevel = !FLEXI_J16GE ? 0 : 1;
		$prompt  = '<br>'.JText::_('FLEXI_DEFAULT_MENU_ITEM_PROMPT');

		// Check menu item exists
		$config_saved = (bool) $params->get('flexi_cat_extension');
		if ( !$menu ) {
			if ( $config_saved ) {
				$app->enqueueMessage( JText::_('FLEXI_DEFAULT_MENU_ITEM_MISSING_DISABLED').$prompt, 'notice' );
			}
			return $return = false;
		}
		// Check pointing to FLEXIcontent
		if ( @$menu->query['option']!='com_flexicontent' ) {
			$app->enqueueMessage( JText::_('FLEXI_DEFAULT_MENU_ITEM_ISNON_FLEXI').$prompt, 'notice' );
			return $return = false;
		}
		// Check public access level
		if ( $menu->access!=$public_acclevel ) {
			$app->enqueueMessage( JText::_('FLEXI_DEFAULT_MENU_ITEM_ISNON_PUBLIC').$prompt, 'notice' );
			return $return = false;
		}

		// Verify that language of menu item is not empty
		if ( FLEXI_J16GE && $menu->language=='' ) {
			$query 	=	"UPDATE #__menu SET `language`='*' WHERE id=". (int)$default_menu_itemid;
			$this->_db->setQuery($query);
			$result = $this->_db->execute();
		}

		// All checks passed
		return $return = true;
	}

	/**
	 * Method to check if there is at least one type created
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistType() {
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$query = 'SELECT COUNT( id )'
			. ' FROM #__flexicontent_types'
			;
		$this->_db->setQuery( $query );
		$count = $this->_db->loadResult();
		$return = $count > 0;

		return $return;
	}


	/**
	 * Method to check if there is at least the default fields in the FLEXIcontent fields TABLE
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistCoreFields()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$query = 'SELECT COUNT(id)'
			. ' FROM #__flexicontent_fields'
			. ' WHERE iscore = 1'
			;
		$this->_db->setQuery( $query );
		$count = $this->_db->loadResult();
		$return = $count > 13;

		return $return;
	}


	/**
	 * Method to check if there is at least the default fields in the FLEXIcontent fields TABLE
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistCpFields()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		//JFactory::getLanguage()->load('plg_flexicontent_fields_coreprops', JPATH_ADMINISTRATOR, 'en-GB', true);
		//JFactory::getLanguage()->load('plg_flexicontent_fields_coreprops', JPATH_ADMINISTRATOR, null, true);

		$p = 'FLEXI_COREPROPS_';
		$coreprop_names = array
		(
			// Single properties
			'id' => 'FLEXI_ID', 'alias' => 'FLEXI_ALIAS', 'category' => $p.'CATEGORY_MAIN', 'lang' => $p.'LANGUAGE', 'vstate' => $p.'PUBLISH_CHANGES',
			'disable_comments' => $p.'DISABLE_COMMENTS', 'notify_subscribers' => $p.'NOTIFY_SUBSCRIBERS', 'notify_owner' => $p.'NOTIFY_OWNER',
			'captcha' => $p.'CAPTCHA', 'layout_selection' => $p.'LAYOUT_SELECT',

			//Publishing
			'timezone_info' => $p.'TIMEZONE', 'created_by_alias' => $p.'CREATED_BY_ALIAS',
			'publish_up' => $p.'PUBLISH_UP', 'publish_down' => $p.'PUBLISH_DOWN',
			'access' => $p.'VIEW_ACCESS',

			// Attibute groups or other composite data
			'item_screen' => $p.'VERSION_INFOMATION', 'lang_assocs' => $p.'LANGUAGE_ASSOCS',
			'jimages' => $p.'JIMAGES', 'jurls' => $p.'JURLS',
			'metadata' => $p.'META', 'seoconf' => $p.'SEO',
			'display_params' => $p.'DISP_PARAMS', 'layout_params' => $p.'LAYOUT_PARAMS',
			'perms' => 'FLEXI_PERMISSIONS', 'versions' => 'FLEXI_VERSIONS',
		);

		$types_count = (int) $this->_db->setQuery('SELECT COUNT(id) FROM `#__flexicontent_types`')->loadResult();

		$query = 'SELECT f.name, COUNT(rel.type_id) as types_assigned'
			. ' FROM #__flexicontent_fields AS f '
			. ' LEFT JOIN #__flexicontent_fields_type_relations AS rel ON f.id = rel.field_id'
			. ' WHERE f.field_type = "coreprops" AND f.name LIKE "form_%" AND f.published = 1'
			. ' GROUP BY f.id'
			;
		$fields = $this->_db->setQuery( $query )->loadObjectList();

		/**
		 * Unset any $coreprop_names that have been found assigned to all types
		 */
		foreach ($fields as $i => $field)
		{
			$propname = str_replace('form_', '', $field->name);
			if ((int) $field->types_assigned === $types_count && isset($coreprop_names[$propname]))
			{
				unset($coreprop_names[$propname]);
			}
		}
		//echo $query . '<br><pre>'; print_r($fields); echo '</pre><br>' .count($coreprop_names) . '<br>'; exit;

		// All coreprop_names should have been eliminated
		$return = count($coreprop_names) ? false : true;
		return $return;
	}


	/**
	 * Method to check if there is at least the default flexicontent_fields PLUGINs
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistFieldsPlugins()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$query = 'SELECT COUNT(extension_id)'
			. ' FROM #__extensions'
			. ' WHERE `type`= '.$this->_db->Quote('plugin').' AND folder = ' . $this->_db->Quote('flexicontent_fields')
			;
		$this->_db->setQuery( $query );
		$count = $this->_db->loadResult();
		$return = $count > 13;

		return $return;
	}

	/**
	 * Method to check if the search plugin is installed
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistSearchPlugin()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$query = 'SELECT COUNT( extension_id )'
		. ' FROM #__extensions'
		. ' WHERE `type`='.$this->_db->Quote('plugin').' AND element = ' . $this->_db->Quote('flexisearch')
		;
		$this->_db->setQuery( $query );
		$return = $this->_db->loadResult() ? true : false;

		return $return;
	}

	/**
	 * Method to check if the system plugin is installed
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistSystemPlugin()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$query = 'SELECT COUNT( extension_id )'
		. ' FROM #__extensions'
		. ' WHERE `type`='.$this->_db->Quote('plugin').' AND element = ' . $this->_db->Quote('flexisystem')
		;
		$this->_db->setQuery( $query );
		$return = $this->_db->loadResult() ? true : false;

		return $return;
	}

	/**
	 * Method to check if all plugins are published
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getAllPluginsPublished()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		// Make sure basic CORE fields are published
		$q = 'UPDATE #__flexicontent_fields SET published=1 WHERE id > 0 AND id < 7';
		$this->_db->setQuery($q)->execute();

		$query 	= 'SELECT COUNT( extension_id )'
			. ' FROM #__extensions'
			. ' WHERE `type`=' . $this->_db->Quote('plugin')
			. ' AND (folder = ' . $this->_db->Quote('flexicontent_fields')
			. ' OR element = ' . $this->_db->Quote('flexisystem')
			. ' OR element = ' . $this->_db->Quote('flexiadvroute')
			. ' OR (folder = ' . $this->_db->Quote('osmap') . ' AND element = ' . $this->_db->Quote('com_flexicontent') . ')'
			//. ' OR element = ' . $this->_db->Quote('flexiadvsearch')
			//. ' OR element = ' . $this->_db->Quote('flexisearch')
			. ')'
			. ' AND enabled <> 1'
			;
		$this->_db->setQuery( $query );
		$return = $this->_db->loadResult() ? false : true;

		return $return;
	}

	/**
	 * Method to check if the language column exists
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistLanguageColumns()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$columns = $this->_db->getTableColumns('#__flexicontent_items_ext');
		$result_lang_col = array_key_exists('language', $columns) ? true : false;
		$result_tgrp_col = array_key_exists('lang_parent_id', $columns) ? true : false;

		$return = $result_lang_col && $result_tgrp_col;

		return $return;
	}



	/**
	 * Method to sync language between Joomla and FLEXIcontent tables
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since 1.5
	 */
	function syncItemsLang()
	{
		$db = JFactory::getDbo();

		// This should be match items that come from J1.5 upgrade only
		// and copy the J1.5 language from items_ext table into the content table
		$query 	= 'UPDATE #__content AS i'
					.' LEFT JOIN #__flexicontent_items_ext as ie ON i.id=ie.item_id'
				. ' SET i.language = ie.language'
				. ' WHERE ie.language<>"" AND ('
				. '  i.language="" OR (i.language="*" AND i.language<>ie.language)'
				. ' )'
				;
		$db->setQuery($query);
		$result1 = $db->execute();

		// Sync language of items_ext table using the language from Joomla content table
		$query 	= 'UPDATE #__flexicontent_items_ext AS ie'
					.' LEFT JOIN #__content as i ON i.id=ie.item_id'
				. ' SET ie.language = i.language'
				. ' WHERE i.language<>ie.language'
				;
		$db->setQuery($query);
		$result1 = $db->execute();
	}


	/**
	 * Method to set the default site language the items with no language
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since 1.5
	 */
	function setItemsDefaultLang($lang)
	{
		$db = JFactory::getDbo();

		// Set default language for items that do not have their language set
		$query 	= 'UPDATE #__flexicontent_items_ext'
				. ' SET language = ' . $db->Quote($lang)
				. ' WHERE language = ""'
				;
		$db->setQuery($query);
		$result1 = $db->execute();

		$query 	= 'UPDATE #__flexicontent_items_tmp'
				. ' SET language = ' . $db->Quote($lang)
				. ' WHERE language = ""'
				;
		$db->setQuery($query);
		$result1a = $db->execute();

		$query 	= 'UPDATE #__content'
				. ' SET language = ' . $db->Quote($lang)
				. ' WHERE language = ""'
				;
		$db->setQuery($query);
		$result2 = $db->execute();

		return $result1 && $result1a && $result2;
	}


	/**
	 * Method to get if main category of items exists in both category table and in flexicontent category-items relation table
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since 1.5
	 */
	function getItemsNoCat()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$query = "SELECT rel.itemid"
			." FROM #__flexicontent_cats_item_relations AS rel"
			." LEFT JOIN #__content AS i ON i.id = rel.itemid"
			." WHERE i.id IS NULL"
			." LIMIT 1";
		$this->_db->setQuery($query);
		$item_id = $this->_db->loadResult();
		if ($item_id) return $return = true;

		$query = "SELECT i.id"
			." FROM #__content AS i"
			." JOIN #__flexicontent_items_ext as ie ON i.id=ie.item_id "
			." LEFT JOIN #__flexicontent_cats_item_relations as rel ON rel.catid=i.catid AND i.id=rel.itemid "
			." WHERE rel.catid IS NULL"
			." LIMIT 1";
		$this->_db->setQuery($query);
		$item_id = $this->_db->loadResult();
		if ($item_id) return $return = true;

		return $return;
	}


	// Check and if needed install Joomla template overrides into current Joomla template
	function install_template_overrides()
	{
		flexicontent_html::install_template_overrides(true);
	}


	// Check and if needed install 3rd party plugins that do not use Joomla plugin system
	function install_3rdParty_plugins()
	{
		jimport('joomla.filesystem.path' );
		jimport('joomla.filesystem.folder');
		jimport('joomla.filesystem.file');

		// ****************************
		// Handle jcomments integration
		// ****************************

		$destpath = JPATH_SITE.DS.'components'.DS.'com_jcomments'.DS.'plugins';

		// Check if JComments installed and active
		if (JFolder::exists($destpath) && JPluginHelper::isEnabled('system', 'jcomments'))
		{
			$dest   = $destpath.DS.'com_flexicontent.plugin.php';
			$source = JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'librairies'.DS.'jcomments'.DS.'com_flexicontent.plugin.php';
			$plg_exists = JFile::exists($dest);

			if (!$plg_exists || filemtime(__FILE__) > filemtime($dest))
			{
				if (!JFolder::exists($destpath)) {
					if (!JFolder::create($destpath)) {
						JFactory::getApplication()->enqueueMessage(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_CREATE_DIRECTORY', 'jComments plugin for FLEXIcontent', $destpath), 'warning');
					}
				}
				if (!JFile::copy($source, $dest)) {
					JFactory::getApplication()->enqueueMessage(JText::_('FLEXI_FAILED_TO') . JText::_(!$plg_exists ? 'JLIB_INSTALLER_INSTALL' : 'JLIB_INSTALLER_UPDATE') . ' jComments plugin for FLEXIcontent', 'warning');
				} else {
					JFactory::getApplication()->enqueueMessage('<span class="badge">' . JText::_(!$plg_exists ? 'FLEXI_INSTALLED' : 'FLEXI_UPDATED') . '</span> jComments plugin for FLEXIcontent', 'message');
				}
			}
		}


		// *************************
		// Handle falang integration
		// *************************

		$destpath = JPATH_ADMINISTRATOR.DS.'components'.DS.'com_falang'.DS.'contentelements';

		if (JFolder::exists($destpath) && JPluginHelper::isEnabled('system', 'falangdriver'))
		{
			$sourcepath = JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'librairies'.DS.'joomfish';
			$files = glob($sourcepath."/*.xml");
			$elements_count[0] = $elements_count[1] = 0;
			foreach ($files as $file)
			{
				$file_dest = $destpath.DS.basename($file);
				$plg_exists = JFile::exists($file_dest);
				if (!$plg_exists || filemtime($file) > filemtime($file_dest))
				{
					JFile::copy($file, $file_dest);
					$elements_count[$plg_exists ? 1 : 0]++;
				}
			}
			if ($elements_count[0]) JFactory::getApplication()->enqueueMessage('<span class="badge">' . JText::_('FLEXI_INSTALLED') . '</span> ' . $elements_count[0] . ' Falang elements for FLEXIcontent', 'message');
			if ($elements_count[1]) JFactory::getApplication()->enqueueMessage('<span class="badge">' . JText::_('FLEXI_UPDATED')   . '</span> ' . $elements_count[1] . ' Falang elements for FLEXIcontent', 'message');
		}


		// **********************
		// Handle JCE integration
		// **********************

		$pathDestName   = JPath::clean(JPATH_ROOT.'/components/com_jce/editor/extensions/links');
		$pathSourceName = JPath::clean(JPATH_ROOT.'/components/com_flexicontent/librairies/JCE/links');

		// Check if JCE installed and active
		if (!JFolder::exists($pathDestName) || !JPluginHelper::isEnabled('editors', 'jce'))
		{
			return true; // Nothing to do, JCE not installed
		}

		$plg_exists = JFile::exists($pathDestName.'/flexicontentlinks.php');
		if ($plg_exists && filemtime(__FILE__) < filemtime($pathDestName.'/flexicontentlinks.php'))
		{
			return true; // Nothing to do, already up-to-date
		}

		// 2. Copy all files
		$files = glob($pathSourceName."/*.*");
		foreach ($files as $file)
		{
			$file_dest = $pathDestName .DS. basename($file);
			JFile::copy($file, $file_dest);
		}

		// Check DESTINATION folder
		$pathSourceName = JPath::clean($pathSourceName.'/flexicontentlinks');
		$pathDestName   = JPath::clean($pathDestName.'/flexicontentlinks');
		if ( !JFolder::exists($pathDestName) && !JFolder::create($pathDestName) )
		{
			JFactory::getApplication()->enqueueMessage(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_CREATE_DIRECTORY', 'JCE Links plugin for FLEXIcontent', $pathDestName), 'warning');
		}

		// Copy all files
		$files = glob($pathSourceName."/*.*");
		foreach ($files as $file)
		{
			$file_dest = $pathDestName .DS. basename($file);
			JFile::copy($file, $file_dest);
		}

		$folders = array('css', 'images');
		foreach ($folders as $folder)
		{
			// Check DESTINATION folder
			$sub_pathSourceName = JPath::clean($pathSourceName.'/'.$folder);
			$sub_pathDestName   = JPath::clean($pathDestName.'/'.$folder);
			if ( !JFolder::exists($sub_pathDestName) && !JFolder::create($sub_pathDestName) )
			{
				JFactory::getApplication()->enqueueMessage(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_CREATE_DIRECTORY', 'JCE Links plugin for FLEXIcontent', $sub_pathDestName), 'warning');
			}

			// Copy all files
			$files = glob($sub_pathSourceName."/*.*");
			foreach ($files as $file)
			{
				$file_dest = $sub_pathDestName .DS. basename($file);
				JFile::copy($file, $file_dest);
			}
		}

		JFactory::getApplication()->enqueueMessage('<span class="badge">' . JText::_(!$plg_exists ? 'FLEXI_INSTALLED' : 'FLEXI_UPDATED') . '</span> JCE Links plugin for FLEXIcontent', 'message');
	}


	/**
	 * Method to fix collations
	 *
	 */
	function checkCollations()
	{
		$db = $this->_db;
		$session = JFactory::getSession();
		$app = JFactory::getApplication();

		$dbprefix = $app->getCfg('dbprefix');
		$dbname   = $app->getCfg('db');

		$jversion = new JVersion;

		$collation_version = $session->get('flexicontent.collation_version');
		if ($collation_version == $jversion->getShortVersion())  return;

		$docheck = version_compare( $jversion->getShortVersion(), '3.4.99', '>' );
		if ($docheck)
		{
			$full_tbl_name = $dbprefix . 'content';
			$query = "SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '".$dbname."' AND TABLE_NAME = '".$full_tbl_name."' AND COLUMN_NAME IN ('language')";
			$db->setQuery($query);
			$col_data = $db->loadAssocList('COLUMN_NAME');
			$jchset = $col_data['language']['CHARACTER_SET_NAME'];   // ? 'utf8mb4'
			$jcname = $col_data['language']['COLLATION_NAME'];   // ? 'utf8mb4_unicode_ci'

			// Data Types of columns
			$tbl_names_arr = array(
				'flexicontent_items_ext'=>array(
					'language' => "VARCHAR(7) CHARACTER SET ".$jchset." COLLATE ".$jcname." NOT NULL DEFAULT '*'"
				),
				'flexicontent_items_tmp'=>array(
					'title' => "VARCHAR(255) CHARACTER SET ".$jchset." COLLATE ".$jcname." NOT NULL",
					'alias' => "VARCHAR(400) CHARACTER SET ".$jchset." COLLATE ".$jcname." NOT NULL",
					'language' => "VARCHAR(7) CHARACTER SET ".$jchset." COLLATE ".$jcname." NOT NULL DEFAULT '*'"
				),
				'flexicontent_fields'=>array(
					'field_type' => "VARCHAR(50) CHARACTER SET ".$jchset." COLLATE ".$jcname." NOT NULL default ''"
				)
			);

			foreach ($tbl_names_arr as $tbl_name => $tbl_cols)
			{
				$full_tbl_name = $dbprefix . $tbl_name;
				$query = "SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '".$dbname."' AND TABLE_NAME = '".$full_tbl_name."' AND COLUMN_NAME IN ('".implode("','", array_keys($tbl_cols))."')";
				$db->setQuery($query);
				$col_data = $db->loadAssocList('COLUMN_NAME');
				foreach($col_data as $col => $data) {
					if ($data['CHARACTER_SET_NAME'] <> $jchset || $data['COLLATION_NAME'] <> $jcname) {
						$query = "ALTER TABLE ".$full_tbl_name." MODIFY `".$col."` ". $tbl_cols[$col];
						$db->setQuery($query);
						$col_data = $db->execute();
					}
				}
			}
		}

		$session->set('flexicontent.collation_version', $jversion->getShortVersion());
	}


	/**
	 * Method to get if language of items is initialized properly
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since 1.5
	 */
	function getItemsBadLang()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		$cparams = JComponentHelper::getParams( 'com_flexicontent' );
		//$useAssocs = flexicontent_db::useAssociations();

		// Clean orphan assosiations
		$query = 'DELETE e.* FROM #__associations AS e WHERE e.context = "com_content.item" AND e.id IN (SELECT tmp.id FROM (' .
			'SELECT a.id AS id FROM #__associations AS a ' .
			'LEFT JOIN #__content AS c ON a.id = c.id ' .
			'WHERE a.context = "com_content.item" AND c.id IS NULL' .
		') AS tmp )';
		try { $this->_db->setQuery($query)->execute(); }
		catch (Exception $e) {
			echo '<div class="fcclear"></div><div class="alert alert-warning">' . $e->getMessage() . '<br>' . $query . '</div>';
		}

		// Check for emtpy language in flexicontent EXT table
		$query = "SELECT COUNT(*)"
			." FROM #__flexicontent_items_ext as ie"
			." WHERE ie.language='' "
			." LIMIT 1";
		$this->_db->setQuery($query);
		$cnt = $this->_db->loadResult();
		if ($cnt) return $return = true;

		$query = "SELECT COUNT(*)"  // Check for emtpy language in Joomla content EXT table
			." FROM #__content as i"
			." WHERE i.language=''"
			." LIMIT 1";
		$this->_db->setQuery($query);
		$cnt = $this->_db->loadResult();
		if ($cnt) return $return = true;

		$query = "SELECT COUNT(*)"
			." FROM #__content as i"
			." JOIN #__flexicontent_items_ext as ie ON i.id=ie.item_id "
			." WHERE i.language<>ie.language"
			." LIMIT 1";
		$this->_db->setQuery($query);
		$cnt = $this->_db->loadResult();
		if ($cnt) return $return = true;

		// Check for not yet transfered language associations
		$query = "SELECT COUNT(*)"
			." FROM #__flexicontent_items_ext as ie"
			." WHERE ie.lang_parent_id <> 0"
			." LIMIT 1";
		$this->_db->setQuery($query);
		$cnt = $this->_db->loadResult();
		if ($cnt) return $return = true;

		return $return;
	}


	/**
	 * Method to get if temporary item data table is up-to-date
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since 1.5
	 */
	function getItemCountingDataOK()
	{
		static $return;
		if ($return !== NULL) return $return;
		$return = false;

		// Clear orphan data from the EXTENDED data tables
		$query = "DELETE d.* FROM #__flexicontent_items_tmp AS d"
			." LEFT JOIN #__content AS c ON d.id = c.id"
			." WHERE c.id IS NULL";
		$this->_db->setQuery($query);
		$this->_db->execute();

		// Clear orphan data from the TMP data tables
		$query = "DELETE d.* FROM #__flexicontent_items_ext AS d"
			." LEFT JOIN #__content AS c ON d.item_id = c.id"
			." WHERE c.id IS NULL";
		$this->_db->setQuery($query);
		$this->_db->execute();

		// Find columns cached
		$cache_tbl = "#__flexicontent_items_tmp";
		$tbls = array($cache_tbl);
		foreach ($tbls as $tbl) $tbl_fields[$tbl] = $this->_db->getTableColumns($tbl);

		// Get the column names
		$tbl_fields = array_keys($tbl_fields[$cache_tbl]);

		$subquery = " SELECT COUNT(*) "
			." FROM `#__flexicontent_items_ext` AS ie"
			." JOIN `#__content` AS i ON ie.item_id=i.id"
			." WHERE 1 ".(!FLEXI_J16GE ? ' AND i.sectionid = ' . (int)FLEXI_SECTION : '')
			;
		$query = "SELECT COUNT(*) AS total1, (".$subquery.") AS total2"
			." FROM `#__content` AS i"
			." JOIN `#__flexicontent_items_tmp` AS ca ON i.id=ca.id"
			." JOIN `#__flexicontent_items_ext` AS ie ON ie.item_id=i.id"
			." WHERE 1 " . (!FLEXI_J16GE ? ' AND i.sectionid = ' . (int)FLEXI_SECTION : '')
			;
		foreach ($tbl_fields as $col_name) {
			if ($col_name == "id" || $col_name == "hits")
				continue;
			else if ( $col_name=='type_id' || $col_name=='lang_parent_id')
				$query .= " AND ie.`".$col_name."`=ca.`".$col_name."`";
			else if ( $col_name=='publish_up' || $col_name=='publish_down')
				$query .= " AND (i.`".$col_name."`=ca.`".$col_name."` OR (i.`".$col_name."` IS NULL AND ca.`".$col_name."` IS NULL))";
			else
				$query .= " AND i.`".$col_name."`=ca.`".$col_name."`";
		}

		// Check missing in item counting table
		$this->_db->setQuery($query);
		$res = $this->_db->loadObject();

		$return = $res->total1 == $res->total2;
		return $return;
	}


	/**
	 * Method to check if the versions table is created
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistVersionsTable()
	{
		static $return;
		if ($return === NULL) {
			$query = 'SHOW TABLES LIKE ' . $this->_db->Quote('%flexicontent_versions');
			$this->_db->setQuery($query);
			$return = $this->_db->loadResult() ? true : false;
		}
		return $return;
	}

	/**
	 * Method to check if the versions table is created
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistAuthorsTable()
	{
		static $return;
		if ($return === NULL) {
			$query = 'SHOW TABLES LIKE ' . $this->_db->Quote('%flexicontent_authors_ext');
			$this->_db->setQuery($query);
			$return = $this->_db->loadResult() ? true : false;
		}
		return $return;
	}


	/**
	 * Method to check if the versions table is created
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistDBindexes($check_only=true, & $update_queries = array())
	{
		static $missing;
		if ($missing !== NULL) return $check_only ? empty($missing) : $missing;

		jimport('joomla.filesystem.file');
		$app = JFactory::getApplication();
		$dbprefix = $app->getCfg('dbprefix');
		$dbname   = $app->getCfg('db');

		$tblname_indexnames = array(
			'flexicontent_tags'=>array('name'=>0, 'alias'=>0, 'published'=>0, 'jtag_id'=>0),
			'flexicontent_types'=>array('name'=>0, 'alias'=>0, 'published'=>0, 'access'=>0),
			'flexicontent_items_ext'=>array('type_id'=>0, 'is_uptodate'=>0, 'lang_parent_id'=>0),
			'flexicontent_items_tmp'=>array(
				'title'=>array(
					'custom_add'=>'ADD FULLTEXT KEY',
					'cols'=>array('title'=>0)
				),
				'alias'=>64, 'state'=>0, 'catid'=>0,
				'created_by'=>0, 'access'=>0, 'featured'=>0,
				'language'=>0, 'type_id'=>0, 'lang_parent_id'=>0
			),

			'flexicontent_reviews'=>array(
				'title'=>array(
					'custom_add'=>'ADD FULLTEXT KEY',
					'cols'=>array('title'=>0)
				),
				'text'=>array(
					'custom_add'=>'ADD FULLTEXT KEY',
					'cols'=>array('text'=>0)
				),
				'state'=>0, 'approved'=>0, 'verified'=>0,
				'useful_yes'=>0, 'useful_no'=>0,
			),

			'flexicontent_fields_item_relations'=>array(
				'value'=>32,
				'value_integer'=>array('update'=>'CAST(value AS SIGNED)'),
				'value_decimal'=>array('update'=>'CAST(value AS DECIMAL(65,15))'),
				'value_datetime'=>array('update'=>'CAST(value AS DATETIME)'),
				//'reference_1'=>0,
				'PRIMARY'=>array(
					'custom_drop'=>'DROP PRIMARY KEY',
					'custom_add'=>'ADD PRIMARY KEY',
					'cols'=>array('field_id'=>0, 'item_id'=>0, 'valueorder'=>0, 'suborder'=>0)
				)
			),
			'flexicontent_mediadatas'=>array(
				'bits_per_sample'=>0,
			),
			'flexicontent_items_versions'=>array(
				'value'=>32,
				'PRIMARY'=>array(
					'custom_drop'=>'DROP PRIMARY KEY',
					'custom_add'=>'ADD PRIMARY KEY',
					'cols'=>array('version'=>0, 'field_id'=>0, 'item_id'=>0, 'valueorder'=>0, 'suborder'=>0)
				)
			),
			'flexicontent_download_history'=>array('user_id'=>0, 'file_id'=>0),
			'flexicontent_download_coupons'=>array('user_id'=>0, 'file_id'=>0, 'token'=>0, 'expire_on'=>0),
			'flexicontent_templates'=>array(
				'configuration'=>array(
					'cols'=>array('template'=>0, 'cfgname'=>0, 'layout'=>0, 'position'=>0)
				)
			),
			'flexicontent_favourites'=>array(
				'PRIMARY'=>array(
					'custom_drop'=>'DROP PRIMARY KEY',
					'custom_add'=>'ADD PRIMARY KEY',
					'cols'=>array('id'=>0,'itemid'=>0, 'userid'=>0, 'type'=>0)
				),
				'unique_rec'=>array(
					'custom_drop'=>'DROP INDEX `unique_rec`',
					//'cols'=>array()  // Empty cols, we only want to drop the index if it exists
				)
			),
			'flexicontent_items_extravote'=>array(
				'PRIMARY'=>array(
					'custom_add'=>'ADD PRIMARY KEY',
					'cols'=>array('content_id'=>0, 'field_id'=>0)
				)
			)
		);

		$missing = array();
		$all_started = true;
		foreach($tblname_indexnames as $tblname => $indexnames)
		{
			$indexing_started = false;
			$file = JPATH_SITE.DS.'tmp'.DS.'tbl_indexes_'.$tblname;
			if ( JFile::exists($file) )
			{
				$indexing_start_secs = (int) file_get_contents($file);
				$indexing_started = $indexing_start_secs + 3600 > time();
				if (!$indexing_started) {
					JFile::delete($file);
				}
			}

			$_update_clauses = array();
			foreach($indexnames as $indexname => $iconf)
			{
				$query = "SELECT 1"
					. " FROM INFORMATION_SCHEMA.STATISTICS"
					. " WHERE TABLE_SCHEMA = '".$dbname."' AND TABLE_NAME = '".$dbprefix.$tblname."' AND index_name='".$indexname."'"
					. (is_array($iconf) && !empty($iconf['cols'])
						? " AND COLUMN_NAME IN ('" . implode("','", array_keys($iconf['cols'])) . "')"
						: "")
					. " GROUP BY TABLE_NAME"
					. (is_array($iconf) && !empty($iconf['cols'])
						? " HAVING COUNT(TABLE_NAME) = ".count($iconf['cols'])
						: "")
					;
				//if (is_array($iconf) && !empty($iconf['cols'])) echo $query ."<br/>";

				$this->_db->setQuery($query);
				$exists = $this->_db->loadResult();
				$exists = is_array($iconf) && !empty($iconf['custom_drop']) && empty($iconf['cols']) ? !$exists : $exists;   // If 'custom_drop' exists but we have zero 'cols' it means we want to drop the index

				if ($indexing_started)
				{
					if ($exists) {
						JFile::delete($file);
						continue;
					}
					else $missing[$tblname]['__indexing_started__'] = 1;
				}

				else if (!$exists)
				{
					$all_started = false;

					// Check for case that index is a column name needed an UPDATE query
					if ( is_array($iconf) && !empty($iconf['update']))
					{
						$colname = $indexname;
						$_update_clauses[] = $colname . ' = ' . $iconf['update'];
						unset($iconf['update']);
						if (empty($iconf)) $iconf = 0;
					}

					$missing[$tblname][$indexname] = $iconf;
				}
			}

			if (count($_update_clauses))
			{
				$update_queries[$tblname] = 'UPDATE #__' . $tblname . ' SET ' . implode(' , ', $_update_clauses);
			}
		}

		// Indexing for all tables has started, clear the 'missing' array ... so that post-installation task will not appear
		if ($all_started)
		{
			$missing = array();
		}

		return $check_only
			? empty($missing)
			: $missing;
	}


	/**
	 * Method to check if the system plugin is installed
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistVersionsPopulated() {
		static $return;
		if ($return === NULL) {
			$query 	= 'SELECT COUNT( version )'
					. ' FROM #__flexicontent_items_versions'
					;
			$this->_db->setQuery( $query );
			if(!$this->_db->loadResult()) {
				$return = true;
			} else {
				$query 	= 'SELECT COUNT( id )'
						. ' FROM #__flexicontent_versions'
						;
				$this->_db->setQuery( $query );
				$return = $this->_db->loadResult() ? true : false;
			}
		}
		return $return;
	}

	/**
	 * Method to check if the permissions of Phpthumb cache folder
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getCacheThumbPerms()
	{
		static $return;
		if ($return!==null) return $return;

		jimport('joomla.filesystem.file');
		jimport('joomla.filesystem.folder');
		jimport('joomla.filesystem.path');

		$conf_override_file = JPath::clean(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'librairies'.DS.'phpthumb'.DS.'phpThumb.config_OVERRIDE.php');

		// CHECK phpThumb configuration override file exists and create it, if it does not exist
		if ( !JFile::exists($conf_override_file) )
		{
			$file_contents =
				'<?php'."\n".
				'// THIS FILES IS NOT OVERWRITTEN BY FLEXICONTENT'."\n".
				'// PLEASE ADD YOUR CUSTOM CONFIGURATION STRINGS HERE'."\n".
				''."\n".
				'// * DocumentRoot configuration'."\n".
				'// phpThumb() depends on $_SERVER[\'DOCUMENT_ROOT\'] to resolve path/filenames. This value is usually correct,'."\n".
				'// but has been known to be broken on some servers. This value allows you to override the default value.'."\n".
				'// Do not modify from the auto-detect default value unless you are having problems.'."\n".
				''."\n".
				'// $PHPTHUMB_CONFIG[\'document_root\'] =  ...;'."\n";

			// write .htaccess file
			$fh = @ fopen($conf_override_file, 'w');
			if (!$fh) {
				JFactory::getApplication()->enqueueMessage( 'Cannot create/write file: '.$conf_override_file, 'notice' );
			} else {
				fwrite($fh, $file_contents);
				fclose($fh);
			}
		}


		$phpthumbcache 	= JPath::clean(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'librairies'.DS.'phpthumb'.DS.'cache');

		// CHECK phpThumb cache exists and create the folder
		if ( !JFolder::exists($phpthumbcache) && !JFolder::create($phpthumbcache) )
		{
			JError::raiseWarning(100, 'Error: Unable to create phpThumb folder: '. $phpthumbcache .' image thumbnail will not work properly' );
			$return = true;  // Cancel task !! to allow user to continue
			return;
		}

		// CHECK phpThumb cache permissions
		$perms = JPath::getPermissions($phpthumbcache);
		$return = preg_match('/rwx....../i', $perms) ? true : false;  //'/rwxr.xr.x/i'
		if ( $return && preg_match('/....w..w./i', $perms) )
		{
			JPath::setPermissions($phpthumbcache, '0600', '0700');
		}

		// If permissions not good check if we can change them
		if ( !$return && !JPath::canChmod($phpthumbcache) )
		{
			JError::raiseWarning(100, 'Error: Unable to change phpThumb folder permissions: '. $phpthumbcache .' there maybe a wrong owner of the folder. Correct permissions are important for proper thumbnails and for -security-' );
			$return = true;  // Cancel task !! to allow user to continue
			return;
		}

		return $return;
	}

	/**
	 * TODO IF/WHEN THIS LIST GROWS: Move it to an optional "Cleanup task" or use both session and joomla caching with long-expire to recheck it
	 *
	 * Method to check if the files from beta3 still exist in the category and item view
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getDeprecatedFiles(&$deprecated = null, $done = false)
	{
		// Store JPATH_BASE variable (needed in case of hard linking to flexicontent files outside of Joomla folder)
		if (JPATH_BASE != realpath(__DIR__.'/../..') || !file_exists(__DIR__.'/tasks/defines.php') || filemtime(__FILE__) >= filemtime(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'tasks'.DS.'defines.php'))
		{
			file_put_contents(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'tasks'.DS.'defines.php', '<?php'."\n".'define(\'JPATH_BASE\', \''.JPATH_SITE.'\');'."\n");
		}
		if (JPATH_BASE != realpath(__DIR__.'/..') || !file_exists(__DIR__.'/tasks/defines.php') || filemtime(__FILE__) >= filemtime(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_flexicontent'.DS.'tasks'.DS.'defines.php'))
		{
			file_put_contents(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_flexicontent'.DS.'tasks'.DS.'defines.php', '<?php'."\n".'define(\'JPATH_BASE\', \''.JPATH_ADMINISTRATOR.'\');'."\n");
		}

		$deprecated = array();
		static $finished;

		if ($finished===true)
		{
			return $finished;
		}

		$finished = false;

		jimport('joomla.filesystem.file');
		jimport('joomla.filesystem.folder');

		$deprecated['files'] = array();
		$deprecated['folders'] = array();

		$done_file = JPath::clean(JPATH_ADMINISTRATOR . '/components/com_flexicontent/helpers/deprecated_done');
		$depr_file = JPath::clean(JPATH_ADMINISTRATOR . '/components/com_flexicontent/helpers/deprecated_list.php');

		// If file / folder removal already done then stop further steps
		if (JFile::exists($done_file) && (filemtime($done_file) > filemtime($depr_file)))
		{
			$finished = true;
			return $finished;
		}

		// Mark file / folder removal as finished and stop further steps
		if ($done)
		{
			touch ($done_file);
			$finished = true;
			return $finished;
		}

		// Load list of depreacted files and folders
		include($depr_file);

		foreach ($files as $file)
		{
			if (JFile::exists($file))
			{
				$deprecated['files'][] = $file;
			}
		}

		foreach ($folders as $folder)
		{
			if (JFolder::exists($folder))
			{
				$deprecated['folders'][] = $folder;
			}
		}

		// Calculate if finished
		$deprecated_count = count($deprecated['files']) + count($deprecated['folders']);
		$finished = $deprecated_count ? false : true;

		// Mark file / folder removal as finished if zero files and folders need to be removed
		if ($finished)
		{
			touch ($done_file);
		}

		return $finished;
	}


	/**
	 * Method to check if the field positions were converted
	 * and if not, convert them
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function convertOldFieldsPositions()
	{
		static $return;
		if ($return!==null) return $return;
		$return = true;  // only call once

		$query 	= "SELECT name, positions"
				. " FROM #__flexicontent_fields"
				. " WHERE positions <> ''"
				;
		$this->_db->setQuery( $query );
		$fields = $this->_db->loadObjectList();

		if (empty($fields)) return $return;

		// create a temporary table to store the positions
		$this->_db->setQuery( "DROP TABLE IF EXISTS #__flexicontent_positions_tmp" );
		$this->_db->execute();
		$query = "
				CREATE TABLE #__flexicontent_positions_tmp (
				  `field` varchar(100) NOT NULL default '',
				  `view` varchar(30) NOT NULL default '',
				  `folder` varchar(100) NOT NULL default '',
				  `position` varchar(255) NOT NULL default ''
				) ENGINE=MyISAM DEFAULT CHARSET=utf8
				";
		$this->_db->setQuery( $query );
		$this->_db->execute();

		foreach ($fields as $field) {
			$field->positions = explode("\n", $field->positions);
			foreach ($field->positions as $pos) {
				$pos = explode('.', $pos);
				$query = 'INSERT INTO #__flexicontent_positions_tmp (`field`, `view`, `folder`, `position`) VALUES(' . $this->_db->Quote($field->name) . ',' . $this->_db->Quote($pos[1]) . ',' . $this->_db->Quote($pos[2]) . ',' . $this->_db->Quote($pos[0]) . ')';
				$this->_db->setQuery($query);
				$this->_db->execute();
			}
		}

		$tmpls   = flexicontent_tmpl::getTemplates();
		$folders = flexicontent_tmpl::getThemes();
		$views   = array('items', 'category');

		foreach ($folders as $folder)
		{
			foreach ($views as $view)
			{
				$groups = @ $tmpls->{$view}->{$folder}->positions;
				if ($groups) {
					foreach ($groups as $group) {
						$query 	= 'SELECT field'
								. ' FROM #__flexicontent_positions_tmp'
								. ' WHERE view = ' . $this->_db->Quote($view)
								. ' AND folder = ' . $this->_db->Quote($folder)
								. ' AND position = ' . $this->_db->Quote($group)
								;
						$this->_db->setQuery( $query );
						$fieldstopos = $this->_db->loadColumn();

						if ($fieldstopos)
						{
							$field = implode(',', $fieldstopos);

							$query = 'INSERT INTO #__flexicontent_templates (`template`, `layout`, `position`, `fields`) VALUES(' . $this->_db->Quote($folder) . ',' . $this->_db->Quote($view) . ',' . $this->_db->Quote($group) . ',' . $this->_db->Quote($field) . ')';
							$this->_db->setQuery($query);

							// By catching SQL error (e.g. layout configuration of template already exists),
							// we will allow execution to continue, thus clearing "positions" column in fields table
							try { $this->_db->execute(); } catch (Exception $e) { echo $e->getMessage(); }
						}
					}
				}
			}
		}

		// delete the temporary table
		$query = 'DROP TABLE #__flexicontent_positions_tmp';
		$this->_db->setQuery( $query );
		$this->_db->execute();

		// delete the old positions
		$query 	= "UPDATE #__flexicontent_fields SET positions = ''";
		$this->_db->setQuery( $query );
		$this->_db->execute();

		// alter ordering field for releases prior to beta5
		$query 	= "ALTER TABLE #__flexicontent_cats_item_relations MODIFY `ordering` int(11) NOT NULL default '0'";
		$this->_db->setQuery( $query );
		$this->_db->execute();
		$query 	= "ALTER TABLE #__flexicontent_fields_type_relations MODIFY `ordering` int(11) NOT NULL default '0'";
		$this->_db->setQuery( $query );
		$this->_db->execute();

		return $return;
	}


	/**
	 * Method to check if there are still old core fields data in the fields_items_relations table
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getNoOldFieldsData()
	{
		static $return;
		if ($return === NULL) {
			$query 	= 'SELECT COUNT( item_id )'
					. ' FROM #__flexicontent_fields_item_relations'
					. ' WHERE field_id < 15'
					. ' LIMIT 1';
					;
			$this->_db->setQuery( $query );
			$return = $this->_db->loadResult() ? false : true;
		}
		return $return;
	}


	/**
	 * Method to check if there is at least one category created
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistcat()
	{
		$query 	= 'SELECT COUNT( id )'
				. ' FROM #__categories as cat'
				. ' WHERE cat.extension="'.FLEXI_CAT_EXTENSION.'" AND lft> ' . $this->_db->Quote(FLEXI_LFT_CATEGORY) . ' AND rgt<' . $this->_db->Quote(FLEXI_RGT_CATEGORY)
				;
		$this->_db->setQuery( $query );
		$count = $this->_db->loadResult();

		if ($count > 0) {
			return true;
		}
		return false;
	}


	/**
	 * Method to check if there is at list one menu item is created
	 *
	 * @access public
	 * @return	boolean	True on success
	 */
	function getExistmenu()
	{
		$component = JComponentHelper::getComponent('com_flexicontent');
		$app = JFactory::getApplication();

		if(FLEXI_J16GE) {
			$query 	=	"SELECT COUNT(*) FROM #__menu WHERE `type`='component' AND `published`=1 AND `component_id`='{$component->id}' ";
			$this->_db->setQuery($query);
			$count = $this->_db->loadResult();
		} else {
			$menus = $app->getMenu('site', array());
			$items = $menus->getItems('componentid', $component->id);
			$count = count($items);
		}

		if ($count > 0) {
			return true;
		}
		return false;
	}


	function getDiffVersions($current_versions=array(), $last_versions=array())
	{
		// check if the category was chosen to avoid adding data on static contents
		if (!FLEXI_CAT_EXTENSION) return array();

		if(!$current_versions) {
			$current_versions = FLEXIUtilities::getCurrentVersions();
		}
		if(!$last_versions) {
			$last_versions = FLEXIUtilities::getLastVersions();
		}

		$difference = $current_versions;
		foreach($current_versions as $key1 => $value1) {
			foreach($last_versions as $key2 => $value2) {
				if( ($value1["id"]==$value2["id"]) && ($value1["version"]==$value2["version"]) ) {
					unset($difference[$key1]);
				}
			}
		}
		return $difference;
	}


	function checkCurrentVersionData() {
		// verify that every current version is in the versions table and it's data in the flexicontent_items_versions table
		//$and = "";

		// check if the section was chosen to avoid adding data on static contents
		if (!FLEXI_CAT_EXTENSION) return false;
		return FLEXIUtilities::currentMissing();
	}


	function addCurrentVersionData($item_id = null, $clean_database = false)
	{
		// check if the section was chosen to avoid adding data on static contents
		if (!FLEXI_CAT_EXTENSION) return true;

		$db = $this->_db;
		$nullDate	= $db->getNullDate();

		// @TODO: move somewhere else
		$this->formatFlexiPlugins();

		// Get some basic info of all items, or of the given item
		$query = "SELECT c.id,c.catid,c.version,c.created,c.modified,c.created_by,c.introtext,c.`fulltext`"
			." FROM #__content as c"
			. " JOIN #__categories as cat ON c.catid=cat.id "
			." WHERE cat.extension='".FLEXI_CAT_EXTENSION."'" // ."AND cat.lft >= ".$this->_db->Quote(FLEXI_LFT_CATEGORY)." AND cat.rgt <= ".$this->_db->Quote(FLEXI_RGT_CATEGORY).";";
			.($item_id ? " AND c.id=".$item_id : "")
			;

		$db->setQuery($query);
		$rows = $db->loadObjectList('id');

		if (!$item_id) {
			// Get current version ids of ALL ITEMS not having current versions
			$diff_arrays = $this->getDiffVersions();
		} else {
			// Get current version id of a SPECIFIC ITEM
			$diff_arrays = array( FLEXIUtilities::getCurrentVersions($item_id) );
		}

		//$jcorefields = flexicontent_html::getJCoreFields();
		$add_cats = true;
		$add_tags = true;

		// For all items not having the current version, add it
		foreach($diff_arrays as $item)
		{
			$item_id = @ (int)$item["id"];
			if( isset( $rows[$item_id] ) )
			{
				$row = & $rows[$item_id];

				// Get field values of the current item version
				$query = "SELECT f.id,fir.value,f.field_type,f.name,fir.valueorder,fir.suborder,f.iscore "
						." FROM #__flexicontent_fields_item_relations as fir"
					//." LEFT JOIN #__flexicontent_items_versions as iv ON iv.field_id="
						." LEFT JOIN #__flexicontent_fields as f on f.id=fir.field_id "
						." WHERE fir.item_id=".$row->id." AND f.iscore=0";  // old versions stored categories & tags into __flexicontent_fields_item_relations
				$db->setQuery($query);
				$fieldsvals = $db->loadObjectList();

				// Delete existing unversioned (current version) field values ONLY if we are asked to 'clean' the database
				if ($clean_database && $fieldsvals) {
					$query = 'DELETE FROM #__flexicontent_fields_item_relations WHERE item_id = '.$row->id;
					$db->setQuery($query);
					$db->execute();
				}

				// Delete any existing versioned field values to avoid conflicts, this maybe redudant, since they should not exist,
				// but we do it anyway because someone may have truncated or delete records only in table 'flexicontent_versions' ...
				// NOTE: we do not delete data with field_id negative as these exist only in the versioning table
				$query = 'DELETE FROM #__flexicontent_items_versions WHERE item_id = '.$row->id .' AND version= '.$row->version.' AND field_id > 0';
				$db->setQuery($query);
				$db->execute();

				// Add the 'maintext' field to the fields array for adding to versioning table
				$f = new stdClass();
				$f->id					= 1;
				$f->iscore			= 1;
				$f->valueorder	= 1;
				$f->suborder		= 1;
				$f->field_type	= "maintext";
				$f->name				= "text";
				$f->value				= $row->introtext;
				if ( StringHelper::strlen($row->fulltext) > 1 ) {
					$f->value .= '<hr id="system-readmore" />' . $row->fulltext;
				}
				if(substr($f->value, 0, 3)!="<p>") {
					$f->value = "<p>".$f->value."</p>";
				}
				$fieldsvals[] = $f;

				// Add the 'categories' field to the fields array for adding to versioning table
				$query = "SELECT catid FROM #__flexicontent_cats_item_relations WHERE itemid='".$row->id."';";
				$db->setQuery($query);
				$categories = $db->loadColumn();
				if (!$categories || !count($categories))
				{
					$categories = array($catid = $row->catid);
					$query = "INSERT INTO #__flexicontent_cats_item_relations VALUES('$catid','".$row->id."', '0');";
					$db->setQuery($query);
					$db->execute();
				}
				$f = new stdClass();
				$f->id 					= 13;
				$f->iscore			= 1;
				$f->valueorder	= 1;
				$f->suborder		= 1;
				$f->version		= (int)$row->version;
				$f->value		= serialize($categories);
				if ($add_cats) $fieldsvals[] = $f;

				// Add the 'tags' field to the fields array for adding to versioning table
				$query = "SELECT tid FROM #__flexicontent_tags_item_relations WHERE itemid='".$row->id."';";
				$db->setQuery($query);
				$tags = $db->loadColumn();
				$f = new stdClass();
				$f->id 					= 14;
				$f->iscore			= 1;
				$f->valueorder	= 1;
				$f->suborder		= 1;
				$f->version		= (int)$row->version;
				$f->value		= serialize($tags);
				if ($add_tags) $fieldsvals[] = $f;

				// Add field values to field value versioning table
				foreach($fieldsvals as $fieldval)
				{
					// add the new values to the database
					$obj = new stdClass();
					$obj->field_id   = $fieldval->id;
					$obj->item_id    = $row->id;
					$obj->valueorder = $fieldval->valueorder;
					$obj->suborder   = $fieldval->suborder;
					$obj->version    = (int)$row->version;
					$obj->value      = $fieldval->value;
					//echo "version: ".$obj->version.",fieldid : ".$obj->field_id.",value : ".$obj->value.",valueorder : ".$obj->valueorder.",suborder : ".$obj->suborder."<br />";
					//echo "inserting into __flexicontent_items_versions<br />";
					$db->insertObject('#__flexicontent_items_versions', $obj);
					if( $clean_database && !$fieldval->iscore )  // If clean_database is on we need to re-add the deleted values
					{
						unset($obj->version);
						//echo "inserting into __flexicontent_fields_item_relations<br />";
						$db->insertObject('#__flexicontent_fields_item_relations', $obj);
						flexicontent_db::setValues_commonDataTypes($obj);
					}
					//$searchindex 	.= @$fieldval->search;
				}

				// **********************************************************************************
				// Add basic METADATA of current item version (kept in table #__flexicontent_versions)
				// **********************************************************************************
				$v = new stdClass();
				$v->item_id    = (int)$row->id;
				$v->version_id = (int)$row->version;
				$v->created    = ($row->modified && ($row->modified != $nullDate)) ? $row->modified : $row->created;
				$v->created_by = $row->created_by;
				$v->comment    = '';
				//echo "inserting into __flexicontent_versions<br />";
				$db->insertObject('#__flexicontent_versions', $v);
			}
		}
		return true;
	}


	function formatFlexiPlugins()
	{
		$db = $this->_db;
		$tbl   = FLEXI_J16GE ? '#__extensions' : '#__plugins';
		$idcol = FLEXI_J16GE ? 'extension_id' : 'id';

		$query	= 'SELECT '.$idcol.' AS id, name, element FROM '.$tbl
				. ' WHERE folder =' . $db->Quote('flexicontent_fields')
				. (FLEXI_J16GE ? ' AND `type`=' . $db->Quote('plugin') : '')
				;
		$db->setQuery($query);
		$flexiplugins = $db->loadObjectList();

		$query = 'UPDATE '.$tbl.' SET name = CASE '.$idcol;
		$cases   = array();
		$ext_ids = array();
		foreach ($flexiplugins as $fp) {
			if ( substr($fp->name, 0, 15) == 'FLEXIcontent - ' ) continue;
			$cases[] = '	WHEN '.(int)$fp->id.' THEN '.$db->Quote('FLEXIcontent - '.$fp->name);
			$ext_ids[] = $fp->id;
		}
		$ext_ids_list = implode(', ', $ext_ids);
		$query .= implode(' ',$cases)
			. ' END'
			. ' WHERE '.$idcol.' IN ('.$ext_ids_list.')'
			. '  AND folder =' . $db->Quote('flexicontent_fields')
			. '  AND `type`=' . $db->Quote('plugin')
			;
		if ( count($cases) )
		{
			$db->setQuery($query)->execute();
		}

		/*$map = array(
			'account_via_submit'=>'FLEXIcontent - User account via submit',
			'authoritems'=>'FLEXIcontent - Author Items (More items by this Author)',
			'addressint'=>'FLEXIcontent - Address International / Google Maps',
			'checkbox'=>'FLEXIcontent - Checkbox',
			'checkboximage'=>'FLEXIcontent - Checkbox Image',
			'color'=>'FLEXIcontent - Color',
			'core'=>'FLEXIcontent - Core Fields (Joomla article properties)',
			'date'=>'FLEXIcontent - Date / Timestamp / Publish Up-Down Dates',
			'email'=>'FLEXIcontent - Email',
			'fcloadmodule'=>'FLEXIcontent - Load Module / Module position',
			'fcpagenav'=>'FLEXIcontent - Navigation (Next/Previous Item)',
			'file'=>'FLEXIcontent - File (Download/View/Share/Download cart)',
			'custom_form_html'=>'FLEXIcontent - Custom HTML / Item Form Tab / Fieldset',
			'image'=>'FLEXIcontent - Image or Gallery (image + details)',
			'linkslist'=>'FLEXIcontent - HTML list of URLs/Anchors/JS links',
			'mediafile'=>'FLEXIcontent - Media file player',
			'phonenumbers'=>'FLEXIcontent - Phone Numbers',
			'radio'=>'FLEXIcontent - Radio',
			'radioimage'=>'FLEXIcontent - Radio Image',
			'relation'=>'FLEXIcontent - Relation (List of related items)',
			'relation_reverse'=>'FLEXIcontent - Relation - Reverse',
			'select'=>'FLEXIcontent - Select',
			'selectmultiple'=>'FLEXIcontent - Select Multiple',
			'sharedmedia'=>'FLEXIcontent - Shared Video/Audio (Youtube,etc / SoundCloud,Last.fm,etc)',
			'text'=>'FLEXIcontent - Text (number/time/etc/custom validation)',
			'textarea'=>'FLEXIcontent - Textarea',
			'textselect'=>'FLEXIcontent - TextSelect (Text with existing value selection)',
			'toolbar'=>'FLEXIcontent - Toolbar (social share/other tools)',
			'weblink'=>'FLEXIcontent - Weblink'
		);

		$query = 'UPDATE '.$tbl.' SET name = CASE element';
		$cases    = array();
		$elements = array();
		foreach ($flexiplugins as $fp) {
			if ( empty($map[$fp->element]) ) continue;
			$cases[] = '	WHEN '.$db->Quote($fp->element).' THEN '.$db->Quote($map[$fp->element]);
			$elements[] = $db->Quote($fp->element);
		}
		$elements_list = implode(', ', $elements);
		$query .= implode(' ',$cases)
			. ' END'
			. ' WHERE folder =' . $db->Quote('flexicontent_fields')
			. (FLEXI_J16GE ? ' AND `type`='. $db->Quote('plugin') : '')
			. ' AND element IN ('.$elements_list.')'
			;
		if ( count($cases) )
		{
			$db->setQuery($query);
			$db->execute();
		}*/
	}

	function createLanguagePack($code = 'en-GB', $method = '', $params = array())
	{
		jimport('joomla.filesystem.file');

		$prefix 	= $code . '.';
		$suffix 	= '.ini';
		$missing 	= array();
		$namea		= '';
		$names		= '';

		$adminpath 		= JPATH_ADMINISTRATOR.DS.'language'.DS.$code.DS;
		$refadminpath 	= JPATH_ADMINISTRATOR.DS.'language'.DS.'en-GB'.DS;

		$adminfiles = array(
		// component files
			'com_flexicontent',
			'com_flexicontent.sys',
		// plugin files  --  flexicontent_fields
			'plg_flexicontent_fields_addressint',
			'plg_flexicontent_fields_checkbox',
			'plg_flexicontent_fields_checkboximage',
			'plg_flexicontent_fields_color',
			'plg_flexicontent_fields_core',
			'plg_flexicontent_fields_date',
			'plg_flexicontent_fields_email',
			'plg_flexicontent_fields_fcloadmodule',
			'plg_flexicontent_fields_fcpagenav',
			'plg_flexicontent_fields_file',
			'plg_flexicontent_fields_custom_form_html',
			'plg_flexicontent_fields_image',
			'plg_flexicontent_fields_linkslist',
			'plg_flexicontent_fields_mediafile',
			'plg_flexicontent_fields_phonenumbers',
			'plg_flexicontent_fields_radio',
			'plg_flexicontent_fields_radioimage',
			'plg_flexicontent_fields_relation',
			'plg_flexicontent_fields_relation_reverse',
			'plg_flexicontent_fields_select',
			'plg_flexicontent_fields_selectmultiple',
			'plg_flexicontent_fields_sharemedia',
			'plg_flexicontent_fields_text',
			'plg_flexicontent_fields_textarea',
			'plg_flexicontent_fields_textselect',
			'plg_flexicontent_fields_toolbar',
			'plg_flexicontent_fields_weblink',
		// plugin files  --  finder
			(FLEXI_J16GE ? 'plg_finder_flexicontent' : ''),
			(FLEXI_J16GE ? 'plg_finder_flexicontent.sys' : ''),
		// plugin files  --  content
			'plg_content_flexibreak',
		// plugin files  --  flexicontent
			'plg_flexicontent_flexinotify',
		// plugin files  --  search
			'plg_search_flexiadvsearch',
			'plg_search_flexisearch',
		// plugin files  --  system
			'plg_system_flexiadvroute',
			'plg_system_flexisystem'
		);

		$sitepath 		= JPATH_SITE.DS.'language'.DS.$code.DS;
		$refsitepath 	= JPATH_SITE.DS.'language'.DS.'en-GB'.DS;
		$sitefiles 	= array(
		// component files
			'com_flexicontent',
		// module files
			'mod_flexiadvsearch',
			'mod_flexicontent',
			'mod_flexitagcloud',
			'mod_flexifilter'
		);
		$targetfolder = JPATH_SITE.DS.'tmp'.DS.$code."_".time();

		if ($method == 'zip') {
			if (count($adminfiles))
				JFolder::create($targetfolder.DS.'admin', 0755);
			if (count($sitefiles))
				JFolder::create($targetfolder.DS.'site', 0755);
		}

		foreach ($adminfiles as $file) {
			if (!$file) continue;
			if (!JFile::exists($adminpath.$prefix.$file.$suffix)) {
				$missing['admin'][] = $file;
				if ($method == 'create')
					JFile::copy($refadminpath.'en-GB.'.$file.$suffix, $adminpath.$prefix.$file.$suffix);
			} else {
				if ($method == 'zip') {
					JFile::copy($adminpath.$prefix.$file.$suffix, $targetfolder.DS.'admin'.DS.$prefix.$file.$suffix);
					$namea .= "\n".'			            <filename>'.$prefix.$file.$suffix.'</filename>';
				}
			}
		}
		foreach ($sitefiles as $file) {
			if (!$file) continue;
			if (!JFile::exists($sitepath.$prefix.$file.$suffix)) {
				$missing['site'][] = $file;
				if ($method == 'create')
					JFile::copy($refsitepath.'en-GB.'.$file.$suffix, $sitepath.$prefix.$file.$suffix);
			} else {
				if ($method == 'zip') {
					JFile::copy($sitepath.$prefix.$file.$suffix, $targetfolder.DS.'site'.DS.$prefix.$file.$suffix);
					$names .= "\n".'			            <filename>'.$prefix.$file.$suffix.'</filename>';
				}
			}
		}

		if ($method == 'zip')
		{
			$mailfrom 	= @$params['email']	? $params['email']	: 'emmanuel.danan@gmail.com';
			$fromname 	= @$params['name'] 	? $params['name'] 	: 'Emmanuel Danan';
			$website 	= @$params['web'] 	? $params['web'] 	: 'http://www.flexicontent.org';

			// prepare the manifest of the language archive
			$date = JFactory::getDate();

			$xmlfile = $targetfolder.DS.'install.xml';

			$xml = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>
			<install type="language" version="1.5" client="both" method="upgrade">
			    <name>FLEXIcontent '.$code.'</name>
			    <tag>'.$code.'</tag>
			    <creationDate>'.(FLEXI_J16GE ? $date->format('Y-M-d', $local = true) : $date->toFormat("%Y-%m-%d")).'</creationDate>
			    <author>'.$fromname.'</author>
			    <authorEmail>'.$mailfrom.'</authorEmail>
			    <authorUrl>'.$website.'</authorUrl>
			    <copyright>(C) '.(FLEXI_J16GE ? $date->format('Y', $local = true) : $date->toFormat("%Y")).' '.$fromname.'</copyright>
			    <license>http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL</license>
			    <description>'.$code.' language pack for FLEXIcontent</description>
			    <administration>
			        <files folder="admin">'.$namea.'
			        </files>
			    </administration>
			    <site>
			        <files folder="site">'.$names.'
			        </files>
			    </site>
			</install>'
			   ;
			// save xml manifest
			JFile::write($xmlfile, $xml);


			$fileslist  = JFolder::files($targetfolder, '.', true, true, array('.svn', 'CVS', '.DS_Store'));
			$archivename = $targetfolder.'.com_flexicontent'. (FLEXI_J16GE ? '.zip' : '.tar.gz');

			// Create the archive
			echo JText::_('FLEXI_SEND_LANGUAGE_CREATING_ARCHIVE')."<br>";

			$files = array();
			foreach ($fileslist as $i => $filename) {
				$files[$i]=array();
				$files[$i]['name'] = preg_replace("%^(\\\|/)%", "", str_replace($targetfolder, "", $filename) );  // STRIP PATH for filename inside zip
				$files[$i]['data'] = implode('', file($filename));   // READ contents into string, here we use full path
				$files[$i]['time'] = time();
			}

			jimport('joomla.archive.archive');
			$packager = JArchive::getAdapter('zip');
			if (!$packager->create($archivename, $files)) {
				echo JText::_('FLEXI_OPERATION_FAILED');
				return false;
			}

			// Remove temporary folder structure
			if (!JFolder::delete(($targetfolder)) ) {
				echo JText::_('FLEXI_SEND_DELETE_TMP_FOLDER_FAILED');
			}
		}

		// messages
		if ($method == 'zip') {
			return '<h3 class="lang-success">' . JText::_( 'FLEXI_SEND_LANGUAGE_ARCHIVE_SUCCESS' ) . '</span>';
		}
		return (count($missing) > 0) ? $missing : '<span class="fc-mssg fc-success">'. JText::sprintf( 'FLEXI_SEND_LANGUAGE_NO_MISSING', $code ) .'</span>';
	}


	function checkInitialPermission()
	{
		$debug_initial_perms = JComponentHelper::getParams('com_flexicontent')->get('debug_initial_perms');

		static $init_required = null;
		if ( $init_required !== null ) return $init_required;

		$db = $this->_db;
		$component_name = 'com_flexicontent';


		// DELETE old namespace (flexicontent.*) permissions of v2.0beta, we do not try to rename them ... instead we will use com_content (for some of them),
		$query = $db->getQuery(true)->delete('#__assets')->where('name LIKE ' . $db->quote('flexicontent.%'));
		$db->setQuery($query);

		try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }

		// DELETE bad top-level assets, only root.1 should exist
		$query = $db->getQuery(true)->delete('#__assets')->where('(parent_id=0 OR level=0) AND name<>' . $db->quote('root.1'));
		$db->setQuery($query);

		try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }

		// SET Access View Level to public (=1) for fields that do not have their Level set
		$query = $db->getQuery(true)->update('#__flexicontent_fields')->set('access = 1')->where('access = 0');
		$db->setQuery($query);

		try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }

		// SET Access View Level to public (=1) for types that do not have their Level set
		$query = $db->getQuery(true)->update('#__flexicontent_types')->set('access = 1')->where('access = 0');
		$db->setQuery($query);

		try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }

		// CHECK that we have the same Component Actions in assets DB table with the Actions as in component's access.xml file
		$asset	= JTable::getInstance('asset');
		if ($comp_section = $asset->loadByName($component_name))    // Try to load component asset, if missing it returns false
		{
			$this->verifyExtraRules();  // Verify that com_content component asset has the extra FC specific rules

			// ok, component asset not missing, proceed to cross check for deleted / added actions
			$rules = new JAccessRules($asset->rules);
			$rules_data = $rules->getData();
			$component_actions = JAccess::getActionsFromFile(
				JPATH_ADMINISTRATOR . '/components/' . $component_name . '/access.xml',
				"/access/section[@name='component']/"
			);

			$db_action_names = array();
			foreach ($rules_data as $action_name => $data)  $db_action_names[]   = $action_name;
			foreach ($component_actions as $action)         $file_action_names[] = $action->name;
			$deleted_actions =  array_diff($db_action_names,   $file_action_names);
			$added_actions   =  array_diff($file_action_names, $db_action_names  );
			foreach($added_actions as $i => $action_name)
			{
				if (substr($action_name, 0, 5) === 'core.') unset($added_actions[$i]);
			}

			$comp_section = ! ( count($deleted_actions) || count($added_actions) );  // false if deleted or addeded actions exist
			if ($debug_initial_perms) { echo "Deleted actions: "; print_r($deleted_actions); echo "<br> Added actions: "; print_r($added_actions); echo "<br>"; }
		}

		if ($debug_initial_perms)
		{
			echo "Component DB Rule Count " . ( ($comp_section) ? count($rules->getData()) : 0 ) . "<br />";
			echo "Component File Rule Count " .
				count(JAccess::getActionsFromFile(
					JPATH_ADMINISTRATOR . '/components/' . $component_name . '/access.xml',
					"/access/section[@name='component']/"
				)) .
				"<br />";
		}

		// Get a list com_content TOP-LEVEL categories that have wrong asset names (do not point to 'com_content' asset)
		// (NOTE: we do not longer force category asset creation if asset is not set, so we will not check them here)
		// !!! WARNING this query must be same like the one USED in function initialPermission()
		$com_content_asset	= JTable::getInstance('asset');
		$com_content_asset->loadByName('com_content');
		$query = $db->getQuery(true)
			->select('c.id')
			->from('#__assets AS se')->join('RIGHT', '#__categories AS c ON se.id=c.asset_id AND se.name=concat("com_content.category.",c.id)')
			->where( '(c.parent_id=1 AND se.parent_id!='.(int)$com_content_asset->id.')' )
			//->where( '(se.id is NULL OR (c.parent_id=1 AND se.parent_id!='.(int)$com_content_asset->id.') )' )
			->where( 'c.extension = ' . $db->quote('com_content') );

		$db->setQuery($query);

		try { $result = $db->loadObjectList(); } catch (Exception $e) { $result = array(); echo $e->getMessage(); }

		if (!empty($result) && $debug_initial_perms) { echo "bad assets for categories: "; print_r($result); echo "<br>"; }
		$category_section = count($result) == 0 ? 1 : 0;

		// CHECK if some fields don't have permissions set, !!! WARNING this query must be same like the one USED in function initialPermission()
		$query = $db->getQuery(true)
			->select('se.id')
			->from('#__assets AS se')->join('RIGHT', '#__flexicontent_fields AS ff ON se.id=ff.asset_id AND se.name=concat("com_flexicontent.field.",ff.id)')
			->where('se.id is NULL');
		$db->setQuery($query);

		try { $result = $db->loadObjectList(); } catch (Exception $e) { $result = array(); echo $e->getMessage(); }

		if (!empty($result) && $debug_initial_perms) { echo "bad assets for fields: "; print_r($result); echo "<br>"; }
		$field_section = count($result) == 0 ? 1 : 0;

		// CHECK if some types don't have permissions set, !!! WARNING this query must be same like the one USED in function initialPermission()
		$query = $db->getQuery(true)
			->select('se.id')
			->from('#__assets AS se')->join('RIGHT', '#__flexicontent_types AS ff ON se.id=ff.asset_id AND se.name=concat("com_flexicontent.type.",ff.id)')
			->where('se.id is NULL');
		$db->setQuery($query);

		try { $result = $db->loadObjectList(); } catch (Exception $e) { $result = array(); echo $e->getMessage(); }

		if (!empty($result) && $debug_initial_perms) { echo "bad assets for types: "; print_r($result); echo "<br>"; }
		$type_section = count($result) == 0 ? 1 : 0;

		if ($debug_initial_perms) { echo "PASSED comp_section:$comp_section && category_section:$category_section && field_section:$field_section && type_section:$type_section <br>"; }

		$init_required = $comp_section && $category_section && $field_section && $type_section;
		return $init_required;
	}


	function updateInitialPermission()
	{
		$app = JFactory::getApplication();
		$component_name	= $app->input->get('option', '', 'CMD');
		$db = $this->_db;
		$asset	= JTable::getInstance('asset');   // Create an asset object

		/*** Component assets ***/
		$asset_exists = $asset->loadByName($component_name);
		if ($asset_exists)
		{
			$rules_arr = strlen(trim($asset->rules))  ?  json_decode($asset->rules, true)  :  array();
		}

		if ( !$asset_exists || !count($rules_arr) )
		{
			// Component asset entry does not exist or is empty: We will create initial rules for all component's actions

			// Get root asset
			$root = JTable::getInstance('asset');
			$root->loadByName('root.1');

			// Initialize component asset
			$asset->name = $component_name;
			$asset->title = $component_name;
			$asset->setLocation($root->id,'last-child');  // father of compontent asset it the root asset

			// Create initial component rules and set them into the asset
			$component_rules_arr = $this->_createComponentRules($component_name);
			$component_rules = new JAccessRules($component_rules_arr);
			$asset->rules = (string) $component_rules;

			// Save the asset into the DB
			if (!$asset->check() || !$asset->store())
			{
				echo $asset->getError();
				$this->setError($asset->getError());
				return false;
			}
		}

		else
		{
			// Component assets entry already exists and is non-empty: We will check if it has exactly the actions specified in component's access.xml file

			// Get existing DB rules and component's actions from the access.xml file
			$existing_rules = new JAccessRules($asset->rules);
			$rules_data = $existing_rules->getData();
			$component_actions = JAccess::getActionsFromFile(
				JPATH_ADMINISTRATOR . '/components/' . $component_name . '/access.xml',
				"/access/section[@name='component']/"
			);

			// Find any deleted / added actions ...
			$db_action_names = array();
			foreach ($rules_data as $action_name => $data)  $db_action_names[]   = $action_name;
			foreach ($component_actions as $action)         $file_action_names[] = $action->name;
			$deleted_actions =  array_diff($db_action_names,   $file_action_names);
			$added_actions   =  array_diff($file_action_names, $db_action_names  );
			foreach($added_actions as $i => $action_name)
			{
				if (substr($action_name, 0, 5) === 'core.') unset($added_actions[$i]);
			}

			if ( count($deleted_actions) || count($added_actions) )
			{
				// We have changes in the component actions

				// First merge the existing component (db) rules into the initial rules
				$component_rules_arr = $this->_createComponentRules($component_name, $added_actions);
				$component_rules = new JAccessRules($component_rules_arr);
				$component_rules->merge($existing_rules);

				// Second, check if obsolete rules are contained in the existing component (db) rules, if so create a new rules object without the obsolete rules
				if ($deleted_actions)
				{
					$rules_data = $component_rules->getData();
					foreach($deleted_actions as $action_name)
					{
						unset($rules_data[$action_name]);
					}
					$component_rules = new JAccessRules($rules_data);
				}

				// Set asset rules
				$asset->rules = (string) $component_rules;

				// Save the asset
				if (!$asset->check() || !$asset->store())
				{
					echo $asset->getError();
					$this->setError($asset->getError());
					return false;
				}
			}
		}

		// Load component asset
		$component_asset = JTable::getInstance('asset');
		$component_asset->loadByName($component_name);

		// Load com_content asset
		$com_content_asset = JTable::getInstance('asset');
		$com_content_asset->loadByName('com_content');
		$com_content_name = 'com_content';

		/*** CATEGORY assets ***/

		// Get a list com_content TOP-LEVEL categories that have wrong asset names (do not point to 'com_content' asset)
		// (NOTE: we do not longer force category asset creation if asset is not set)
		$query = $db->getQuery(true)
			->select('c.id, c.parent_id, c.title, c.asset_id')
			->from('#__assets AS se')->join('RIGHT', '#__categories AS c ON se.id=c.asset_id AND se.name=concat("com_content.category.",c.id)')
			->where( '(c.parent_id=1 AND se.parent_id!='.(int)$com_content_asset->id.')' )
			//->where( '(se.id is NULL OR (c.parent_id=1 AND se.parent_id!='.(int)$com_content_asset->id.') )' )
			->where( 'c.extension = ' . $db->quote('com_content') )
			->order('c.level ASC');   // IMPORTANT create categories asset using increasing depth level, so that get parent assetid will not fail

		$results = $db->setQuery($query)->loadObjectList();

		// Check that any assets of top-level categories point to the correct component (we used to make these point to 'com_flexicontent' asset)
		$bad_cat_assets = array();
		foreach($results as $category)
		{
			$parentId = $this->_getAssetParentId(null, $category);
			$name = "com_content.category.{$category->id}";

			// Try to load asset for the current CATEGORY ID
			$asset_found = $asset->loadByName($name);
			if ( !$asset_found ) continue; // nothing to do

			// Since this is a top level category make sure, that the asset points to the correct component asset (com_content)
			$asset->setLocation($parentId, 'last-child');

			// Save the category asset (create or update it)
			if (!$asset->check() || !$asset->store(false))
			{
				//echo $asset->getError();
				//echo " Problem for asset with id: ".$asset ->id;
				//echo " Deleting but category asset for category #: ".$category->id. "(".$category->title.")";
				//$this->setError($asset->getError());
				//return false;
				$bad_cat_assets[] = $category->id;

				// DELETE bad category asset
				$query = $db->getQuery(true)
					->delete('#__assets')
					->where( ($asset->id ? ' id = ' . (int)$asset->id .' AND ' : '') . ' name = ' . $db->quote($name) );
				$db->setQuery($query);

				try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }

				// Nothing more to do
				continue;
			}

			// Assign the asset to the category, if it is not already assigned
			$query = $db->getQuery(true)
				->update('#__categories')
				->set('asset_id = ' . (int)$asset->id)
				->where('id = ' . (int)$category->id);
			$db->setQuery($query);
			try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }
		}
		if (!empty($bad_cat_assets))
		{
			echo '
			<div class="alert alert-warning">Please refresh this page, deleted bad assets for category IDs:
				'. print_r($bad_cat_assets, true) .'
			</div>';
		}


		/*** FLEXIcontent FIELDS assets ***/

		// Get a list flexicontent fields that do not have assets
		$query = $db->getQuery(true)
			->select('ff.id, ff.name, ff.label, ff.asset_id')
			->from('#__assets AS se')->join('RIGHT', '#__flexicontent_fields AS ff ON se.id=ff.asset_id AND se.name=concat("com_flexicontent.field.",ff.id)')
			->where('se.id is NULL');
		$db->setQuery($query);
		$results = $db->loadObjectList();

		// Add an asset to every field that doesnot have one
		if ($results)
		{
			foreach($results as $field)
			{
				$name = "com_flexicontent.field.{$field->id}";

				// Test if an asset for the current FIELD ID already exists and load it instead of creating a new asset
				if ( ! $asset->loadByName($name) )
				{
					if ($field->asset_id)
					{
						// asset name not found but field has an asset id set ?, we could delete it here
						// but it maybe dangerous to do so ... it might be a legitimate asset_id for something else
					}

					// Initialize field asset
					$asset->id = null;
					$asset->name		= $name;
					$asset->title		= $field->label;
					$asset->setLocation($component_asset->id, 'last-child');     // Permissions of fields are directly inheritted by component

					// Set asset rules to empty, (DO NOT set any ACTIONS, just let them inherit ... from parent)
					$asset->rules = new JAccessRules();
					/*
					$actions = JAccess::getActionsFromFile(
						JPATH_ADMINISTRATOR . '/components/' . $component_name . '/access.xml',
						"/access/section[@name='field']/"
					);
					$rules 		= json_decode($component_asset->rules);
					foreach ($actions as $action) {
						$fieldrules[$action->name] = $rules->{$action->name};
					}
					$asset->rules = new JAccessRules(json_encode($fieldrules));
					*/
					$asset->rules = (string) $asset->rules;

					// Save the asset
					if (!$asset->check() || !$asset->store(false)) {
						echo $asset->getError();
						$this->setError($asset->getError());
						return false;
					}
				}

				// Assign the asset to the field
				$query = $db->getQuery(true)
					->update('#__flexicontent_fields')
					->set('asset_id = ' . (int)$asset->id)
					->where('id = ' . (int)$field->id);
				$db->setQuery($query);
				try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }
			}
		}


		/*** FLEXIcontent TYPES assets ***/

		// Get a list flexicontent types that do not have assets
		$query = $db->getQuery(true)
			->select('ff.id, ff.alias, ff.name, ff.asset_id')
			->from('#__assets AS se')->join('RIGHT', '#__flexicontent_types AS ff ON se.id=ff.asset_id AND se.name=concat("com_flexicontent.type.",ff.id)')
			->where('se.id is NULL');
		$db->setQuery($query);
		$results = $db->loadObjectList();

		// Add an asset to every type that doesnot have one
		if($results)
		{
			foreach($results as $type)
			{
				$name = "com_flexicontent.type.{$type->id}";

				// Test if an asset for the current TYPE ID already exists and load it instead of creating a new asset
				if ( ! $asset->loadByName($name) ) {
					if ($type->asset_id) {
						// asset name not found but type has an asset id set ?, we could delete it here
						// but it maybe dangerous to do so ... it might be a legitimate asset_id for something else
					}

					// Initialize type asset
					$asset->id = null;
					$asset->name		= $name;
					$asset->title		= $type->name;
					$asset->setLocation($component_asset->id, 'last-child');     // Permissions of types are directly inheritted by component

					// Set asset rules to empty, (DO NOT set any ACTIONS, just let them inherit ... from parent)
					$asset->rules = new JAccessRules();
					/*
					$actions = JAccess::getActionsFromFile(
						JPATH_ADMINISTRATOR . '/components/' . $component_name . '/access.xml',
						"/access/section[@name='type']/"
					);
					$rules 		= json_decode($component_asset->rules);
					foreach ($actions as $action) {
						$typerules[$action->name] = $rules->{$action->name};
					}
					$asset->rules = new JAccessRules(json_encode($typerules));
					*/
					$asset->rules = (string) $asset->rules;

					// Save the asset
					if (!$asset->check() || !$asset->store(false)) {
						echo $asset->getError();
						$this->setError($asset->getError());
						return false;
					}
				}

				// Assign the asset to the type
				$query = $db->getQuery(true)
					->update('#__flexicontent_types')
					->set('asset_id = ' . (int)$asset->id)
					->where('id = ' . (int)$type->id);
				$db->setQuery($query);
				try { $db->execute(); } catch (Exception $e) { echo $e->getMessage(); }
			}
		}

		/**
		 * Clean component's VIEW Cache and categories cache
		 * so that per user permissions objects are recalculated
		 */
		$this->cleanCache(null, $client = 0);
		$this->cleanCache(null, $client = 1);
		$this->cleanCache($group = 'com_flexicontent_cats', $client = 0);
		$this->cleanCache($group = 'com_flexicontent_cats', $client = 1);

		// Indicate to our system plugin that its category cache needs to be cleaned
		JFactory::getSession()->set('clear_cats_cache', 1, 'flexicontent');

		return true;
	}


	/**
	 * Method to check if search indexes need to be updated because of changing publication state or search flags of fields
	 *
	 * @access public
	 * @return array
	*/
	function checkDirtyFields()
	{
		if ( !FlexicontentHelperPerm::getPerm()->CanFields ) return;

		$db  = JFactory::getDbo();
		$app = JFactory::getApplication();

		/**
		 * GET fields having dirty field properties,
		 * NOTE: a dirty field property means that search index must be updated,
		 *   even if the field was unpublished,
		 *   because the field values may still exists in the search index for some items,
		 */

		// Regardless publication state
		$query = $db->getQuery(true)
			->select('COUNT(*)')
			->from('#__flexicontent_fields')
			->where('issearch=-1 OR issearch=2 OR isfilter=-1 OR isfilter=2')
			;
		$dirty_basic = $db->setQuery($query)->loadResult();

		$query = $db->getQuery(true)
			->select('COUNT(*)')
			->from('#__flexicontent_fields')
			->where('isadvsearch=-1 OR isadvsearch=2 OR isadvfilter=-1 OR isadvfilter=2')
			;
		$dirty_advanced = $db->setQuery($query)->loadResult();

		if ($dirty_basic)
		{
			echo '
			<div class="fcclear"></div>
			<div class="alert alert-info">' .
				JText::sprintf('FLEXI_ALERT_UPDATE_SINDEX_BASIC',
					$dirty_basic,
					' href="index.php?option=com_flexicontent&view=search&layout=indexer&tmpl=component&indexer=basic" '.
					' class="btn" onclick="var url = jQuery(this).attr(\'href\'); fc_showDialog(url, \'fc_modal_popup_container\', 0, 550, 420, function(){window.location.reload(false)}); return false;" '
				) . '
			</div>';
		}
		if ($dirty_advanced)
		{
			echo '
			<div class="fcclear"></div>
			<div class="alert alert-info">' .
				JText::sprintf('FLEXI_ALERT_UPDATE_SINDEX_ADVANCED',
					$dirty_advanced,
					' href="index.php?option=com_flexicontent&view=search&layout=indexer&tmpl=component&indexer=advanced" ' .
					' class="btn" onclick="var url = jQuery(this).attr(\'href\'); fc_showDialog(url, \'fc_modal_popup_container\', 0, 550, 420, function(){window.location.reload(false)}); return false;" '
				) . '
			</div>';
		}
	}


	/**
	 * Creates initial component actions based on global config and on some ... logic
	 *
	 * @return  array
	 * @since   11.1
	 */
	protected function _createComponentRules($component, $added_actions=false)
	{
		// ***
		// *** Get com_flexicontent asset
		// ***

		$comp_asset = JTable::getInstance('asset');
		$existing_rules = $comp_asset->loadByName('com_flexicontent') && !empty($comp_asset->rules)
			? json_decode($comp_asset->rules, true)
			: array();
		$asset_is_empty = !count($existing_rules);


		// ***
		// *** Get flexicontent ACTION names
		// ***

		$flexi_actions = JAccess::getActionsFromFile(
			JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml',
			"/access/section[@name='component']/"
		);

		foreach($flexi_actions as $action)
		{
			$flexi_action_names[$action->name] = 1;
		}

		// We will either populate all action names or just those that were given (new actions)
		$new_actions = is_array($added_actions)
			? array_flip($added_actions)
			: $flexi_action_names;

		// Initialize non-existing flexicontent ACL rules to empty
		$flexi_rules = array();
		foreach($new_actions as $action_name => $_i)
		{
			// * WE NEED THIS (even if it remains empty array), because we will compare COMPONENT actions in DB when checking initial permissions
			$flexi_rules[$action_name] = !isset($flexi_rules[$action_name])
				? array()
				: $flexi_rules[$action_name];
		}


		// ***
		// *** Get com_content asset and its rule names
		// ***

		$com_content_asset = JTable::getInstance('asset');
		$com_content_asset->loadByName('com_content');
		$com_content_rules = json_decode($com_content_asset->rules, true);

		foreach ($com_content_rules as $action_name => $data)
		{
			$joomla_action_names[$action_name] = 1;
		}
		//echo "<pre>"; print_r($com_content_rules); echo "</pre>"; exit;


		// ***
		// *** If com_flexicontent ASSET was empty then copy rules from com_content asset
		// ***

		if ( $asset_is_empty )
		{
			// Handle some special case of custom-added ACTIONs
			// e.g. Grant --OWNED-- actions if they have the corresponding --GENERAL-- actions
			if ( !isset($com_content_rules['core.delete.own']) )
			{
				$com_content_rules['core.delete.own'] = isset($com_content_rules['core.delete']) ? $com_content_rules['core.delete'] : array();
			}
			if ( !isset($com_content_rules['core.edit.state.own']) )
			{
				$com_content_rules['core.edit.state.own'] = isset($com_content_rules['core.edit.state']) ? $com_content_rules['core.edit.state'] : array();
			}

			// Copy rules from com_content asset
			foreach ($com_content_rules as $action_name => $data)
			{
				$flexi_rules[$action_name] = $data;
			}

			// Save the asset into the DB
			$com_content_asset->rules = json_encode($com_content_rules);
			if (!$com_content_asset->check() || !$com_content_asset->store())
			{
				die($com_content_asset->getError());
			}

			// By default DO NOT SET the edit field values privilege, because we have another parameter "allow any editor" and also to allow easier configuration via SOFT DENY
			//$flexi_rules['flexicontent.editfieldvalues'] = $flexi_rules['core.edit'];  // can EditFieldValues
		}


		// ***
		// *** Grant FLEXIcontent specific rules to user having GLOBAL "core.manage"
		// ***

		$groups = $this->_getUserGroups();
		$added = false;

		foreach($groups as $group)
		{
			// This unlike JUser::authorize will not return true for super-user, (we don't need to set anything for super-user group, because its users will be authorized by default)
			if ( JAccess::checkGroup($group->id, 'core.manage') ) foreach($new_actions as $action_name => $_i)
			{
				// Set flexicontent specific rule
				$flexi_rules[$action_name][$group->id] = 1;
				$added = true;
			}
		}

		if (!$added) foreach($groups as $group)
		{
			// Since there is none User Group with core.manage, we will have to grant these to superadmins so that they are not empty ...
			if ( JAccess::checkGroup($group->id, 'core.admin') ) foreach($new_actions as $action_name => $_i)
			{
				// Set flexicontent specific rule
				$flexi_rules[$action_name][$group->id] = 1;
				$added = true;
			}
		}
		//echo "<pre>"; print_r($flexi_rules); $component_rules = new JAccessRules($flexi_rules); echo $asset_rules = (string) $component_rules; echo "</pre>"; exit;


		// ***
		// *** Rules that should be allowed by default, give these to the "Public" and "Registered" user groups
		// ***

		$grant_to_all = array('flexicontent.change.cat', 'flexicontent.change.cat.sec', 'flexicontent.change.cat.feat', 'flexicontent.uploadfiles', 'flexicontent.editownfile', 'flexicontent.publishownfile', 'flexicontent.deleteownfile');
		foreach($grant_to_all as $_name)
		{
			if ( !isset($new_actions[$_name] ) ) continue;
			$flexi_rules[$_name][1] = $flexi_rules[$_name][2] = 1;
		}
		//echo "<pre>"; print_r($flexi_rules); echo "</pre>"; exit;

		return $flexi_rules;
	}


	/**
	 * Get a list of the user groups.
	 *
	 * @return  array
	 * @since   11.1
	 */
	protected function _getUserGroups()
	{
		// Initialise variables.
		$query	= $this->_db->getQuery(true);
		$query->select('a.id, a.title, COUNT(DISTINCT b.id) AS level, a.parent_id')
			->from('#__usergroups AS a')
			->leftJoin('#__usergroups AS b ON a.lft > b.lft AND a.rgt < b.rgt')
			->group('a.id')
			->order('a.lft ASC');

		$this->_db->setQuery($query);
		$options = $this->_db->loadObjectList();

		return $options;
	}

	/**
	 * Get the parent asset id for the record
	 *
	 * @param   JTable   $table  A JTable object for the asset parent.
	 * @param   object  $data
	 *
	 * @return  integer  The id of the asset's parent
	 */
	protected function _getAssetParentId($table = null, $data = null)
	{
		// Initialise variables.
		$assetId = null;
		static $comp_assetid = null;

		// Get asset id of the component, if we have done already
		if ( $comp_assetid===null ) {
			$query	= $this->_db->getQuery(true)
				->select('id')
				->from('#__assets')
				->where('name = '.$this->_db->quote('com_content'));
			$this->_db->setQuery($query);
			$comp_assetid = (int) $this->_db->loadResult();
		}

		// This is a category under a category with id 'parent_id', or an item assigned to a category with id 'parent_id' (... see query above)
		if ($data->parent_id > 1) {
			// Build the query to get the asset id for the parent category.
			$query	= $this->_db->getQuery(true);
			$query->select('asset_id');
			$query->from('#__categories');
			$query->where('id = '.(int) $data->parent_id);

			// Get the asset id from the database.
			$this->_db->setQuery($query);
			if ($result = $this->_db->loadResult()) {
				$assetId = (int) $result;
			}
		}

		// This is a category that needs to parent with the extension.
		if ($assetId === null || $assetId === false) {
			$assetId = $comp_assetid;
		}

		// Return the asset id.
		return $assetId;
		/*if ($assetId) {
			return $assetId;
		} else {
			return parent::_getAssetParentId($table, $id);
		}*/
	}


	protected function verifyExtraRules()
	{
		$debug_initial_perms = JComponentHelper::getParams('com_flexicontent')->get('debug_initial_perms');

		$fc_asset = JTable::getInstance('asset');
		$fc_asset->loadByName('com_flexicontent');
		$fc_asset_rules = json_decode($fc_asset->rules, true);
		if ( !count($fc_asset_rules) )  return; // The asset is empty do not try anything

		$com_content_asset = JTable::getInstance('asset');
		$com_content_asset->loadByName('com_content');
		$com_content_rules = json_decode($com_content_asset->rules, true);

		$save_asset = false;

		foreach($com_content_rules as $rule_name => $rule_data)
		{
			if ( isset($fc_asset_rules[$rule_name]) && $com_content_rules[$rule_name] != $fc_asset_rules[$rule_name] )
			{
				$com_content_rules[$rule_name] = $fc_asset_rules[$rule_name];
				$save_asset = true;
			}
		}

		if ( isset($fc_asset_rules['core.delete.own']) )
		{
			if ( !isset($com_content_rules['core.delete.own']) || $com_content_rules['core.delete.own'] != $fc_asset_rules['core.delete.own'] )
			{
				$com_content_rules['core.delete.own'] = $fc_asset_rules['core.delete.own'];
				$save_asset = true;
			}
		}

		if ( isset($fc_asset_rules['core.edit.state.own']) )
		{
			if ( !isset($com_content_rules['core.edit.state.own']) || $com_content_rules['core.edit.state.own'] != $fc_asset_rules['core.edit.state.own'] )
			{
				$com_content_rules['core.edit.state.own'] = $fc_asset_rules['core.edit.state.own'];
				$save_asset = true;
			}
		}

		if ( !isset($com_content_rules['core.delete.own']) )       $com_content_rules['core.delete.own'] = array();
		if ( !isset($com_content_rules['core.edit.state.own']) )   $com_content_rules['core.edit.state.own'] = array();

		if ($save_asset)
		{
			$rules = new JAccessRules($com_content_rules);
			$com_content_asset->rules = (string) $rules;
			if (!$com_content_asset->check() || !$com_content_asset->store())
			{
				throw new RuntimeException($com_content_asset->getError());
			}
			if ($debug_initial_perms) JFactory::getApplication()->enqueueMessage( 'Updated component asset with extra rules', 'notice' );
		}
		else {
			if ($debug_initial_perms) JFactory::getApplication()->enqueueMessage( 'No update needed for component asset with extra rules', 'notice' );
		}
	}
}