<?php

/**

 * @version		$Id: plugin.php 117 2009-06-23 11:32:36Z happynoodleboy $

 * @package		JCE

 * @copyright	Copyright (C) 2009 Ryan Demmer. All rights reserved.

 * @copyright	Copyright (C) 2005 - 2007 Open Source Matters. All rights reserved.

 * @license		GNU/GPL

 * This version may have been modified pursuant

 * to the GNU General Public License, and as distributed it includes or

 * is derivative of works licensed under the GNU General Public License or

 * other free or open source software licenses.

 */



// Check to ensure this file is within the rest of the framework

defined('JPATH_BASE') or die ();



require_once (JPATH_ADMINISTRATOR.DS.'components'.DS.'com_jce'.DS.'plugins'.DS.'plugin.php');



/**

 * Plugin installer

 *

 * @package		JCE

 * @subpackage	Installer

 * @since		1.5

 */

class JCEInstallerPlugin extends JObject

{

    /**

     * Constructor

     *

     * @access	protected

     * @param	object	$parent	Parent object [JInstaller instance]

     * @return	void

     * @since	1.5

     */

    function __construct( & $parent)

    {

        $this->parent = & $parent;

    }



    /**

     * Custom install method

     *

     * @access	public

     * @return	boolean	True on success

     * @since	1.5

     * Minor alteration - see below

     */

    function install()

    {

        // Get a database connector object

        $db = & $this->parent->getDBO();



        // Get the extension manifest object

        $manifest = & $this->parent->getManifest();

        $this->manifest = & $manifest->document;



        /**

         * ---------------------------------------------------------------------------------------------

         * Manifest Document Setup Section

         * ---------------------------------------------------------------------------------------------

         */



        // Set the plugin name

        $name = & $this->manifest->getElementByPath('name');

        $this->set('name', $name->data());



        // Get the plugin description

        $description = & $this->manifest->getElementByPath('description');

        if (is_a($description, 'JSimpleXMLElement')) {

            $this->parent->set('message', $description->data());

        }

        else {

            $this->parent->set('message', '');

        }



        $element = & $this->manifest->getElementByPath('files');



        // Plugin name is specified

        $plugin = $this->manifest->attributes('plugin');



        if (! empty($plugin)) {

            $this->parent->setPath('extension_root', JPATH_PLUGINS.DS.'editors'.DS.'jce'.DS.'tiny_mce'.DS.'plugins'.DS.$plugin);

        }

        else {

            $this->parent->abort('Extension Install: '.JText::_('No JCE Plugin file specified'));

            return false;

        }



        /**

         * ---------------------------------------------------------------------------------------------

         * Filesystem Processing Section

         * ---------------------------------------------------------------------------------------------

         */



        // If the extension directory does not exist, lets create it

        $created = false;

        if (!file_exists($this->parent->getPath('extension_root'))) {

            if (!$created = JFolder::create($this->parent->getPath('extension_root'))) {

                $this->parent->abort('Plugin Install: '.JText::_('Failed to create directory').': "'.$this->parent->getPath('extension_root').'"');

                return false;

            }

        }

        // Set overwrite flag if not set by Manifest

        $this->parent->setOverwrite(true);



        /*

         * If we created the extension directory and will want to remove it if we

         * have to roll back the installation, lets add it to the installation

         * step stack

         */

        if ($created) {

            $this->parent->pushStep( array ('type'=>'folder', 'path'=>$this->parent->getPath('extension_root')));

        }



        // Copy all necessary files

        if ($this->parent->parseFiles($element, -1) === false) {

            // Install failed, roll back changes

            $this->parent->abort();

            return false;

        }



        // Parse optional tags -- language files for plugins

        $this->parent->parseLanguages($this->manifest->getElementByPath('languages'), 0);



        // If there is an install file, lets copy it.

        $installScriptElement = & $this->manifest->getElementByPath('installfile');

        if (is_a($installScriptElement, 'JSimpleXMLElement')) {

            // Make sure it hasn't already been copied (this would be an error in the xml install file)

            if (!file_exists($this->parent->getPath('extension_root').DS.$installScriptElement->data()))

            {

                $path['src'] = $this->parent->getPath('source').DS.$installScriptElement->data();

                $path['dest'] = $this->parent->getPath('extension_root').DS.$installScriptElement->data();

                if (!$this->parent->copyFiles( array ($path))) {

                    // Install failed, rollback changes

                    $this->parent->abort(JText::_('Component').' '.JText::_('Install').': '.JText::_('Could not copy PHP install file.'));

                    return false;

                }

            }

            $this->set('install.script', $installScriptElement->data());

        }



        // If there is an uninstall file, lets copy it.

        $uninstallScriptElement = & $this->manifest->getElementByPath('uninstallfile');

        if (is_a($uninstallScriptElement, 'JSimpleXMLElement')) {

            // Make sure it hasn't already been copied (this would be an error in the xml install file)

            if (!file_exists($this->parent->getPath('extension_root').DS.$uninstallScriptElement->data()))

            {

                $path['src'] = $this->parent->getPath('source').DS.$uninstallScriptElement->data();

                $path['dest'] = $this->parent->getPath('extension_root').DS.$uninstallScriptElement->data();

                if (!$this->parent->copyFiles( array ($path))) {

                    // Install failed, rollback changes

                    $this->parent->abort(JText::_('Component').' '.JText::_('Install').': '.JText::_('Could not copy PHP uninstall file.'));

                    return false;

                }

            }

        }



        /**

         * ---------------------------------------------------------------------------------------------

         * Database Processing Section

         * ---------------------------------------------------------------------------------------------

         */



        // Check to see if a plugin by the same name is already installed

        $query = 'SELECT id'.

        ' FROM #__jce_plugins'.

        ' WHERE name = '.$db->Quote($plugin);

        $db->setQuery($query);

        if (!$db->Query()) {

            // Install failed, roll back changes

            $this->parent->abort('Plugin Install: '.$db->stderr(true));

            return false;

        }

        $id = $db->loadResult();



        $row = & JTable::getInstance('plugin', 'JCETable');



        if ($id) {



            if (!$this->parent->getOverwrite()) {

                // Install failed, roll back changes

                $this->parent->abort('Plugin Install: '.JText::_('Plugin').' "'.$plugin.'" '.JText::_('already exists!'));

                return false;

            } else {

                $row->load($id);

            }



        }

        $icon = $this->manifest->getElementByPath('icon');

        $layout = $this->manifest->getElementByPath('layout');



        $row->title = $this->get('name');

        $row->name = $this->manifest->attributes('plugin');

        $row->type = 'plugin';

        $row->row = 4;

        $row->ordering = 1;

        $row->published = 1;

        $row->editable = 1;

        $row->icon = $icon->data();

        $row->layout = $layout->data();

        $row->iscore = 0;



        if (!$row->store()) {

            // Install failed, roll back changes

            $this->parent->abort('Plugin Install: '.$db->stderr(true));

            return false;

        }



        // Process default extension installation (files are assumed to have been copied!)

        $element = & $this->manifest->getElementByPath('extensions');

        if (is_a($element, 'JSimpleXMLElement') && count($element->children())) {

            $extensions = & $element->children();

            foreach ($extensions as $extension) {

                if ($extension->attributes('name')) {

                    $query = 'INSERT INTO `#__jce_extensions` '.

                    ' VALUES ("", '.(int)$row->id.', '.$db->Quote($extension->attributes('title')).', '.$db->Quote($extension->attributes('name')).', '.$db->Quote($extension->attributes('folder')).', 1 )';



                    $db->setQuery($query);

                    if (!$db->query()) {

                        // Install failed, raise error

                        JError::raiseWarning(100, 'Plugin Install: Unable to install default extension '.$extension->attributes('title'));

                        return false;

                    }

                }

            }

        }



        // Since we have created a plugin item, we add it to the installation step stack

        // so that if we have to rollback the changes we can undo it.

        $this->parent->pushStep( array ('type'=>'plugin', 'id'=>$row->id));

         

         /**

         * ---------------------------------------------------------------------------------------------

         * Install plugin into Default Group

         * ---------------------------------------------------------------------------------------------

         */

        // Add to Default Group

        if ($row->type == 'plugin') {

            JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_jce'.DS.'groups');

            $group = & JTable::getInstance('groups', 'JCETable');



            $query = 'SELECT id'

            .' FROM #__jce_groups'

            .' WHERE name = '.$db->Quote('Default')

            ;

            $db->setQuery($query);

            $gid = $db->loadResult();



            $group->load($gid);

            // Add to plugins list

			$plugins = explode(',', $group->plugins);

			if(!in_array($row->id, explode(',', $group->plugins))){

				$group->plugins .= ','.$row->id;

			}

            // Add to last row if plugin has a layout icon

            if ($row->layout) {

            	if (!in_array($row->id, preg_split('/[;,]+/', $group->rows))) {

            		$group->rows .= ','.$row->id;

            	}

			}

            if (!$group->store()) {

                JError::raiseWarning(100, 'Plugin Install: Unable to add plugin to Default group');

            }

        }



        /**

         * ---------------------------------------------------------------------------------------------

         * Finalization and Cleanup Section

         * ---------------------------------------------------------------------------------------------

         */



        // Lastly, we will copy the manifest file to its appropriate place.

        if (!$this->parent->copyManifest(-1)) {

            // Install failed, rollback changes

            $this->parent->abort('Plugin Install: '.JText::_('Could not copy setup file'));

            return false;

        }



        /*

         * If we have an install script, lets include it, execute the custom

         * install method, and append the return value from the custom install

         * method to the installation message.

         */

        if ($this->get('install.script')) {

            if (is_file($this->parent->getPath('extension_root').DS.$this->get('install.script'))) {

                ob_start();

                ob_implicit_flush(false);

                require_once ($this->parent->getPath('extension_root').DS.$this->get('install.script'));

                if (function_exists('jce_install')) {

                    if (jce_install() === false) {

                        $this->parent->abort(JText::_('Plugin').' '.JText::_('Install').': '.JText::_('Custom install routine failure'));

                        return false;

                    }

                }else if (function_exists('com_install')) {

                    if (com_install() === false) {

                        $this->parent->abort(JText::_('Plugin').' '.JText::_('Install').': '.JText::_('Custom install routine failure'));

                        return false;

                    }

                }

                $msg = ob_get_contents();

                ob_end_clean();

                if ($msg != '') {

                    $this->parent->set('extension.message', $msg);

                }

            }

        }

        return true;

    }



    /**

     * Custom uninstall method

     *

     * @access	public

     * @param	int		$cid	The id of the plugin to uninstall

     * @param	int		$clientId	The id of the client (unused)

     * @return	boolean	True on success

     * @since	1.5

     */

    function uninstall($id, $clientId)

    {

        // Initialize variables

        $row = null;

        $retval = true;

        $db = & $this->parent->getDBO();



        // First order of business will be to load the module object table from the database.

        // This should give us the necessary information to proceed.



        // ^ Changes to plugin parameters. Use JCEPluginsTable class.

        $row = & JTable::getInstance('plugin', 'JCETable');

        $row->load((int)$id);



        // Is the plugin we are trying to uninstall a core one?

        // Because that is not a good idea...

        if ($row->iscore) {

            JError::raiseWarning(100, 'Plugin Uninstall: '.JText::sprintf('WARNCOREPLUGIN', $row->title)."<br />".JText::_('WARNCOREPLUGIN2'));

            return false;

        }



        // Get the plugin folder so we can properly build the plugin path

        if (trim($row->name) == '') {

            JError::raiseWarning(100, 'Plugin Uninstall: '.JText::_('Plugin field empty, cannot remove files'));

            return false;

        }



        // Set the plugin root path

        $this->parent->setPath('extension_root', JPATH_PLUGINS.DS.'editors'.DS.'jce'.DS.'tiny_mce'.DS.'plugins'.DS.$row->name);



        $manifestFile = $this->parent->getPath('extension_root').DS.$row->name.'.xml';



        if (file_exists($manifestFile))

        {

            $xml = & JFactory::getXMLParser('Simple');



            // If we cannot load the xml file return null

            if (!$xml->loadFile($manifestFile)) {

                JError::raiseWarning(100, 'Plugin Uninstall: '.JText::_('Could not load manifest file'));

                return false;

            }



            /*

             * Check for a valid XML root tag.

             * @todo: Remove backwards compatability in a future version

             * Should be 'install', but for backward compatability we will accept 'mosinstall'.

             */

            $root = & $xml->document;

            if ($root->name() != 'install' && $root->name() != 'mosinstall') {

                JError::raiseWarning(100, 'Plugin Uninstall: '.JText::_('Invalid manifest file'));

                return false;

            }



            // Remove the plugin files

            $this->parent->removeFiles($root->getElementByPath('files'), -1);

            JFile::delete($manifestFile);



            // Remove all media and languages as well

            $this->parent->removeFiles($root->getElementByPath('languages'), 0);



            /**

             * ---------------------------------------------------------------------------------------------

             * Custom Uninstallation Script Section

             * ---------------------------------------------------------------------------------------------

             */



            // Now lets load the uninstall file if there is one and execute the uninstall function if it exists.

            $uninstallfileElement = & $root->getElementByPath('uninstallfile');

            if (is_a($uninstallfileElement, 'JSimpleXMLElement')) {

                // Element exists, does the file exist?

                if (is_file($this->parent->getPath('extension_root').DS.$uninstallfileElement->data())) {

                    ob_start();

                    ob_implicit_flush(false);

                    require_once ($this->parent->getPath('extension_root').DS.$uninstallfileElement->data());

                    if (function_exists('com_uninstall')) {

                        if (com_uninstall() === false) {

                            JError::raiseWarning(100, JText::_('Plugin').' '.JText::_('Uninstall').': '.JText::_('Custom Uninstall script unsuccessful'));

                            $retval = false;

                        }

                    }

                    $msg = ob_get_contents();

                    ob_end_clean();

                    if ($msg != '') {

                        $this->parent->set('extension.message', $msg);

                    }

                }

            }



            // Remove extension installations from #__jce_extensions

            $query = 'DELETE'.

            ' FROM `#__jce_extensions`'.

            ' WHERE pid='.(int)$id;

            $db->setQuery($query);

            if (!$db->query()) {

                JError::raiseWarning(100, 'Plugin Uninstall: Unable to remove extension records.');

            }



            // Remove from Groups

            if ($row->type == 'plugin') {

                JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_jce'.DS.'groups');

                $grow = & JTable::getInstance('groups', 'JCETable');



                $query = 'SELECT id, name, plugins, rows'

                .' FROM #__jce_groups'

                ;

                $db->setQuery($query);

                $groups = $db->loadObjectList();



                foreach ($groups as $group) {

                    $plugins = explode(',', $group->plugins);

                    // Existence check

                    if (in_array($row->id, $plugins)) {

                        // Load tables

                        $grow->load($group->id);

                        // Remove from plugins list

                        foreach ($plugins as $k=>$v) {

                            if ($row->id == $v) {

                                unset ($plugins[$k]);

                            }

                        }

                        $grow->plugins = implode(',', $plugins);

                        // Remove from rows

                        if ($row->layout) {

                            $lists = array ();

                            foreach (explode(';', $group->rows) as $list) {

                                $icons = explode(',', $list);

                                foreach ($icons as $k=>$v) {

                                    if ($row->id == $v) {

                                        unset ($icons[$k]);

                                    }

                                }

                                $lists[] = implode(',', $icons);

                            }

                            $grow->rows = implode(';', $lists);

                        }

                        if (!$grow->store()) {

                            JError::raiseWarning(100, 'Plugin Install: Unable to remove plugin from Group: '.$grow->name);

                        }

                    }

                }

            }



            // Now we will no longer need the plugin object, so lets delete it

            $row->delete($row->id);

            unset ($row);



        }

        else {

            JError::raiseWarning(100, 'Plugin Uninstall: Manifest File invalid or not found. Plugin entry removed from database.');



            $row->delete($row->id);

            unset ($row);

            $retval = false;

        }

        // If the folder is empty, let's delete it

        $files = JFolder::files($this->parent->getPath('extension_root'));

        if (!count($files)) {

            JFolder::delete($this->parent->getPath('extension_root'));

        }



        return $retval;

    }



    /**

     * Custom rollback method

     * 	- Roll back the plugin item

     *

     * @access	public

     * @param	array	$arg	Installation step to rollback

     * @return	boolean	True on success

     * @since	1.5

     * Minor changes to the db query

     */

    function _rollback_plugin($arg)

    {

        // Get database connector object

        $db = & $this->parent->getDBO();



        // Remove the entry from the #__jce_plugins table

        $query = 'DELETE'.

        ' FROM `#__jce_plugins`'.

        ' WHERE id='.(int)$arg['id'];

        $db->setQuery($query);

        return ($db->query() !== false);

    }

}

