<?php
/**
 * @version   	   1.23.0
 * @package        Joomla
 * @subpackage     EDocman
 * @author         Ossolution
 * @copyright      Copyright (C) 2011 - 2025 Ossolution Team
 * @license        GNU/GPL, see LICENSE.php
 */

// No direct access
defined('_JEXEC') or die();

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Image\Image;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Table\Table;
use Joomla\CMS\Uri\Uri;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Form\FormHelper;
use Joomla\Utilities\ArrayHelper;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

/**
 * EDocman helper.
 */
class EDocmanHelper
{
	/**
	 * Method to call a static overridable helper method
	 *
	 * @param   string  $helper
	 * @param   string  $method
	 * @param   array   $methodArgs
	 *
	 * @return mixed
	 *
	 * @throws Exception
	 */
	public static function callOverridableHelperMethod($helper, $method, $methodArgs = [])
	{
		$callableMethods = [];

		if (strtolower($helper) == 'helper')
		{
			$helperMethod = 'EDocmanHelper::' . $method;
		}
		else
		{
			$helperMethod = 'EDocmanHelper' . ucfirst($helper) . '::' . $method;
		}

		$callableMethods[] = $helperMethod;

		$callableMethods[] = 'EDocmanHelperOverride' . ucfirst($helper) . '::' . $method;

		foreach (array_reverse($callableMethods) as $callable)
		{
			if (is_callable($callable))
			{
				return call_user_func_array($callable, $methodArgs);
			}
		}

		throw new Exception(sprintf('Method %s does not exist in the helper %s', $method, $helper));
	}

	public static function addScript($path, $unique_name = '')
	{
		if($unique_name == '')
		{
			$file_name = pathinfo($path, PATHINFO_FILENAME);
			$unique_name = "com_edocman.".$file_name;
		}
		$wa  = Factory::getApplication()->getDocument()->getWebAssetManager();
		$wa->registerAndUseScript($unique_name, $path);
	}

	public static function addStyleSheet($path, $unique_name = '')
	{
		if($unique_name == '')
		{
			$file_name = pathinfo($path, PATHINFO_FILENAME);
			$unique_name = "com_edocman.".$file_name;
		}
		$wa  = Factory::getApplication()->getDocument()->getWebAssetManager();
		$wa->registerAndUseStyle($unique_name, $path);
	}

	public static function addSideBarmenus($vName = '')
	{
	}
	
	/**
	 * Configure the Linkbar.
	 */
	public static function addSubmenus($vName = '')
	{
	}


	/**
	 * Get list of categories which the current user can perform a certain action
	 *
	 * @param $action
	 *
	 * @return mixed
	 */
	public static function getAuthorisedCategories($action)
	{
		$user = Factory::getApplication()->getIdentity();
		$db = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('*')
			->from('#__edocman_categories')
			->where('published = 1');
		$db->setQuery($query);
		$rows = $db->loadObjectList();
		for ($i =  0, $n = count($rows) ; $i < $n; $i++)
		{
			$row = $rows[$i];
			if (!$user->authorise($action, 'com_edocman.category.'.$row->id))
			{
				unset($rows[$i]);
			}
		}

		return $rows;
	}
	/**
	 * This function is used to find the link to possible views in the component
	 *
	 * @param array $views
	 *
	 * @return string|NULL
	 */
	public static function getViewUrl($views = array())
	{
		$app       = Factory::getApplication();
		$menus     = $app->getMenu('site');
		$component = ComponentHelper::getComponent('com_edocman');
		$items     = $menus->getItems('component_id', $component->id);
		foreach ($views as $view)
		{
			$viewUrl = 'index.php?option=com_edocman&view=' . $view;
			foreach ($items as $item)
			{
				if (strpos($item->link, $viewUrl) !== false)
				{
					if (strpos($item->link, 'Itemid=') === false)
					{
						return Route::_($item->link . '&Itemid=' . $item->id);
					}
					else
					{
						return Route::_($item->link);
					}
				}
			}
		}

		return null;
	}

	/**
	 * Get details information of a category based on it's id
	 *
	 * @param int $id
	 *
	 * @return object
	 */
	public static function getCategory($id)
	{
		$db    = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('*')
			->from('#__edocman_categories')
			->where('id=' . (int) $id);
		$db->setQuery($query);

		return $db->loadObject();
	}

	/**
	 * Function to load jQuery chosen plugin
	 */
	public static function chosen($selector = 'select')
	{
		static $chosenLoaded;
		if (!$chosenLoaded)
		{
			if (version_compare(JVERSION, '3.0', 'ge'))
			{
				HTMLHelper::_('formbehavior.chosen', $selector);
			}
			else
			{
				$document = Factory::getApplication()->getDocument();
				self::addScript(Uri::root() . 'components/com_edocman/assets/chosen/chosen.jquery.js');
				self::addStyleSheet(Uri::root() . 'components/com_edocman/assets/chosen/chosen.css');
				$document->getWebAssetManager()->addInlineScript(
					"jQuery(document).ready(function(){
                            jQuery(\"" . $selector . "\").chosen();
                        });");
			}
			$chosenLoaded = true;
		}
	}

	/**
	 * Gets a list of the actions that can be performed.
	 *
	 * @return JObject
	 */
	public static function getActions($view = 'categories', OSModelState $state = null)
	{
		$user   = Factory::getApplication()->getIdentity();
		$result = new CMSObject();
		switch ($view)
		{
			case 'categories':
				$assetName = 'com_edocman';
				break;
			case 'category':
				if ($state->id)
				{
					$assetName = 'com_edocman.category.' . $state->id;
				}
				else
				{
					$assetName = 'com_edocman';
				}
				break;
			case 'documents':
				if ($state->filter_category_id)
				{
					$assetName = 'com_edocman.category.' . $state->filter_category_id;
				}
				else
				{
					$assetName = 'com_edocman';
				}
				break;
			case 'document':
				if ($state->id)
				{
					$assetName = 'com_edocman.document.' . $state->id;
				}
				else
				{
					$assetName = 'com_edocman';
				}
				break;
			default:
				$assetName = 'com_edocman';
				break;
		}
		$actions = array('core.admin', 'core.manage', 'core.create', 'core.edit', 'core.edit.own', 'core.edit.state', 'core.delete');
		foreach ($actions as $action)
		{
			$result->set($action, $user->authorise($action, $assetName));
		}

		return $result;
	}

	/**
	 * Get list of parent categories
	 *
	 * @param $categoryId int
	 *                    the current category Id
	 *
	 * @return array list of parent categoies
	 */
	public static function getParentCategories($categoryId)
	{
		$db      = Factory::getContainer()->get('db');
		$parents = array();
		while (true)
		{
			if($categoryId > 0)
			{

				$sql = "SELECT id, title, parent_id, category_layout, notify_group_ids FROM #__edocman_categories WHERE id = " . $categoryId . " AND published=1";
				$db->setQuery($sql);
				$row = $db->loadObject();
				if ($row)
				{
					$sql = 'SELECT COUNT(*) FROM #__edocman_categories WHERE parent_id=' . $row->id;
					$db->setQuery($sql);
					$total               = $db->loadResult();
					$row->total_children = $total;
					$parents[]           = $row;
					$categoryId          = $row->parent_id;
				}
				else
				{
					break;
				}
			}
			else
			{
				break;
			}
		}

		return $parents;
	}

	public static function getCategoriesBreadcrumb($id, $parentId)
	{
		$db    = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('id, title, parent_id')
			->from('#__edocman_categories')
			->where('published=1');
		$db->setQuery($query);
		$categories = $db->loadObjectList('id');
		$paths      = array();
		while ($id != $parentId)
		{
			if (isset($categories[$id]))
			{
				$paths[] = $categories[$id];
				$id      = $categories[$id]->parent_id;
			}
			else
			{
				break;
			}
		}

		return $paths;
	}

	/**
	 * Count total documents from a given category and all it's sub-categories
	 *
	 * @param int $categoryId
	 *            the category which we want to get total documents
	 *
	 * @return int total documents
	 */
	public static function countDocuments($categoryId)
	{
		$config = EDocmanHelper::getConfig();
		$db     = Factory::getContainer()->get('db');
		$query  = $db->getQuery(true);
		$user   = Factory::getApplication()->getIdentity();
		$userId = $user->get('id');

		// Get all children categories of this category
		$categoryIds = EDocmanHelper::getAllChildrenCategories(array($categoryId));

		$query->select('COUNT(tbl.id)')
			->from('#__edocman_documents AS tbl');

		if (!$user->authorise('core.admin', 'com_edocman'))
		{
			$usergroup          = $user->groups;
			$usergroupArr       = array();
			$usergroupSql       = "";
			if(count($usergroup) > 0){
				foreach ($usergroup as $group){
					$usergroupArr[] = " (`groups`='$group' OR `groups` LIKE '$group,%' OR `groups` LIKE '%,$group,%' OR `groups` LIKE '%,$group') AND `data_type` = '1'";
				}
				$usergroupSql = implode(" OR ",$usergroupArr);
				$usergroupSql = " tbl.id in (Select item_id from #__edocman_levels where $usergroupSql) ";
				$usergroupSql = " OR ( (tbl.user_ids = '' OR tbl.user_ids = 0) AND tbl.accesspicker = '1' AND $usergroupSql ) ";
			}
			$groupQuery = EdocmanHelper::buildUserGroupQuery('tbl.owner_group_ids');
			$query->where('tbl.published=1')
				->where("(((tbl.user_ids = '' OR tbl.user_ids = 0) AND tbl.access IN (" . implode(',', $user->getAuthorisedViewLevels()) . ")) $usergroupSql $groupQuery OR tbl.user_ids='$userId' OR tbl.user_ids LIKE '$userId,%' OR tbl.user_ids LIKE '%,$userId,%' OR tbl.user_ids LIKE '%,$userId' OR (tbl.created_user_id=$userId AND tbl.created_user_id > 0))");
		}

		$query->where('tbl.id IN (SELECT document_id FROM #__edocman_document_category WHERE category_id IN(' . implode(',', $categoryIds) . '))');

		// Filter by start and end dates.
		if ((!$user->authorise('core.edit.state', 'com_edocman')) && (!$user->authorise('core.edit', 'com_edocman')))
		{
			$nullDate = $db->quote($db->getNullDate());
			$nowDate  = $db->quote(Factory::getDate()->toSql());
			$query->where('(tbl.publish_up = ' . $nullDate . ' OR tbl.publish_up <= ' . $nowDate . ')')
				->where('(tbl.publish_down = ' . $nullDate . ' OR tbl.publish_down >= ' . $nowDate . ')');
		}

		// Multilingual filter
		if ($config->activate_multilingual_feature && Factory::getApplication()->getLanguageFilter())
		{
			$query->where('tbl.language IN (' . $db->Quote(Factory::getLanguage()->getTag()) . ',' . $db->Quote('*') . ', "")');
		}

		$db->setQuery($query);

		return (int) $db->loadResult();
	}

	/**
	 *
	 * @param $items
	 * @param $numberDaysForNew
	 */
	public static function setNewIndicator($items, $numberDaysForNew)
	{
		foreach($items as $item)
		{
			if ($item->number_created_days <= $numberDaysForNew)
			{
				$item->new_indicator = 1;
			}
		}
	}

	/**
	 *
	 * @param $items
	 * @param $numberDaysForNew
	 */
	public static function setUpdateIndicator($items, $numberDaysForUpdatew)
	{
		foreach($items as $item)
		{
			if ($item->number_updated_days <= $numberDaysForUpdatew)
			{
				$item->update_indicator = 1;
			}
		}
	}
	/**
	 * Display copyright of the extension
	 */
	public static function displayCopyright()
	{
		//echo '<div class="clearfix"></div><div class="copyright" style="text-align:center;margin-top: 5px;"><a href="http://joomdonation.com/components/edocman.html" target="_blank"><strong>EDocman</strong></a> version ' . self::getInstalledVersion() . ', Copyright (C) 2011-' .
			//date('Y') . ' <a href="http://joomdonation.com" target="_blank"><strong>Ossolution Team</strong></a></div>';

		?>
		<footer class="bg-white text-center py-3 mt-5 shadow-sm rounded" style="max-width: 100%; margin: 40px auto 0 auto;">
			<small class="text-muted">
				<i class="fas fa-copyright me-1"></i>
				<a href="http://joomdonation.com/components/edocman.html" target="_blank" class="text-primary fw-semibold text-decoration-none">
					EDocman
				</a>
				version <?php echo self::getInstalledVersion(); ?>, Copyright &copy; 2011-<?php echo date('Y'); ?>
				<a href="http://joomdonation.com" target="_blank" class="text-primary fw-semibold text-decoration-none">
					Ossolution Team
				</a>
			</small>
		</footer>

		<?php
	}

	/**
	 * Load language
	 */
	public static function loadLanguage()
	{
		static $loaded;
		if (!$loaded)
		{
			$lang = Factory::getApplication()->getLanguage();
			$tag  = $lang->getTag();
			if (!$tag)
			{
				$tag = 'en-GB';
			}
			$lang->load('com_edocman', JPATH_ROOT, $tag);
			$loaded = true;
		}
	}

	public static function getItemid($itemId = 0)
	{
		require_once JPATH_ROOT.'/components/com_edocman/helper/route.php';

		$views = array('categories', 'category', 'document');

		foreach($views as $view)
		{
			if ($item = EDocmanHelperRoute::findView($view, $itemId))
			{
				return $item;
			}
		}

		return 0;
	}


	/**
	 * Get config value from database
	 *
	 * @param string $configKey
	 * @param string $default
	 */
	public static function getConfigValue($configKey, $default = null)
	{
		static $configValues;
		if (!isset($configValues["$configKey"]))
		{
			$db  = Factory::getContainer()->get('db');
			$sql = 'SELECT config_value FROM #__edocman_configs WHERE config_key="' . $configKey . '"';
			$db->setQuery($sql);
			$configValues[$configKey] = $db->loadResult();
		}

		return $configValues[$configKey] ? $configValues[$configKey] : $default;
	}

	/**
	 *
	 *
	 * Resize image to a pre-defined size
	 *
	 * @param string $srcFile
	 * @param string $desFile
	 * @param int    $thumbWidth
	 * @param int    $thumbHeight
	 * @param string $method
	 *            gd1 or gd2
	 * @param int    $quality
	 */
	public static function resizeImage($srcFile, $desFile, $thumbWidth, $thumbHeight)
	{
        /*
		$image = new JImage($srcFile);
		$image->resize($thumbWidth, $thumbHeight, false);
		$image->toFile($desFile);
        */
        require_once(JPATH_ROOT.'/components/com_edocman/helper/images.php');
        if($thumbWidth > 0 && $thumbHeight == 0)
        {
            $info = getimagesize($srcFile);
            $width = $info[0];
            $height = $info[1];
            $thumbHeight = round($thumbWidth * $height / $width);
        }
        else if($thumbWidth == 0 && $thumbHeight > 0)
        {
            $info = getimagesize($srcFile);
            $width = $info[0];
            $height = $info[1];
            $thumbWidth = round($thumbHeight * $width / $height);
        }
        else if($thumbWidth == 0 && $thumbHeight == 0)
        {
            $thumbWidth = 100;
            $info = getimagesize($srcFile);
            $width = $info[0];
            $height = $info[1];
            $thumbHeight = round($thumbWidth * $height / $width);
        }
        OsImageHelper::createImage($srcFile, $desFile, $thumbWidth, $thumbHeight, true, 100);
		return true;
	}

	/**
	 * Get configuration object
	 */
	public static function getConfig()
	{
		static $config;
		if ($config == null)
		{
			$config = new stdClass();
			$db     = Factory::getContainer()->get('db');
			$sql    = 'SELECT * FROM #__edocman_configs';
			$db->setQuery($sql);
			$rows = $db->loadObjectList();
			for ($i = 0, $n = count($rows); $i < $n; $i++)
			{
				$row            = $rows[$i];
				$key            = $row->config_key;
				$value          = $row->config_value;
				$config->{$key} = $value;
			}
		}

		return $config;
	}


	public static function loadConfig()
	{
		static $config;

		if ($config === null)
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_edocman/libraries/rad/config/config.php';

			$config = new OSConfig('#__edocman_configs');
		}
		return $config;
	}
 

	/**
	 * Generate User Input Select
	 *
	 * @param int $userId
	 */
	public static function getUserInput($userIds, $multipleUser = true)
	{
		self::loadJQuery();
		if (Factory::getApplication()->isClient('site') || version_compare(JVERSION, '4.0.0-dev', 'lt'))
		{
			$app = Factory::getApplication();
			// Initialize variables.
			$html = array();
			$link = Uri::root().'index.php?option=com_edocman&amp;view=users&amp;layout=modal&amp;tmpl=component&amp;field=user_id';
			// Initialize some field attributes.
			$attr = ' class="input-large form-control"';
			// Load the modal behavior script.
			//JHtml::_('behavior.modal', 'a.modal_user_id');
			EDocmanHelperJquery::colorbox('modal_user_id');
			// Build the script.
			$script   = array();
			$script[] = '	function jSelectUser_user_id(id, title) {';
			$script[] = '		var old_ids = document.getElementById("jform_user_ids").value;';
			$script[] = '		if (old_ids) {';
			$script[] = '			document.getElementById("jform_user_ids").value = old_ids + "," + id;';
			$script[] = '		} else {';
			$script[] = '			document.getElementById("jform_user_ids").value = id; ';
			$script[] = '		}';
			$script[] = '		parent.jQuery.colorbox.close(); return false;';
			$script[] = '	}';
			
			

			// Add the script to the document head.
			Factory::getApplication()->getDocument()->getWebAssetManager()->addInlineScript(implode("\n", $script));
			// Load the current username if available.
			// Create a dummy text field with the user name.
			$html[] = '<div class="input-append btn-group">';
			$html[] = '	<input type="text" name="jform[user_ids]" id="jform_user_ids"' . ' value="' . $userIds . '"' . $attr . ' />';
			// Create the user select button.
			$html[] = '<a class="modal_user_id btn btn-primary" title="' . Text::_('JLIB_FORM_CHANGE_USER') . '"' . ' href="' . $link . '"' .
				' rel="{handler: \'iframe\', size: {x: 800, y: 500}}">';
			$html[] = '	<i class="icon-user icon-white"></i></a>';
			$html[] = '</div>';

			return implode("\n", $html);
		}
		else
		{
			HTMLHelper::_('jquery.framework');
			$field = FormHelper::loadFieldType('User');
            $element = new SimpleXMLElement('<field />');
            $element->addAttribute('name', 'jform[user_ids]');
            $element->addAttribute('class', 'readonly');
			$element->addAttribute('type', 'user');
            $field->setup($element, $userIds);

            return $field->input;
		}
	}

	public static function getUserInputBackend($userIds, $multipleUser = true)
	{
		self::loadJQuery();
		
		$html = array();
		$link = Uri::root().'index.php?option=com_edocman&amp;view=users&amp;layout=modal&amp;tmpl=component&amp;field=user_id';
		
		// Load required assets for Joomla 4+
		$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
		$wa->useScript('bootstrap.modal');
		$wa->useScript('jquery');
		
		// Build the script for Joomla 4+
		$script = array();
		$script[] = 'window.jSelectUser_user_id = function(id, title) {';
		$script[] = '    var userIdsField = document.getElementById("jform_user_ids");';
		$script[] = '    if (userIdsField) {';
		$script[] = '        var currentIds = userIdsField.value ? userIdsField.value.split(",") : [];';
		$script[] = '        // Kiểm tra user đã tồn tại chưa';
		$script[] = '        if (currentIds.indexOf(id.toString()) === -1) {';
		if ($multipleUser) {
			$script[] = '            if (userIdsField.value) {';
			$script[] = '                userIdsField.value = userIdsField.value + "," + id;';
			$script[] = '            } else {';
			$script[] = '                userIdsField.value = id;';
			$script[] = '            }';
			$script[] = '            // Cập nhật danh sách hiển thị';
			$script[] = '            updateUserList();';
		} else {
			$script[] = '            userIdsField.value = id;';
			$script[] = '            updateUserList();';
		}
		$script[] = '        } else {';
		$script[] = '            alert("' . Text::_('User already selected') . '");';
		$script[] = '        }';
		$script[] = '    }';
		$script[] = '    // Close modal';
		$script[] = '    var modals = document.querySelectorAll(".modal.show");';
		$script[] = '    modals.forEach(function(modal) {';
		$script[] = '        var modalInstance = bootstrap.Modal.getInstance(modal);';
		$script[] = '        if (modalInstance) modalInstance.hide();';
		$script[] = '    });';
		$script[] = '    return false;';
		$script[] = '};';
		
		// Function to update user list display
		$script[] = 'function updateUserList() {';
		$script[] = '    var userIdsField = document.getElementById("jform_user_ids");';
		$script[] = '    var userListDiv = document.getElementById("selected_users_list");';
		$script[] = '    if (!userIdsField.value) {';
		$script[] = '        userListDiv.innerHTML = "<em>' . Text::_('No users selected') . '</em>";';
		$script[] = '        return;';
		$script[] = '    }';
		$script[] = '    var userIds = userIdsField.value.split(",");';
		$script[] = '    var html = "";';
		$script[] = '    userIds.forEach(function(userId) {';
		$script[] = '        if (userId.trim()) {';
		$script[] = '            html += "<div class=\"badge bg-primary me-2 mb-2 d-flex align-items-center\">";';
		$script[] = '            html += "<span class=\"me-2\">User ID: " + userId + "</span>";';
		$script[] = '            html += "<button type=\"button\" class=\"btn-close btn-close-white\" ";';
		$script[] = '            html += "onclick=\"removeUser(\'" + userId + "\')\"></button>";';
		$script[] = '            html += "</div>";';
		$script[] = '        }';
		$script[] = '    });';
		$script[] = '    userListDiv.innerHTML = html;';
		$script[] = '}';
		
		// Function to remove user
		$script[] = 'function removeUser(userId) {';
		$script[] = '    var userIdsField = document.getElementById("jform_user_ids");';
		$script[] = '    var currentIds = userIdsField.value.split(",");';
		$script[] = '    var newIds = currentIds.filter(function(id) {';
		$script[] = '        return id.trim() !== userId.trim();';
		$script[] = '    });';
		$script[] = '    userIdsField.value = newIds.join(",");';
		$script[] = '    updateUserList();';
		$script[] = '}';
		
		// Function to clear all users
		$script[] = 'function clearAllUsers() {';
		$script[] = '    document.getElementById("jform_user_ids").value = "";';
		$script[] = '    updateUserList();';
		$script[] = '}';
		
		// Initialize on page load
		$script[] = 'document.addEventListener("DOMContentLoaded", function() {';
		$script[] = '    updateUserList();';
		$script[] = '});';

		// Add the script
		$wa->addInlineScript(implode("\n", $script));
		
		// Create HTML with Bootstrap 5 modal
		$modalId = 'userSelectModal_' . uniqid();
		
		$html[] = '<div class="user-selector-container">';
		
		// Hidden input field
		$html[] = '<input type="hidden" name="jform[user_ids]" id="jform_user_ids" value="' . htmlspecialchars($userIds) . '" />';
		
		// Control buttons
		$html[] = '<div class="mb-3">';
		$html[] = '    <button type="button" class="btn btn-primary me-2" data-bs-toggle="modal" data-bs-target="#' . $modalId . '">';
		$html[] = '        <span class="icon-user" aria-hidden="true"></span> ' . Text::_('JLIB_FORM_SELECT_USER');
		$html[] = '    </button>';
		$html[] = '    <button type="button" class="btn btn-outline-danger" onclick="clearAllUsers()">';
		$html[] = '        <span class="icon-delete" aria-hidden="true"></span> ' . Text::_('EDOCMAN_CLEAR_ALL');
		$html[] = '    </button>';
		$html[] = '</div>';
		
		// Selected users display area
		$html[] = '<div class="selected-users-area">';
		$html[] = '    <label class="form-label">' . Text::_('EDOCMAN_SELECTED_OWNERS') . ':</label>';
		$html[] = '    <div id="selected_users_list" class="p-2 border rounded bg-light min-height-50">';
		$html[] = '        <em>' . Text::_('No users selected') . '</em>';
		$html[] = '    </div>';
		$html[] = '</div>';
		
		// Modal HTML
		$html[] = '<div class="modal fade" id="' . $modalId . '" tabindex="-1" aria-labelledby="' . $modalId . 'Label" aria-hidden="true">';
		$html[] = '    <div class="modal-dialog modal-lg">';
		$html[] = '        <div class="modal-content">';
		$html[] = '            <div class="modal-header">';
		$html[] = '                <h5 class="modal-title" id="' . $modalId . 'Label">' . Text::_('JLIB_FORM_SELECT_USER') . '</h5>';
		$html[] = '                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>';
		$html[] = '            </div>';
		$html[] = '            <div class="modal-body p-0">';
		$html[] = '                <iframe src="' . $link . '" width="100%" height="500" frameborder="0" style="border: none;"></iframe>';
		$html[] = '            </div>';
		$html[] = '        </div>';
		$html[] = '    </div>';
		$html[] = '</div>';
		
		$html[] = '</div>';
		
		// Add some CSS
		$css = '
		.user-selector-container .min-height-50 {
			min-height: 50px;
		}
		.user-selector-container .badge {
			font-size: 0.875em;
		}
		.user-selector-container .btn-close-white {
			font-size: 0.75em;
		}
		';
		$wa->addInlineStyle($css);

		return implode("\n", $html);
	}


	public static function processMassDownload($filePath, $filename = 'massdownload.zip')
    {

        $cont_dis = 'attachment';
        $config   = EDocmanHelper::getConfig();
        $fsize    = @filesize($filePath);
        $mod_date = date('r', filemtime($filePath));
        $ext      = 'zip';
        $mime     = 'application/zip';

        $stream = fopen($filePath, 'rb');
        if ($stream === false)
        {
            return false;
        }

        // required for IE, otherwise Content-disposition is ignored
        if (ini_get('zlib.output_compression'))
        {
            ini_set('zlib.output_compression', 'Off');
        }
        header("Pragma: public");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Expires: 0");
        header("Content-Transfer-Encoding: binary");
        header(
            'Content-Disposition:' . $cont_dis . ';' . ' filename="'.$filename.'";' . ' modification-date="' .
            $mod_date . '";' . ' size=' . $fsize . ';'); // RFC2183
        header("Content-Type: " . $mime); // MIME type
        header("Content-Length: " . $fsize);

        if (!ini_get('safe_mode'))
        { // set_time_limit doesn't work in safe mode
            @set_time_limit(0);
        }
        EDocmanHelper::readfile_chunked($stream);
    }

	public static function processDocumentCsv($filePath, $filename = '')
    {

		if($filename == '')
		{
			$filename = 'document.csv';
		}
        $cont_dis = 'attachment';
        $config   = EDocmanHelper::getConfig();
        $fsize    = @filesize($filePath);
        $mod_date = date('r', filemtime($filePath));
        $ext      = 'csv';
        $mime     = 'text/x-comma-separated-values';

        $stream = fopen($filePath, 'rb');
        if ($stream === false)
        {
            return false;
        }

        // required for IE, otherwise Content-disposition is ignored
        if (ini_get('zlib.output_compression'))
        {
            ini_set('zlib.output_compression', 'Off');
        }
        header("Pragma: public");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Expires: 0");
        header("Content-Transfer-Encoding: binary");
        header(
            'Content-Disposition:' . $cont_dis . ';' . ' filename="'.$filename.'";' . ' modification-date="' .
            $mod_date . '";' . ' size=' . $fsize . ';'); // RFC2183
        header("Content-Type: " . $mime); // MIME type
        header("Content-Length: " . $fsize);

        if (!ini_get('safe_mode'))
        { // set_time_limit doesn't work in safe mode
            @set_time_limit(0);
        }
        EDocmanHelper::readfile_chunked($stream);
    }
	/**
	 * Process downloading file
	 *
	 * @param string $filePath
	 *            Path to the file
	 * @param string $filename
	 *            Name of the file
	 */
    public static function processDownload($filePath, $filename, $original_filename, $download = false, $fileid = 0, $cloud_id = '')
	{
		PluginHelper::importPlugin('edocman');
		$app = Factory::getApplication();
		$results = $app->triggerEvent('onGetDocumentFile', array($filename, $fileid, $cloud_id));
		
		$result = null;
		if (count($results)) {
			foreach ($results as $res) {
				if (!empty($res)) {
					$result = $res;
					break;
				}
			}
		}

		$cont_dis = $download ? 'attachment' : 'inline';
		
		if (!empty($result)) {
			$stream   = $result['stream'];
			$fsize    = $result['Content-Length'];
			$mod_date = $result['modification-date'];
			$mime     = $result['Content-Type'];
		} else {
			$config   = EDocmanHelper::getConfig();
			$filePath = $config->documents_path . '/' . $filename;
			
			// Kiểm tra file tồn tại
			if (!file_exists($filePath)) {
				return false;
			}
			
			$fsize    = filesize($filePath);
			$mod_date = date('r', filemtime($filePath));
			$ext      = self::getFileExt($filename);
			$mime     = EDocmanHelper::getMimeType($ext);

			$stream = fopen($filePath, 'rb');
			if ($stream === false) {
				return false;
			}
		}

		// Tắt compression
		if (ini_get('zlib.output_compression')) {
			ini_set('zlib.output_compression', 'Off');
		}
		
		// Clear any previous output
		if (ob_get_level()) {
			ob_end_clean();
		}

		// Set headers theo thứ tự đúng
		header("Content-Type: " . $mime);
		header("Content-Length: " . $fsize);
		header('Content-Disposition: ' . $cont_dis . '; filename="' . 
			(strlen($original_filename) ? basename($original_filename) : basename($filename)) . '"');
		header("Content-Transfer-Encoding: binary");
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Pragma: public");
		header("Expires: 0");

		if (!ini_get('safe_mode')) {
			@set_time_limit(0);
		}
		
		self::readfile_chunked($stream);
	}


	/**
	 * Process downloading file
	 *
	 * @param string $filePath
	 *            Path to the file
	 * @param string $filename
	 *            Name of the file
	 */
    public static function processDownloadtotmp($filePath,$filename,$original_filename, $download = false, $fileid = 0, $folder = 'edocmanviewer')
    {
		if(! is_dir(Path::clean(JPATH_ROOT.'/'.$folder)))
		{
			Folder::create(JPATH_ROOT.'/'.$folder);
		}
        PluginHelper::importPlugin('edocman');
        $app = Factory::getApplication();

        $results = $app->triggerEvent('onGetDocumentFile', array($filename, $fileid));
        if (count($results))
        {
            foreach ($results as $result)
            {
                if (!empty($result))
                {
                    break;
                }
            }
        }

        if ($download)
        {
            $cont_dis = 'attachment';
        }
        else
        {
            $cont_dis = 'inline';
        }
        if (!empty($result))
        {
            $stream   = $result['stream'];
            $fsize    = $result['Content-Length'];
            $mod_date = $result['modification-date'];
            $mime     = $result['Content-Type'];
        }
        else
        {
            $config   = EDocmanHelper::getConfig();
            $filePath = $config->documents_path . '/' . $filename;
            $fsize    = @filesize($filePath);
            $mod_date = date('r', filemtime($filePath));
            $ext      = self::getFileExt($filename);
            $mime     = EDocmanHelper::getMimeType($ext);

            $stream = fopen($filePath, 'rb');
            if ($stream === false)
            {
                return false;
            }
        }
        // required for IE, otherwise Content-disposition is ignored
		$filename = (strlen($original_filename) ? basename($original_filename) : basename($filename));
		if($folder == "edocmanviewer")
		{
			$fileExtension = substr(strrchr($filename, '.'), 1);
			$filename      = md5($filename . time()) . '.' . $fileExtension;
		}
		else
		{
			$filename = str_replace(" ","_", $filename);
			$filename = str_replace(".".$ext,"", $filename);
			$filename = str_replace(".","_", $filename);
			$filename = str_replace("&","", $filename);
			$filename .= ".".$ext;
		}
		//if(!File::exists(JPATH_ROOT.'/'.$folder.'/'.$filename))
		//{
		//always download to update latest version of file
		file_put_contents(JPATH_ROOT.'/'.$folder.'/'.$filename, $stream);
		//}
        if(file_exists(JPATH_ROOT.'/'.$folder.'/'.$filename))
        {
			if($folder == "edocmanviewer")
			{
				return $filename;
			}
			else
			{
				//for indexing purpose
				return JPATH_ROOT.'/'.$folder.'/'.$filename;
			}
        }
        else
        {
            return '';
        }
    }

    /**
     * Get mimetype of a file
     *
     * @return string
     */
    public static function getMimeType($ext)
    {
        require_once JPATH_ROOT . "/components/com_edocman/helper/mime.mapping.php";
        foreach ($mime_extension_map as $key => $value)
        {
            if ($key == $ext)
            {
                return $value;
            }
        }

        return "";
    }

    /**
     * Read file
     *
     * @param string $filename
     * @param        $retbytes
     *
     * @return unknown
     */
    public static function readfile_chunked($handle, $retbytes = true)
    {
        $chunksize = 1 * (1024 * 1024); // how many bytes per chunk
        $buffer    = '';
        $cnt       = 0;
        while (!feof($handle))
        {
            $buffer = fread($handle, $chunksize);
            echo $buffer;
            @ob_flush();
            flush();
            if ($retbytes)
            {
                $cnt += strlen($buffer);
            }
        }

        $status = null;
        if (is_resource($handle))
        {
            $status = fclose($handle);
        }

        if ($retbytes && $status)
        {
            return $cnt; // return num. bytes delivered like readfile() does.
        }

        return $status;
    }

	/**
	 * Check to see whether users can access to the category
	 *
	 * @param int $categoryId
	 *            Id of the category users accessing to
	 *
	 * @return boolean true if users can access, fail if not
	 *
     * Update version 1.9.10
	 */
	public static function canAccessCategory($categoryId)
	{
		$user  = Factory::getApplication()->getIdentity();
		$db    = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('*')
			->from('#__edocman_categories')
			->where('id = ' . $categoryId);
		$db->setQuery($query);
		$row = $db->loadObject();

		// Invalid category, so of course, it could not be accessed
		if (!$row)
		{
			return false;
		}

		// Users with super admin permission should be able to access all categories
		if ($user->authorise('core.admin'))
		{
			return true;
		}

		if ($row->user_ids != "" || $row->owner_group_ids != "")
		{
			if($row->user_ids != "")
			{
				$userIds = explode(',', $row->user_ids);
				if (in_array($user->get('id'), $userIds))
				{
					return true;
				}
			}

			if($row->owner_group_ids != "")
			{
				$usergroups = $user->groups;
				
				$owner_group_ids = explode(",", $row->owner_group_ids);
				if(count($owner_group_ids) > 0 && count($usergroups) > 0)
				{
					foreach($usergroups as $group)
					{
						if(in_array($group,$owner_group_ids))
						{
							return true;
						}
					}
				}          
			}
		}
		else
		{
		    if($row->accesspicker == 0) 
			{
                if (!in_array($row->access, $user->getAuthorisedViewLevels())) 
				{
                    return false;
                }
            }
			else
			{
                $usergroup          = $user->groups;
                if(count($usergroup) > 0)
				{
                    foreach ($usergroup as $group)
					{
                        $query->clear();
                        $query->select('count(id)')->from('#__edocman_levels')->where('data_type = 0')->where('(`groups`="'.$group.'" OR `groups` LIKE "'.$group.',%" OR `groups` LIKE "%,'.$group.',%" OR `groups` LIKE "%,'.$group.'")')->where('item_id = "'.$categoryId.'"');
                        $db->setQuery($query);
                        $count = $db->loadResult();
                        if($count > 0){
                            return true;
                        }
                    }
					return false;
                }
				return false;
            }
		}

		return true;
	}

	/**
	 * Check to see whether users can access to a document
	 *
	 * @param int $documentId
	 *
	 * @return boolean
	 */
	public static function canAccessDocument($documentId)
	{
		$user  = Factory::getApplication()->getIdentity();
		$db    = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('*')
			->from('#__edocman_documents')
			->where('id = ' . $documentId);
		$db->setQuery($query);
		$row = $db->loadObject();
		if (!$row)
		{
			return false;
		}

		// Users has super admin permission should be able to access to all documents
		if ($user->authorise('core.admin'))
		{
			return true;
		}

		// Owner of the document of course can viwe it
		if ($user->id == $row->created_user_id)
		{
			return true;
		}
		if (($row->user_ids != "" && $row->user_ids != 0) || $row->owner_group_ids != "")
		{
			$userIds = explode(',', $row->user_ids);
			if (in_array($user->id, $userIds))
			{
				return true;
			}

			if($row->owner_group_ids != "")
			{
				$usergroups = $user->groups;
				if($row->owner_group_ids != "")
				{
					$owner_group_ids = explode(",", $row->owner_group_ids);
					if(count($owner_group_ids) > 0 && count($usergroups) > 0)
					{
						foreach($usergroups as $group)
						{
							if(in_array($group,$owner_group_ids))
							{
								return true;
							}
						}
					}
				}
			}

			return false;
		}
		else
		{
			$assetName = 'com_edocman.document.' . $documentId;
			if ($user->authorise('core.edit', $assetName) || $user->authorise('core.delete', $assetName) || $user->id == $row->created_user_id)
			{
				return true;
			}
			elseif (!in_array($row->access, $user->getAuthorisedViewLevels())  && $row->accesspicker == 0)
			{
				return false;
			}
			elseif($row->accesspicker == 1)
			{
				$usergroup          = $user->groups;
                if(count($usergroup) > 0){
                    foreach ($usergroup as $group){
                        $query->clear();
                        $query->select('count(id)')->from('#__edocman_levels')->where('data_type = 1')->where('(`groups`="'.$group.'" OR `groups` LIKE "'.$group.'%" OR `groups` LIKE "%,'.$group.',%" OR `groups` LIKE "%,'.$group.'")')->where('item_id = "'.$documentId.'"');
                        $db->setQuery($query);
                        $count = $db->loadResult();
                        if($count > 0){
                            return true;
                        }
                    }
                }
				return false;
			}
		}

		return true;
	}

	/**
	 * Send upload notification emails to administrator when someone upload document from front-end
	 *
	 * @param object $row
	 *            Document object
	 * @param object $config
	 *            Configuration data
	 */
	static function sendUploadNotificationEmail($row, $config, $categoryId)
	{
		$jconfig = new JConfig();
		$user    = Factory::getApplication()->getIdentity();
		$subject = $config->upload_email_subject;
		$body    = nl2br($config->upload_email_body);
		if ($user->id)
		{
			$username = $user->username;
			$name     = $user->name;
		}
		else
		{
			$username = Text::_('EDOCMAN_GUEST');
			$name     = Text::_('EDOCMAN_GUEST');
		}
		$category			= self::getCategory($categoryId);
		$userIp             = @$_SERVER['REMOTE_ADDR'];
		$documentTitle      = $row->title;
		$documentShortDesc  = $row->short_description;
		$documentDesc		= $row->description;
		$body               = str_replace('[USERNAME]', $username, $body);
		$body               = str_replace('[NAME]', $name, $body);
		$body               = str_replace('[USER_IP]', $userIp, $body);
		$body               = str_replace('[DOCUMENT_TITLE]', $documentTitle, $body);
		$body               = str_replace('[DOCUMENT_SHORT_DESC]', $documentShortDesc, $body);
		$body               = str_replace('[DOCUMENT_DESC]', $documentDesc, $body);
		$body				= str_replace('[CATEGORY]', $category->title, $body);
		$document_link      = Uri::root().'administrator/index.php?option=com_edocman&task=document.edit&id='.$row->id;
		$body               = str_replace('[DOCUMENT_LINK]', $document_link, $body);
		$body				= self::convertImgTags($body);
		$subject		    = str_replace('[DOCUMENT_TITLE]', $documentTitle, $subject);
		$mailer             = Factory::getMailer();
		$notificationEmails = '';
		if ($categoryId)
		{
			$db = Factory::getContainer()->get('db');
			while ($categoryId > 0)
			{
				$sql = 'SELECT parent_id, notification_emails FROM #__edocman_categories WHERE id=' . $categoryId;
				$db->setQuery($sql);
				$rowCategory        = $db->loadObject();
				$notificationEmails = $rowCategory->notification_emails;
				$categoryId         = $rowCategory->parent_id;
				if ($notificationEmails)
				{
					break;
				}
			}
		}
		if (!$notificationEmails)
		{
			$notificationEmails = trim($config->notification_emails);
		}
		if (strlen($notificationEmails) < 5)
		{
			$notificationEmails = $jconfig->mailfrom;
		}
		$notificationEmails = explode(',', $notificationEmails);
		for ($i = 0, $n = count($notificationEmails); $i < $n; $i++)
		{
			$email = trim($notificationEmails[$i]);
			if ($email)
			{
				try
				{
					$mailer->sendMail($jconfig->mailfrom, $jconfig->fromname, $email, $subject, $body, 1);
				}
				catch (Exception $e)
				{
					Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning');
				}
				$mailer->ClearAllRecipients();
			}
		}
	}

	/**
	 * Send document approval notification emails to created user when their document is published
	 *
	 * @param object $row
	 *            Document object
	 * @param object $config
	 *            Configuration data
	 */
	static function sendUploadApprovalEmail($row, $config)
	{
		$jconfig = new JConfig();
		if($row->created_user_id > 0)
		{
			$user				= Factory::getUser($row->created_user_id);
			$subject			= $config->document_approved_subject;
			$body				= nl2br($config->document_approved_body);
			if ($user->id)
			{
				$username		= $user->username;
				$name			= $user->name;
			}
			else
			{
				$username = Text::_('EDOCMAN_GUEST');
				$name     = Text::_('EDOCMAN_GUEST');
			}
			$category			= self::getCategory($categoryId);
			$userIp             = @$_SERVER['REMOTE_ADDR'];
			$documentTitle      = $row->title;
			$documentShortDesc  = $row->short_description;
			$documentDesc		= $row->description;
			$body               = str_replace('[USERNAME]', $username, $body);
			$body               = str_replace('[NAME]', $name, $body);
			$body               = str_replace('[USER_IP]', $userIp, $body);
			$body               = str_replace('[DOCUMENT_TITLE]', $documentTitle, $body);
			$body               = str_replace('[DOCUMENT_SHORT_DESC]', $documentShortDesc, $body);
			$body               = str_replace('[DOCUMENT_DESC]', $documentDesc, $body);
			$body				= str_replace('[CATEGORY]', $category->title, $body);
			$document_link      = Uri::root().'administrator/index.php?option=com_edocman&task=document.edit&id='.$row->id;
			$body               = str_replace('[DOCUMENT_LINK]', $document_link, $body);
			$body				= self::convertImgTags($body);
			$subject		    = str_replace('[DOCUMENT_TITLE]', $documentTitle, $subject);
			$mailer             = Factory::getMailer();
			$email				= $user->email;
			
			if ($email && $subject != "" && $body != "")
			{
				try
				{
					$mailer->sendMail($jconfig->mailfrom, $jconfig->fromname, $email, $subject, $body, 1);
				}
				catch (Exception $e)
				{
					Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning');
				}
				$mailer->ClearAllRecipients();
			}
		}
	}

	/**
	 *
	 * @param Boolean $loadJs
	 */
	public static function loadBootstrap($loadJs = true)
	{
		$document = Factory::getApplication()->getDocument();
		/*
		EdocmanHelper::addStyleSheet(Uri::root() . 'components/com_edocman/assets/bootstrap/css/bootstrap.css');
		if (Factory::getApplication()->isClient('administrator'))
		{
			EdocmanHelper::addStyleSheet(Uri::root() . 'components/com_edocman/assets/bootstrap/css/bootstrap-tabs.css');
		}
		if ($loadJs)
		{
			self::loadJQuery();
			EdocmanHelper::addScript(Uri::root() . 'components/com_edocman/assets/bootstrap/js/bootstrap.min.js');
		}
		*/
	}

	/**
	 * Load jQuery library
	 */
	public static function loadJQuery()
	{
		$document = Factory::getApplication()->getDocument();
		HTMLHelper::_('jquery.framework');
		EdocmanHelper::addScript(Uri::root() . 'components/com_edocman/assets/js/noconflict.js');
		
		//HTMLHelper::_('bootstrap.loadCss');
	}

	/**
	 * Load bootstrap js
	 */
	public static function loadBootstrapJs()
	{
		if (version_compare(JVERSION, '3.0', 'ge'))
		{
			HTMLHelper::_('script', 'jui/bootstrap.min.js', false, true, false, false, false);
		}
		else
		{
			EdocmanHelper::addScript(Uri::root(true) . '/components/com_edocman/assets/bootstrap/js/bootstrap.min.js');
		}
	}

	/**
	 * Send notification emails to users who are assigned the document to
	 *
	 * @param object $row
	 *            Document object
	 */
	public static function sendDocumentAssignedEmails($row, $oldUserIds)
	{
		$mailer  = Factory::getMailer();
		$db      = Factory::getContainer()->get('db');
		$jconfig = new JConfig();
		$config  = self::getConfig();
		$category= self::getDocumentCategory($row->id);
		$user    = Factory::getApplication()->getIdentity();
		$subject = $config->document_assigned_email_subject;
		$body    = nl2br($config->document_assigned_email_body);
		$userIds = $row->user_ids;
		if ($user->id)
		{
			$username = $user->username;
			$name     = $user->name;
		}
		$documentTitle = $row->title;
		// subject Email
		$subject = str_replace('[OWNER_USERNAME]', $username, $subject);
		$subject = str_replace('[OWNER_NAME]', $name, $subject);
		$subject = str_replace('[DOCUMENT_TITLE]', $documentTitle, $subject);

		// body email
		$body = str_replace('[CATEGORY]', $category->title, $body);
		$body = str_replace('[OWNER_USERNAME]', $username, $body);
		$body = str_replace('[OWNER_NAME]', $name, $body);
		$body = str_replace('[DOCUMENT_TITLE]', $documentTitle, $body);
		$body = self::convertImgTags($body);
		// get Name Email
		$query = $db->getQuery(true);
		$query->select('id, username, name, email');
		$query->from($db->quoteName('#__users'));
		$query->where($db->quoteName('id') . 'IN (' . $userIds . ')');
		$db->setQuery($query);
		$documentEmails = $db->loadObjectList();
		$oldUserIds     = explode(',', $oldUserIds);
		ArrayHelper::toInteger($oldUserIds);
		for ($i = 0, $n = count($documentEmails); $i < $n; $i++)
		{
			$email = $documentEmails[$i];
			if (in_array($email->id, $oldUserIds))
			{
				continue;
			}
			$emailSubject = $subject;
			$emailBody    = $body;
			$emailSubject = str_replace('[NAME]', $email->name, $emailSubject);
			$emailSubject = str_replace('[USERNAME]', $email->username, $emailSubject);
			$emailBody    = str_replace('[NAME]', $email->name, $emailBody);
			$emailBody    = str_replace('[USERNAME]', $email->username, $emailBody);
			try
			{
				$mailer->sendMail($jconfig->mailfrom, $jconfig->fromname, $email->email, $emailSubject, $emailBody, 1);
			}
			catch (Exception $e)
			{
				Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning');
			}
			$mailer->ClearAllRecipients();
		}
	}

	public static function getChildrenCategories($categoryId)
	{
		return self::getAllChildrenCategories(array($categoryId));
	}


	public static function getAllChildrenCategories($categoryIds = array())
	{
		$db = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('id, parent_id')
			->from('#__edocman_categories')
			->where('published = 1');
		$db->setQuery($query);
		$rows = $db->loadObjectList();

		$children = array();
		// first pass - collect children
		if (count($rows))
		{
			foreach ($rows as $v)
			{
				$pt   = $v->parent_id;
				$list = @$children[$pt] ? $children[$pt] : array();
				array_push($list, $v->id);
				$children[$pt] = $list;
			}
		}

		$queues = $categoryIds;
		$allCategories = $categoryIds;
		while (count($queues))
		{
			$id = array_pop($queues);
			if (isset($children[$id]))
			{
				$allCategories = array_merge($allCategories, $children[$id]);
				$queues = array_merge($queues, $children[$id]);
			}
		}

		return $allCategories;
	}

	/**
	 *
	 * Apply some fixes for request data
	 *
	 * @return void
	 */
	public static function prepareRequestData()
	{
		//Remove cookie vars from request data
		$cookieVars = array_keys($_COOKIE);
		if (count($cookieVars))
		{
			foreach ($cookieVars as $key)
			{
				if (!isset($_POST[$key]) && !isset($_GET[$key]))
				{
					unset($_REQUEST[$key]);
				}
			}
		}
		if (isset($_REQUEST['start']) && !isset($_REQUEST['limitstart']))
		{
			$_REQUEST['limitstart'] = $_REQUEST['start'];
		}
		if (!isset($_REQUEST['limitstart']))
		{
			$_REQUEST['limitstart'] = 0;
		}
	}

	/**
	 * Prepare data before saving to database
	 *
	 * @param $row
	 * @param $categoryId
	 */
	public static function prepareDocument($row, $categoryId)
	{
		$db    = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$user = Factory::getApplication()->getIdentity();
		if (!$row->id)
		{
			
			$query = $db->getQuery(true);
			$query->select('MAX(ordering)')
				->from('#__edocman_documents AS a')
				->innerJoin('#__edocman_document_category AS b ON a.id = b.document_id')
				->where('b.category_id = ' . $categoryId);
			$db->setQuery($query);
			$row->ordering = 1 + (int) $db->loadResult();
		}

		$row->title = htmlspecialchars_decode($row->title, ENT_QUOTES);
		if (empty($row->alias))
		{
			$row->alias = $row->title;
		}
		$row->alias = ApplicationHelper::stringURLSafe($row->alias);

		$query->clear();
		$query->select('count(id)')->from('#__edocman_documents')->where('`alias` = "'.$row->alias.'"');
		$db->setQuery($query);

		$count_alias = $db->loadResult();
		if($count_alias > 0)
        {
            $count_alias = (int) $count_alias + 1;
            $row->alias .= "-".$count_alias;
        }

		if (empty($row->id))
		{
			if (property_exists($row, 'created_time') && !$row->created_time)
			{
				$row->created_time = Factory::getDate()->toSql();
			}

			if (property_exists($row, 'created_user_id') && !$row->created_user_id)
			{
				$row->created_user_id = $user->get('id');
			}
		}

		if (property_exists($row, 'modified_time') && !$row->modified_time)
		{
			$row->modified_time = Factory::getDate()->toSql();
		}
		if (property_exists($row, 'modified_user_id') && !$row->modified_user_id)
		{
			$row->modified_user_id = $user->get('id');
		}
		if (property_exists($row, 'params') && is_array($row->params))
		{
			$row->params = json_encode($row->params);
		}
	}

	/**
	 * Calculate level for categories, used when upgrade from old version to new version
	 *
	 * @param     $id
	 * @param     $list
	 * @param     $children
	 * @param int $maxlevel
	 * @param int $level
	 *
	 * @return mixed
	 */
	public static function calculateCategoriesLevel($id, $list, &$children, $maxlevel = 9999, $level = 1)
	{
		if (@$children[$id] && $level <= $maxlevel)
		{
			foreach ($children[$id] as $v)
			{
				$id = $v->id;
				$v->level = $level;
				$list[$id] = $v;
				$list = self::calculateCategoriesLevel($id, $list, $children, $maxlevel, $level + 1);
			}
		}

		return $list;
	}

    /**
     * @param $item
     */
    public static function getFileExtension($item){
        $original_filename = $item->original_filename;
        $original_filename = explode(".",$original_filename);
        $extension         = $original_filename[count($original_filename) - 1];
        if($extension == ""){
            return "generic";
        }else {
            return $extension;
        }
    }

	public static function cleanPath($path, $removeLastSlashes = true) {
		$path = (string) $path;
		$path = trim($path);
		if(!empty($path)) {
			/*//add slash at the end of path
			$path .= '/';*/
			//clean slashes
			$path = Path::clean($path, '/');
			//remove first slashes
			$path = preg_replace("/^\/*/", '', $path);
			//remove last slashes
			if($removeLastSlashes) {
				$path = preg_replace("/\/*$/", '', $path);
			}
			//encode url
			//$path = urlencode($path);
		}
		return $path;
	}

	public static function isDropBoxTurnedOn()
    {
        $db = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('count(extension_id)')->from('#__extensions')->where('type="plugin" and `element`= "dropbox" and enabled = "1"');
        $db->setQuery($query);
        $count = $db->loadResult();
        if($count > 0)
        {
			$query->clear();
			$query->select('`params`')->from('#__extensions')->where('type="plugin" and `element`= "dropbox" and enabled = "1"');
			$db->setQuery($query);
			$params = $db->loadResult();
			$registry = new Registry ();
			$registry->loadString ( $params );
			$data = $registry->toArray ();
			if($data['app_key'] != "" && $data['app_secret'] != "")
			{
				return true;
			}
			else
			{
				return false;
			}
        }
        else
        {
            return false;
        }
    }

    public static function isAmazonS3TurnedOn()
	{
		try {
			$db = Factory::getContainer()->get('db');
			$query = $db->getQuery(true);
			
			// First check if plugin exists and is enabled
			$query->select('COUNT(extension_id)')
				->from('#__extensions')
				->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
				->where($db->quoteName('element') . ' = ' . $db->quote('amazon'))
				->where($db->quoteName('enabled') . ' = 1');
			
			$db->setQuery($query);
			$count = $db->loadResult();
			
			if ($count == 0) {
				return false;
			}
			
			// Get plugin parameters
			$query->clear();
			$query->select($db->quoteName('params'))
				->from('#__extensions')
				->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
				->where($db->quoteName('element') . ' = ' . $db->quote('amazon'))
				->where($db->quoteName('enabled') . ' = 1');
			
			$db->setQuery($query);
			$params = $db->loadResult();
			
			if (empty($params)) {
				return false;
			}
			
			// Parse parameters
			$registry = new Registry();
			$registry->loadString($params);
			$data = $registry->toArray();
			
			// Check if required credentials are present and not empty
			return !empty($data['access_key']) && !empty($data['secret_key']);
			
		} catch (Exception $e) {
			// Log error if needed
			Factory::getApplication()->enqueueMessage('Error checking Amazon S3 plugin: ' . $e->getMessage(), 'error');
			return false;
		}
	}


    public static function isGdriveTurnedOn()
	{
		static $result = null;
		
		// Cache result to avoid multiple database queries
		if ($result !== null) {
			return $result;
		}
		
		try {
			$db = Factory::getContainer()->get('DatabaseDriver');
			$query = $db->getQuery(true);
			
			// Get plugin parameters in single query
			$query->select($db->quoteName('params'))
				->from('#__extensions')
				->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
				->where('(' . $db->quoteName('element') . ' = ' . $db->quote('googledrive') . 
						' OR ' . $db->quoteName('element') . ' = ' . $db->quote('googledrivev3') . ')')
				->where($db->quoteName('enabled') . ' = 1')
				->setLimit(1); // Only need one result
			
			$db->setQuery($query);
			$params = $db->loadResult();
			
			if (empty($params)) {
				return $result = false;
			}
			
			// Parse parameters
			$registry = new Registry();
			$registry->loadString($params);
			$data = $registry->toArray();
			
			// Check if required credentials are present and not empty
			return $result = (!empty($data['google_client_id']) && !empty($data['google_client_secret']));
			
		} catch (Exception $e) {
			// Log error if needed
			Factory::getApplication()->enqueueMessage('Error checking Google Drive plugin: ' . $e->getMessage(), 'error');
			return $result = false;
		}
	}


    public static function isUploadLimitTurnedOn()
    {
        $db = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('count(extension_id)')->from('#__extensions')->where('type="plugin" and `element`= "limitupload" and enabled = "1"');
        $db->setQuery($query);
        $count = $db->loadResult();
        if($count > 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public static function isViewPDFTurnedOn()
    {
        $db = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('count(extension_id)')->from('#__extensions')->where('type="plugin" and `element`= "viewpdf" and enabled = "1"');
        $db->setQuery($query);
        $count = $db->loadResult();
        if($count > 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

	public static function getDefaultLicense(){
		$db = Factory::getContainer()->get('db');
		$config = self::getConfig();
		if ($config->use_default_license){
			$query = $db->getQuery(true);
			$query->select('id');
			$query->from('#__edocman_licenses');
			$query->where('published=1 and default_license=1');
			$db->setQuery($query);
			return (int)$db->loadResult();
		}else{
			return 0;
		}
	}

	static function generateThumbnail($document){
		jimport('joomla.file.filesystem');
		$config			= self::getConfig();
		$thumbname		= md5(date('Y-m-d H:i:s:u'));
		$thumbname		.= ".jpg";
		$target			= JPATH_ROOT.'/media/com_edocman/document/'.$thumbname;
		/*
		$im				= new Imagick($source."[0]"); // 0-first page, 1-second page
		$im->setImageColorspace(255); // prevent image colors from inverting
		$im->setimageformat("jpg");
		$im->thumbnailimage(160, 120); // width and height
		$im->writeimage($target);
		$im->clear();
		$im->destroy();
		*/
		$pdf = $source."[0]";
		exec("convert $pdf convert-img/".$target); 
		File::copy($target,JPATH_ROOT.'/media/com_edocman/document/thumbs/'.$thumbname);
		return $thumbname;
	}

	public static function getDocumentCategory($documentId){
		$db = Factory::getContainer()->get('db');
		$db->setQuery("Select a.* from #__edocman_categories as a inner join #__edocman_document_category as b on b.category_id = a.id where b.document_id = '$documentId' and b.is_main_category = '1'");
		$category = $db->loadObject();
		return $category;
	} 

	/**
	static function buildUserGroupQuery($group_col){
		$user		= Factory::getApplication()->getIdentity();
		//get user groups
		$returnSql	= "";
		$db			= Factory::getContainer()->get('db');
		$tempQuery	= array();
        $groups = $user->getAuthorisedGroups();
		if(count($groups)){
			foreach($groups as $group){
				$tempQuery[] = " ".$group_col." ='".$group."' OR ".$group_col." LIKE '".$group.",%' OR ".$group_col." LIKE '%,".$group.",%' OR ".$group_col." LIKE '%,".$group."'";
			}
		}
		if(count($tempQuery)){
			$returnSql = " or (".implode(" or ",$tempQuery).")";
		}
		return $returnSql;
	}
		*/
	
	static function buildUserGroupQuery($group_col) {
		$user = Factory::getApplication()->getIdentity();
		$groups = $user->getAuthorisedGroups();
		$tempQuery = [];
		
		if (count($groups)) {
			foreach ($groups as $group) {
				$tempQuery[] = "$group_col ='$group' OR $group_col LIKE '$group,%' OR $group_col LIKE '%,$group,%' OR $group_col LIKE '%,$group'";
			}
		}
		
		if (count($tempQuery)) {
			return " OR (" . implode(" OR ", $tempQuery) . ")";
		}
		
		return "";
	}


	/**
	 * Build the list representing the menu tree
	 *
	 * @param   integer  $id         Id of the menu item
	 * @param   string   $indent     The indentation string
	 * @param   array    $list       The list to process
	 * @param   array    &$children  The children of the current item
	 * @param   integer  $maxlevel   The maximum number of levels in the tree
	 * @param   integer  $level      The starting level
	 * @param   int      $type       Set the type of spacer to use. Use 1 for |_ or 0 for -
	 *
	 * @return  array
	 *
	 * @since   1.5
	 */
	public static function treerecurse($id, $indent, $list, &$children, &$prgarr, $maxlevel = 5, $level = 0, $type = 1)
	{
		if ($level <= $maxlevel && @$children[$id])
		{
			foreach ($children[$id] as $v)
			{
				$id = $v->id;
				if(!in_array($id, $prgarr)){
					$prgarr[] = $id;
					$level = self::getCategoryLevel($id);
					if ($v->parent_id == 0)
					{
						$txt = $v->title;
					}
					else
					{
						if ($type)
						{
							$pre    = '<sup>|_</sup>&#160;';
							$spacer = '';
							for($j=1;$j<=$level;$j++){
								$spacer .= '.&#160;&#160;&#160;&#160;&#160;&#160;';
							}
						}
						else
						{
							$pre    = '- ';
							$spacer = '';
							for($j=1;$j<=$level;$j++){
								$spacer .= '&#160;&#160;';
							}
						}
						$txt = $pre . $v->title;
					}
					$list[$id]           = $v;
					$list[$id]->treename = $indent . $spacer . $txt;
					$list[$id]->children = count((array)@$children[$id]);
					$list                = self::treerecurse($id, $indent . $spacer, $list, $children, $prgarr, $maxlevel, $level + 1, $type);
				}
			}
		}

		return $list;
	}

	public static function getCategoryLevel($id){
		$db = Factory::getContainer()->get('db');
		$level = 0;
		while($id > 0){
			$db->setQuery("Select parent_id from #__edocman_categories where id = '$id'");
			$id = $db->loadResult();
			if($id > 0){
				$level++;
			}
		}
		return $level;
	}

    /**
     * This function is used to check if the document is viewable
     * @param $item
     * @return int
     */
	static function canView($item){
	    $config                 = self::getConfig();
        $extsForView            = explode(',', $config->exts_for_view);
        for ($i = 0, $n = count($extsForView); $i < $n; $i++)
        {
            $extsForView[$i]    = strtolower(trim($extsForView[$i]));
        }
        $fileName               = $item->filename;
        $fileExt                = strtolower(self::getFileExt($fileName));
        if (in_array($fileExt, $extsForView) || $item->view_url != '')
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }

    /**
     * This function is used to check if Google Drive plugin is enabled or not
     * @return bool
     */
    static function isGoogleDrivePluginEnabled()
	{
        $db = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('count(extension_id)')->from('#__extensions')->where('`type`= "plugin"')->where('`element` = "googledrive" or `element` = "googledrivev3"')->where('`folder` = "edocman"')->where('enabled = "1"');
        $db->setQuery($query);
        $count = $db->loadResult();
        if($count > 0)
		{
            return true;
        }
		else
		{
            return false;
        }
    }

    /**
     * Render showon string
     *
     * @param array $fields
     *
     * @return string
     */
    public static function renderShowon($fields)
    {
        $output = array();

        $i = 0;

        foreach ($fields as $name => $values)
        {
            $i++;

            $values = (array) $values;

            $data = array(
                'field'  => $name,
                'values' => $values
            );

            if (version_compare(JVERSION, '3.6.99', 'ge'))
            {
                $data['sign'] = '=';
            }

            $data['op'] = $i > 1 ? 'AND' : '';

            $output[] = json_encode($data);
        }

        return '[' . implode(',', $output) . ']';
    }

	static function getGroupLevels($data_type,$item_id){
        $db = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('`groups`')->from('#__edocman_levels')->where('data_type='.$data_type)->where('item_id='.$item_id);
        $db->setQuery($query);
        return $db->loadResult();
    }

    /**
     * Return Access groups of item
     * @param $data_type
     * @param $item_id
     * @return string
     */
    static function getAccessGroup($data_type,$item_id){
        $db             = Factory::getContainer()->get('db');
        $query          = $db->getQuery(true);
        $groups         = self::getGroupLevels($data_type,$item_id);
        $returnArr      = array();
        if($groups != ''){
            $groupArr   = explode(",",$groups);
            foreach ($groupArr as $group){
                $query->clear();
                $query->select('title')->from('#__usergroups')->where('id = '.(int) $group);
                $db->setQuery($query);
                $title  = $db->loadResult();
                $returnArr[] = $title;
            }
        }
        return implode(", ", $returnArr);
    }

    /**
     * Return the configuration field checkboxes
     * @param $fieldname
     * @param $fieldvalue
     */
    public static function showCheckboxfield($fieldname,$fieldvalue,$option1='',$option2='',$add_jform_prefix = true)
    {
        if($option1 == ""){
            $option1 = Text::_('OS_YES');
        }
        if($option2 == ""){
            $option2 = Text::_('OS_NO');
        }
        if (version_compare(JVERSION, '3.0', 'lt')) 
		{
            $optionArr = array();
            $optionArr[] = HTMLHelper::_('select.option',1,$option1);
            $optionArr[] = HTMLHelper::_('select.option',0,$option2);
            echo HTMLHelper::_('select.genericlist',$optionArr,$fieldname,'class="input-mini"','value','text',$fieldvalue);
        }
		else
		{
            $name = $fieldname;
			if(!self::isJoomla4())
			{
				if(intval($fieldvalue) == 1)
				{
					$checked2 = 'checked="checked"';
					$checked1 = "";
				}
				else
				{
					$checked1 = 'checked="checked"';
					$checked2 = "";
				}
				
				if($add_jform_prefix)
				{
					$name1 = "jform[".$name."]";
				}
				else
				{
					$name1 = $name;
				}
				?>
				<fieldset id="jform_params_<?php echo $name;?>" class="radio btn-group">
					<input type="radio" id="jform_params_<?php echo $name;?>0" name="<?php echo $name1;?>" value="0" <?php echo $checked1;?> onclick="javascript:updateRadioButton(0);"/>
					<label for="jform_params_<?php echo $name;?>0"><?php echo $option1;?></label>
					<input type="radio" id="jform_params_<?php echo $name;?>1" name="<?php echo $name1;?>" value="1" <?php echO $checked2;?> onclick="javascript:updateRadioButton(1);"/>
					<label for="jform_params_<?php echo $name;?>1"><?php echo $option2;?></label>
				</fieldset>
				<?php
			}
			else
			{
				if(intval($fieldvalue) == 1)
				{
					$checked2 = 'selected';
					$checked1 = "";
				}
				elseif(intval($fieldvalue) == 0)
				{
					$checked1 = 'selected';
					$checked2 = "";
				}
				?>
				<select name="jform[<?php echo $name; ?>]" class="input-large form-select uk-select" id="jform_params_<?php echo $name;?>" onChange="javascript:updateRadioButton(this.value);">
					<option value="0" <?php echo $checked1; ?>><?php echo $option1;?></option>
					<option value="1" <?php echo $checked2; ?>><?php echo $option2;?></option>
				</select>
				<?php
			}
        }
    }

	public static function showCheckboxfield2($name, $value ,$option1='',$option2='')
    {

        if($option1 == ""){
            $option1 = Text::_('JNO');
        }
        if($option2 == ""){
            $option2 = Text::_('JYES');
        }

        HTMLHelper::_('jquery.framework');
        $field = FormHelper::loadFieldType('Radio');

        $element = new SimpleXMLElement('<field />');
        $element->addAttribute('name', $name);

        if (EdocmanHelper::isJoomla4())
        {
            $element->addAttribute('layout', 'joomla.form.field.radio.switcher');
        }
        else
        {
            $element->addAttribute('class', 'radio btn-group btn-group-yesno');
        }

        $element->addAttribute('default', '0');

        $node = $element->addChild('option', $option1);
        $node->addAttribute('value', '0');

        $node = $element->addChild('option', $option2);
        $node->addAttribute('value', '1');

        $field->setup($element, $value);

        return $field->input;
    }

	public static function showCheckboxfield3options($fieldname,$fieldvalue,$option1='',$option2='', $option3='')
    {
		$name = $fieldname;
		if(!self::isJoomla4())
		{
			if(intval($fieldvalue) == 1)
			{
				$checked2 = 'checked="checked"';
				$checked1 = "";
				$checked3 = "";
			}
			elseif(intval($fieldvalue) == 0)
			{
				$checked1 = 'checked="checked"';
				$checked2 = "";
				$checked3 = "";
			}
			else
			{
				$checked3 = 'checked="checked"';
				$checked2 = "";
				$checked1 = "";
			}
			?>
			<fieldset id="jform_params_<?php echo $name;?>" class="radio btn-group">
				<input type="radio" id="jform_params_<?php echo $name;?>0" name="jform[<?php echo $name; ?>]" value="0" <?php echO $checked1;?> onclick="javascript:updateRadioButton(0);"/>
				<label for="jform_params_<?php echo $name;?>0"><?php echo $option1;?></label>
				<input type="radio" id="jform_params_<?php echo $name;?>1" name="jform[<?php echo $name; ?>]" value="1" <?php echO $checked2;?> onclick="javascript:updateRadioButton(1);"/>
				<label for="jform_params_<?php echo $name;?>1"><?php echo $option2;?></label>
				<input type="radio" id="jform_params_<?php echo $name;?>2" name="jform[<?php echo $name; ?>]" value="2" <?php echO $checked3;?> onclick="javascript:updateRadioButton(2);"/>
				<label for="jform_params_<?php echo $name;?>2"><?php echo $option3;?></label>
			</fieldset>
			<?php
		}
		else
		{
			if(intval($fieldvalue) == 1)
			{
				$checked2 = 'selected';
				$checked1 = "";
				$checked3 = "";
			}
			elseif(intval($fieldvalue) == 0)
			{
				$checked1 = 'selected';
				$checked2 = "";
				$checked3 = "";
			}
			else
			{
				$checked3 = 'selected';
				$checked2 = "";
				$checked1 = "";
			}
			?>
			<select name="jform[<?php echo $name; ?>]" class="input-large form-select uk-select" id="jform_params_<?php echo $name;?>" onChange="javascript:updateRadioButton(this.value);">
				<option value="0" <?php echo $checked1; ?>><?php echo $option1;?></option>
				<option value="1" <?php echo $checked2; ?>><?php echo $option2;?></option>
				<option value="2" <?php echo $checked3; ?>><?php echo $option3;?></option>
			</select>
			<?php
		}

    }

    /**
     * This function is used to calculate total files uploaded by user
     * @return int
     */
    static function getTotalUploadFile()
    {
        $user  = Factory::getApplication()->getIdentity();
        $db    = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('count(id)')->from('#__edocman_documents')->where('created_user_id = "'.$user->id.'"');
        $db->setQuery($query);
        return (int)$db->loadResult();
    }

    /**
     * This function is used to calculate total size of files have been uploaded by current logged user
     */
    static function getCurrentUserUploadedSize()
    {
        $user  = Factory::getApplication()->getIdentity();
        $db    = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('`file_size`')->from('#__edocman_documents')->where('created_user_id = "'.$user->id.'"');
        $db->setQuery($query);
        $rows  = $db->loadObjectList();
        $total = 0;
        if(count($rows))
        {
            foreach($rows as $row)
            {
                $filesize = $row->file_size;
                $filesize = explode(" ",$filesize);
                $size     = $filesize[0];
                $filetype = $filesize[1];
                switch ($filetype)
                {
                    case "Byte":
                        $total += (float) $size;
                        break;
                    case "KB":
                        $total += (float) $size * 1024;
                        break;
                    case "MB":
                        $total += (float) $size * 1024 * 1024;
                        break;
                    case "GB":
                        $total += (float) $size * 1024 * 1024 * 1024;
                        break;
                    case "TB":
                        $total += (float) $size * 1024 * 1024 * 1024 * 1024;
                        break;
                }
            }
        }
        return $total;
    }

    static function calculateExpiredDates($unpublished_date)
    {
        $day = 3600*24;
        $hour = 3600;
        $current_time = time();
        $unpublished_date = strtotime($unpublished_date);
        if($unpublished_date > $current_time)
        {
            $period = $unpublished_date - $current_time;
            $nday = $period / $day;
            if($nday > 1 && $nday < 7)
            {
                return round($nday). " ". Text::_('EDOCMAN_DAYS');
            }
            else
            {
                $nhour = $period / $hour;
                return round($nhour). " ". Text::_('EDOCMAN_HOURS');
            }
        }
    }

    /**
     * Record transaction details in log record
     * @param   object  $user    Saves getting the current user again.
     * @param   int     $tran_id  The transaction id just created or updated
     * @param   int     $id  Passed id reference from the form to identify if new record
     * @return  boolean	True
     */
    public static function recordActionLog($user = null, $tran_id = 0, $id = 0, $con_type = '')
    {
        if (version_compare(JVERSION, '3.9.0', 'ge'))
        {
            $db                             = Factory::getContainer()->get('db');
            // get the transaction details for use in the log for easy reference
            switch ($con_type)
            {
                case "document":
                    if ($id == 1)
                    {
                        $messageLanguageKey = Text::_('EDOCMAN_CREATE_LINK');
                    }
                    elseif($id == 0)
                    {
                        $messageLanguageKey = Text::_('EDOCMAN_UPDATE_LINK');
                    }
                    elseif($id == 2)
                    {
                        $messageLanguageKey = Text::_('EDOCMAN_DOCUMENT_DELETE');
                    }
                    $db->setQuery("Select title from #__edocman_documents where id = '$tran_id'");
                    $title                  = $db->loadResult();
                    break;
                case "category":
                    if ($id == 1)
                    {
                        $messageLanguageKey = Text::_('EDOCMAN_CATEGORY_CREATE_LINK');
                    }
                    elseif($id == 0)
                    {
                        $messageLanguageKey = Text::_('EDOCMAN_CATEGORY_UPDATE_LINK');
                    }
                    elseif($id == 2)
                    {
                        $messageLanguageKey = Text::_('EDOCMAN_CATEGORY_DELETE');
                    }
                    $db->setQuery("Select title from #__edocman_categories where id = '$tran_id'");
                    $title                  = $db->loadResult();
                    break;
                case "download":
                    $messageLanguageKey     = Text::_('EDOCMAN_DOCUMENT_DOWNLOAD_LINK');
                    $db->setQuery("Select title from #__edocman_documents where id = '$tran_id'");
                    $title                  = $db->loadResult();
                    break;
				case "view":
					$messageLanguageKey     = Text::_('EDOCMAN_DOCUMENT_VIEW_LINK');
                    $db->setQuery("Select title from #__edocman_documents where id = '$tran_id'");
                    $title                  = $db->loadResult();
                    break;
					break;
            }


            $message                        = array();
            $message['action']              = $con_type;
            $message['type']                = $title;
            $message['id']                  = $tran_id;
            $message['title']               = "Edocman";
            $message['extension_name']      = "Edocman";
            if($id != 2)
            {
                switch ($con_type)
                {
                    case "document":
                    case "download":
                        $message['itemlink'] = "index.php?option=com_edocman&task=document.edit&id=" . $tran_id;
                        break;
					case "view":
                        $message['itemlink'] = "index.php?option=com_edocman&task=document.viewDoc&id=" . $tran_id;
                        break;
                    case "category":
                        $message['itemlink'] = "index.php?option=com_edocman&task=category.edit&id=" . $tran_id;
                        break;
                }
            }
            if($user->id > 0)
            {
                $message['userid']          = $user->id;
                $message['username']        = $user->username;
                $message['accountlink']     = "index.php?option=com_users&task=user.edit&id=" . $user->id;
            }
            else
            {
                $message['userid']          = 0;
                $message['username']        = Text::_('EDOCMAN_GUEST');
                $message['accountlink']     = "#";
            }
            $messages                       = array($message);
            $context                        = 'Edocman.' . $con_type;
            $fmodel                         = self::getForeignModel('Actionlog', 'ActionlogsModel');
            $fmodel->addLog($messages, $messageLanguageKey, $context, $user->id);
        }
        return true;
    }

    /**
     * Get the Model from another component for use
     * @param   string  $name    The model name. Optional. Default to my own for safety.
     * @param   string  $prefix  The class prefix. Optional
     * @param   array   $config  Configuration array for model. Optional
     * @return object	The model
     */
    public static function getForeignModel($name = 'Transaction', $prefix = 'ActionlogsModel', $config = array('ignore_request' => true))
    {
        BaseDatabaseModel::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models');
        $fmodel = BaseDatabaseModel::getInstance($name, $prefix, $config);
        return $fmodel;
    }


	/**
	 * Convert src of img tags to use absolute links instead of ralative link
	 *
	 * @param $html_content
	 *
	 * @return mixed
	 */
	public static function convertImgTags($html_content)
	{
		$patterns     = array();
		$replacements = array();
		$i            = 0;
		$src_exp      = "/src=\"(.*?)\"/";
		$link_exp     = "[^http:\/\/www\.|^www\.|^https:\/\/|^http:\/\/]";
		$siteURL      = Uri::root();
		preg_match_all($src_exp, $html_content, $out, PREG_SET_ORDER);
		foreach ($out as $val)
		{
			$links = preg_match($link_exp, $val[1], $match, PREG_OFFSET_CAPTURE);
			if ($links == '0')
			{
				$patterns[$i]     = $val[1];
				$patterns[$i]     = "\"$val[1]";
				$replacements[$i] = $siteURL . $val[1];
				$replacements[$i] = "\"$replacements[$i]";
			}
			$i++;
		}
		$mod_html_content = str_replace($patterns, $replacements, $html_content);

		return $mod_html_content;
	}

	/**
	 * Get URL of the site, using for Ajax request
	 *
	 * @return string
	 *
	 * @throws Exception
	 */
	public static function getSiteUrl()
	{
		$uri  = Uri::getInstance();
		$base = $uri->toString(array('scheme', 'host', 'port'));

		if (strpos(php_sapi_name(), 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI']))
		{
			$script_name = $_SERVER['PHP_SELF'];
		}
		else
		{
			$script_name = $_SERVER['SCRIPT_NAME'];
		}

		$path = rtrim(dirname($script_name), '/\\');

		if ($path)
		{
			$siteUrl = $base . $path . '/';
		}
		else
		{
			$siteUrl = $base . '/';
		}

		if (Factory::getApplication()->isClient('administrator'))
		{
			$adminPos = strrpos($siteUrl, 'administrator/');
			$siteUrl  = substr_replace($siteUrl, '', $adminPos, 14);
		}

		return $siteUrl;
	}

	public static function getSiteTitle()
	{
		$jconfig	= new JConfig();
		$config		= EDocmanHelper::getConfig();
		if($config->show_site_title)
		{
			return $jconfig->sitename. ' - ';
		}
		else
		{
			return '';
		}
	}

	public static function generateThumbImages($row)
    {
        $db                     = Factory::getContainer()->get('db');
        $config                 = self::getConfig();
        $documents_path         = $config->documents_path;
        if(!self::isAmazonS3TurnedOn() && !self::isGdriveTurnedOn() && !self::isDropBoxTurnedOn())
        {
            //check to see if this is picture
            $original_filename  = $row->original_filename;
            $dotpos             = strrpos($original_filename, ".");
            $file_extension     = strtolower(substr($original_filename, $dotpos + 1));
            $imageArr           = array('png','gif','png','jpg','jpeg');
            if(in_array($file_extension, $imageArr))
            {
                $imageFile      = $documents_path.'/'.$row->filename;
                if(file_exists($imageFile))
                {
                    $documentImagePath      = JPATH_ROOT . '/media/com_edocman/document/';
                    $thumbDocumentImagePath = $documentImagePath . 'thumbs/';
                    if(is_file(Path::clean($documentImagePath.$original_filename)))
                    {
                        File::delete($documentImagePath.$original_filename);
                    }
                    if(is_file(Path::clean($thumbDocumentImagePath.$original_filename)))
                    {
                        File::delete($thumbDocumentImagePath.$original_filename);
                    }
                    File::copy($imageFile, $documentImagePath.$original_filename);
                    $width  = $config->document_thumb_width;
                    $height = $config->document_thumb_height;
                    EDocmanHelper::resizeImage($documentImagePath . $original_filename, $thumbDocumentImagePath . $original_filename, $width, $height);
                    $db->setQuery("Update #__edocman_documents set `image` = ".$db->quote($original_filename)." where id = '$row->id'");
                    $db->execute();
                }
            }
        }
    }

	public static function getTags($id)
	{
		$db = Factory::getContainer()->get('db');
		if($id > 0)
		{
			$db->setQuery("Select a.* from #__edocman_tags as a left join #__edocman_document_tags as b on a.id = b.tag_id where b.document_id = '$id'");
			$rows = $db->loadObjectList();
			return $rows;
		}
	}

	public static function countDocumentRelatedTag($id)
	{
		$db = Factory::getContainer()->get('db');
		if($id > 0)
		{
			$db->setQuery("Select count(id) from #__edocman_document_tags where tag_id = '$id'");
			return (int) $db->loadResult();
		}
	}

	/**
	 * Helper method to add multiple language strings to JS
	 *
	 * @param   array  $items
	 */
	public static function addJSStrings($items = [])
	{
		foreach ($items as $item)
		{
			Text::script($item, true);
		}
	}

	public static function getDocumentRating($document_id)
	{
		$db						= Factory::getContainer()->get('db');
		$query					= $db->getQuery(true);
		$query->select('*')->from('#__edocman_ratings')->where('document_id='.$document_id);
		$db->setQuery($query);
		$rating					= $db->loadObjectList();
		$return					= array();
		$totalVotes				= 0;
		if(count($rating))
		{
			foreach($rating as $rate)
			{
				$totalVotes += $rate->rate;
			}

			$rate = round($totalVotes/count($rating),2);
			$return['totalVotes']	= $totalVotes;
			$return['numberVotes']	= count($rating);
			$return['rating']		= $rate;
		}
		else
		{
			$return['totalVotes']	= 0;
			$return['numberVotes']	= 0;
			$return['rating']		= 0;
		}
		return $return;
	}

	public static function showDocumentRating($document_id, $show_label)
	{
		?>
		<div class="avg-rating">
			<?php
			if($show_label == 1)
			{
			?>
        		<strong class="hasTip" title="<?php echo Text::_('EDOCMAN_AVERAGE');?>"><?php echo Text::_('EDOCMAN_AVERAGE');?>:</strong>
			<?php
			}
			$rating = self::getDocumentRating($document_id);
			$rating_width = (int)($rating['rating']*90/5);
			?>
            <span class="avg-stars">
                <label class="hasTip" for="title" title="<?php echo number_format($rating['rating'],2);?>">
                    <span class="rating-foreground" style="width:<?php echo $rating_width;?>px;"></span>
                </label>    
            </span>
        </div>
		<?php
	}

	public static function canRate($documentId)
	{
		$user = Factory::getApplication()->getIdentity();
		if((int) $user->id == 0)
		{
			return false;
		}
		$db   = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('count(id)')->from('#__edocman_ratings')->where('document_id='.$documentId)->where('user_id='.$user->id);
		$db->setQuery($query);
		$count = $db->loadResult();
		if($count == 0)
		{
			return true;
		}
		return false;
	}

	public static function isAlreadyRate($documentId)
	{
		$user = Factory::getApplication()->getIdentity();
		if((int) $user->id == 0)
		{
			return false;
		}
		$db   = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('count(id)')->from('#__edocman_ratings')->where('document_id='.$documentId)->where('user_id='.$user->id);
		$db->setQuery($query);
		$count = $db->loadResult();
		if($count > 0)
		{
			return true;
		}
		return false;
	}

	public static function getYourRating($documentId)
	{
		$user = Factory::getApplication()->getIdentity();
		$db   = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('*')->from('#__edocman_ratings')->where('document_id='.$documentId)->where('user_id='.$user->id);
		$db->setQuery($query);
		$rate = $db->loadObject();
		return $rate;
	}

	public static function isAvailableCategories()
	{
		$db = Factory::getContainer()->get('db');
		$db->setQuery("Select count(id) from #__edocman_categories");
		$count = $db->loadResult();
		if($count > 0)
		{
			return true;
		}
		return false;
	}

	public static function isPDFFile($filename)
	{
		if($filename != "")
		{
			$filenameArr = explode(".", $filename);
			$fileextension  = $filenameArr[count($filenameArr) - 1];
			if(strtolower($fileextension) == "pdf")
			{
				return true;
			}
		}
		return false;
	}

	public static function isDOCFile($filename)
	{
		if($filename != "")
		{
			$filenameArr = explode(".", $filename);
			$fileextension  = $filenameArr[count($filenameArr) - 1];
			if(strtolower($fileextension) == "doc" || strtolower($fileextension) == "docx")
			{
				return true;
			}
		}
		return false;
	}


	public static function isPopularViewLink($viewLink)
	{
		if(strpos($viewLink,'youtube') > 0 || strpos($viewLink,'vimeo') > 0 || strpos($viewLink,'youtu') > 0 )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	public static function massDownloadShowing($canDownload, $config, $item)
    {
        if($canDownload && $config->enable_massdownload && !self::isGdriveTurnedOn() && !self::isAmazonS3TurnedOn() && !self::isDropBoxTurnedOn() && $item->document_url == "")
        {
            return true;
        }
        return false;
    }

    public static function isAlreadyInMassList($documentId)
    {
        $session            = Factory::getApplication()->getSession();
        $massDownloadIds    = $session->get('massDownloadIds', '');
        if($massDownloadIds != "")
        {
            $massDownloadIds = explode(",", $massDownloadIds);
            if(in_array($documentId, $massDownloadIds))
            {
                return true;
            }
        }
        return false;
    }

    public static function createZipFile( $files = [], $destination = '', $overwrite = true )
    {

        // if the zip file already exists and overwrite is false, return false
        if(is_file(Path::clean($destination)) && !$overwrite) {
            return false;
        }
        // vars
        $valid_files = [];

        // if files were passed in...
        if(is_array($files)) 
		{
            // cycle through each file
            foreach($files as $file) 
			{
                // make sure the file exists
                if(is_file(Path::clean($file))) 
				{
                    $valid_files[] = $file;
                }
            }
        }

        // if we have valid files
        if(count($valid_files)) 
		{
            // create the archive
            $zip = new ZipArchive();
            $limit = 250;

            $result = $zip->open($destination, ZipArchive::CREATE | ZipArchive::OVERWRITE);

            if (!$result === TRUE)
			{
                return false;
            }

            // add the files
            foreach($valid_files as $file) 
			{

                // special function for trouble when we have to many files
                $only_filename = basename($file);
                //$zip->addFile($file, $only_filename);
                $zip->addFile($file, iconv('UTF-8', 'CP866', $only_filename)); // bugfix by 'Makulia'
            }
            // close the zip -- done!
            $zip->close();

            // check to make sure the file exists
            return file_exists($destination);
        } 
		else 
		{
            return false;
        }
    }

	//chosen Joomla4
	public static function getChoicesJsSelect($html, $hint = '')
	{
		static $isJoomla4;

		if ($isJoomla4 === null)
		{
			$isJoomla4 = self::isJoomla4();
		}

		if ($isJoomla4)
		{
			Text::script('JGLOBAL_SELECT_NO_RESULTS_MATCH');
			Text::script('JGLOBAL_SELECT_PRESS_TO_SELECT');

			Factory::getApplication()->getDocument()->getWebAssetManager()
				->usePreset('choicesjs')
				->useScript('webcomponent.field-fancy-select');

			$attributes = [];

			$hint = $hint ?: Text::_('JGLOBAL_TYPE_OR_SELECT_SOME_OPTIONS');

			$attributes[] = 'placeholder="' . $hint . '""';
			$attributes[] = 'search-placeholder="' . $hint . '""';


			return '<joomla-field-fancy-select ' . implode(' ', $attributes) . '>' . $html . '</joomla-field-fancy-select>';
		}

		return $html;
	}

	public static function canDownload($documentId)
	{
		$db     = Factory::getContainer()->get('db');
		$user   = Factory::getApplication()->getIdentity();
		$userId = $user->id;
		$query  = $db->getQuery(true);
		
		$query->select('*')
			->from('#__edocman_documents')
			->where('id=' . (int) $documentId)
			->where('published = 1');
		
		$db->setQuery($query);
		$item = $db->loadObject();

		if (!$item)
		{
			return false;
		}
        if ($user->authorise('core.admin', 'com_edocman'))
        {
            return true;
        }

		if($item->disable_download > 0 && $item->downloads >= $item->disable_download)
		{
			return false;
		}
		
		//owner groups
		if($item->owner_group_ids != "")
		{
			$usergroups = $user->groups;
			
			$owner_group_ids = explode(",", $item->owner_group_ids);
			if(count($owner_group_ids) > 0 && count($usergroups) > 0)
			{
				foreach($usergroups as $group)
				{
					if(in_array($group,$owner_group_ids))
					{
						return true;
					}
				}
			}          
		}

		$canDownload    = $user->authorise('edocman.download', 'com_edocman.document.'.$documentId);
		$canDownload    = ($item->created_user_id == $userId && $item->created_user_id > 0) || ( ($item->user_ids == "" || $item->user_ids == 0) && $canDownload) || ($item->user_ids != '' && $item->user_ids != '0' && in_array($userId, explode(',', $item->user_ids))) ;



		return $canDownload;
	}

	public static function categoryList($categoryId, $input_style = 'input-medium imedium form-select', $search = 0)
	{
		$config = self::getConfig();
		$user = Factory::getApplication()->getIdentity();
		$db = Factory::getContainer()->get('db');
		$userId = $user->id;
		$currentLanguage = Factory::getLanguage()->getTag(); // Lấy ngôn ngữ hiện tại

		// Xử lý điều kiện usergroup
		$usergroupArr = [];
		$usergroupSql = "";
		if (!empty($user->groups)) {
			foreach ($user->groups as $group) {
				$usergroupArr[] = " (`groups`='$group' OR `groups` LIKE '$group,%' OR `groups` LIKE '%,$group,%' OR `groups` LIKE '%,$group') AND `data_type` = '0'";
			}
			$usergroupSql = implode(" OR ", $usergroupArr);
			$usergroupSql = " a.id IN (SELECT item_id FROM #__edocman_levels WHERE $usergroupSql) ";
			$usergroupSql = " OR ((a.user_ids = '' OR a.user_ids = '0') AND a.accesspicker = '1' AND $usergroupSql ) ";
		}

		$query = $db->getQuery(true);
		$query->select('id, title, parent_id')
			->from('#__edocman_categories AS a')
			->where('published = 1')
			->where("(a.language = '*' OR a.language = '$currentLanguage')"); 

		// Kiểm tra quyền admin và điều kiện user group
		if ($config->user_group_ids) {
			$groupQuery = EdocmanHelper::buildUserGroupQuery('a.owner_group_ids');
			$query->where("(((a.user_ids = '' OR a.user_ids IS NULL OR a.user_ids = 0) AND a.owner_group_ids = '' AND a.access IN (" . implode(',', $user->getAuthorisedViewLevels()) . ")) $usergroupSql $groupQuery OR a.user_ids='$userId' OR a.user_ids LIKE '$userId,%' OR a.user_ids LIKE '%,$userId,%' OR a.user_ids LIKE '%,$userId' OR (a.created_user_id=$userId AND a.created_user_id > 0))");
		} else {
			$query->where("(((a.user_ids = '' OR a.user_ids IS NULL OR a.user_ids = 0) AND a.access IN (" . implode(',', $user->getAuthorisedViewLevels()) . ")) $usergroupSql OR a.user_ids='$userId' OR a.user_ids LIKE '$userId,%' OR a.user_ids LIKE '%,$userId,%' OR a.user_ids LIKE '%,$userId' OR (a.created_user_id=$userId AND a.created_user_id > 0))");
		}

		// Xử lý điều kiện loại trừ danh mục
		if (!empty($config->exclude_categories)) {
			$exclude_categories = ArrayHelper::toInteger(explode(",", $config->exclude_categories));
			$query->where('id NOT IN (' . implode(",", $exclude_categories) . ')');
		}

		// Xử lý điều kiện tìm kiếm
		if ($search == 1) {
			$query->where('searchable = 1');
		}

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

		// Xử lý danh sách con
		$children = [];
		if (!empty($rows)) {
			foreach ($rows as $v) {
				$pt = $v->parent_id;
				$children[$pt][] = $v;
			}
		}

		// Tạo danh sách cây
		$list = HTMLHelper::_('menu.treerecurse', 0, '', [], $children, 9999);
		$options = [HTMLHelper::_('select.option', 0, Text::_('EDOCMAN_SELECT_CATEGORY'))];

		if (!empty($list)) {
			foreach ($list as $row) {
				$options[] = HTMLHelper::_('select.option', $row->id, $row->treename);
			}
		}

		// Trả về danh sách select
		return HTMLHelper::_('select.genericlist', $options, 'filter_category_id', [
			'option.text.toHtml' => false,
			'list.attr' => 'class="' . $input_style . ' edocman_search_category form-select"',
			'option.text' => 'text',
			'option.key' => 'value',
			'list.select' => (int)$categoryId
		]);
	}


	/**
	 * Get hased field name to store the time which form started to be rendered
	 *
	 * @return string
	 */
	public static function getHashedFieldName()
	{
		$config = Factory::getApplication()->getConfig();

		$siteName = $config->get('sitename');
		$secret   = $config->get('secret');

		return md5($siteName . $secret);
	}

	public static function generateJoomlaLogin($class)
	{
		$return = self::currentUrl();
		$loginUrl = Route::_('index.php?option=com_users&view=login&return='.$return);
		?>
		<a href="<?php echo $loginUrl?>" class="<?php echo $class;?>" title="<?php echo Text::_('EDOCMAN_LOGIN_TO_DOWNLOAD'); ?>">
			<i class="edicon edicon-user"></i>
			<?php
			echo Text::_('EDOCMAN_LOGIN_TO_DOWNLOAD'); 
			?>
		</a>
		<?php
	}

	public static function currentUrl()
	{
		return base64_encode(Uri::getInstance()->toString());
	}

	public static function isIndexerTurnedOn()
	{
		$db = Factory::getContainer()->get('db');
        $query = $db->getQuery(true);
        $query->select('count(extension_id)')->from('#__extensions')->where('type="plugin" and `element`= "indexer" and enabled = "1"');
        $db->setQuery($query);
        $count = $db->loadResult();
        if($count > 0)
        {
            return true;
        }
        else
        {
            return false;
        }
	}

	public static function updateSubCategoryPaths($id)
	{
		$db			= Factory::getContainer()->get('db');
		$config		= self::getConfig();
		$db->setQuery("Select * from #__edocman_categories where parent_id = '$id'");
		$categories = $db->loadObjectList();
		if(count($categories) > 0)
		{
			$db->setQuery("Select * from #__edocman_categories where id = '$id'");
			$parentCategory = $db->loadObject();

			foreach($categories as $category)
			{
				$path = $category->path; //existing path
				$oldCategoryPath = $path;

				//retrieve documents
				$db->setQuery("Select a.id, a.filename from #__edocman_documents as a inner join #__edocman_document_category as b on a.id = b.document_id where b.category_id = '$category->id' and b.is_main_category = '1'");
				$documents = $db->loadObjectList();

				$pos = strrpos($path, '/');
				if ($pos !== false)
				{
					$path = substr($path, $pos + 1);
				}

				//update data for Category
				$newCategoryPath = $parentCategory->path.'/'.$path;
				$db->setQuery("Update #__edocman_categories set `path` = '".$newCategoryPath."' where id = '$category->id'");
				$db->execute();

				$path = $config->documents_path.'/'.$newCategoryPath;
				if(! is_dir(Path::clean($path)))
				{
					//JFolder::create($path);
					self::recurse_copy ($config->documents_path.'/'.$oldCategoryPath, $path);
				}
				

				//update data for document
				if(count($documents))
				{
					foreach($documents as $document)
					{
						$filename = $document->filename;
						$filename = str_replace($oldCategoryPath."/", $newCategoryPath."/", $filename);
						$db->setQuery("Update #__edocman_documents set `filename` = ".$db->quote($filename)." where id = '$document->id'");
						$db->execute();
					}

				}

				self::updateSubCategoryPaths($category->id);
			}
		}
	}

	public static function recurse_copy($src,$dst) 
	{ 
		if(is_dir(Path::clean($src)))
		{
			$dir = opendir($src); 
			@mkdir($dst); 
			while(false !== ( $file = readdir($dir)) ) { 
				if (( $file != '.' ) && ( $file != '..' )) { 
					if ( is_dir(Path::clean($src . '/' . $file))) { 
						self::recurse_copy($src . '/' . $file,$dst . '/' . $file); 
					} 
					else { 
						copy($src . '/' . $file,$dst . '/' . $file); 
					} 
				} 
			} 
			closedir($dir);
		}
    } 

	/**
	 * Helper method to write data to a log file, for debuging purpose
	 *
	 * @param   string  $logFile
	 * @param   array   $data
	 * @param   string  $message
	 */
	public static function logData($logFile, $data = [], $message = null)
	{
		$text = '[' . gmdate('m/d/Y g:i A') . '] - ';

		foreach ($data as $key => $value)
		{
			$text .= "$key=$value, ";
		}

		$text .= $message;

		$fp = fopen($logFile, 'a');
		fwrite($fp, $text . "\n\n");
		fclose($fp);
	}

	public static function jsonCategories($firstText, $hasFirstOption)
	{
		$db = Factory::getContainer()->get('db');
		if(!file_exists(JPATH_ROOT . '/components/com_edocman/categories.json'))
		{
			$db->setQuery("Select * from #__edocman_categories where published = '1' and title <> ''");
			$categories = $db->loadObjectList();
			$return = [];
			$tmp = [];
			if($hasFirstOption == 1)
			{
				$tmp['id'] = 0;
				$tmp['parent_id'] = 0;
				$tmp['hasChild'] = 0;
				$tmp['title'] = $firstText;
				$return[] = $tmp;
			}
			foreach($categories as $category)
			{
				$tmp = [];
				$tmp['id'] = $category->id;
				$tmp['parent_id'] = $category->parent_id;
				$tmp['title'] = $category->title;

				$db->setQuery("Select count(id) from #__edocman_categories where published = '1'  and title <> '' and parent_id = '$category->id'");
				$count = $db->loadResult();
				if($count > 0)
				{
					$tmp['hasChild'] = 1;
				}
				else
				{
					$tmp['hasChild'] = 0;
				}
				$return[] = $tmp;
			}
			$jSonArr	= self::sortCategories($return);
			$jsonString = json_encode($jSonArr, JSON_PRETTY_PRINT);
			// Write in the file
			$path		= JPATH_ROOT . '/components/com_edocman/categories.json';
			$fp			= fopen($path, 'w');
			fwrite($fp, $jsonString);
			fclose($fp);
		}
		else
		{
			$path		= JPATH_ROOT . '/components/com_edocman/categories.json';
			$jsonString = file_get_contents($path);
			$jSonArr = json_decode($jsonString, true);
		}
		return json_encode($jSonArr);
	}

	public static function sortCategories($data)
	{
		$sort = [];
		$all = [];
		$dangling = [];

		// Initialize arrays
		foreach ($data as $value) 
		{
			$value['subs'] = [];
			$id = $value['id'];

			// If this is a top-level node, add it to the sort immediately
			if ($value['parent_id'] == '0') 
			{
				$all[$id] = $value;
				$sort[] =& $all[$id];

			} else {
				$dangling[$id] = $value; 
			}
		}

		// Process all 'dangling' nodes
		while (count($dangling) > 0) 
		{
			foreach($dangling as $value) 
			{
				$id = $value['id'];
				$pid = $value['parent_id'];

				// If the parent has already been added to the sort, it's
				// safe to add this node too
				if (isset($all[$pid])) 
				{
					$all[$id] = $value;
					$all[$pid]['subs'][] =& $all[$id]; 
					unset($dangling[$value['id']]);
				}
			}
		}

		return $sort;
	}

	public static function generateCategoryList($id, $categoryName, $categoryId, $onChange = '', $firstText = '', $hasFirstOption = 1)
	{
		if($firstText == "")
		{
			$firstText = Text::_('EDOCMAN_SELECT_CATEGORY');
		}
		HTMLHelper::_('jquery.framework');
		EdocmanHelper::addScript(Uri::root(true).'/components/com_edocman/assets/js/tree/comboTreePlugin.js');
		EdocmanHelper::addStyleSheet(Uri::root(true).'/components/com_edocman/assets/js/tree/comboTreeStyle.css');
		$json = EdocmanHelper::jsonCategories($firstText, $hasFirstOption);
		$selected = '';
		if($id > 0)
		{
			$selected =  $id;
		}
		?>
		<input type="text" id="<?php echo $categoryId?>_id" placeholder="<?php echo Text::_('EDOCMAN_SELECT_CATEGORY');?>" autocomplete="off" />
		<input type="hidden" name="<?php echo $categoryName; ?>" id="<?php echo $categoryId; ?>" />
		<script type="text/javascript">
		const jsonData = <?php echo $json;?>;
		var comboTree1;
		  jQuery(document).ready(function ($) {
			comboTree1 = $("#<?php echo $categoryId?>_id").comboTree({
			  source: jsonData,
			  isMultiple: false,
			  cascadeSelect: false,
			  collapse: true,
			  selectAll: false,
			  selected: [ '<?php echo $selected?>'],
			  inputid: '#<?php echo $categoryId; ?>',
			});
			<?php
			if($onChange != "")
			{
			?>
				comboTree1.onChange(function(){<?php echo $onChange; ?>});
			<?php
			}	
			?>
		  });
		  
		</script>
		<?php
	}

	public static function viewable($item)
	{
		if($item->view_url != "")
		{
			$showModal = self::isPopularViewLink($item->view_url);
		}
		else
		{
			$showModal = true;
		}
		return $showModal;
	}

	public static function generateAudioPlayer($item, $showModal)
	{
		$audio_array = ['mp3','ogg'];
		$frame_array = ['flv'];
		$ext = StringHelper::strtolower(self::getFileExt($item)) ;
		if(in_array($ext,$audio_array) && !$showModal)
		{
			$audio_player = "rel=\"{handler: 'iframe', size: {x: 300, y: 50}, iframeOptions: {scrolling: 'no'}}\"";
		}
		elseif(in_array($ext,$frame_array))
		{
			$audio_player = "rel=\"{handler: 'iframe', size: {x: 450, y: 300}, iframeOptions: {scrolling: 'no'}}\"";
		}
		else
		{
			$audio_player = "";
		}
		return $audio_player;
	}

	public static function returnPlayExtension()
	{
		return ['mp4','flv','mp3','ogg','ogv','png','jpg','jpeg','gif','m4a','oga'];
	}

	public static function retrieveAllChildCategories($id, & $returnArr = [])
	{
		$db = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		$query->select('id')->from('#__edocman_categories')->where('parent_id='.$id)->where('published=1');
		$db->setQuery($query);
		$returnCategories = $db->loadColumn();
		if(count($returnCategories))
		{
			foreach($returnCategories as $category)
			{
				$returnArr[] = $category;
				self::retrieveAllChildCategories($category, $returnArr);
			}
		}
	}

	/**
	 * Export database to SQL file
	 *
	 * @param array $options Export options
	 * @return array Result with success status and file path
	 */
	public static function exportDatabase($options = [])
	{
		$db = Factory::getContainer()->get('db');
		$app = Factory::getApplication();
		
		try {
			// Default options
			$defaultOptions = [
				'include_categories' => true,
				'include_documents' => true,
				'include_tags' => true,
				'include_configs' => false,
				'filename' => 'edocman_export_' . date('Y-m-d_H-i-s') . '.sql'
			];
			
			$options = array_merge($defaultOptions, $options);
			
			// Get export path
			$exportPath = JPATH_ADMINISTRATOR . '/tmp/' . $options['filename'];
			
			// Start building SQL content
			$sqlContent = "-- EDocman Export File\n";
			$sqlContent .= "-- Generated on: " . date('Y-m-d H:i:s') . "\n\n";
			$sqlContent .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
			
			// Export tables based on options
			$tables = [];
			if ($options['include_categories']) {
				$tables[] = '#__edocman_categories';
			}
			if ($options['include_documents']) {
				$tables[] = '#__edocman_documents';
				$tables[] = '#__edocman_document_category';
			}
			if ($options['include_tags']) {
				$tables[] = '#__edocman_tags';
				$tables[] = '#__edocman_document_tags';
			}
			if ($options['include_configs']) {
				$tables[] = '#__edocman_configs';
			}
			
			foreach ($tables as $table) {
				$sqlContent .= self::exportTable($table);
			}
			
			$sqlContent .= "\nSET FOREIGN_KEY_CHECKS = 1;\n";
			
			// Write to file
			if (File::write($exportPath, $sqlContent)) {
				return [
					'success' => true,
					'message' => Text::_('EDOCMAN_EXPORT_SUCCESS'),
					'file' => $exportPath,
					'filename' => $options['filename']
				];
			} else {
				return [
					'success' => false,
					'message' => Text::_('EDOCMAN_EXPORT_ERROR_WRITE_FILE')
				];
			}
			
		} catch (Exception $e) {
			return [
				'success' => false,
				'message' => Text::_('EDOCMAN_EXPORT_ERROR') . ': ' . $e->getMessage()
			];
		}
	}

	/**
	 * Export single table to SQL
	 *
	 * @param string $table Table name
	 * @return string SQL content
	 */
	private static function exportTable($table)
	{
		$db = Factory::getContainer()->get('db');
		$query = $db->getQuery(true);
		
		// Get table structure
		$sql = "SHOW CREATE TABLE " . $db->quoteName($table);
		$db->setQuery($sql);
		$result = $db->loadRow();
		
		$sqlContent = "\n-- Table structure for " . $table . "\n";
		$sqlContent .= "DROP TABLE IF EXISTS " . $db->quoteName($table) . ";\n";
		$sqlContent .= $result[1] . ";\n\n";
		
		// Get table data
		$query->clear()
			->select('*')
			->from($table);
		$db->setQuery($query);
		$rows = $db->loadAssocList();
		
		if (!empty($rows)) {
			$sqlContent .= "-- Data for table " . $table . "\n";
			$sqlContent .= "INSERT INTO " . $db->quoteName($table) . " VALUES\n";
			
			$values = [];
			foreach ($rows as $row) {
				$rowValues = [];
				foreach ($row as $value) {
					if ($value === null) {
						$rowValues[] = 'NULL';
					} else {
						$rowValues[] = $db->quote($value);
					}
				}
				$values[] = '(' . implode(', ', $rowValues) . ')';
			}
			
			$sqlContent .= implode(",\n", $values) . ";\n\n";
		}
		
		return $sqlContent;
	}

	/**
	 * Import database from SQL file
	 *
	 * @param string $filePath Path to SQL file
	 * @param array $options Import options
	 * @return array Result with success status
	 */
	public static function importDatabase($filePath, $options = [])
	{
		$db = Factory::getContainer()->get('db');
		
		try {
			// Check file exists
			if (!File::exists($filePath)) {
				return [
					'success' => false,
					'message' => Text::_('EDOCMAN_IMPORT_ERROR_FILE_NOT_FOUND')
				];
			}
			
			// Read SQL file
			$sqlContent = File::read($filePath);
			if (empty($sqlContent)) {
				return [
					'success' => false,
					'message' => Text::_('EDOCMAN_IMPORT_ERROR_EMPTY_FILE')
				];
			}
			
			// Split SQL statements
			$statements = self::splitSqlStatements($sqlContent);
			
			$successCount = 0;
			$errorCount = 0;
			$errors = [];
			
			foreach ($statements as $statement) {
				$statement = trim($statement);
				if (empty($statement) || strpos($statement, '--') === 0) {
					continue;
				}
				
				try {
					$db->setQuery($statement);
					$db->execute();
					$successCount++;
				} catch (Exception $e) {
					$errorCount++;
					$errors[] = $e->getMessage();
				}
			}
			
			if ($errorCount > 0) {
				return [
					'success' => false,
					'message' => Text::sprintf('EDOCMAN_IMPORT_PARTIAL_SUCCESS', $successCount, $errorCount),
					'errors' => $errors
				];
			}
			
			return [
				'success' => true,
				'message' => Text::sprintf('EDOCMAN_IMPORT_SUCCESS', $successCount)
			];
			
		} catch (Exception $e) {
			return [
				'success' => false,
				'message' => Text::_('EDOCMAN_IMPORT_ERROR') . ': ' . $e->getMessage()
			];
		}
	}

	/**
	 * Split SQL content into individual statements
	 *
	 * @param string $sql SQL content
	 * @return array Array of SQL statements
	 */
	private static function splitSqlStatements($sql)
	{
		// Remove comments
		$sql = preg_replace('/^--.*$/m', '', $sql);
		
		// Split by semicolon but not inside quotes
		$statements = [];
		$current = '';
		$inQuotes = false;
		$quoteChar = '';
		
		for ($i = 0; $i < strlen($sql); $i++) {
			$char = $sql[$i];
			
			if (!$inQuotes && ($char === '"' || $char === "'")) {
				$inQuotes = true;
				$quoteChar = $char;
			} elseif ($inQuotes && $char === $quoteChar) {
				// Check for escaped quote
				if ($i > 0 && $sql[$i-1] !== '\\') {
					$inQuotes = false;
				}
			} elseif (!$inQuotes && $char === ';') {
				$statements[] = trim($current);
				$current = '';
				continue;
			}
			
			$current .= $char;
		}
		
		if (!empty(trim($current))) {
			$statements[] = trim($current);
		}
		
		return array_filter($statements);
	}

	/**
	 * Get export/import statistics
	 *
	 * @return array Statistics data
	 */
	public static function getExportImportStats()
	{
		$db = Factory::getContainer()->get('db');
		$stats = [];
		
		// Count categories
		$query = $db->getQuery(true);
		$query->select('COUNT(*)')
			->from('#__edocman_categories');
		$db->setQuery($query);
		$stats['categories'] = (int) $db->loadResult();
		
		// Count documents
		$query->clear()
			->select('COUNT(*)')
			->from('#__edocman_documents');
		$db->setQuery($query);
		$stats['documents'] = (int) $db->loadResult();
		
		// Count tags
		$query->clear()
			->select('COUNT(*)')
			->from('#__edocman_tags');
		$db->setQuery($query);
		$stats['tags'] = (int) $db->loadResult();
		
		// Count configs
		$query->clear()
			->select('COUNT(*)')
			->from('#__edocman_configs');
		$db->setQuery($query);
		$stats['configs'] = (int) $db->loadResult();
		
		return $stats;
	}

	/**
	 * Clean up temporary export files
	 *
	 * @param int $olderThanDays Delete files older than X days
	 * @return int Number of files deleted
	 */
	public static function cleanupExportFiles($olderThanDays = 7)
	{
		$tmpPath = JPATH_ADMINISTRATOR . '/tmp/';
		$files = Folder::files($tmpPath, 'edocman_export_.*\.sql');
		$deleted = 0;
		
		$cutoffTime = time() - ($olderThanDays * 24 * 60 * 60);
		
		foreach ($files as $file) {
			$filePath = $tmpPath . $file;
			if (filemtime($filePath) < $cutoffTime) {
				if (File::delete($filePath)) {
					$deleted++;
				}
			}
		}
		
		return $deleted;
	}

	public static function formatBytes($bytes, $precision = 2)
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB');
        
        for ($i = 0; $bytes > 1024; $i++) {
            $bytes /= 1024;
        }
        
        return round($bytes, $precision) . ' ' . $units[$i];
    }


	public static function isPDFViewerEnabled()
	{
		return true;
	}

	public static function generateHumanTitle($title)
	{
		$config = self::getConfig();
		if($config->human_title)
		{
			$returnTitle		= "";
			$originalFileArr	= explode(".", $title);
			if(count($originalFileArr) > 1)
			{
				for($j = 0; $j < count($originalFileArr) - 1; $j++)
				{
					$returnTitle .= $originalFileArr[$j];
				}
			}
			else
			{
				$returnTitle    = $originalFileArr[0];
			}

			$returnTitle		= str_replace("-", " ", $returnTitle);
			$returnTitle		= str_replace("_", " ", $returnTitle);
			$returnTitle		= ucfirst($returnTitle);
			
			return $returnTitle;
		}
		else
		{
			return $title;
		}
	}

	/**
	 * Method to get file extension
	 *
	 * @param   string  $file
	 *
	 * @return string
	 */
	public static function getExt($file)
	{
		if (is_object($file)) {
			$file = $file->original_filename;
		}
		// Use framework code if available
		if (is_callable([File::class, 'getExt']))
		{
			return File::getExt($file);
		}

		// String manipulation should be faster than pathinfo() on newer PHP versions.
		$dot = strrpos($file, '.');

		if ($dot === false)
		{
			return '';
		}

		$ext = substr($file, $dot + 1);

		// Extension cannot contain slashes.
		if (strpos($ext, '/') !== false || (DIRECTORY_SEPARATOR === '\\' && strpos($ext, '\\') !== false))
		{
			return '';
		}

		return $ext;
	}

	public static function getFileExt($file)
	{
		return self::getExt($file);
	}

	public static function noindex()
	{
		$document = Factory::getApplication()->getDocument();
		$document->addCustomTag('<meta name="robots" content="nofollow" />');
        $document->setMetaData( "robots", "noindex" );
	}
	
	/**
	 * Helper method to determine if we are in Joomla 4
	 *
	 * @return bool
	 */
	public static function isJoomla4()
	{
		return version_compare(JVERSION, '4.0.0-dev', 'ge');
	}

	/**
	 * Helper method to determine if we are in Joomla 4
	 *
	 * @return bool
	 */
	public static function isJoomla5()
	{
		return version_compare(JVERSION, '4.4.99', '>');
	}
	/**
	 * Get the version which is currently installed on the site
	 *
	 * @return string
	 */
	public static function getInstalledVersion()
	{
		return '3.0';
	}
}
