<?php

/**
 * Goweb Sitemanager 5 Framework
 *
 * Ficheiro de metodos comuns
 *
 * @version    5.0.24
 * @category   Goweb
 * @package    Goweb
 * @author     I&D <dev@goweb.pt>, Pedro Pinto <ppinto@goweb.pt>
 * @copyright  2010 (c) Goweb (http://www.goweb.pt)
 */

/**
 * Goweb_Exception
 */
require_once 'Goweb/Exception.php';

require_once 'Zend/Registry.php';
require_once 'Zend/Debug.php';
require_once 'Zend/Loader.php';

error_reporting(E_ALL);
// Same as error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 'on');

/**
 * Classe Final de metodos comuns
 *
 * @version    5.0.24
 * @category   Goweb
 * @package    Goweb
 * @author     I&D <dev@goweb.pt>, Pedro Pinto <ppinto@goweb.pt>
 * @copyright  2010 (c) Goweb (http://www.goweb.pt)
 */
final class Goweb {

    /**
     * Registo de objectos partilhados do tipo Goweb_Model
     *
     * @var  array
     */
    static private $_models = array();

    /**
     * Registo de Javascripts a carregar.
     *
     * @var  array
     */
    static private $_oldJavascripts = array();

    /**
     * Registo de CSS a carregar.
     *
     * @var  array
     */
    static private $_oldCss = array();

    /**
     * Registo de Javascripts a carregar.
     *
     * @var  array
     */
    static private $_javascripts = array();

    /**
     * Registo de CSS a carregar.
     *
     * @var  array
     */
    static private $_css = array();

    /**
     * Registo de RSS a carregar.
     *
     * @var  array
     */
    static private $_rss = array();

    /**
     * Objecto de traduções
     *
     * @var  Goweb_Translator
     */
    static private $_translator = null;

    /**
     * Objecto de traduções
     *
     * @var  Goweb_Translator
     */
    static private $_translatorAdmin = null;

    /**
     * Esta classe não pode ser instanciada
     */
    private function __construct() {}

    /**
     * Carrega a class existente num ficheiro PHP.
     * O ficheiro deve ter o nome formatado como "$classUri.php"
     *
     * A variável $basePath e facultativo e serve para indicar o caminho completo
     * onde se encontra o ficheiro.
     *
     * A variável $once e facultativo e serve para indicar se carrega apenas uma vez.
     *
     * @param   string   $classUri
     * @param   string   $basePath
     * @param   boolean  $once
     * @return  void
     */
    static public function loadClass($classUri, $basePath = null, $once = true) {
        $path = str_replace('_', DIRECTORY_SEPARATOR, $classUri);
        $class = basename($path);
        $path = dirname($path);

        if (class_exists($classUri)) {
            return;
        }

        if (isset($basePath)) {
            $classCompleteUri = $basePath . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . $class . '.php';
        } else {
            return Zend_Loader::loadClass($classUri);
        }

        if (is_readable($classCompleteUri) && is_file($classCompleteUri)) {
            if ($once) {
                $loaded = include_once $classCompleteUri;
            } else {
                $loaded = include $classCompleteUri;
            }
        } else {
            throw new Goweb_Exception("O ficheiro $class.php n&atilde;o foi encontrado.");
        }

        if (!class_exists($classUri, false) && !interface_exists($classUri, false)) {
            throw new Goweb_Exception("O ficheiro $class.php foi encontrado. Mas a classe $classUri n&atilde;o foi encontrada.");
        }
    }

    /**
     * Carrega o interface existente num ficheiro PHP.
     * O ficheiro deve ter o nome formatado como "$interfaceUri.php"
     *
     * A variável $basePath e facultativo e serve para indicar o caminho completo
     * onde se encontra o ficheiro.
     *
     * A variável $once e facultativo e serve para indicar se carrega apenas uma vez.
     *
     * @param   string   $interfaceUri
     * @param   string   $basePath
     * @param   boolean  $once
     * @return  void
     */
    static public function loadInterface($interfaceUri, $basePath = null, $once = true) {
        Zend_Loader::loadClass($classUri, $basePath);
    }

    /**
     * Carrega a class do tipo Goweb_Db_Model existente num ficheiro PHP
     * na pasta APPLICATION_PATH
     *
     * @param   string   $modelName
     * @param   boolean  $once
     * @return  void
     */
    static public function loadModel($modelName, $once = true) {
        return Goweb::loadClass($modelName, APPLICATION_PATH, $once);
    }

    /**
     * Obtem a instancial do $modelName
     *
     * @param String $modelName
     * @param String|Zend_Db $db
     * @param boolean $loadForeigns
     * @param boolean $reset
     * @return Goweb_Db_Model
     */
    static public function getModelInstance($modelName, $db, $loadForeigns = true, $reset = true) {
        $model = null;
        if (is_string($db)) {
        	$db_name = $db;
        } else {
        	$db_name = get_class($db);
        }
        if (!array_key_exists($db_name . '_' . $modelName, Goweb::$_models)) {
            Goweb::loadClass($modelName, APPLICATION_PATH);
            $model = new $modelName($db, $loadForeigns);
            Goweb::$_models[$db_name . '_' . $modelName] = $model;
        } else {
            $model = Goweb::$_models[$db_name . '_' . $modelName];
            if ($reset) {
                $model->reset();
            }
        }

        /**
         * desactivar cache de queries nos models
         */
        if (goweb::registry('config')->cache->models){
            $model->setUseCache(true);
        } else {
            $model->setUseCache(false);
        }
        /**
         * Para permitir usar instancias com e sem carregamento das chaves estrangeiras,
         * é um erro comum dos programadores, usar o getModelInstance
         * e ir mudando o parametro $loadForeigns, o que não era suportado correctamente.
         */
        $model->loadForeigns($loadForeigns);
        return $model;
    }

    /**
     * Regista um objecto partilhado
     *
     * @param   string           $name    O nome para o objecto
     * @param   object           $object  O objecto para ser registado
     * @throws  Goweb_Exception
     * @return  void
     */
    static public function register($name, $object) {
        Zend_Registry::set($name, $object);
    }

    /**
     * Retorna um object registado
     *
     * @see     register()
     * @param   string           $name    O nome do objecto
     * @throws  Goweb_Exception
     * @return  object           O objecto registado
     */
    static public function registry($name) {
        /**
         * Compatibilidade
         * @todo retirar todos os Goweb::registry('request'); e substituir por Zend_Controller_Front::getInstance()->getRequest()
         */
        if (strcmp($name, 'request') === 0) return Zend_Controller_Front::getInstance()->getRequest();
        return Zend_Registry::get($name);
    }

    /**
     * Retorna TRUE se o objecto registado com o nome $name existir.
     *
     * @param   string   $name  O nome do objecto
     * @return  boolean
     */
    static public function isRegistered($name) {
        return Zend_Registry::isRegistered($name);
    }

    /**
     * Regista um nome do ficheiro RSS a ser carregado.
     *
     * @param  string  $css
     */
    static public function loadRss($rss) {
        $controllerName = explode("/", $rss);
        $controllerName = ucfirst($controllerName[1]);
        if (!file_exists(APPLICATION_PATH . DIRECTORY_SEPARATOR . $controllerName . DIRECTORY_SEPARATOR . 'config.ini')) return false;
        $tmp_config = new Goweb_Config(Goweb_Config_Ini::load(APPLICATION_PATH . DIRECTORY_SEPARATOR . $controllerName . DIRECTORY_SEPARATOR . 'config.ini', 'base'));
        if ($tmp_config->rss && $tmp_config->rss->activo){
            if (!in_array($rss, self::$_rss)) {
                array_push(self::$_rss, $rss);
            }
        }
    }

    /**
     * Regista um nome do ficheiro Javascript a ser carregado.
     *
     * @param  string  $javascript
     */
    static public function loadJavascript($javascript) {
        if ($javascript == '/media/js/prototype.js') {
            $javascript = '/admin/media/js/prototype.js';
        }
        if (!in_array($javascript, self::$_oldJavascripts) && !in_array($javascript, self::$_javascripts) && is_file(WWW_PATH . $javascript)) {
            array_push(self::$_javascripts, $javascript);
        }
    }

    /**
     * Regista um nome do ficheiro CSS a ser carregado.
     *
     * @param  string  $css
     */
    static public function loadCss($css) {
        if (!in_array($css, self::$_oldCss) && !in_array($css, self::$_css) && is_file(WWW_PATH . $css)) {
            array_push(self::$_css, $css);
        }
    }

    /**
     * Retorna os Javascripts para serem carregados.
     *
     * @return  array
     */
    static public function getJavascripts() {
        self::$_oldJavascripts = self::$_javascripts;
        self::$_javascripts = array();
        return self::$_oldJavascripts;
    }

    /**
     * Retorna os CSS para serem carregados.
     *
     * @return  array
     */
    static public function getCss() {
        self::$_oldCss = self::$_css;
        self::$_css = array();
        return self::$_oldCss;
    }

    /**
     * Retorna os RSS para serem carregados.
     *
     * @return  array
     */
    static public function getRss() {
        return self::$_rss;
    }

    /**
     * Retorna TRUE se o $filename pode ser lido, caso contrário retornar FALSE.
     *
     * @param   string   $filename
     * @return  boolean
     */
    static public function isReadable($filename, $basePath = null) {
        /**
         * não é 100% compativel, foi costumizado.....
         */
        $path = str_replace('_', DIRECTORY_SEPARATOR, $filename);
        $filename = basename($path);
        $path = dirname($path);

        if (isset($basePath)) {
            $completeUri = $basePath . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . $filename . '.php';
        } else {
            $completeUri = $path . DIRECTORY_SEPARATOR . $filename . '.php';
        }
        return Zend_Loader::isReadable($completeUri);
    }

    /**
     * Retorna o URL formatado para mod_rewrite ou normal.
     *
     * O formato do $rewriteLink tem de ser:
     * /controller/action/param1/value1/param2/value2
     *
     * @param   string   $rewriteLink
     * @return  boolean
     */
    static public function link($rewriteLink, $query = null, $forceSlash = false) {
        $view = Zend_Registry::get('view');
        $rewriteLink = $view->link($rewriteLink);
        if ($query) {
            $rewriteLink .= '?' . $query;
        }
        if ($forceSlash && substr($rewriteLink, -1) != '/') {
            $rewriteLink .= '/';
        }
        return $rewriteLink;
    }

    /**
     * Esta funcao eh uma funcao auxiliar que devolve o array dos
     * objectos registados no sistema
     *
     * @return array
     */
    static public function getRegistries() {
        return Zend_Registry::getArrayCopy();
    }

    /**
     * Funcao de debug. Utiliza a funcao var_dump() e adiciona o elemento <pre />
     * Corre o htmlentities() antes de enviar o output.
     *
     * @param   mixed    $var    A variável para o dump
     * @param   string   $label  Um label opcional
     * @param   boolean  $echo   Flag opcional para efectuar o echo
     * @return  string
     */
    static public function dump($var, $label = '', $echo = true) {
        $config = goweb::registry('config');
        if ($config->debug){
            $logger = goweb::registry('Log_Firebug');
            $logger->err($var);
        }
        return Zend_Debug::dump($var, $label, $echo);
    }

    /**
     * Traduz uma string para a lingua na sessco
     *
     * @param   mixed
     * @return  string  A string traduzida
     */
    static function translate() {
        if (is_null(Goweb::$_translator)) {
            Goweb::$_translator = Goweb::registry('translator');
        }
        $args = func_get_args();
        return call_user_func_array(array(Goweb::$_translator, 'translate'), $args);
    }

    /**
     * Traduz uma string para a lingua na sessco
     *
     * @param   mixed
     * @return  string  A string traduzida
     */
    static function translateAdmin() {
        if (is_null(Goweb::$_translatorAdmin)) {
            Goweb::$_translatorAdmin = Goweb::registry('translatorAdmin');
        }
        $args = func_get_args();
        return call_user_func_array(array(Goweb::$_translatorAdmin, 'translate'), $args);
    }

    /**
     * Verifica se o site tem conectividade ....
     *
     * @return bool
     */
    static function isOnline(){
        $is_conn = false;
        $session = goweb::registry('session');
        if (!$session->gowebIsOnline) {
            if (Goweb::isLocalIP()){
                $is_conn = false;
            } else {
                try {
                    $connected = @fsockopen("195.200.253.81", 80, $errno, $errstr, 5);
                    if ($connected){
                        $is_conn = true;
                        fclose($connected);
                    }else{
                        $is_conn = false;
                    }
                } catch (Exception $e) {}
            }
            $session->gowebIsOnline = $is_conn;
            return $is_conn;
        }
        return $session->gowebIsOnline;
    }

    /**
     * Detects whether IP address is local or not
     *
     * @param string $ip IP address to check
     * @return bool
     */
    static function isLocalIP($ip = null) {
        if (is_null($ip)){
            $ip = isset($_SERVER['LOCAL_ADDR']) ? $_SERVER['LOCAL_ADDR'] : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : gethostbyname($_SERVER['SERVER_NAME'])));
        }

        $regex = '/(192\.168\.[0-9]{1,3}\.[0-9]{1,3})';
        $regex .= '|(10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})';
        $regex .= '|(172\.0?([1][6-9])Â¦([2][0-9])Â¦([3][0-1])\.[0-9]{1,3}\.[0-9]{1,3})';
        $regex .= '|(127\.0\.0\.1)/';

        return (bool)preg_match($regex, $ip);
    }

    /**
     * Faz Cambio de um certo valor para outra moeda seleccionada na sessao
     *
     * @param String|int $valor
     * @param int $view
     * @param int $ncd numero de casas decimais
     * @return string
     */
    static public function cambio($valor, $view = 0, $ncd = 2) {
        $valor = str_replace(',', '.', $valor);
        $valor_base = '&euro;&nbsp;' . number_format($valor, $ncd, ',','');
        $session = Goweb::registry('session') ;
        switch ($view){
            case '0':
                foreach ($session->cambios as $cambio):
                if($session->cambio == $cambio['nome']) {
                    if($cambio['nome'] == 'Euro') return $valor_base;
                    if($cambio['cambio'] > 0)
                    $string = $valor * $cambio['cambio'];
                    else return $valor_base;
                    if($cambio['position'] == 'left') $string = $cambio['simbolo']  . number_format($string,2, ',', '');
                    elseif ($cambio['position'] == 'right') $string = $string   . $cambio['simbolo']  ;
                    break;
                }
                endforeach;
                break;
            case '1':
                foreach ($session->cambios as $cambio):
                if($session->cambio == $cambio['nome']) {
                    if($cambio['nome'] == 'Euro') return $valor_base;
                    if($cambio['cambio'] > 0)
                    $string = $valor * $cambio['cambio'];
                    else return $valor_base;
                    if($cambio['position'] == 'left') $string = $cambio['simbolo'] . number_format($string,2, ',', '');
                    elseif ($cambio['position'] == 'right') $string = $string  . $cambio['simbolo']  ;
                    break;
                }
                endforeach;
                break;
            case '2':
                foreach ($session->cambios as $cambio):
                if($session->cambio == $cambio['nome']) {
                    if($cambio['nome'] == 'Euro') return $valor_base;
                    if($cambio['cambio'] > 0)
                    $string = $valor * $cambio['cambio'];
                    else return $valor_base;
                    if($cambio['position'] == 'left') $string = $cambio['simbolo'] . number_format($string,2, ',', '');
                    elseif ($cambio['position'] == 'right') $string = $string   . $cambio['simbolo']  ;

                    $string = $valor_base . '&nbsp;(' . $string . ')';
                    break;
                }
                endforeach;
                break;
        }
        return $string;
    }

}

/**
 * @tutorial fix for stupid system administrators
 */
if(!function_exists('mime_content_type')) {
    function mime_content_type($filename) {
        $mime_types = array(

            'txt' => 'text/plain',
            'htm' => 'text/html',
            'html' => 'text/html',
            'php' => 'text/html',
            'css' => 'text/css',
            'js' => 'application/javascript',
            'json' => 'application/json',
            'xml' => 'application/xml',
            'swf' => 'application/x-shockwave-flash',
            'flv' => 'video/x-flv',

        // images
            'png' => 'image/png',
            'jpe' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'jpg' => 'image/jpeg',
            'gif' => 'image/gif',
            'bmp' => 'image/bmp',
            'ico' => 'image/vnd.microsoft.icon',
            'tiff' => 'image/tiff',
            'tif' => 'image/tiff',
            'svg' => 'image/svg+xml',
            'svgz' => 'image/svg+xml',

        // archives
            'zip' => 'application/zip',
            'rar' => 'application/x-rar-compressed',
            'exe' => 'application/x-msdownload',
            'msi' => 'application/x-msdownload',
            'cab' => 'application/vnd.ms-cab-compressed',

        // audio/video
            'mp3' => 'audio/mpeg',
            'qt' => 'video/quicktime',
            'mov' => 'video/quicktime',

        // adobe
            'pdf' => 'application/pdf',
            'psd' => 'image/vnd.adobe.photoshop',
            'ai' => 'application/postscript',
            'eps' => 'application/postscript',
            'ps' => 'application/postscript',

        // ms office
            'doc' => 'application/msword',
            'rtf' => 'application/rtf',
            'xls' => 'application/vnd.ms-excel',
            'ppt' => 'application/vnd.ms-powerpoint',

        // open office
            'odt' => 'application/vnd.oasis.opendocument.text',
            'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
        );
        $ext=explode('.',$filename);
        $ext=array_pop($ext);
        $ext = strtolower($ext);
        if (array_key_exists($ext, $mime_types)) {
            return $mime_types[$ext];
        }elseif (function_exists('finfo_open')) {
            $finfo = finfo_open(FILEINFO_MIME);
            $mimetype = finfo_file($finfo, $filename);
            finfo_close($finfo);
            return $mimetype;
        }else {
            return 'application/octet-stream';
        }
    }
}

/**
 * @tutorial fix for lame servers
 */
ini_set('mime_magic.magicfile', LIBRARY_PATH . '/External/mime.types');

if (get_magic_quotes_gpc()) {
    function stripslashes_deep($value)
    {
        $value = is_array($value) ?
                    array_map('stripslashes_deep', $value) :
                    stripslashes($value);

        return $value;
    }

    $_POST = array_map('stripslashes_deep', $_POST);
    $_GET = array_map('stripslashes_deep', $_GET);
    $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
    $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}

if (false === function_exists('lcfirst')) {
    function lcfirst($str) {
        return (string)(strtolower(substr($str, 0, 1)) . substr($str, 1));
    }
}


function exceptions_error_handler($severity, $message, $filename, $lineno) {
        if ($severity != E_STRICT && $severity > 2) {
            goweb::loadClass('Zend_Log');
            goweb::loadClass('Zend_Log_Writer_Stream');
            $log = new Zend_Log( new Zend_Log_Writer_Stream( CACHE_PATH . '/goweb_errors.log' ));
            $log->debug('Message: "' . $message . '" in file: "' . $filename . '" in line "' . $lineno . '"');
            throw new ErrorException($message, 0, $severity, $filename, $lineno);
        }
}
set_error_handler('exceptions_error_handler');

register_shutdown_function('handleShutdown');

function handleShutdown() {
        $error = error_get_last();
        if(!is_null($error) && $error['type'] != E_STRICT){
            goweb::loadClass('Zend_Log');
            goweb::loadClass('Zend_Log_Writer_Stream');
            $log = new Zend_Log( new Zend_Log_Writer_Stream( CACHE_PATH . '/goweb_errors.log' ));
            $log->debug('Message: "' . $error['message'] . '" in file: "' . $error['file'] . '" in line "' . $error['line'] . '"');
            Goweb::loadClass('Goweb_Controller_Action_Error');
            
            Goweb::loadClass('Goweb_Mail');
            $mail = new Goweb_Mail();
            $mail->setSupportMail();

            $mail->setSubject(html_entity_decode('SM5 - BUG FATAL - CORRIGIR IMEDIATAMENTE', ENT_NOQUOTES, CHARSET));

            $mail->setBodyHtml(Goweb_Controller_Action_Error::fileExcerpt($error));

            try {
                $mail->send();
            } catch (Exception $e) {
                // nao faz nada
            }
        }
    }
