<?php

/**
 * @copyright (C) 2013 iJoomla, Inc. - All rights reserved.
 * @license GNU General Public License, version 2 (http://www.gnu.org/licenses/gpl-2.0.html)
 * @author iJoomla.com <webmaster@ijoomla.com>
 * @url https://www.jomsocial.com/license-agreement
 * The PHP code portions are distributed under the GPL license. If not otherwise stated, all images, manuals, cascading style sheets, and included JavaScript *are NOT GPL, and are released under the IJOOMLA Proprietary Use License v1.0
 * More info at https://www.jomsocial.com/license-agreement
 */

use Joomla\CMS\Access\Access;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Table\Table;
use Joomla\CMS\Uri\Uri;

// no direct access
defined('_JEXEC') or die('Restricted access');

if (version_compare(JVERSION, '4', '>=')) {
	require_once JPATH_ROOT . '/components/com_community/libraries/j3.php';
}

jimport('joomla.plugin.plugin');
jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');
jimport('joomla.event.dispatcher');

// Define autoload function
spl_autoload_register('CFactory::autoload_models');
spl_autoload_register('CFactory::autoload_libraries');
spl_autoload_register('CFactory::autoload_helpers');
spl_autoload_register('CFactory::autoload_events');
spl_autoload_register('CFactory::autoload_tables');

// @todo: to be removed once the functions has be autoloaded
require_once (JPATH_ROOT . '/components/com_community/defines.community.php');

/**
 * Register Joomla! autoloading
 */
/* Register our APIs classes */
JLoader::discover('CApi', COMMUNITY_PATH_SITE . '/apis');
JLoader::discover('C', COMMUNITY_PATH_SITE . '/libraries');

Table::addIncludePath(JPATH_ROOT . '/administrator/components/com_community/tables');
Table::addIncludePath(COMMUNITY_COM_PATH . '/tables');

// In case our core.php files are loaded by 3rd party extensions, we need to define the plugin path environments for Zend.
$paths = explode(PATH_SEPARATOR, get_include_path());

// to prevent fatal error at jomsocial API
try {
    Factory::getLanguage()->load('com_community');   
} catch (Exception $e) {
    // do nothing
}

class CFactory {

    static $instances = array(); // user instances

    /**
     * Function to allow caller to get a user object while
     * it is not authenticated provided that it has a proper tokenid
     * */
    static public function getUserFromTokenId($tokenId, $userId) {
        $db = Factory::getDBO();

        $query = 'SELECT COUNT(*) '
                . 'FROM ' . $db->quoteName('#__community_photos_tokens') . ' '
                . 'WHERE ' . $db->quoteName('token') . '=' . $db->Quote($tokenId) . ' '
                . 'AND ' . $db->quoteName('userid') . '=' . $db->Quote($userId);

        $db->setQuery($query);

        $count = $db->loadResult();

        // We can assume that the user parsed in correct token and userid. So,
        // we return them the proper user object.
        if ($count >= 1) {
            $user = CFactory::getUser($userId);

            return $user;
        }

        // If it doesn't bypass our tokens, we assume they are really trying
        // to hack or got in here somehow.
        $user = CFactory::getUser(null);

        return $user;
    }

    /**
     * Load multiple users at a same time to save up on the queries.
     * @return	boolean		True upon success
     * @param	Array	$userIds	An array of user ids to be loaded.
     */
    static public function loadUsers($userIds) {

        $userIds = array_diff_key( $userIds, self::$instances );

        if (empty($userIds)) {
            return;
        }

        $ids = implode(",", $userIds);
        $db = Factory::getDBO();
        $query = 'SELECT  '
                . ' a.' . $db->quoteName('userid') . ' as _userid ,'
                . ' a.' . $db->quoteName('status') . ' as _status , '
                . ' a.' . $db->quoteName('points') . ' as _points, '
                . ' a.' . $db->quoteName('posted_on') . ' as _posted_on, '
                . ' a.' . $db->quoteName('avatar') . ' as _avatar , '
                . ' a.' . $db->quoteName('thumb') . ' as _thumb , '
                . ' a.' . $db->quoteName('invite') . ' as _invite, '
                . ' a.' . $db->quoteName('params') . ' as _cparams,  '
                . ' a.' . $db->quoteName('view') . ' as _view, '
                . ' a.' . $db->quoteName('friends') . ' as _friends, '
                . ' a.' . $db->quoteName('groups') . ' as _groups, '
                . ' a.' . $db->quoteName('events') . ' as _events, '
                . ' a.' . $db->quoteName('alias') . '	as _alias, '
                . ' a.' . $db->quoteName('profile_id') . ' as _profile_id, '
                . ' a.' . $db->quoteName('friendcount') . ' as _friendcount, '
                . ' a.' . $db->quoteName('storage') . ' as _storage, '
                . ' a.' . $db->quoteName('watermark_hash') . ' as _watermark_hash, '
                . ' a.' . $db->quoteName('search_email') . ' AS _search_email, '
                . ' s.' . $db->quoteName('userid') . ' as _isonline, u.* '
                . ' FROM ' . $db->quoteName('#__community_users') . ' as a '
                . ' LEFT JOIN ' . $db->quoteName('#__users') . ' u '
                . ' ON u.' . $db->quoteName('id') . '=a.' . $db->quoteName('userid')
                . ' LEFT OUTER JOIN ' . $db->quoteName('#__session') . 's '
                . ' ON s.' . $db->quoteName('userid') . '=a.' . $db->quoteName('userid')
                . ' WHERE a.' . $db->quoteName('userid') . ' IN (' . $ids . ')';

        $db->setQuery($query);
        $objs = $db->loadObjectList();

        foreach ($objs as $obj) {
            $user = new CUser($obj->_userid);
            $isNewUser = $user->init($obj);

            $user->getThumbAvatar();

            // technically, we should not fetch any new user here
            if ($isNewUser) {
                // New user added to jomSocial database
                // trigger event onProfileInit
                $appsLib = CAppPlugins::getInstance();
                $appsLib->loadApplications();

                $args = array();
                $args[] = $user;
                $appsLib->triggerEvent('onProfileCreate', $args);
            }

            CFactory::getUser($obj->_userid, $user);
        }
    }

    /**
     * Retrieves a CUser object given the user id.
     *
     * @return	CUser	A CUser object
     * @param	int		$id		A user id (optional)
     * @param	CUser	$obj	An existing user object (optional)
     */
    public static function getUser($id = null, $obj = null) {
        if ($id != 0 && !is_null($obj)) {
            if($obj->_cover != ''){ // somehow the cover is missing, do not assign the user object if the cover is missing.
                self::$instances[$id] = $obj;
            }
            return;
        }

        if ($id === 0) {
            $user = Factory::getUser();
            $id = $user->id;
        } else {
            $db = Factory::getDBO();

            if ($id == null) {
                $user = Factory::getUser();
                $id = $user->id;
            }

            if ($id != null && !is_numeric($id)) {
                $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__users') . ' WHERE UCASE(' . $db->quoteName('username') . ') like UCASE(' . $db->Quote($id) . ')';
                $db->setQuery($query);
                $id = $db->loadResult();
            }

            if(is_numeric($id) && empty(self::$instances[$id])){
                //we must make sure this user exists
                $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__users') . ' WHERE ' . $db->quoteName('id') . ' = ' . $db->Quote($id);
                $db->setQuery($query);
                $testUser = $db->loadResult();

                $id = ($testUser) ? $id : 0;
            }
        }

        if (empty(self::$instances[$id])) {
            if (!is_numeric($id) && !is_null($id)) {
                Factory::getApplication()->enqueueMessage(Text::sprintf('COM_COMMUNITY_CANNOT_LOAD_USER', $id), 'error');
            }

            self::$instances[$id] = new CUser($id);
            $isNewUser = self::$instances[$id]->init();
            self::$instances[$id]->getThumbAvatar();

            if ($isNewUser) {
                // New user added to jomSocial database
                // trigger event onProfileInit
                $appsLib = CAppPlugins::getInstance();
                $appsLib->loadApplications();

                $args = array();
                $args[] = self::$instances[$id];
                $appsLib->triggerEvent('onProfileCreate', $args);
            }

            // Guess need to have avatar as well.
            if ($id == 0) {
                Factory::getLanguage()->load('com_community');

                self::$instances[$id]->name = Text::_('COM_COMMUNITY_ACTIVITIES_GUEST');
                self::$instances[$id]->username = Text::_('COM_COMMUNITY_ACTIVITIES_GUEST');
                self::$instances[$id]->_avatar = 'components/com_community/assets/default.jpg';
                self::$instances[$id]->_thumb = 'components/com_community/assets/default_thumb.jpg';
            }
        }
        return self::$instances[$id];
    }

    /**
     * Retrieves CConfig configuration object
     * @return	object	CConfig object
     * @param
     */
    public static function getConfig() {
        return CConfig::getInstance();
    }

    public static function getJomsVersion()
    {
        $file = JPATH_ADMINISTRATOR . '/components/com_community/community.xml';
        if (file_exists($file)) {
            $xml = simplexml_load_file($file);

            return (string) $xml->version;
        } else {
            return '1.0.0';
        }
    }

    /**
     * Return fast, memory-based JCache object. For now, only APC cache
     * will be supported
     */
    public static function getFastCache($type = 'output') {
        static $instance = null;

        if (is_null($instance)) {
            jimport('joomla.cache.cache');

            // Check for APC
            $options = array('storage' => 'apc', 'lifetime' => '300');
            if (extension_loaded('apc')) {
                $options['caching'] = true;
            } else {
                // Disable caching
                $options['caching'] = false;
            }

            $cache = Cache::getInstance($type, $options);
            $instance = new CFastCache($cache);
        }

        return $instance;
    }

    /**
     * Returns a configured version of Zend_Cache object
     *
     * @param	string	$frontendEngine		Frontend engine to use
     * @param	string	$frontendOptions	Additional options for the frontend object
     * @return	object	Zend_Cache object
     */
    public function deprecated_getCache($frontendEngine, $frontendOptions = array()) {
        $app = Factory::getApplication();
        //$jConfig	= Factory::getConfig();
        // If Joomla cache folder does not exist, try to create them.
        if (!Folder::exists(JPATH_ROOT . '/cache')) {
            Folder::create(JPATH_ROOT . '/cache');
            File::copy(JPATH_ROOT . '/components/com_community/index.html', JPATH_ROOT . '/cache/index.html');
        }

        // Configure additional options for frontend
        $defaultOptions = array(
            'lifetime' => 86400, // cache lifetime of 24 hours (time is in seconds)
            'automatic_serialization' => true, //default is false
            'cache_id_prefix' => '_com_community', //prefix
            'caching' => Factory::getConfig()->get('caching') //$jConfig->getValue('caching') // enable or disable caching
        );

        switch ($frontendEngine) {
            case 'Core':
                break;
            case 'Output':
                break;
            case 'Class':
                break;
            case 'Function':
                break;
        }
        $frontendOptions = array_merge($defaultOptions, $frontendOptions);

        $backendOptions = array();
        $backendEngine = '';

        //switch($jConfig->getValue('cache_handler')){
        switch (Factory::getConfig()->get('cache_handler')) {
            case 'file':
                $backendOptions = array(
                    'cache_dir' => JPATH_ROOT . '/cache/');
                $backendEngine = 'File';
                break;
            case 'apc':
                $backendOptions = array(
                    'cache_dir' => JPATH_ROOT . '/cache');
                $backendEngine = 'Apc';
                break;

            // not supportted for now, return a dummy cache object
            case 'xcache':
            case 'eaccelerator':
            case 'memcache':
            default:
                $backendOptions = array(
                    'cache_dir' => JPATH_ROOT . '/cache/');
                $backendEngine = 'File';
                $frontendOptions['caching'] = FALSE;
                break;
        }

        $zend_cache = Zend_Cache::factory($frontendEngine, $backendEngine, $frontendOptions, $backendOptions);
        return $zend_cache;
    }

    /**
     * Register autoload functions, using JImport::JLoader
     */
    public function autoload() {
        //JLoader::register('classname', 'filename');
    }

    /**
     * Return CInput instance
     */
    static public function getInput() {
        static $inputInstance = null;
        if (!isset($inputInstance)) {
            $inputInstance = new CInput;
        }
        return $inputInstance;
    }

    /**
     * Return the model object, responsible for all db manipulation. Singleton
     *
     * @param	string		model name
     * @param	string		any class prefix
     * @return	object		model object
     */
    static public function getModel($name = '', $prefix = '', $config = array()) {
        static $modelInstances = null;

        if (!isset($modelInstances)) {
            $modelInstances = array();
            include_once(JPATH_ROOT . '/components/com_community/libraries/error.php');
        }

        if (!isset($modelInstances[$name . $prefix])) {
            include_once( JPATH_ROOT . '/components/com_community/models/models.php');

            // @rule: We really need to test if the file really exists.
            $modelFile = JPATH_ROOT . '/components/com_community/models/' . strtolower($name) . '.php';
            if (!File::exists($modelFile)) {
                $modelInstances[$name . $prefix] = false;
            } else {
                include_once( $modelFile );
                $classname = $prefix . 'CommunityModel' . $name;
                $modelInstances[$name . $prefix] = new $classname;
            }
        }

        return $modelInstances[$name . $prefix];
    }

    // @getBookmarks deprecated.
    // since 1.5
    static public function getBookmarks($uri) {
        static $bookmark = null;

        if (is_null($bookmark)) {
            //CFactory::load( 'libraries' , 'bookmarks' );
            $bookmark = new CBookmarks($uri);
        }
        return $bookmark;
    }

    static public function getToolbar() {
        // We need to load the language code here since some plugin
        // apparently modify this before language code is loaded
        Factory::getLanguage()->load('com_community');

        static $toolbar = null;

        if (is_null($toolbar)) {
            //CFactory::load( 'libraries' , 'toolbar' );

            $toolbar = new CToolbar();
        }
        return $toolbar;
    }

    /**
     * Return the view object, responsible for all db manipulation. Singleton
     *
     * @param	string		model name
     * @param	string		any class prefix
     * @return	object		model object
     */
    static public function getView($name = '', $prefix = '', $viewType = '') {
        static $viewInstances = null;

        if (!isset($viewInstances)) {
            $viewInstances = array();
            include_once(JPATH_ROOT . '/components/com_community/libraries/error.php');
        }

        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;

        $viewType = $jinput->request->get('format', 'html', 'NONE');
        // if(CTemplate::mobileTemplate())
        // 	$viewType = 'mobile';

        if ($viewType == 'json')
            $viewType = 'html';

        if (!isset($viewInstances[$name . $prefix . $viewType])) {
            jimport('joomla.filesystem.file');

            $viewFile = JPATH_COMPONENT . '/views' . '/' . $name . '/view.' . $viewType . '.php';

            if (File::exists($viewFile)) {
                include_once( $viewFile );
            } else {
                //@rule: when feed is not available, we include the main view file.
                if ($viewType == 'feed') {
                    include_once( JPATH_COMPONENT . '/views' . '/' . $name . '/view.html.php' );
                } else {
                    //Factory::getApplication()->enqueueMessage(JText::sprintf('COM_COMMUNITY_VIEW_NOT_FOUND', JPATH_COMPONENT . '/views' . '/' . $name . '/view.html.php'), 'error');
                    return;
                }
            }

            $classname = $prefix . 'CommunityView' . ucfirst($name);
            if (!class_exists($classname)) {
                Factory::getApplication()->enqueueMessage(Text::sprintf('COM_COMMUNITY_VIEW_NOT_FOUND', $classname), 'error');
                return;
            }

            $viewInstances[$name . $prefix . $viewType] = new $classname;
        }

        return $viewInstances[$name . $prefix . $viewType];
    }

    /**
     * return the currently viewed user profile object,
     * for now, just return an object with username, id, email
     * @deprecated since 1.6.x
     */
    static public function getActiveProfile() {

        $my = Factory::getUser();
        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;

        $uid = $jinput->request->get('userid', 0, 'INT');

        if ($uid == 0) {
            $uid = $jinput->cookie->get('activeProfile', null);
        }

        $obj = CFactory::getUser($uid);

        return $obj;
    }

    /**
     * Returns the current user requested 'userid', should be part of the request
     * parameter
     *
     * @param
     * @return	object	Current CUser object
     */
    static public function getRequestUser() {
        static $usersCollection = array();

        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;
        $id = $jinput->get('userid', '', 'INT');

        if($id == '' && array_key_exists(0, $usersCollection)){
            return $usersCollection[0];
        }elseif(!array_key_exists($id, $usersCollection)){

            $user = CFactory::getUser($id);
            $id = ($id) ? $id : 0;
            $usersCollection[$id] = $user;
        }

        return $usersCollection[$id];
    }

    /**
     * Return standard joomla filter objects
     *
     * @param	boolean		$allowHTML	True if you want to allow safe HTML through
     * @param	boolean		$simpleHTML	True if you want to allow simple HTML tags
     * @return	object		JFilterInput object
     */
    static public function getInputFilter($allowHTML = false, $safeTagsCustom  = array(), $safeAttrCustom = array()) {
        jimport('joomla.filter.filterinput');
        $safeTags = array();
        $safeAttr = array();

        if ($allowHTML) {
            $safeAttr = array('abbr', 'accept', 'accept-charset', 'accesskey', 'action', 'align', 'alt', 'axis', 'border', 'cellpadding', 'cellspacing', 'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'clear', 'cols', 'colspan', 'color', 'compact', 'coords', 'datetime', 'dir', 'disabled', 'enctype', 'for', 'frame', 'headers', 'height', 'href', 'hreflang', 'hspace', 'id', 'ismap', 'label', 'lang', 'longdesc', 'maxlength', 'media', 'method', 'multiple', 'name', 'nohref', 'noshade', 'nowrap', 'prompt', 'readonly', 'rel', 'rev', 'rows', 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', 'span', 'src', 'start', 'style', 'summary', 'tabindex', 'target', 'title', 'type', 'usemap', 'valign', 'value', 'vspace', 'width');
            $safeTags = array('a', 'abbr', 'acronym', 'address', 'area', 'b', 'big', 'blockquote', 'br', 'button', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', 'ol', 'optgroup', 'option', 'p', 'pre', 'q', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var');
        }

        if(count($safeTagsCustom)) {
            $safeTags = $safeTagsCustom;
        }

        if(count($safeAttrCustom)) {
            $safeAttr= $safeAttrCustom;
        }

        $safeHtmlFilter = InputFilter::getInstance($safeTags, $safeAttr);

        return $safeHtmlFilter;
    }

    /**
     * Set current active profile
     * @param	integer id	Current user id
     * @deprecated	since 1.6.x
     */
    static public function setActiveProfile($id = '') {
        if (empty($id)) {
            $my = CFactory::getUser();
            $id = $my->id;
        }

        $app = Factory::getApplication();
        $lifetime = Factory::getConfig()->get('lifetime');

        setcookie('activeProfile', $id, time() + ($lifetime * 60), '/');
    }

    /**
     * @deprecated since 1.6.x
     */
    static public function unsetActiveProfile() {

        $app = Factory::getApplication();
        $lifetime = Factory::getConfig()->get('lifetime');

        setcookie('activeProfile', false, time() + ($lifetime * 60 ), '/');
    }

    /**
     * Sets the current requested URI in the cookie so the system knows where it should
     * be redirected to.
     *
     * @param
     * @return
     */
    static public function setCurrentURI() {
        $uri = Uri::getInstance();
        $current = $uri->toString();

        setcookie('currentURI', $current, time() + 60 * 60 * 24, '/');
    }

    /**
     * Gets the last accessed URI from the cookie if user is coming from another page.
     *
     * @param
     * @return	string	The last accessed URI in the cookie (E.g http://site.com/index.php)
     */
    static public function getLastURI() {
        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;

        $uri = $jinput->cookie->get('currentURI', null);

        $match = array();
        preg_match('/(?i)ajax/',$uri, $match); // @since 3.3 if this url contains ajax, assign to root url as well

        if (is_null($uri) || (isset($match[0]) && !empty($match[0])) ) {
            $uri = Uri::root();
        }
        return $uri;
    }

    /**
     * Return the view object, responsible for all db manipulation. Singleton
     *
     * @param	string		type	libraries/helper
     * @param	string		name 	class prefix
     */
    static public function load($type, $name) {
        if ($type == 'models')
            return;

        include_once(JPATH_ROOT . '/components/com_community/libraries/error.php');

        // Test if file really exists before php throws errors.
        $path = JPATH_ROOT . '/components/com_community/' . $type . '/' . strtolower($name) . '.php';
        if (File::exists($path)) {
            include_once( $path );
        }

        // If it is a library, we call the object and call the 'load' method
        if ($type == 'libraries') {
            $classname = 'C' . $name;
            if (class_exists($classname)) {
                // OK, class exist
            }
        }
    }

    /**
     * Autoload class
     */
    static function autoload_models($classname) {
        // These interfaces doesn't have specific naming logic. Define them manually
        $classes = array(
            'CTaggable_Item' => '/models/tags.php',
            'CGeolocationInterface' => '/models/models.php',
            'CLimitsInterface' => '/models/models.php',
            'CommunityModelActivities' => '/models/activities.php',
            'CommunityModelApplications' => '/models/applications.php',
            'CommunityModelApps' => '/models/apps.php',
            'CommunityModelAvatar' => '/models/avatar.php',
            'CommunityModelBlock' => '/models/block.php',
            'CommunityModelBulletins' => '/models/bulletins.php',
            'CommunityModelCommunity' => '/models/community.php',
            'CommunityModelConfiguration' => '/models/configurations.php',
            'CommunityModelConnect' => '/models/connect.php',
            'CommunityModelDiscussions' => '/models/discussion.php',
            'CommunityModelEventCategories' => '/models/eventcategories.php',
            'CommunityModelEvents' => '/models/events.php',
            'CommunityModelFeatured' => '/models/featured.php',
            'CommunityModelFiles' => '/models/files.php',
            'CommunityModelFriends' => '/models/friends.php',
            'CommunityModelGroupCategories' => '/models/groupcategories.php',
            'CommunityModelGroups' => '/models/groups.php',
            'CommunityModelPolls' => '/models/polls.php',
            'CommunityModelInbox' => '/models/inbox.php',
            'CommunityModelLike' => '/models/like.php',
            'CommunityModelMailq' => '/models/mailq.php',
            'CommunityModelMailqueue' => '/models/mailqueue.php',
            'CommunityModelMemberlist' => '/models/memberlist.php',
            'JCCModel' => '/models/models.php',
            'CommunityModelMultiProfile' => '/models/multiprofile.php',
            'CommunityModelNetwork' => '/models/network.php',
            'CommunityModelNotification' => '/models/notification.php',
            'CommunityModelPhotos' => '/models/photos.php',
            'CommunityModelPhotoTagging' => '/models/phototagging.php',
            'CommunityModelProfile' => '/models/profile.php',
            'CommunityModelProfiles' => '/models/profiles.php',
            'CommunityModelRegister' => '/models/register.php',
            'CommunityModelReporters' => '/models/reporters.php',
            'CommunityModelReports' => '/models/reports.php',
            'CommunityModelSearch' => '/models/search.php',
            'CommunityModelStatus' => '/models/status.php',
            'CommunityModelTags' => '/models/tags.php',
            'CommunityModelToolbar' => '/models/toolbar.php',
            'CommunityModelUser' => '/models/user.php',
            'CommunityModelUserPoints' => '/models/userpoints.php',
            'CommunityModelUsers' => '/models/users.php',
            'CommunityModelVideos' => '/models/videos.php',
            'CommunityModelVideosCategories' => '/models/videoscategories.php',
            'CommunityModelVideoTagging' => '/models/videotagging.php',
            'CommunityModelWall' => '/models/wall.php',
            'CommunityModelHashtags' => '/models/hashtags.php',
            'CommunityModelManualDbUpgrade' => '/models/manualdbupgrade.php',
            'CommunityModelMigrators' => '/models/migrators.php',
            'CommunityModelMigratorCB' => '/models/migratorCB.php',
            'CommunityModelMigratorEasySocial' => '/models/migratorEasySocial.php',
            'CommunityModelDigest' => '/models/digest.php',
            'CommunityModelChat' => '/models/chat.php',
            'CommunityModelFollowers' => '/models/followers.php',
            'CommunityModelPageCategories' => '/models/pagecategories.php',
            'CommunityModelPages' => '/models/pages.php',
        );

        $app = Factory::getApplication();
        if ($app->isClient('administrator') && array_key_exists($classname, $classes) && file_exists(JPATH_ROOT . '/administrator/components/com_community' . $classes[$classname])) {
            require_once(JPATH_ROOT . '/administrator/components/com_community' . $classes[$classname]);
        }elseif(array_key_exists($classname, $classes) && file_exists(JPATH_ROOT . '/components/com_community' . $classes[$classname])) {
            require_once(JPATH_ROOT . '/components/com_community' . $classes[$classname]);
        }
    }

    /**
     * Autoload class
     */
    static function autoload_libraries($classname) {
        $classes = array(
            'CInput' => '/libraries/input.php',
            'CAppPlugins' => '/libraries/apps.php',
            'CError' => '/libraries/error.php',
            'CFastCache' => '/libraries/cache.php',
            'CStorage' => '/libraries/storage.php',
            'CStorageMethod' => '/libraries/storage.php',
            'CUser' => '/libraries/user.php',
            'CParameter' => '/libraries/parameter.php',
            'CActivityStream' => '/libraries/activities.php',
            'CActivities' => '/libraries/activities.php',
            'CTemplate' => '/libraries/template.php',
            'CActivities' => '/libraries/activities.php',
            'CAdminstreams' => '/libraries/adminstreams.php',
            'CAkismet' => '/libraries/akismet.php',
            'Akismet' => '/libraries/akismet_base.php',
            'CAppPlugins' => '/libraries/apps.php',
            'CAvatar' => '/libraries/avatar.php',
            'blockUser' => '/libraries/block.php',
            'CBookmarks' => '/libraries/bookmarks.php',
            'CBrowser' => '/libraries/browser.php',
            'CFastCache' => '/libraries/cache.php',
            'CCarousel' => '/libraries/carousel.php',
            'CComment' => '/libraries/comment.php',
            'CConnectionLibrary' => '/libraries/connection.php',
            'CCron' => '/libraries/cron.php',
            'CDatetime' => '/libraries/datetime.php',
            'CEditor' => '/libraries/editor.php',
            'CEmailTypes' => '/libraries/emailtypes.php',
            'CError' => '/libraries/error.php',
            'CEvents' => '/libraries/events.php',
            'CFacebook' => '/libraries/facebook.php',
            'CFeatured' => '/libraries/featured.php',
            'CFiles' => '/libraries/files.php',
            'CFilesLibrary' => '/libraries/files.php',
            'CFilterBar' => '/libraries/filterbar.php',
            'CFormElement' => '/libraries/formelement.php',
            'CFriends' => '/libraries/friends.php',
            'CGroups' => '/libraries/groups.php',
            'CICal' => '/libraries/ical.php',
            'CImage' => '/libraries/image.php',
            'CInvitationMail' => '/libraries/invitation.php',
            'CInvitation' => '/libraries/invitation.php',
            'CJForm' => '/libraries/jform.php',
            'CJSMin' => '/libraries/jsmin.php',
            'JSNetworkLibrary' => '/libraries/jsnetwork.php',
            'CKarma' => '/libraries/karma.php',
            'CLike' => '/libraries/like.php',
            'CLimitsLibrary' => '/libraries/limits.php',
            'CMailq' => '/libraries/mailq.php',
            'CMapping' => '/libraries/mapping.php',
            'CMessaging' => '/libraries/messaging.php',
            'CMiniHeader' => '/libraries/miniheader.php',
            'CDocumentMobile' => '/libraries/mobile.php',
            'CMyBlog' => '/libraries/myblog.php',
            'CNotification' => '/libraries/notification.php',
            'CNotificationLibrary' => '/libraries/notification.php',
            'CNotificationTypes' => '/libraries/notificationtypes.php',
            'CExtraNotification' => '/libraries/extra_notification.php',
            'CParameter' => '/libraries/parameter.php',
            'CPhotos' => '/libraries/photos.php',
            'CPhotoTagging' => '/libraries/phototagging.php',
            'CPrivacy' => '/libraries/privacy.php',
            'CProfile' => '/libraries/profile.php',
            'CProfileLibrary' => '/libraries/profile.php',
            'CommunityRelationshipLib' => '/libraries/relationship.php',
            'CReporting' => '/libraries/reporting.php',
            'CReportingLibrary' => '/libraries/reporting.php',
            'CSpamFilter' => '/libraries/spamfilter.php',
            'CStaticmap' => '/libraries/staticmap.php',
            'CStorage' => '/libraries/storage.php',
            #'CStorage'                => '/libraries/streamer.php',
            'CTags' => '/libraries/tags.php',
            'CAdvanceSearch' => '/libraries/advancesearch.php',
            'CToolbar' => '/libraries/toolbar.php',
            'cAvatarTooltip' => '/libraries/tooltip.php',
            #'CAdvanceSearch'          => '/libraries/url.php',
            'CUser' => '/libraries/user.php',
            'CUserPoints' => '/libraries/userpoints.php',
            'CUserStatus' => '/libraries/userstatus.php',
            'CUserStatusCreator' => '/libraries/userstatus.php',
            'CVideos' => '/libraries/videos.php',
            'CVideoTagging' => '/libraries/videotagging.php',
            'CWallLibrary' => '/libraries/wall.php',
            'CWall' => '/libraries/wall.php',
            'CWindow' => '/libraries/window.php',
            'CZencoderOutput' => '/libraries/zencoder.php',
            'CMinitip' => '/libraries/minitip.php',
            'CVideoLibrary' => '/libraries/videos.php',
            'CToolbarLibrary' => '/libraries/toolbar.php',
            'CTooltip' => '/libraries/tooltip.php',
            'CCommentInterface' => '/libraries/comment.php',
            'CFieldsBirthdate' => '/libraries/fields/birthdate.php',
            'CFieldsCheckbox' => '/libraries/fields/checkbox.php',
            'JFormFieldCMultiList' => '/libraries/fields/cmultilist.php',
            'CFieldsLocation' => '/libraries/fields/location.php',
            'CFieldsCountry' => '/libraries/fields/country.php',
            'CFieldsDate' => '/libraries/fields/date.php',
            'CFieldsEmail' => '/libraries/fields/email.php',
            'CFieldsGender' => '/libraries/fields/gender.php',
            'CFieldsLabel' => '/libraries/fields/label.php',
            'CFieldsList' => '/libraries/fields/list.php',
            'CProfileField' => '/libraries/fields/profilefield.php',
            'CFieldsRadio' => '/libraries/fields/radio.php',
            'CFieldsSelect' => '/libraries/fields/select.php',
            'CFieldsSingleselect' => '/libraries/fields/singleselect.php',
            'CFieldsText' => '/libraries/fields/text.php',
            'CFieldsTextarea' => '/libraries/fields/textarea.php',
            'CFieldsTime' => '/libraries/fields/time.php',
            'CFieldsUrl' => '/libraries/fields/url.php',
            'CFieldsProfiletypes' => '/libraries/fields/profiletypes.php', // for joomlaxi
            'CFieldsTemplates'   => '/libraries/fields/templates.php', // for joomlaxi
            'FacebookApiException' => '/libraries/facebook/base_facebook.php',
            //'BaseFacebook' => '/libraries/facebook/base_facebook.php',
            //'FacebookLib' => '/libraries/facebook/facebook.php',
            'File_CStorage' => '/libraries/storage/file.php',
            'S3_CStorage' => '/libraries/storage/s3.php',
            'CTableStorageS3' => '/libraries/storage/s3.php',
            'S3' => '/libraries/storage/s3_lib.php',
            'S3Request' => '/libraries/storage/s3_lib.php',
            'tmhOAuth' => '/libraries/twitter/tmhOAuth.php',
            'tmhUtilities' => '/libraries/twitter/tmhUtilities.php',
            'CFilesLibrary' => '/libraries/files.php',
            'CTwitter' => '/libraries/twitter.php',
            'CEngagement' => '/libraries/engagement.php',
            'CActivity' => '/libraries/activity.php',
            /* Services */
            'CServiceAbstract' => '/libraries/services/abstract.php',
            'CServiceGoogle' => '/libraries/services/google.php',
            'CEmbedly' => '/libraries/services/embedly.php',
            'CCurl' => '/libraries/curl.php',
            /* Parsers */
            'CParserAbstract' => '/libraries/parsers/abstract.php',
            'CParserUrls' => '/libraries/parsers/urls.php',
            'CParserMetas' => '/libraries/parsers/metas.php',
            'CAssets' => '/libraries/assets.php',
            'CObject' => 'libraries/object.php',
            'CPages' => '/libraries/pages.php',
            'CLinkedin' => '/libraries/linkedin.php',
            'CGoogle' => '/libraries/google.php'
        );

        if (array_key_exists($classname, $classes)) {
            if (!class_exists($classname)) {
                require_once(JPATH_ROOT . '/components/com_community' . $classes[$classname]);
            }
        }
    }

    /**
     * Autoload helper class
     */
    static function autoload_helpers($classname) {
        $classes = array(
            'CAccess' => '/helpers/access.php',
            'CKses' => '/helpers/kses.php',
            'CCalendar' => '/helpers/Calendar.php',
            'CPluginHelper' => '/helpers/plugins.php',
            'CFriendsHelper' => '/helpers/friends.php',
            'CAccess' => '/helpers/access.php',
            'CAjaxHelper' => '/helpers/ajax.php',
            'CAlbumsGroupHelperHandler' => '/helpers/albums.php',
            'CAutoSuggest' => '/helpers/autousersuggest.php',
            'CCalendar' => '/helpers/calendar.php',
            'CCategoryHelper' => '/helpers/category.php',
            'CContentHelper' => '/helpers/content.php',
            'CCSV' => '/helpers/csv.php',
            'CEmails' => '/helpers/emails.php',
            'CEventGroupHelperHandler' => '/helpers/event.php',
            'CFileHelper' => '/helpers/file.php',
            'CFriendsHelper' => '/helpers/friends.php',
            'CGroupHelper' => '/helpers/group.php',
            'CImageHelper' => '/helpers/image.php',
            'CKses' => '/helpers/kses.php',
            'CLimitsHelper' => '/helpers/limits.php',
            'CLinkGeneratorHelper' => '/helpers/linkgenerator.php',
            'CMapsHelper' => '/helpers/maps.php',
            'CMenuHelper' => '/helpers/menu.php',
            'CNotificationTypesHelper' => '/helpers/notificationtypes.php',
            'COwnerHelper' => '/helpers/owner.php',
            'CPhone' => '/helpers/phone.php',
            'CPhotosHelper' => '/helpers/photos.php',
            'CPluginHelper' => '/helpers/plugins.php',
            'CProgressbarHelper' => '/helpers/progressbar.php',
            'HcaptchaCCaptchaHelper'=>'/helpers/captcha/hcaptcha.php',
            'RecaptchaCCaptchaHelper' => '/helpers/captcha/recaptcha.php',
            'CloudflareCCaptchaHelper' => '/helpers/captcha/cloudflare.php',
            'BaseCCaptchaHelper' => '/helpers/captcha/base.php',
            'ReCaptchaResponse' => '/helpers/captcha/recaptcha.php',
            'CRemoteHelper' => '/helpers/remote.php',
            'CStringHelper' => '/helpers/string.php',
            'CTemplateHelper' => '/helpers/template.php',
            'CTimeHelper' => '/helpers/time.php',
            'CDate' => '/helpers/time.php',
            'CUrl' => '/helpers/url.php',
            'CUrlHelper' => '/helpers/url.php',
            'CUserHelper' => '/helpers/user.php',
            'CValidateHelper' => '/helpers/validate.php',
            'CVideosHelper' => '/helpers/videos.php',
            'CEventHelper' => '/helpers/event.php',
            'CPollHelper' => '/helpers/poll.php',
            'CAlbumsHelper' => '/helpers/albums.php',
            'CHeadHelper' => '/helpers/head.php',
            'CFetchHelper' => '/helpers/fetch.php',
            'CLikesHelper' => '/helpers/likes.php',
            'CActivitiesHelper' => '/helpers/activities.php',
            'CSystemHelper' => '/helpers/system.php',
            'CModuleHelper' => '/helpers/module.php',
            'CMultiprofileHelper' => '/helpers/multiprofile.php',
            'CInboxHelper' => '/helpers/inbox.php',
            'CServiceCommentHelper' => '/helpers/commentservice.php',
            'CFollowersHelper' => '/helpers/followers.php',
            'CPageHelper' => '/helpers/page.php',
        );

        if (array_key_exists($classname, $classes)) {
            require_once(JPATH_ROOT . '/components/com_community' . $classes[$classname]);
        }
    }

    /**
     * Autoload helper class
     */
    static function autoload_tables($classname) {
        $classes = array(
            'CTableActivity' => '/tables/activity.php',
            'CTableAlbum' => '/tables/album.php',
            'CTableApp' => '/tables/app.php',
            'CTableBulletin' => '/tables/bulletin.php',
            'CTableCategory' => '/tables/category.php',
            'CTableConnect' => '/tables/connect.php',
            'CTableDiscussion' => '/tables/discussion.php',
            'CTableEvent' => '/tables/event.php',
            'CTableEventCategory' => '/tables/eventcategory.php',
            'CTableEventMembers' => '/tables/eventmembers.php',
            'CTableFeatured' => '/tables/featured.php',
            'CTableFieldValue' => '/tables/fieldvalue.php',
            'CTableFile' => '/tables/file.php',
            'CTableGroup' => '/tables/group.php',
            'CTableGroupCategory' => '/tables/groupcategory.php',
            'CTableGroupInvite' => '/tables/groupinvite.php',
            'CTableGroupMembers' => '/tables/groupmembers.php',
            'CTableInvitation' => '/tables/invitation.php',
            'CTableLike' => '/tables/like.php',
            'CTableLocationCache' => '/tables/locationcache.php',
            'CTableMemberList' => '/tables/memberlist.php',
            'CTableMemberListCriteria' => '/tables/memberlistcriteria.php',
            'CTableMessage' => '/tables/message.php',
            'CTableMultiProfile' => '/tables/multiprofile.php',
            'CTableMultiProfileFields' => '/tables/multiprofilefields.php',
            'CTableNotification' => '/tables/notification.php',
            'CTableOauth' => '/tables/oauth.php',
            'CTablePhoto' => '/tables/photo.php',
            'CTableProfile' => '/tables/profile.php',
            'CTableProfileField' => '/tables/profilefield.php',
            'CTableTag' => '/tables/tag.php',
            'CTableTagword' => '/tables/tagword.php',
            'CTableVideo' => '/tables/video.php',
            'CTableVideosCategory' => '/tables/videoscategory.php',
            'CTableWall' => '/tables/wall.php',
            'CTableHashtag' => '/tables/hashtag.php',
            'CTablePollCategory' => '/tables/pollcategory.php',
            'CTablePoll' => '/tables/poll.php',
            'CTablePollItem' => '/tables/pollitem.php',
            'CTablePollUser' => '/tables/polluser.php',
            'CTableFollower' => '/tables/follower.php',
            'CTablePage' => '/tables/page.php',
            'CTablePageMembers' => '/tables/pagemembers.php',
            'CTablePageCategory' => '/tables/pagecategory.php',
            'CTablePageInvite' => '/tables/pageinvite.php',
            'CTableRating' => '/tables/rating.php'
        );

        $backendClassname = array(
            'CommunityTableConfiguration' => '/tables/configuration.php',
            'CommunityTableProfiles' => '/tables/profiles.php',
            'CommunityTableReports' => '/tables/reports.php',
            'CommunityTableUserPoints' => '/tables/userpoints.php',
            'CommunityTableUsers' => '/tables/users.php',
            'CommunityTableVideosCategories' => '/tables/videocategories.php',
            'CommunityTableEventCategories' => '/tables/eventcategories.php',
            'CommunityTableGroupCategories' => '/tables/groupcategories.php',
            'CommunityTablePollCategories' => '/tables/pollcategories.php',
            'CommunityTableGroups' => '/tables/pages.php',
            'CommunityTableGroups' => '/tables/groups.php',
            'CommunityTablePolls' => '/tables/polls.php',
            'CommunityTableMailQueue' => '/tables/mailqueue.php',
            'CommunityTableNetwork' => '/tables/network.php',
            'CommunityTableEvents' => '/tables/events.php',
            'CommunityTableDigestEmail' => '/tables/digest.php',
            'CommunityTableRegisterInvite' => '/tables/registerinvites.php',
            'CommunityTablePageCategories' => '/tables/pagecategories.php',
        );

        if (array_key_exists($classname, $backendClassname)) {
            require_once(JPATH_ROOT . '/administrator/components/com_community' . $backendClassname[$classname]);
        }

        if (array_key_exists($classname, $classes)) {
            require_once(JPATH_ROOT . '/components/com_community' . $classes[$classname]);
        }
    }

    /**
     * Autoload helper class
     */
    static function autoload_events($classname) {
        $classes = array(
            'CEventTrigger' => '/events/router.php'
        );

        if (array_key_exists($classname, $classes)) {
            require_once(JPATH_ROOT . '/components/com_community' . $classes[$classname]);
        }
    }

    /**
     * Wrapped CPath->registerNamespace as shortcut
     * @param type $namespace
     * @param type $path
     */
    public static function registerNamespace($namespace, $path) {
        $path = CPath::getInstance();
        $path->registerNamespace($namespace, $path);
    }

    /**
     * Wrapped CPath->getPath as shortcut
     * @param type $key
     * @return string
     */
    public static function getPath($key) {
        $path = CPath::getInstance();
        return $path->getPath($key);
    }

    /**
     * Wrapped CPath->getUrl as shortcut
     * @param type $key
     * @return type
     */
    public static function getUrl($key) {
        $path = CPath::getInstance();
        return $path->getUrl($key);
    }

    /**
     * Attach assets
     * @param type $path
     * @param type $type
     * @param type $assetPath
     */
    public static function attach($path, $type, $assetPath = '') {
        $assets = CAssets::getInstance();
        $assets->attach($path, $type, $assetPath);
    }

    protected static $clientIP = '';
    public static function getClientIP()
    {
        if (!self::$clientIP) {
            if (getenv('HTTP_X_FORWARDED_FOR')) {
                self::$clientIP = getenv('HTTP_X_FORWARDED_FOR');
            } else if (getenv('REMOTE_ADDR')) {
                self::$clientIP = getenv('REMOTE_ADDR');
            }
        }

        return self::$clientIP;
    }
}

/**
 * Provide global access to JomSocial configuration and paramaters
 */
jimport('joomla.html.parameter');

/**
 * Provide global access to JomSocial configuration and paramaters
 */
class CConfig /* extends JRegistry */ {

    var $_defaultParam;
    private $_jparam = null;

    /**
     * Return reference to global config object
     *
     * @return	object		JParams object
     */
    static public function &getInstance() {
        static $instance = null;
        if (!$instance) {
            jimport('joomla.filesystem.file');

            // First we need to load the default INI file so that new configuration,
            // will not cause any errors.
            $ini = JPATH_ROOT . '/administrator/components/com_community/default.ini';
            $data = file_get_contents($ini);

            $instance = new CConfig();
            $instance->_jparam = new CParameter($data);

            Table::addIncludePath(JPATH_ROOT . '/administrator/components/com_community/tables');
            $config = Table::getInstance('configuration', 'CommunityTable');
            $config->load('config');

            $instance->_jparam->bind($config->params);

            // call trigger to allow configuration override
            $appsLib = CAppPlugins::getInstance();
            $appsLib->loadApplications();

            $args = array();
            $args[] = $instance;
            $appsLib->triggerEvent('onAfterConfigCreate', $args);

            /*
             * To fix the date format when setting format is set to Fixed.
             * This function retrieves the wrong format and set it to the correct one.
             */
            $overrideTimeFormat = array('%b %d' => 'M d Y', '%d %b' => 'd M Y');
            $eventdateFormat = $instance->_jparam->get('eventdateformat');
            if (strpos($eventdateFormat, '%') !== false) {
                $eventdateFormat = $overrideTimeFormat[$eventdateFormat];
            }

            $profileDateFormat = $instance->_jparam->get('profileDateFormat');
            $profileDateFormat = str_replace('%', '', $profileDateFormat);

            $instance->_jparam->set('profileDateFormat', $profileDateFormat);
            $instance->_jparam->set('eventdateformat', $eventdateFormat);
            $instance->_jparam->set('activitiesdayformat', 'F d');
            $instance->_jparam->set('activitiestimeformat', 'h:i A');
        }

        return $instance;
    }

    /**
     * Sets a specific property of the config value
     *
     * @param	string	$key
     * @param	string	$value
     *
     * */
    public function set($key, $value) {
        $this->_jparam->set($key, $value);
    }

    /**
     * Redirect all call to JParams object to $this->_jparam->
     * @param <type> $name
     * @param <type> $arguments
     */
    public function __call($name, $arguments) {
        // call_user_func($this->_jparam->$name, $arguments);
    }

    /**
     * Get a value
     *
     * @access	public
     * @param	string The name of the param
     * @param	mixed The default value if not found
     * @return	string
     */
    public function get($key, $default = '', $group = '_default') {
        $value = $this->_jparam->get($key, $default, $group);

        // Backward compatibility support since now configuration words are split by an underscore.
        if (empty($value)) {
            $key = CString::str_ireplace('_', '', $key);
            $value = $this->_jparam->get($key, $default, $group);
        }

        return $value;
    }

    public function getString($key, $default = '', $group = '_default') {
        $value = $this->get($key, $default, $group);
        return (string) $value;
    }

    public function getBool($key, $default = '', $group = '_default') {
        $value = $this->get($key, $default, $group);
        return (bool) $value;
    }

    public function getInt($key, $default = '', $group = '_default') {
        $value = $this->get($key, $default, $group);
        return (int) $value;
    }

}

class CApplications extends CMSPlugin {

    //@todo: Do some stuff so the childs get inheritance?
    var $params = '';
    public $userparams;

    public function __construct(& $subject, $config = null) {
        // Set the params for the current object
        parent::__construct($subject, $config);
        //$this->_getUserParams(  );
    }

    /**
     * Function is Deprecated.
     * -	 Should only be used in profile area.
     * */
    public function loadUserParams() {
        $model = CFactory::getModel('apps');
        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;

        $my = CFactory::getUser();
        $userid = $jinput->get('userid', $my->id, 'INT');
        $user = CFactory::getUser($userid);

        //$user	= CFactory::getActiveProfile();
        $appName = $this->_name;

        $position = $model->getUserAppPosition($user->id, $appName);
        $this->params->set('position', $position, 'content');

        $params = $model->getUserAppParams($model->getUserApplicationId($appName, $user->id));

        $this->userparams = new CParameter($params);
    }

    public function setNewLayout($position = "") {
        $layout = !empty($position) ? $position : 'content';
        $this->params->set('newlayout', $layout);
        return true;
    }

    public function getLayout() {
        $newLayout = $this->params->get('newlayout', '');
        $currentLayout = $this->params->get('position');

        $layout = empty($newLayout) ? $currentLayout : $newLayout;
        return $layout;
    }

    public function getRefreshAction($script = array()) {
        return $script;
    }

}

class CRoute {

    var $menuname = 'mainmenu';

    /**
     * Method to wrap around getting the correct links within the email
     * DEPRECATED since 1.5
     */
    static function emailLink($url, $xhtml = false) {
        return CRoute::getExternalURL($url, $xhtml);
    }

    /**
     * Method to wrap around getting the correct links within the email
     *
     * @return string $url
     * @param string $url
     * @param boolean $xhtml
     */
    static function getExternalURL($url, $xhtml = false) {
        $uri = Uri::getInstance();
        $base = $uri->toString(array('scheme', 'host', 'port'));

        return $base . CRoute::_($url, $xhtml);
    }

    static function getURI($xhtml = true) {
        // #1506 missing icon when saved privacy page
        //return htmlspecialchars(JUri::getInstance()->toString());
        return Uri::getInstance()->toString();
    }

    /**
     * Wrapper to JRoute to handle itemid
     * We need to try and capture the correct itemid for different view
     */
    static function _($url, $xhtml = true, $ssl = null) {
        global $Itemid;

        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;
        $config = CFactory::getConfig();

        $cache = CFactory::getFastCache();
        $cacheid = __FILE__ . __LINE__ . serialize(func_get_args()) . $Itemid;
        if ($data = $cache->get($cacheid)) {
            $data = Route::_($data, $xhtml, $ssl);
            return $data;
        }

        static $itemid = array();

        parse_str(str_ireplace('index.php?', '', $url), $result);

        if (isset($result['view'])) {
            $view = $result['view'];
        } else {
            $view = 'frontpage';
        }

        if (empty($view)) {
            $view = 'frontpage';
        }

        if (isset($option) && $option != 'com_community') {
            if (!$Itemid) {
                $db = Factory::getDBO();
                $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__menu') . ' '
                        . 'WHERE ' . $db->quoteName('link') . ' LIKE ' . $db->Quote('%' . $url . '%');
                $db->setQuery($query);
                $id = $db->loadResult();

                $url .= '&Itemid=' . $id;
            }

            return Route::_($url, $xhtml, $ssl);
        }

        if (empty($itemid[$view])) {
            global $Itemid;
            $isValid = false;

            $currentView = $jinput->get('view', 'frontpage', 'NONE');
            $currentOption = $jinput->get('option', '', 'STRING');
            // If the current Itemid match the expected Itemid based on view
            // we'll just use it
            $db = Factory::getDBO();
            $viewId = CRoute::_getViewItemid($view);

            // if current itemid
            if ($currentOption == 'com_community' && $currentView == $view && $Itemid != 0) {
                $itemid[$view] = $Itemid;
                $isValid = true;
            } else if ($viewId === $Itemid && !is_null($viewId) && $Itemid != 0) {
                $itemid[$view] = $Itemid;
                $isValid = true;
            } else if ($viewId) {
                $itemid[$view] = $viewId;
                $isValid = true;
                // See if language is there
                // $lang = $jinput->get('language', '', 'NONE');
                // if (!empty($lang)) {
                //     $itemid[$view] = $viewId;
                //     $isValid = true;
                // } else {
                //     // using jomsocial frontpage if exist
                //     $defaultItemid = CRoute::_getDefaultItemid();
                    
                //     if (!$defaultItemid) {
                //         $itemid[$view] = $viewId;
                //         $isValid = true;
                //     }
                // }
            }

            if (!$isValid) {
                $id = CRoute::_getDefaultItemid();
                if ($id !== 0 && !is_null($id)) {
                    $itemid[$view] = $id;
                }
                $isValid = true;
            }

            // Search the mainmenu for the 1st itemid of jomsocial we can find, that match the current language code
            if (!$isValid) {


                $db = Factory::getDBO();
                $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__menu') . ' WHERE '
                        . $db->quoteName('link') . ' LIKE ' . $db->Quote('%com_community%')
                        . 'AND ' . $db->quoteName('published') . '=' . $db->Quote(1) . ' '
                        . 'AND ' . $db->quoteName('menutype') . '=' . $db->Quote('{CRoute::menuname}')
                        . 'AND ' . $db->quoteName('menutype') . '!=' . $db->Quote(CFactory::getConfig()->get('toolbar_menutype')) . ' '
                        . 'AND ' . $db->quoteName('type') . '=' . $db->Quote('component');
                $db->setQuery($query);
                $isValid = $db->loadResult();

                if (!empty($isValid)) {
                    $itemid[$view] = $isValid;
                }
            }

            // If not in mainmenu, seach in any menu
            if (!$isValid) {
                $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__menu') . ' WHERE '
                        . $db->quoteName('link') . ' LIKE ' . $db->Quote('%com_community%')
                        . 'AND ' . $db->quoteName('published') . '=' . $db->Quote(1) . ' '
                        . 'AND ' . $db->quoteName('menutype') . '!=' . $db->Quote($config->get('toolbar_menutype')) . ' '
                        . 'AND ' . $db->quoteName('type') . '=' . $db->Quote('component');
                $db->setQuery($query);
                $isValid = $db->loadResult();
                if (!empty($isValid))
                    $itemid[$view] = $isValid;
            }
        }

        $pos = strpos($url, '#');
        if ($pos === false) {
            if (isset($itemid[$view])) {
                if (strpos($url, 'Itemid=') === false && strpos($url, 'com_community') !== false) {
                    $url .= '&Itemid=' . $itemid[$view];
                }
            }
        } else {
            if (isset($itemid[$view]))
                $url = str_ireplace('#', '&Itemid=' . $itemid[$view] . '#', $url);
        }

        $data = Route::_($url, $xhtml, $ssl);
        $cache->store($url, $cacheid);
        return $data;
    }

    /**
     * Return the Itemid specific for the given view.
     */
    static function _getViewItemid($view) {
        static $itemid = array();

        if (empty($itemid[$view])) {
            $config = CFactory::getConfig();
            $siteMenu = Factory::getApplication()->getMenu();
            $menus = $siteMenu->getItems(array('component'), array('com_community'));
            $val = '';

            foreach ($menus as $menu) {
                if ($menu->menutype !== $config->get('toolbar_menutype')
                    && isset($menu->query['view'])
                    && $menu->query['view'] === $view) {

                    $val = $menu->id;
                    break;
                }
            }

            $itemid[$view] = $val;
        } else {
            $val = $itemid[$view];
        }

        return $val;
    }

    /**
     * Retrieve the Itemid of JomSocial's menu. If you are creating a link to JomSocial, you
     * will need to retrieve the Itemid.
     * */
    static function getItemId() {
        return CRoute::_getDefaultItemid();
    }

    /**
     * Return the Itemid for default view, frontpage
     */
    static function _getDefaultItemid() {
        static $defaultId = null;

        if ($defaultId != null)
            return $defaultId;

        $db = Factory::getDBO();

        $url = $db->quote("index.php?option=com_community&view=frontpage");
        $type = $db->quote('component');

        $mainframe = Factory::getApplication();
        $jinput = $mainframe->input;

        // See if language is there
        $lang = $jinput->get('language', '', 'NONE');
        $langFilter = '';
        if ($lang) {
            $langs = implode(',', $db->q(array($lang, '*')));
            $langFilter .= ' AND '.$db->quoteName('language').' IN (' . $langs . ') ';
        }

        $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__menu')
                . ' WHERE ' . $db->quoteName('link') . ' = ' . $url . ' AND ' . $db->quoteName('published') . '=' . $db->Quote(1) . ' '
                . 'AND ' . $db->quoteName('type') . '=' . $db->Quote('component') . $langFilter;
        $db->setQuery($query);
        $val = $db->loadResult();

        if (!$val) {
            $url = $db->quote("%option=com_community%");

            $query = 'SELECT ' . $db->quoteName('id') . ' FROM ' . $db->quoteName('#__menu')
                    . ' WHERE ' . $db->quoteName('link') . ' LIKE ' . $url . ' AND ' . $db->quoteName('published') . '=' . $db->Quote(1) . ' '
                    . 'AND ' . $db->quoteName('type') . '=' . $db->Quote('component');
            $db->setQuery($query);
            $val = $db->loadResult();
        }

        $defaultId = $val;
        return $val;
    }

}

/**
 *
 */
class CDispatcher extends JDispatcher {

    /**
     * Overide JDispatcher::getInstance function.
     * @staticvar CDispatcher $instance
     * @return \CDispatcher
     */
    public static function getInstanceStatic() {
        static $instance;

        if (!is_object($instance)) {
            $instance = new CDispatcher();
            //link JDispatcher's properties to CDispatcher's properties
            $dispatcher = JDispatcher::getInstance();
            $arr_p = get_object_vars($dispatcher);
            foreach ($arr_p as $key => $value) {
                $instance->$key = &$dispatcher->$key;
            }

            if (version_compare(JVERSION, '4', '>=')) {
                $d = Factory::getApplication()->getDispatcher();
                $listeners = $d->getListeners();
                $addedClass = [];
                foreach ($listeners as $listener) {
                    if (is_array($listener)) {
                        foreach ($listener as $obj) {
                            if ($obj instanceof Closure) {
                                $r = new ReflectionFunction($obj);
                                $observer = $r->getClosureThis();
                                if (is_object($observer)) {
                                    $className = strtolower(get_class($observer));
                                    if (strpos($className, 'plgcommunity') === 0 && !in_array($className, $addedClass)) {
                                        $addedClass[] = $className;
                                        $instance->_observers[] = $observer;
                                    }
                                }
                            }
                        }
                    }

                }
            }
        }
        return $instance;
    }

    /**
     * Contructor, inherrit from parrent.
     * */
    public function getObservers() {
        return $this->_observers;
    }

}

class CPluginWrapper extends CMSPlugin {

    private $JplgObj;

    /**
     * Contructor, inherrit from parrent.
     * */
    public function __construct($JplgObj) {
        if (
            is_object($JplgObj) 
            && (is_subclass_of($JplgObj, JPlugin::class) || is_subclass_of($JplgObj, CMSPlugin::class))
        ) {
            $this->JplgObj = $JplgObj;
        }
    }

    public function getPluginType() {
        if ($this->JplgObj) {
            return $this->JplgObj->_type;
        }
        return '';
    }

    public function getPluginName() {
        if ($this->JplgObj) {
            return $this->JplgObj->_name;
        }
        return '';
    }

}

class CACL {

    public static function getInstance() {
        static $instance;
        if (!is_object($instance)) {
            $instance = new CACLAccess();
        }
        return $instance;
    }

}

class CACLAccess extends Access {

    public function getGroupsByUserId($userId) {
        $groupIds = Access::getGroupsByUser($userId);
        return $this->getGroupName(end($groupIds));
    }

    public function getGroupUser($userId) {
        $groupIds = Access::getGroupsByUser($userId, false);
        return $this->getGroupName($groupIds[0]);
    }

    public function getGroupID($groupname) {
        $db = Factory::getDbo();
        $query = 'Select '
                . $db->quoteName('id') . ' from '
                . $db->quoteName('#__usergroups') . ' where '
                . $db->quoteName('title') . '='
                . $db->quote($groupname);
        $db->setQuery($query);
        return $db->loadResult();
    }

    public function getGroupName($groupId) {
        if ($groupId !== '') {
            $db = Factory::getDbo();
            $query = 'Select '
                    . $db->quoteName('title') . ' from '
                    . $db->quoteName('#__usergroups') . ' where '
                    . $db->quoteName('id') . '='
                    . $db->quote($groupId);
            $db->setQuery($query);
            return $db->loadResult();
        }

        return '';
    }

    public function is_group_child_of($grp_src, $grp_tgt) {
        $gid_src = $this->getGroupID($grp_src);
        $gid_tgt = $this->getGroupID($grp_tgt);
        if ($gid_src && $gid_tgt) {
            $group_path = Access::getGroupPath($gid_src);
            if (is_array($group_path) && in_array($gid_tgt, $group_path)) {
                return true;
            }
        }

        return false;
    }

}

class CString {

    static public function str_ireplace($search, $replace, $str, $count = NULL) {
        $str =  $str ? $str : '';
        if ($count === FALSE) {
            return self::_utf8_ireplace($search, $replace, $str);
        } else {
            return self::_utf8_ireplace($search, $replace, $str, $count);
        }
    }

    static public function _utf8_ireplace($search, $replace, $str, $count = NULL) {

        if (!is_array($search)) {

            $slen = strlen($search);
            $lendif = strlen($replace) - $slen;
            if ($slen == 0) {
                return $str;
            }

            $search = CStringHelper::strtolower($search);

            $search = preg_quote($search, '/');
            $lstr = CStringHelper::strtolower($str);
            $i = 0;
            $matched = 0;
            while (preg_match('/(.*)' . $search . '/Us', $lstr, $matches)) {
                if ($i === $count) {
                    break;
                }
                $mlen = strlen($matches[0]);
                $lstr = substr($lstr, $mlen);
                $str = substr_replace($str, $replace, $matched + strlen($matches[1]), $slen);
                $matched += $mlen + $lendif;
                $i++;
            }
            return $str;
        } else {

            foreach (array_keys($search) as $k) {

                if (is_array($replace)) {

                    if (array_key_exists($k, $replace)) {

                        $str = CString::_utf8_ireplace($search[$k], $replace[$k], $str, $count);
                    } else {

                        $str = CString::_utf8_ireplace($search[$k], '', $str, $count);
                    }
                } else {

                    $str = CString::_utf8_ireplace($search[$k], $replace, $str, $count);
                }
            }
            return $str;
        }
    }

}

/**
 *
 * For list of social object, please refer to http://code.jomsocial.com/default.asp?W287
 */
class CSocialObject extends cobject {

}

interface CStreamable {

    /** Return HTML formatted stream data * */
    public function getStreamHTML($object);

    /** Return true is the user can post to the stream * */
    public function isAllowStreamPost($userid, $itemid);

    /** Return an array of activities app code * */
    static public function getStreamAppCode();
}

interface CAccessInterface {

    /** Return authorise in bool * */
    static public function authorise();
}

/**
 * Load core scripts
 * @since 3.2
 */
// $app = Factory::getApplication();

// only load within community component
// if ($app->isSite() && ( $app->input->get('option') == 'com_community' || JVERSION < 3.2)) {
    // $js = 'assets/stream.js';
    // CFactory::attach($js, 'js');

    // $map = 'https://maps.googleapis.com/maps/api/js?libraries=places&sensor=false';
    // $doc = Factory::getDocument();
    // $doc->addScript($map);
// }

/**
 * Get and store into session current user IP
 * @since 3.2
 */
$session = Factory::getSession();
if (!$session->get('jomsocial_userip')) {
    /**
     * Get vistor IP
     */
    $client = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote = CFactory::getClientIP();

    if (filter_var($client, FILTER_VALIDATE_IP)) {
        $ip = $client;
    } elseif (filter_var($forward, FILTER_VALIDATE_IP)) {
        $ip = $forward;
    } else {
        $ip = $remote;
    }
    $session->set('jomsocial_userip', $ip);
}
