<?php
#BEGIN_LICENSE
#-------------------------------------------------------------------------
# Module: CMSMSExt (c) 2020-2021 by CMS Made Simple Foundation
#  An add-on module for CMS Made Simple to provide useful functions
#  and commonly used gui capabilities to other modules.
#-------------------------------------------------------------------------
# A fork of:
#
# Module: CGExtensions (c) 2008-2014 by Robert Campbell
#         (calguy1000@cmsmadesimple.org)
#
#-------------------------------------------------------------------------
#
# CMSMS - CMS Made Simple is (c) 2006 - 2021 by CMS Made Simple Foundation
# CMSMS - CMS Made Simple is (c) 2005 by Ted Kulp (wishy@cmsmadesimple.org)
# Visit the CMSMS Homepage at: http://www.cmsmadesimple.org
#
#-------------------------------------------------------------------------
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# However, as a special exception to the GPL, this software is distributed
# as an addon module to CMS Made Simple.  You may not use this software
# in any Non GPL version of CMS Made simple, or in any version of CMS
# Made simple that does not indicate clearly and obviously in its admin
# section that the site was built with CMS Made simple.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Or read it online: http://www.gnu.org/licenses/licenses.html#GPL
#
#-------------------------------------------------------------------------
#END_LICENSE

use CMSMS\HookManager;
use CMSMSExt\FileTemplateResource;
use CMSMSExt\HourlyHookTask;
use CMSMSExt\DailyHookTask;
use CMSMSExt\internal\settings;
use CMSMSExt\smarty_plugins;

/**
 * @ignore
 */
define('CMSMSEXT_TABLE_ASSOCDATA', cms_db_prefix() . 'module_cmsmsext_assocdata');

function __xt_unserialize_callback(string $classname)
{
  //throw new \RuntimeException('Cannot unserialize object of type ' . $classname);
  \audit(0, $classname, 'Cannot unserialize object of type ' . $classname);
}

# a minor temp hack for now (JM)
include_once cms_join_path( __DIR__ , 'lib' , 'class.XTModule.php');

/**
 * A base class for CMSMS modules
 * to provide optimizations
 * and conveniences that are not built into CMSMS.
 *
 * @package CMSMSExt
 */
class CMSMSExt extends \CMSMSExt\XTModule
{
  /**
   * @ignore
   */
  private static $_initialized;
  private static $api_action_name = '';
  
  function __construct()
  {
    spl_autoload_register([$this, 'autoload']);
    
    parent::__construct();
  
    global $CMS_INSTALL_PAGE, $CMS_PHAR_INSTALL;
  
    if(isset($CMS_INSTALL_PAGE) || isset($CMS_PHAR_INSTALL)){ return; }
    
    $class = get_class($this);
  
    if(!defined('MOD_' . strtoupper($class)))
    {
      /**
       * allow to access the Module class as a  constant MOD_MYMODULENAME
       * now this can be explicitly set to MOD_CMSMSEXT
       * as the inheritable class is \CMSMSExt\XTModule
       * and all that logic has moved to it
       *
       * @ignore
       */
      
      define('MOD_CMSMSEXT', __CLASS__);
    }
    
    /**
     * Make sure we don't run the following more than once
     */
    if(self::$_initialized) { return; }
  
    # have not run this yet so set the flag and move on
    self::$_initialized = TRUE;
    
    # we'll use pid to create a unique route for the module api action  uri
    $pid = getmypid();
    self::$api_action_name = 'cmsmsext-' . $pid . '-api';
    $returnid = cmsms()->GetContentOperations()->GetDefaultContent();
    
    $parms = [
      'action'   => self::$api_action_name ,
      'returnid' => $returnid,
    ];
    
    $route = new CmsRoute(self::$api_action_name, $this->GetName(), $parms, TRUE);
    cms_route_manager::register($route);
    # set the api action name in the app data to be retrievable globally if needed
    cms_utils::set_app_data('cmsmsext_api_action_name', self::$api_action_name);
    
    ini_set('unserialize_callback_func', '__xt_unserialize_callback');
    $this->_includes();
    
    # we add a hook to Core::ContentPostRender
    HookManager::add_hook('Core::ContentPostRender', [$this, 'onContentPostRender'], HookManager::PRIORITY_LOW);
    HookManager::add_hook('Core::ContentPreRender', [$this, 'onContentPreRender'], HookManager::PRIORITY_LOW);
  
    $smarty = $this->cms->GetSmarty();
  
    if(!$smarty)  { return; }

    $smarty->register_resource('xt_modfile', new FileTemplateResource());
    $plugins_dir = cms_join_path( $this->GetModulePath(), 'lib', 'internal_plugins' );
    $smarty->addPluginsDir($plugins_dir);

    # ????
    $_plugins = new smarty_plugins($this, $smarty);
    $_utils   = new xt_utils($this, $this->xt_settings());
    $_image   = new xt_image($this->xt_settings()->thumbnailsize);
    $_setup   = new xt_setup($this->config, $this->xt_settings(), $this->GetModulePath());
    
    $db = cms_utils::get_db();
  
    if(is_object($db))
    {
      $query = 'SET @xt_ZEROTIME = NOW() - INTERVAL 150 YEAR,@xt_FUTURETIME = NOW() + INTERVAL 5 YEAR';
      $db->Execute($query);

      $config = \CMSMSExt\config::GetInstance();
      if( xt_param::get_bool( (array)$config, 'xt_relax_sql' ) )
      {
        $query = 'SET SESSION sql_mode=\'TRADITIONAL\'';
        $db->Execute($query);
      }
    }
  }
  
  public function autoload($classname) : bool
  {
    if( !is_object($this) ) { return FALSE; }
    
    // check for classes.
    $path = $this->GetModulePath() . '/lib';
  
    if(FALSE !== strpos($classname, '\\'))
    {
      $t_path = str_replace('\\', '/', $classname);
      
      if(startswith($t_path, $this->GetName() . '/'))
      {
        $classname = basename($t_path);
        $t_path    = dirname($t_path);
        $t_path    = substr($t_path, strlen($this->GetName()) + 1);
        $path      = $this->GetModulePath() . '/lib/' . $t_path;
      }
    }
    
    $fn = $path . "/class.{$classname}.php";
    
    if(is_file($fn))
    {
      require_once($fn);
      
      return TRUE;
    }
    
    // check for abstract classes.
    $fn = $path . "/abstract.{$classname}.php";
    
    if(is_file($fn))
    {
      require_once($fn);
      
      return TRUE;
    }
    
    // check for interfaces
    $fn = $path . "/interface.{$classname}.php";
    
    if(is_file($fn))
    {
      require_once($fn);
      
      return TRUE;
    }
    
    // check for traits
    $fn = $path . "/trait.{$classname}.php";
    
    if(is_file($fn))
    {
      require_once($fn);
      
      return TRUE;
    }
    
    // check for a master file
    $fn = $this->GetModulePath() . '/lib/extraclasses.php';
    
    if(is_file($fn))
    {
      require_once($fn);
      
      return TRUE;
    }
    
    return FALSE;
  }
  
  private function _includes()
  {
    $patterns = [
        cms_join_path(
          $this->GetModulePath(),
          'lib',
          'functions',
          '{function,functions}.*.php'
        ),
        cms_join_path(
          $this->GetModulePath(),
          '.wip',
          'functions',
          '{function,functions}.*.php'
        ),
        cms_join_path(
          $this->GetModulePath(),
          '.wip',
          '{abstract,class,interface,trait}.*.php'
        ),
      ];
    
    foreach($patterns as $pattern)
    {
      foreach(glob($pattern, GLOB_BRACE) as $filename)
      {
        include_once $filename;
      }
    }
  }
  
  /**
   * Return the version of this module.
   *
   * @return string
   * @see CMSModule::GetVersion()
   * @abstract
   */
  public function GetVersion()
  {
    return '1.4.5';
  }
  
  
  /**
   * Return the Author of this module.
   *
   * @return string
   * @see CMSModule::GetAuthor()
   * @abstract
   */
  public function GetAuthor() { return 'Fernando Morgado (Jo Morg)'; }
  
  /**
   * Return the email address for the author of this module.
   *
   * @return string
   * @see CMSModule::GetAuthorEmail()
   */
  public function GetAuthorEmail() { return 'jomorg@cmsmadesimple.org'; }
  
  
  /**
   * Return if this is a plugin module (for the frontend of the website) or not.
   *
   * @return bool
   * @see CMSModule::IsPluginModule()
   */
  public function IsPluginModule()  { return TRUE; }
  
  /**
   * Return if this module has an admin section.
   *
   * @return string
   * @see CMSModule::HasAdmin()
   */
  public function HasAdmin()  { return TRUE; }
  
  public function HandlesEvents()  { return TRUE; }
  
  /**
   * Return the minimum CMSMS version that this module is compatible with.
   *
   * @return string
   */
  public function MinimumCMSVersion(){ return '2.2.9'; }
  
  /**
   * Get a settings object
   *
   * @return settings
   */
  protected function xt_settings() : settings
  {
    static $_obj;
    
    if(!$_obj)
    {
      $_obj = new settings($this->config);
    }
    
    return $_obj;
  }
  
  
  /*************************************/
  /**
   * backward compatibility
   */
  
  /**
   * A convenience method to generate a new smarty template object given a resource string,
   * and a prefix.  This method will also automatically assign a few common smarty variables
   * to the new scope.
   *
   * Note: the parent smarty scope depends on how this function is called.  If called directly from a module action for
   * the same module the parent will be the current smarty scope.  If called from any method that is using a different
   * module than the action module, then the parent scope will be the global smarty scope.
   *
   * @param string      $template_name The desired template name.
   * @param string|null $prefix        an optional prefix for database templates.
   * @param string|null $cache_id      An optional smarty cache id.
   * @param string|null $compile_id    An optional smarty compile id.
   * @param null        $parent        An optional parent template object.
   *
   * @return object
   * @throws \SmartyException
   */
  public function CreateSmartyTemplate(
    string $template_name, string $prefix = NULL, string $cache_id = NULL, string $compile_id = NULL, $parent = NULL
  )
  {
    $smarty = NULL;
    
    if($parent){$smarty = $parent;}
    
    if(!$smarty){$smarty = $this->GetActionTemplateObject();}
    
    if(!$smarty){$smarty = $this->cms->GetSmarty();}
    
    $tpl = $smarty->createTemplate(
      $this->XTGetTemplateResource($template_name, $prefix), $cache_id, $compile_id, $smarty
    );
    
    // for convenience, we assign a few smarty variables.
    $tpl->assign('module', $this->GetName());
    $tpl->assign($this->GetName(), $this);
    $tpl->assign('mod', $this);
    $tpl->assign('actionid', $this->get_action_id());
  
    if(($actionparams = $smarty->getTemplateVars('actionparams')))
    {
      $tpl->assign('actionparams', $actionparams);
    }
  
    return $tpl;
  }
  
  
  /**
   * @ignore
   */
  public function onContentPostRender(array $params)
  {
    if($this->config['debug']) { return; }
    
    $pretty_html = xt_param::get_bool((array)$this->config, 'xt_prettyhtml', FALSE);
    $min_html    = xt_param::get_bool((array)$this->config, 'xt_minhtml', FALSE);
    
    if(!$pretty_html && !$min_html)  { return; }
    
    include_once(__DIR__ . '/event.Core.ContentPostRender.php');
  }
  
  /**
   * @ignore
   */
  public function onContentPreRender(array $params)
  {
    CMSMSExt\set_session_status_flag_file();
  }
  
  
  public function GetHeaderHTML()
  {
    $out = parent::GetHeaderHTML();

    $file = $this->find_module_file('js/common.js');

    if($file)
    {
      //$out .= $this->get_jsloader()->add_jsfile($file); this should not return anything... (JM)
      $this->get_jsloader()->add_jsfile($file);
    }

    $fn = $this->find_module_file('css/admin_styles.css');

    if($fn)
    {
      $css = str_replace(CMS_ROOT_PATH, CMS_ROOT_URL, $fn);
      $out .= '<link rel="stylesheet" href="' . $css . '"/>' . "\n";
    }

    $fn = $this->find_module_file('css/admin_styles.css');

    if($fn)
    {
      $css = str_replace(CMS_ROOT_PATH, CMS_ROOT_URL, $fn);
      $out .= '<link rel="stylesheet" href="' . $css . '"/>' . "\n";
    }

    return $out;
  }
  
  public function DoAction($name, $id, $params, $returnid = '')
  {
    
    if(self::$api_action_name === $name)
    {
      $cms_states     = CmsApp::get_instance()->get_states();
      $CMS_ADMIN_PAGE = in_array(CmsApp::STATE_ADMIN_PAGE, $cms_states);
      $exceptions     = ['ajax_geturl', 'ajax_get_alias'];
      $smarty         = cmsms()->GetSmarty();
      $db             = cmsms()->GetDb(); # needed for includes
      
      $smarty->assign('mod', $this);
      $smarty->assign('actionid', $id);
      $smarty->assign('returnid', $returnid);
      
      if( cmsms()->is_frontend_request() )
      {
        include_once __DIR__ . '/internal/function.api.php';
      }
      
      if($CMS_ADMIN_PAGE)
      {
        // TODO
      }
    }
  }
  
  /*********************************************************************************************************/
  
} // class

/**
 * @ignore
 * @note: revisit!!!!
 * @todo this may have worked with the CGExtensions setup, but we need to check where this should go in the future and to do exactly what???? - JM
 */
function xt_lang()
{
  $mod  = cms_utils::get_module(MOD_CMSMSEXT);
  $args = func_get_args();
  
  return call_user_func_array([$mod, 'Lang'], $args);
}

?>