<?php
/**
 * $Id: plugin.inc.php 7482 2007-10-23 09:54:35Z kevin_fourie $
 *
 * KnowledgeTree Open Source Edition
 * Document Management Made Simple
 * Copyright (C) 2004 - 2007 The Jam Warehouse Software (Pty) Limited
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License version 3 as published by the
 * Free Software Foundation.
 * 
 * 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, see <http://www.gnu.org/licenses/>.
 * 
 * You can contact The Jam Warehouse Software (Pty) Limited, Unit 1, Tramber Place,
 * Blake Street, Observatory, 7925 South Africa. or email info@knowledgetree.com.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * KnowledgeTree" logo and retain the original copyright notice. If the display of the 
 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
 * must display the words "Powered by KnowledgeTree" and retain the original 
 * copyright notice. 
 * Contributor( s): ______________________________________
 *
 */

require_once(KT_LIB_DIR . '/database/sqlfile.inc.php');

class KTPlugin {
    var $sNamespace;
    var $sFilename = null;
    var $bAlwaysInclude = false;
    var $iVersion = 0;
    var $iOrder = 0;
    var $sFriendlyName = null;
    var $sSQLDir = null;

    var $autoRegister = false;

    var $_aPortlets = array();
    var $_aTriggers = array();
    var $_aActions = array();
    var $_aPages = array();
    var $_aAuthenticationProviders = array();
    var $_aAdminCategories = array();
    var $_aAdminPages = array();
    var $_aDashlets = array();
    var $_ai18n = array();
    var $_ai18nLang = array();
    var $_aLanguage = array();
    var $_aHelpLanguage = array();
    var $_aWFTriggers = array();
    var $_aColumns = array();
    var $_aViews = array();
    var $_aNotificationHandlers = array();
    var $_aTemplateLocations = array();
    var $_aWidgets = array();
    var $_aValidators = array();
    var $_aCriteria = array();
    var $_aInterceptors = array();

    function KTPlugin($sFilename = null) {
        $this->sFilename = $sFilename;
    }

    function setFilename($sFilename) {
        $this->sFilename = $sFilename;
    }

    function registerPortlet($aLocation, $sPortletClassName, $sPortletNamespace, $sFilename = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aPortlets[$sPortletNamespace] = array($aLocation, $sPortletClassName, $sPortletNamespace, $sFilename, $this->sNamespace);
    }

    function registerTrigger($sAction, $sStage, $sTriggerClassName, $sTriggerNamespace, $sFilename = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aTriggers[$sTriggerNamespace] = array($sAction, $sStage, $sTriggerClassName, $sTriggerNamespace, $sFilename, $this->sNamespace);
    }

    function registerAction($sActionType, $sActionClassName, $sActionNamespace, $sFilename = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aActions[$sActionNamespace] = array($sActionType, $sActionClassName, $sActionNamespace, $sFilename, $this->sNamespace);
    }

    function registerPage($sWebPath, $sPageClassName, $sFilename = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $sWebPath = sprintf("%s/%s", $this->sNamespace, $sWebPath);
        $this->_aPages[$sWebPath] = array($sWebPath, $sPageClassName, $sFilename, $this->sNamespace);
    }

    function registerWorkflowTrigger($sNamespace, $sTriggerClassName, $sFilename = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aWFTriggers[$sNamespace] = array($sNamespace, $sTriggerClassName, $sFilename);
    }

    function getPagePath($sPath) {
        $sExt = ".php";
        if (KTUtil::arrayGet($_SERVER, 'kt_no_extensions')) {
            $sExt = "";
        }
        $oKTConfig =& KTConfig::getSingleton();
        if ($oKTConfig->get("KnowledgeTree/pathInfoSupport")) {
            return sprintf('%s/plugin%s/%s/%s', $GLOBALS['KTRootUrl'], $sExt, $this->sNamespace, $sPath);
        } else {
            return sprintf('%s/plugin%s?kt_path_info=%s/%s', $GLOBALS['KTRootUrl'], $sExt, $this->sNamespace, $sPath);
        }
    }

    function registerAuthenticationProvider($sName, $sClass, $sNamespace, $sFilename = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aAuthenticationProviders[$sNamespace] = array($sName, $sClass, $sNamespace, $sFilename, $this->sNamespace);
    }

//registerLocation($sName, $sClass, $sCategory, $sTitle, $sDescription, $sDispatcherFilePath = null, $sURL = null)
    function registerAdminPage($sName, $sClass, $sCategory, $sTitle, $sDescription, $sFilename) {
        $sFullname = $sCategory . '/' . $sName;
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aAdminPages[$sFullname] = array($sName, $sClass, $sCategory, $sTitle, $sDescription, $sFilename, null, $this->sNamespace);
    }

    function registerAdminCategory($sPath, $sName, $sDescription) {
        $this->_aAdminCategories[$sPath] = array($sPath, $sName, $sDescription);
    }

    function registerDashlet($sClassName, $sNamespace, $sFilename) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aDashlets[$sNamespace] = array($sClassName, $sNamespace, $sFilename, $this->sNamespace);
    }

    function registeri18n($sDomain, $sPath) {
        $sPath = $this->_fixFilename($sPath);
        $this->_ai18n[$sDomain] = array($sDomain, $sPath);
    }

    function registeri18nLang($sDomain, $sLang, $sPath) {
        if ($sPath !== "default") {
            $sPath = $this->_fixFilename($sPath);
        }
        $this->_ai18nLang["$sDomain/$sLang"] = array($sDomain, $sLang, $sPath);
    }

    function registerLanguage($sLanguage, $sLanguageName) {
        $this->_aLanguage[$sLanguage] = array($sLanguage, $sLanguageName);
    }

    function registerHelpLanguage($sPlugin, $sLanguage, $sBasedir) {
        $this->_aHelpLanguage[$sLanguage] = array($sPlugin, $sLanguage, $sBasedir);
    }

    function registerColumn($sName, $sNamespace, $sClassName, $sFile) {
        $sFile = $this->_fixFilename($sFile);
        $this->_aColumns[$sNamespace] = array($sName, $sNamespace, $sClassName, $sFile);
    }

    function registerView($sName, $sNamespace) {
        $this->_aViews[$sNamespace] = array($sName, $sNamespace);
    }

    function registerNotificationHandler($sName, $sNamespace, $sPath) {
        $sPath = $this->_fixFilename($sPath);
        $this->_aNotificationHandlers[$sNamespace] = array($sNamespace, $sName, $sPath);
    }

    function registerTemplateLocation($sName, $sPath) {
        $sPath = $this->_fixFilename($sPath);
        $this->_aTemplateLocations[$sName] = array($sName, $sPath);
    }


    function registerWidget($sClassname, $sNamespace, $sPath) {
        $sPath = $this->_fixFilename($sPath);
        $this->_aWidgets[$sNamespace] = array($sClassname, $sNamespace, $sPath);
    }

    function registerValidator($sClassname, $sNamespace, $sPath) {
        $sPath = $this->_fixFilename($sPath);
        $this->_aValidators[$sNamespace] = array($sClassname, $sNamespace, $sPath);
    }


    function registerCriterion($sClassName, $sNamespace, $sFilename = null, $aInitialize = null) {
        $sFilename = $this->_fixFilename($sFilename);
        $this->_aCriteria[$sNamespace] = array($sClassName, $sNamespace, $sFilename, $aInitialize);
    }

    function registerInterceptor($sClassname, $sNamespace, $sPath = null) {
        $sPath = $this->_fixFilename($sPath);
        $this->_aInterceptors[$sNamespace] = array($sClassname, $sNamespace, $sPath);
    }

    function _fixFilename($sFilename) {
        if (empty($sFilename)) {
            $sFilename = $this->sFilename;
        }
        if (!KTUtil::isAbsolutePath($sFilename)) {
            if ($this->sFilename) {
                $sDirPath = dirname($this->sFilename);
                $sFilename = sprintf("%s/%s", $sDirPath, $sFilename);
            }
        }
        return $sFilename;
    }

    function isRegistered() {
        if ($this->bAlwaysInclude) {
            return true;
        }

        require_once(KT_LIB_DIR . '/plugins/pluginentity.inc.php');
        $oEntity = KTPluginEntity::getByNamespace($this->sNamespace);
        if (PEAR::isError($oEntity)) {
            if (is_a($oEntity, 'KTEntityNoObjects')) {
                // plugin not registered in database

                // XXX: nbm: Show an error on the page that a plugin
                // isn't registered or something, perhaps.
                return false;
            }
            return false;
        }
        if (!is_a($oEntity, 'KTPluginEntity')) {
            print "isRegistered\n";
            var_dump($oEntity);
            exit(0);
        }
        if ($oEntity->getDisabled()) {
            return false;
        }
        return true;
    }

    function load() {
        if (!$this->isRegistered()) {
            return;
        }
        $this->setup();

        require_once(KT_LIB_DIR . '/actions/actionregistry.inc.php');
        require_once(KT_LIB_DIR . '/actions/portletregistry.inc.php');
        require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php');
        require_once(KT_LIB_DIR . '/plugins/pageregistry.inc.php');
        require_once(KT_LIB_DIR . '/authentication/authenticationproviderregistry.inc.php');
        require_once(KT_LIB_DIR . "/plugins/KTAdminNavigation.php");
        require_once(KT_LIB_DIR . "/dashboard/dashletregistry.inc.php");
        require_once(KT_LIB_DIR . "/i18n/i18nregistry.inc.php");
        require_once(KT_LIB_DIR . "/help/help.inc.php");
        require_once(KT_LIB_DIR . "/workflow/workflowutil.inc.php");
        require_once(KT_LIB_DIR . "/widgets/widgetfactory.inc.php");
        require_once(KT_LIB_DIR . "/validation/validatorfactory.inc.php");
        require_once(KT_LIB_DIR . "/browse/columnregistry.inc.php");
        require_once(KT_LIB_DIR . "/browse/criteriaregistry.php");
        require_once(KT_LIB_DIR . "/authentication/interceptorregistry.inc.php");

        $oPRegistry =& KTPortletRegistry::getSingleton();
        $oTRegistry =& KTTriggerRegistry::getSingleton();
        $oARegistry =& KTActionRegistry::getSingleton();
        $oPageRegistry =& KTPageRegistry::getSingleton();
        $oAPRegistry =& KTAuthenticationProviderRegistry::getSingleton();
        $oAdminRegistry =& KTAdminNavigationRegistry::getSingleton();
        $oDashletRegistry =& KTDashletRegistry::getSingleton();
        $oi18nRegistry =& KTi18nRegistry::getSingleton();
        $oKTHelpRegistry =& KTHelpRegistry::getSingleton();
        $oWFTriggerRegistry =& KTWorkflowTriggerRegistry::getSingleton();
        $oColumnRegistry =& KTColumnRegistry::getSingleton();
        $oNotificationHandlerRegistry =& KTNotificationRegistry::getSingleton();
        $oTemplating =& KTTemplating::getSingleton();
        $oWidgetFactory =& KTWidgetFactory::getSingleton();
        $oValidatorFactory =& KTValidatorFactory::getSingleton();
        $oCriteriaRegistry =& KTCriteriaRegistry::getSingleton();
        $oInterceptorRegistry =& KTInterceptorRegistry::getSingleton();

        foreach ($this->_aPortlets as $k => $v) {
            call_user_func_array(array(&$oPRegistry, 'registerPortlet'), $v);
        }

        foreach ($this->_aTriggers as $k => $v) {
            call_user_func_array(array(&$oTRegistry, 'registerTrigger'), $v);
        }

        foreach ($this->_aActions as $k => $v) {
            call_user_func_array(array(&$oARegistry, 'registerAction'), $v);
        }

        foreach ($this->_aPages as $k => $v) {
            call_user_func_array(array(&$oPageRegistry, 'registerPage'), $v);
        }

        foreach ($this->_aAuthenticationProviders as $k => $v) {
            call_user_func_array(array(&$oAPRegistry, 'registerAuthenticationProvider'), $v);
        }

        foreach ($this->_aAdminCategories as $k => $v) {
            call_user_func_array(array(&$oAdminRegistry, 'registerCategory'), $v);
        }

        foreach ($this->_aAdminPages as $k => $v) {
            call_user_func_array(array(&$oAdminRegistry, 'registerLocation'), $v);
        }

        foreach ($this->_aDashlets as $k => $v) {
            call_user_func_array(array(&$oDashletRegistry, 'registerDashlet'), $v);
        }

        foreach ($this->_ai18n as $k => $v) {
            call_user_func_array(array(&$oi18nRegistry, 'registeri18n'), $v);
        }

        foreach ($this->_ai18nLang as $k => $v) {
            call_user_func_array(array(&$oi18nRegistry, 'registeri18nLang'), $v);
        }

        foreach ($this->_aLanguage as $k => $v) {
            call_user_func_array(array(&$oi18nRegistry, 'registerLanguage'), $v);
        }

        foreach ($this->_aHelpLanguage as $k => $v) {
            call_user_func_array(array(&$oKTHelpRegistry, 'registerHelp'), $v);
        }

        foreach ($this->_aWFTriggers as $k => $v) {
            call_user_func_array(array(&$oWFTriggerRegistry, 'registerWorkflowTrigger'), $v);
        }

        foreach ($this->_aColumns as $k => $v) {
            call_user_func_array(array(&$oColumnRegistry, 'registerColumn'), $v);
        }

        foreach ($this->_aViews as $k => $v) {
            call_user_func_array(array(&$oColumnRegistry, 'registerView'), $v);
        }

        foreach ($this->_aNotificationHandlers as $k => $v) {
            call_user_func_array(array(&$oNotificationHandlerRegistry, 'registerNotificationHandler'), $v);
        }

        foreach ($this->_aTemplateLocations as $k => $v) {
            call_user_func_array(array(&$oTemplating, 'addLocation'), $v);
        }

        foreach ($this->_aCriteria as $k => $v) {
            call_user_func_array(array(&$oCriteriaRegistry, 'registerCriterion'), $v);
        }

        foreach ($this->_aWidgets as $k => $v) {
            call_user_func_array(array(&$oWidgetFactory, 'registerWidget'), $v);
        }

        foreach ($this->_aValidators as $k => $v) {
            call_user_func_array(array(&$oValidatorFactory, 'registerValidator'), $v);
        }

        foreach ($this->_aInterceptors as $k => $v) {
            call_user_func_array(array(&$oInterceptorRegistry, 'registerInterceptor'), $v);
        }
    }

    function setup() {
        return;
    }

    function stripKtDir($sFilename) {
        if (strpos($sFilename, KT_DIR) === 0 ||strpos($sFilename, realpath(KT_DIR)) === 0) {
            return substr($sFilename, strlen(KT_DIR) + 1);
        }
        return $sFilename;
    }

    function upgradePlugin($iStart, $iEnd) {
        if (is_null($this->sSQLDir)) {
            return $iEnd; // no db changes, must reach the "end".
        }
        global $default;
        DBUtil::setupAdminDatabase();
        for ($i = $iStart; $i <= $iEnd; $i++) {
            $sqlfile = sprintf("%s/upgradeto%d.sql", $this->sSQLDir, $i);

            if (!file_exists($sqlfile)) {
                continue; // skip it.
            }
            $queries = SQLFile::sqlFromFile($sqlfile);
            $res = DBUtil::runQueries($queries, $default->_admindb);

            if (PEAR::isError($res)) {
                return $i; // break out completely, indicating how far we got pre-error.
            }
        }
        return $iEnd;
    }

    function register() {
        $oEntity = KTPluginEntity::getByNamespace($this->sNamespace);
        $friendly_name = '';
        if (!empty($this->sFriendlyName)) { $friendly_name = $this->sFriendlyName; }
        if (!PEAR::isError($oEntity)) {

            // check for upgrade.
            $iEndVersion = 0; // dest.
            if ($this->iVersion != $oEntity->getVersion()) {
                // capture the filname version.
                // remember to -start- the upgrade from the "next" version
                $iEndVersion = $this->upgradePlugin($oEntity->getVersion()+1, $this->iVersion);
            }
            if ($iEndVersion != $this->iVersion) {
                // we obviously failed.
                $oEntity->updateFromArray(array(
                    'path' => $this->stripKtDir($this->sFilename),
                    'version' => $iEndVersion,   // as far as we got.
                    'disabled' => true,
                    'unavailable' => false,
                    'friendlyname' => $friendly_name,
                ));
                // FIXME we -really- need to raise an error here, somehow.
                return $oEntity;
            } else {
                $oEntity->updateFromArray(array(
                    'path' => $this->stripKtDir($this->sFilename),
                    'version' => $this->iVersion,
                    'unavailable' => false,
                    'friendlyname' => $friendly_name,
                ));
                return $oEntity;
            }
        }
        $disabled = 1;
        if ($this->bAlwaysInclude || $this->autoRegister) { $disabled = 0; }
        $iEndVersion = $this->upgradePlugin(0, $this->iVersion);
        $oEntity = KTPluginEntity::createFromArray(array(
            'namespace' => $this->sNamespace,
            'path' => $this->stripKtDir($this->sFilename),
            'version' => $iEndVersion,
            'disabled' => $disabled,
            'unavailable' => false,
            'friendlyname' => $friendly_name,
        ));
        if (PEAR::isError($oEntity)) {
            return $oEntity;
        }
        return true;
    }

    function getURLPath($filename = null)
    {
		$config = KTConfig::getSingleton();
		$dir = $config->get('KnowledgeTree/fileSystemRoot');

		$path = substr(dirname($this->sFilename), strlen($dir));
		if (!is_null($filename))
		{
			$path .= '/' . $filename;
		}
		return $path;
    }
}

