<?php
require_once 'SabaiPlugin/Plugin.php';

class Plugg_Plugin extends SabaiPlugin_Plugin
{
    protected $_hasSchema, $_hasModel, $_hasCSS, $_hasLocale, $_nicename, $_application;

    public function Plugg_Plugin($name, $path, $version, array $params, $library, $extra, Plugg $application)
    {
        parent::__construct($name, $path, $version, $params, $library);
        $this->_nicename = @$extra['nicename'];
        $this->_hasSchema = $extra['hasSchema'];
        $this->_hasModel = $extra['hasModel'];
        $this->_hasCSS = $extra['hasCSS'];
        $this->_hasLocale = $extra['hasLocale'];
        $this->_application = $application;
        $this->gettext->loadMessages($this->_name, $this->_library . '.mo');
    }

    public function __get($name)
    {
        return $this->_application->$name;
    }

    public function getNicename()
    {
        return $this->_nicename;
    }

    public function getApplication()
    {
        return $this->_application;
    }

    public function _($msgId)
    {
        if ($this->gettext->dhastext($this->_name, $msgId)) {
            return $this->gettext->dgettext($this->_name, $msgId);
        }

        // If message cannt be found in the domain, find it from the global domain
        return $this->gettext->gettext($msgId);
    }

    public function _e($msgId)
    {
        if ($this->gettext->dhastext($this->_name, $msgId)) {
            echo $this->gettext->dgettext($this->_name, $msgId);
        } else {
            // If message cannt be found in the domain, find it from the global domain
            echo $this->gettext->gettext($msgId);
        }
    }

    public function ngettext($msgId, $msgId2, $num)
    {
        if ($this->gettext->dhastext($this->_name, $msgId)) {
            return $this->gettext->dngettext($this->_name, $msgId, $msgId2, $num);
        }

        // If message cannt be found in the domain, find it from the global domain
        return $this->gettext->ngettext($msgId, $msgId2, $num);
    }

    protected function _onPluggMainRoutes(&$routes)
    {
        $routes['/' . $this->_name] = array(
            'controller' => sprintf('Plugg_%s_Main', $this->_library),
            'file' => $this->_path . '/Main.php',
            'context' => array('plugin' => $this)
        );
    }

    protected function _onPluggAdminRoutes(&$routes)
    {
        $routes['/' . $this->_name] = array(
            'controller' => sprintf('Plugg_%s_Admin', $this->_library),
            'file' => $this->_path . '/Admin.php',
            'context' => array('plugin' => $this)
        );
    }

    public function install(&$message)
    {
        if ($this->_hasSchema) {
            // create database tables
            $schema = $this->getDBSchema();
            if (!$schema->create($this->_path . '/schema/latest.xml')) {
                $message = sprintf('Failed creating database tables using schema. Error: %s', implode(', ', $schema->getErrors()));
                return false;
            }
            $message = 'Database tables created.';
        }
        return true;
    }

    public function uninstall(&$message)
    {
        if ($this->_hasSchema) {
            $schema_dir = $this->_path . '/schema/';
            if (!$dh = opendir($schema_dir)) {
                $message = 'Failed opening schema directory.';
                return false;
            }
            while ($file = readdir($dh)) {
                if (preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\.xml$/', $file)) {
                    $file_version = basename($file, '.xml');
                    if (version_compare($file_version, $this->_version, '<=')) {
                        $schema_old[$file_version] = $schema_dir . $file;
                    }
                }
            }
            closedir($dh);
            if (!empty($schema_old)) {
                ksort($schema_old, SORT_NUMERIC);
                // get the last previous schema file
                $previous_schema = array_pop($schema_old);
            } else {
                $previous_schema = $schema_dir . 'latest.xml';
            }
            $schema = $this->getDBSchema();
            if (!$schema->drop($previous_schema)) {
                $message = sprintf(
                    'Failed deleting database tables using schema %s. Error: %s',
                    str_replace($schema_dir, '', $previous_schema),
                    implode(', ', $schema->getErrors())
                );
                return false;
            }
            $message = 'Database tables deleted.';
        }
        if (!$this->getCache()->clean()) {
            $message .= 'Failed removing cache files.';
        } else {
            $message .= 'Removed cache files.';
        }
        return true;
    }

    public function upgrade($previousVersion, &$message)
    {
        if ($this->_hasSchema) {
            $schema_dir = $this->_path . '/schema/';
            if (!$dh = opendir($schema_dir)){
                $message = 'Failed opening schema directory.';
                return false;
            }
            $schema_new = $schema_old = array();
            while ($file = readdir($dh)) {
                if (preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\.xml$/', $file)) {
                    $file_version = basename($file, '.xml');
                    if (version_compare($file_version, $previousVersion, '>')) {
                        $schema_new[$file_version] = $schema_dir . $file;
                    } else {
                        $schema_old[$file_version] = $schema_dir . $file;
                    }
                }
            }
            closedir($dh);
            if (!empty($schema_new)) {
                $schema = $this->getDBSchema();
                $messages = array();
                ksort($schema_new, SORT_NUMERIC);
                if (!empty($schema_old)) {
                    ksort($schema_old, SORT_NUMERIC);
                    // get the last previous schema file
                    $previous_schema = array_pop($schema_old);
                } else {
                    // No previous schema, so get one from the new
                    $previous_schema = array_shift($schema_new);
                    if (!$schema->create($previous_schema)) {
                        $message = sprintf('Failed creating database tables using schema. Error: %s', implode(', ', $schema->getErrors()));
                        return false;
                    }
                    $messages[] = sprintf('Created database using schema %s.', str_replace($schema_dir, '', $previous_schema));
                }
                // update schema incrementally

                foreach ($schema_new as $new_schema) {
                    if (!$result = $schema->update($new_schema, $previous_schema)) {
                        $message = sprintf(
                            'Failed updating database schema from %s to %s. Error: %s',
                            str_replace($schema_dir, '', $previous_schema),
                            str_replace($schema_dir, '', $new_schema),
                            implode(', ', $schema->getErrors())
                        );
                        return false;
                    }
                    $messages[] = sprintf(
                        'Updated database schema from %s to %s.',
                        str_replace($schema_dir, '', $previous_schema),
                        str_replace($schema_dir, '', $new_schema)
                    );
                    $previous_schema = $new_schema;
                }
                $message = implode('<br />', $messages);
            }
        }
        return true;
    }

    public function getDB()
    {
        $default_table_prefix = $this->locator->getDefaultParam('DB', 'tablePrefix');
        return $this->locator->getService(
            'DB',
            $this->_name,
            array(
                'tablePrefix' => $default_table_prefix . $this->_name . '_'
            )
        );
    }

    public function getDBSchema()
    {
        require_once 'Sabai/DB/Schema.php';
        return Sabai_DB_Schema::factory($this->getDB());
    }

    public function getModel()
    {
        if (!$this->_hasModel) {
            trigger_error(sprintf('No model available for plugin %s', $this->_name), E_USER_WARNING);
            return;
        }
        return $this->locator->getService('PluginModel', $this->_name, array('plugin' => $this));
    }

    public function getCache($cacheLifetime = null)
    {
        // Create new cache object if cache lifetime set, otherwise reuse the last object
        if (!empty($cacheLifetime)) {
            return $this->locator->createService(
                'Cache',
                array(
                    'cacheName' => $this->_name,
                    'lifeTime' => $cacheLifetime,
                )
            );
        } else {
            return $this->locator->getService(
                'Cache',
                $this->_name,
                array(
                    'cacheName' => $this->_name,
                )
            );
        }
    }

    public function getTemplatePath()
    {
        return $this->_path . '/templates';
    }

    public function hasCSS()
    {
        return $this->_hasCSS;
    }

    public function hasLocale()
    {
        return $this->_hasLocale;
    }

    public function loadParams()
    {
        if ($plugin = $this->pluginManager
                ->getPlugin('system')
                ->getModel()
                ->Plugin
                ->fetchByName($this->_name)
        ) {
            $this->_params = $plugin->getParams();
            return true;
        }
        return false;
    }

    public function updateParam($name, $value)
    {
        if (array_key_exists($name, $this->_params)) {
            if ($plugin = $this->pluginManager
                    ->getPlugin('system')
                    ->getModel()
                    ->Plugin
                    ->fetchByName($this->_name)
            ) {
                $this->_params[$name] = $value;
                $plugin->setParams($this->_params);
                return $plugin->commit();
            }
        }
        return false;
    }
}