<?php

Goweb::loadClass('Goweb_Controller_Action_Admin');

/**
 * Goweb Sitemanager 5 Framework
 * @version    5.0.19
 * @category   Backoffice
 * @package    Setup
 * @author     I&D <dev@goweb.pt>
 * @copyright  2010 (c) Goweb (http://www.goweb.pt)
 */
class Setup_GenericController extends Goweb_Controller_Action_Admin {

    /**
     * Titulo do Modulo
     * @var string
     */
    protected $_title;

    /**
     * Controller do Modulo
     * @var string
     */
    protected $_controller = 'setup';

    /**
     * Seccoes do Modulo
     * @var array
     */
    protected $_sections;

    /**
     * Seccao default do Modulo
     * @var array
     */
    protected $_section = 'setup';

    /**
     * Objecto Goweb_Session
     * @var Goweb_Session
     */
    protected $_session = null;

    /**
     * Construtor da classe
     */
    public function init() {
        $this->_title = 'Setup';
        $this->_sections = array(array('title'   => translateAdmin('Setup'),
                                       'section' => 'setup',
                                       'link'    => '/setup/index/'));

        parent::init();
        $this->view->setViewsPath(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views');
    }

    /**
     * Devolve todos os modulos do sistema
     *
     * @return array
     */
    protected function _getModels($path) {
        $models = array();
        if ($modelsHandle = opendir($path)) {
            while (false !== ($file = readdir($modelsHandle))) {
                if ($file != '.' && $file != '..') {
                    $modelFile = explode('.', $file);
                    $models[] = $modelFile[0];
                }
            }
            closedir($modelsHandle);
        }
        return $models;
    }

    /**
     * Lista os modulos para instalação ou actualizacao
     *
     * @param string
     * @param string
     */
    public function indexAction($error = null, $message = null) {
        $path = APPLICATION_PATH . DIRECTORY_SEPARATOR;
        $modulos = array();
        $models = array();
        if ($handle = opendir($path)) {
            while (false !== ($file = readdir($handle))) {
                if (is_dir($path . $file) && $file != '.' && $file != '..') {
                    if (file_exists($path . $file . DIRECTORY_SEPARATOR . 'Model')) {
                        $models[$file] = $this->_getModels($path . $file . DIRECTORY_SEPARATOR . 'Model');
                    }
                    if (file_exists($path . $file . DIRECTORY_SEPARATOR . 'Setup.php')) {
                        $modulos[] = $file;
                    }
                }
            }
            closedir($handle);
        }
        sort($modulos);
        $db = Goweb::registry('db');
        $tables = $db->listTables();

        // cria a tabela sistema_modulo necessária para a instalação de módulos
        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        if (!in_array($moduloModel->getTableName(), $tables)) {
            $sqlArray = $moduloModel->createTableSql();
            foreach ($sqlArray as $table => $t) {
                $db->query($sqlArray[$table]['sql']);
            }
        }

        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        $modulosInstalados = array();
        $modulosRowset = $moduloModel->fetchAll();
        if ($modulosRowset) {
            foreach ($modulosRowset as $row) {
                $modulosInstalados[] = $row->nome;
            }
        }

        $this->view->setViewsPath(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views');
        $this->_initDefaultLinks();
        $this->view->sections = $this->_sections;
        $this->view->modulos_instalados = $modulosInstalados;
        $this->view->modulos = $modulos;
        $this->view->models = $models;
        $this->view->output = $this->view->render('list.tpl');
        $this->view->setViewsPath(GENERIC_VIEWS_PATH);
        $this->view->title = translateAdmin('Instala&ccedil;&atilde;o de M&oacute;dulos');
        $this->view->action = translateAdmin('Listagem');
        $this->view->error = $error;
        $this->view->message = $message;
        $this->view->section_title = translateAdmin('Instala&ccedil;&atilde;o de M&oacute;dulos');
        $this->_helper->viewRenderer->setRender('base');

    }

    /**
     * Adicionar traduções de URL
     *
     */
    public function addUrlTranslateAction(){
        $mtime = microtime();
        $mtime = explode(" ",$mtime);
        $mtime = $mtime[1] + $mtime[0];
        $starttime = $mtime;
        $modulos = array();
        if ($modelsHandle = opendir(APPLICATION_PATH)) {
            while (false !== ($file = readdir($modelsHandle))) {
                if (file_exists(APPLICATION_PATH . '/' . $file . '/Setup.php')){
                    $modulos[] = $file;
                }
            }
            closedir($modelsHandle);
        }

        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        $actionModel = Goweb::getModelInstance('Sistema_Model_Action', 'db');

        foreach ($modulos as $modulo){
            $setupClass = $modulo . '_Setup';
            Goweb::loadClass($setupClass, APPLICATION_PATH);
            $setup = new $setupClass();
            // regista o medulo
            if (!$moduloModel->findBy('nome', $setup->getNome())) {
                $moduloModel->reset();
                $moduloModel->nome = $setup->getNome();
                if ($moduloModel->colExists('nome_traduzido')){
                    $moduloModel->nome_traduzido = $setup->getNome();
                }
                $moduloModel->titulo = $setup->getTitulo();
                $moduloModel->menu = $setup->getMenu() ? '1' : '0';
                $moduloModel->componente = $setup->getComponente() ? '1' : '0';
                $moduloModel->pesquisa = $setup->getPesquisa() ? '1' : '0';
                $moduloModel->permissao = $setup->getPermissao() ? '1' : '0';
                
                $moduloModel->save();
            }
            if (file_exists(APPLICATION_PATH . '/' . $moduloModel->nome . '/Controller.php')){
                $accoes = $this->_getClassActions(APPLICATION_PATH . '/' . $moduloModel->nome . '/Controller.php');
                if (file_exists(APPLICATION_PATH . '/' . $moduloModel->nome . '/GenericController.php')){
                    $accoes =  array_merge($accoes, $this->_getClassActions(APPLICATION_PATH . '/' . $moduloModel->nome . '/GenericController.php'));
                }
                if ($accoes && count($accoes)>1){
                    foreach ($accoes as $accao){
                        $actionModel->where($actionModel->getTableName() . '.modulo_id = ?', $moduloModel->id);
                        $actionModel->where($actionModel->getTableName() . '.nome = ?', $accao);
                        if (!$actionModel->fetchAll()){
                            $actionModel->reset();
                            $actionModel->modulo_id = $moduloModel->id;
                            $actionModel->nome = $accao;
                            if ($actionModel->colExists('nome_traduzido')){
                                $actionModel->nome_traduzido = $accao;
                            }
                            $actionModel->titulo = $accao;
                            $actionModel->save();
                        }
                    }
                }
            }
        }
        reset($modulos);
        foreach ($modulos as $modulo){
            foreach (explode(',', goweb::registry('config')->languages->available) as $lang){
                $sqlFile = APPLICATION_PATH . '/Sistema/sql/' . $moduloModel->getTablePrefix() . '_' . $lang . '.sql';
                if (!is_file($sqlFile) || !is_readable($sqlFile)){
                    $sqlFile = APPLICATION_PATH . '/Sistema/sql/' . $moduloModel->getTablePrefix() . '_en.sql';
                }
                if (is_file($sqlFile) && is_readable($sqlFile)){
                    $actionModel->getAdapter()->query(file_get_contents($sqlFile));
                }
            }
        }
        reset($modulos);
        foreach ($modulos as $modulo){
            foreach (explode(',', goweb::registry('config')->languages->available) as $lang){
                $sqlFile = APPLICATION_PATH . '/Sistema/sql/' . $actionModel->getTablePrefix() . '_' . $lang . '_' . $modulo . '.sql';
                if (!is_file($sqlFile) || !is_readable($sqlFile)){
                    $sqlFile = APPLICATION_PATH . '/Sistema/sql/' . $actionModel->getTablePrefix() . '_en_' . $modulo . '.sql';
                }
                if (is_file($sqlFile) && is_readable($sqlFile)){
                    $actionModel->getAdapter()->query(str_replace('@@modulo_id@@', $moduloModel->id, file_get_contents($sqlFile)));
                }
            }
        }
        $mtime = microtime();
        $mtime = explode(" ",$mtime);
        $mtime = $mtime[1] + $mtime[0];
        $endtime = $mtime;
        $totaltime = ($endtime - $starttime);

        return $this->indexAction(null, translateAdmin('Demorou {{tempo}} segundos a adicionar as tradu&ccedil;&otilde;es', number_format($totaltime, 2, '.', '')));
    }

    /**
     * Este metodo procede com a instalação ou actualizacao do modulo
     *
     * @param string
     * @param string
     */
    public function installAction($error = null, $message = null) {
        $modulo = $this->_getParam('modulo');

        if (!$modulo) {
            return $this->indexAction();
        }


        $setupClass = $modulo . '_Setup';
        Goweb::loadClass($setupClass, APPLICATION_PATH);
        $setup = new $setupClass();

        $db = Goweb::registry('db');
        $db_config = $db->getConfig();
        require_once LIBRARY_PATH . '/External/database.lib.php';
        $scon = New cConnection($db_config['host'], $db_config['username'], $db_config['password']);

        if ( $scon->open() ) {
            ini_set("max_execution_time", "600");
            set_error_handler(create_function('$errno,$errstr', 'return false;'));
            $save = error_reporting();
            error_reporting(E_ALL ^ E_NOTICE);
            $scon->selectDatabase($db_config['dbname']);
            //goweb::dump($tabelas);
            error_reporting($save);
            restore_error_handler();
        }
        $tables = $db->listTables();
        $register = false;

        // cria a tabela sistema_modulo necessária para a instalação de módulos
        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        if (!in_array($moduloModel->getTableName(), $tables)) {
            $sqlArray = $moduloModel->createTableSql();
            foreach ($sqlArray as $table => $t) {
                $db->query($sqlArray[$table]['sql']);
            }
        }

        $setup->initModels();

        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        if ($this->_getParam('execute') == '1') {
            $modulosInstalados = array();
            $modulosRowset = $moduloModel->fetchAll();
            if ($modulosRowset) {
                foreach ($modulosRowset as $row) {
                    $modulosInstalados[] = $row->nome;
                }
            }
            // regista o medulo
            if (!$moduloModel->findBy('nome', $setup->getNome())) {
                $moduloModel->nome = $setup->getNome();
                if ($moduloModel->colExists('nome_traduzido')){
                    $moduloModel->nome_traduzido = $setup->getNome();
                }
                $moduloModel->titulo = $setup->getTitulo();
                $moduloModel->menu = $setup->getMenu() ? '1' : '0';
                $moduloModel->componente = $setup->getComponente() ? '1' : '0';
                $moduloModel->pesquisa = $setup->getPesquisa() ? '1' : '0';
                $moduloModel->permissao = $setup->getPermissao() ? '1' : '0';
                $moduloModel->save();
            }
        } elseif (!$moduloModel->findBy('nome', $setup->getNome())) {
            $register = true;
        }

        $models = array();
        $modelsInstall = array();
        $modelsCreateTableSql = array();
        $modelsAlterTableSql = array();

        $modelsSetup = $setup->getModels();

        foreach ($modelsSetup as $model => $modelObject) {
            $sql = $modelObject->createTableSql();
            $flag = false;
            foreach ($sql as $table => $t) {
                if (!in_array($table, $tables)) {
                    if (array_key_exists($model, $modelsCreateTableSql)) {
                        $modelsCreateTableSql[$model] .= $t['sql'];
                    } else {
                        $modelsCreateTableSql[$model] = $t['sql'];
                    }
                    foreach ($t['indexes'] as $index) {
                        $modelsCreateTableSql[$model] .= $index;
                    }
                    $modelsCreateTableSql[$model] .= "\n";
                    if ($this->_getParam('execute') == '1') {
                        $db->query($t['sql']);
                        foreach ($t['indexes'] as $index) {
                            $db->query($index);
                        }
                    }
                    $flag = true;
                } else {
                    set_error_handler(create_function('$errno,$errstr', 'return false;'));
                    $save = error_reporting();
                    error_reporting(E_ALL ^ E_NOTICE);
                    $tmpSql = $t['sql'];

                    $tmpSql = str_replace($table, $table . '_goweb_tmp', $tmpSql);
                    $scon->query($tmpSql);
                    foreach ($t['indexes'] as $index) {
                        $scon->query(str_replace($table, $table . '_goweb_tmp', $index));
                    }

                    $builder = New cCommandBuilder($scon);
                    $s_tab = $scon->fetchTables($s_db);

                    $item = $builder->alterTable($s_tab[$table], $s_tab[$table. '_goweb_tmp']);
                    $item = str_replace($table. '_goweb_tmp', $table,  $item);
                    // fixes
                    $item = str_replace(" DEFAULT ''", '', $item);
                    $item = str_replace(" COMMENT ''", '', $item);
                    $item = str_replace(" DEFAULT 0 auto_increment", ' auto_increment', $item);
                    $item = preg_replace("/ (.*)#\n/", " $1;\n#\n", $item);
                    if (is_numeric(strpos($item, ' SET;'))) {
                        $item = preg_replace('/.* SET;\n#.*\n#.*\n#.*\n/', '', $item);
                    }
                    /**
                     * @tutorial remove empty newlines
                     */
                    $item = trim($item, "\n");
                    if (strlen($item) > 0){
                        $modelsAlterTableSql[$model] .=  $item;
                    }

                    $scon->query('DROP TABLE '.$table . '_goweb_tmp');
                    error_reporting($save);
                    restore_error_handler();

                }
            }
            if ($flag) {
                $modelsInstall[] = $model;
            }
            $models[] = $model;
        }

        $this->view->setViewsPath(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views');
        $this->_initDefaultLinks();
        $this->view->register = $register;
        $this->view->sections = $this->_sections;
        $this->view->modulo = $modulo;
        $this->view->models = $models;
        $this->view->models_install = $modelsInstall;
        $this->view->models_create_table_sql = $modelsCreateTableSql;
        $this->view->models_alter_table_sql = $modelsAlterTableSql;
        if ($this->_getParam('execute') == '1') {
            if (count($modelsInstall) > 0) {
                $setup->initDefaultData();
            }
            $this->view->output = $this->view->render('install_result.tpl');
        } else {
            $this->view->output = $this->view->render('install.tpl');
        }
        $this->view->setViewsPath(GENERIC_VIEWS_PATH);
        $this->view->title = translateAdmin('Instala&ccedil;&atilde;o de M&oacute;dulos');
        $this->view->action = translateAdmin('Instala&ccedil;&atilde;o');
        $this->view->error = $error;
        $this->view->message = $message;
        $this->view->section_title = translateAdmin('Instala&ccedil;&atilde;o de M&oacute;dulos');
        $this->_helper->viewRenderer->setRender('base');

    }

    /**
     * Actualizar as tabelas para utf8, sem conversão de encoding
     *
     */
    public function updateUtf8Action() {
        $mtime = microtime();
        $mtime = explode(" ",$mtime);
        $mtime = $mtime[1] + $mtime[0];
        $starttime = $mtime;
        $db = Goweb::registry('db');
        $fields = array();
        $tables = $db->listTables();
        foreach ($tables as $table){
            $res_fields = $db->describeTable($table);
            if( is_array( $res_fields ) ){
                foreach( $res_fields as $field ){

                    switch( TRUE ){
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'char' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'varchar' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'text' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'enum' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'set' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'tinytext' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'mediumtext' )===0:
                        case strpos( strtolower( $field['DATA_TYPE'] ), 'longtext' )===0:
                            $fields[$table][$field['COLUMN_NAME']] = $field['DATA_TYPE'] .
                                ($field['LENGTH'] ? ' ('.$field['LENGTH'].')' : '') .
                                ($field['NULLABLE'] ? '' : ' not null') .
                                ($field['DEFAULT'] ? ' DEFAULT "'.$field['DEFAULT'].'"' : '')
                            ;
                            break;
                             
                        default:
                            break;
                    }
                }
            }
        }
        $sql_to_blob		= '';
        $sql_to_utf8		= '';
        $sql_to_original	= '';
        foreach( $fields as $table=>$fields ){
            $sql_to_utf8 .= "\nALTER TABLE ".$table." charset=utf8;";
            if( count( $fields )>0 ){
                foreach( $fields as $name=>$type ){
                    $sql_to_blob .= "\nALTER TABLE ".$table." MODIFY ".$name." BLOB;";
                    $sql_to_original .= "\nALTER TABLE ".$table." MODIFY ".$name." ".$type.";";
                }
            }
        }
        $db_config = $db->getConfig();
        $complete_sql = $sql_to_blob."\nALTER DATABASE ".$db_config['dbname']." charset=utf8;".$sql_to_utf8.$sql_to_original;
        $db->query($complete_sql);
        foreach (array('cache', 'page_cache') as $cacheName) {
            if (goweb::isRegistered($cacheName)){
                $cache = goweb::registry($cacheName);
                $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
            }
        }

        $mtime = microtime();
        $mtime = explode(" ",$mtime);
        $mtime = $mtime[1] + $mtime[0];
        $endtime = $mtime;
        $totaltime = ($endtime - $starttime);

        return $this->indexAction(null, translateAdmin('Demorou {{tempo}} segundos a converter a BD', number_format($totaltime, 2, '.', '')));
    }

    /**
     * Wrapper do installAction mais simplificado.
     *
     * @param string
     * @param string
     */
    public function installRedirectAction($error = null, $message = null) {
        $modulo = $this->_getParam('modulo');

        if (!$modulo) {
            return $this->indexAction();
        }

        $setupClass = $modulo . '_Setup';
        Goweb::loadClass($setupClass, APPLICATION_PATH);
        $setup = new $setupClass();

        $db = Goweb::registry('db');
        $tables = $db->listTables();
        $register = false;

        // cria a tabela sistema_modulo necessária para a instalação de módulos
        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        if (!in_array($moduloModel->getTableName(), $tables)) {

            $createTableSql = $moduloModel->createTableSql();

            if ((is_array($createTableSql)) && (array_key_exists($moduloModel->getTableName(), $createTableSql))) {
                if (array_key_exists('sql', $createTableSql[$moduloModel->getTableName])) {
                    $sqlCreateTableSql = $createTableSql[$moduloModel->getTableName]['sql'];
                    $db->query($sqlCreateTableSql);
                }
            } else {
                foreach ($createTableSql as $table => $t) {
                    $db->query($createTableSql[$table]['sql']);
                }
            }
        }

        $setup->initModels();

        $moduloModel = Goweb::getModelInstance('Sistema_Model_Modulo', 'db');
        $modulosInstalados = array();
        $modulosRowset = $moduloModel->fetchAll();
        if ($modulosRowset) {
            foreach ($modulosRowset as $row) {
                $modulosInstalados[] = $row->nome;
            }
        }
        // regista o medulo
        if (!$moduloModel->findBy('nome', $setup->getNome())) {
            $moduloModel->nome = $setup->getNome();
            if ($moduloModel->colExists('nome_traduzido')){
                $moduloModel->nome_traduzido = $setup->getNome();
            }
            $moduloModel->titulo = $setup->getTitulo();
            $moduloModel->menu = $setup->getMenu() ? '1' : '0';
            $moduloModel->componente = $setup->getComponente() ? '1' : '0';
            $moduloModel->pesquisa = $setup->getPesquisa() ? '1' : '0';
            $moduloModel->permissao = $setup->getPermissao() ? '1' : '0';
            $moduloModel->save();
        }

        $models = array();
        $modelsInstall = array();
        $modelsCreateTableSql = array();

        $models = $setup->getModels();

        foreach ($models as $model => $modelObject) {

            $sql = $modelObject->createTableSql();
            $flag = false;

            foreach ($sql as $table => $t) {
                if (!in_array($table, $tables)) {
                    if (array_key_exists($model, $modelsCreateTableSql)) {
                        $modelsCreateTableSql[$model] .= $t['sql'];
                    } else {
                        $modelsCreateTableSql[$model] = $t['sql'];
                    }
                    foreach ($t['indexes'] as $index) {
                        $modelsCreateTableSql[$model] .= $index;
                    }
                    $modelsCreateTableSql[$model] .= "\n";

                    $db->query($t['sql']);
                    foreach ($t['indexes'] as $index) {
                        $db->query($index);
                    }

                    $flag = true;
                }
            }

            if ($flag) {
                $modelsInstall[] = $model;
            }

            $models[] = $model;
        }

        if (count($modelsInstall) > 0) {
            $setup->initDefaultData();
        }
    }
    protected function _getClassActions($file){
        if (!file_exists($file)) return array();
        $arr_methods = array();
        $arr = file($file);
        foreach ($arr as $line)
        {
            if (preg_match('/function ([_A-Za-z0-9]+)/', $line, $regs)){
                /**
                 * ignorar metodos começados por _ e que não seja Action
                 */
                if (substr($regs[1],0,1) !== '_' && substr($regs[1],-6) === 'Action')
                $arr_methods[] = substr($regs[1],0,-6);
            }
        }
        return $arr_methods;
    }
}