/**
  * Returns collection of all javascript translations data for requested language
  * 
  * This is a javascript special function!
  * The data will be preseted to be included as javascript on client side!
  *
  * NOTE: This function is called from release.php cli script. In this case no 
  *       tine 2.0 core initialisation took place beforehand
  *       
  * @param  Zend_Locale|string $_locale
  * @return string      javascript
  */
 public static function getJsTranslations($_locale, $_appName = 'all')
 {
     $locale = $_locale instanceof Zend_Locale ? $_locale : new Zend_Locale($_locale);
     $localeString = (string) $_locale;
     $availableTranslations = self::getAvailableTranslations();
     $info = isset($availableTranslations[$localeString]) || array_key_exists($localeString, $availableTranslations) ? $availableTranslations[$localeString] : array('locale' => $localeString);
     $baseDir = (isset($info['path']) || array_key_exists('path', $info) ? dirname($info['path']) . '/..' : dirname(__FILE__)) . '/..';
     $defaultDir = dirname(__FILE__) . "/..";
     $genericTranslationFile = "{$baseDir}/Tinebase/js/Locale/static/generic-{$localeString}.js";
     $genericTranslationFile = is_readable($genericTranslationFile) ? $genericTranslationFile : "{$defaultDir}/Tinebase/js/Locale/static/generic-{$localeString}.js";
     $extjsTranslationFile = "{$baseDir}/library/ExtJS/src/locale/ext-lang-{$localeString}.js";
     $extjsTranslationFile = is_readable($extjsTranslationFile) ? $extjsTranslationFile : "{$defaultDir}/library/ExtJS/src/locale/ext-lang-{$localeString}.js";
     if (!is_readable($extjsTranslationFile)) {
         // trying language as fallback if lang_region file can not be found, @see 0008242: Turkish does not work / throws an error
         $language = $locale->getLanguage();
         $extjsTranslationFile = "{$baseDir}/library/ExtJS/src/locale/ext-lang-{$language}.js";
         $extjsTranslationFile = is_readable($extjsTranslationFile) ? $extjsTranslationFile : "{$defaultDir}/library/ExtJS/src/locale/ext-lang-{$language}.js";
     }
     $tine20TranslationFiles = self::getPoTranslationFiles($info);
     $allTranslationFiles = array_merge(array($genericTranslationFile, $extjsTranslationFile), $tine20TranslationFiles);
     $jsTranslations = NULL;
     if (Tinebase_Core::get(Tinebase_Core::CACHE) && $_appName == 'all') {
         // setup cache (saves about 20% @2010/01/28)
         $cache = new Zend_Cache_Frontend_File(array('master_files' => $allTranslationFiles));
         $cache->setBackend(Tinebase_Core::get(Tinebase_Core::CACHE)->getBackend());
         $cacheId = __CLASS__ . "_" . __FUNCTION__ . "_{$localeString}";
         $jsTranslations = $cache->load($cacheId);
     }
     if (!$jsTranslations) {
         $jsTranslations = "";
         if (in_array($_appName, array('Tinebase', 'all'))) {
             $jsTranslations .= "/************************** generic translations **************************/ \n";
             $jsTranslations .= file_get_contents($genericTranslationFile);
             $jsTranslations .= "/*************************** extjs translations ***************************/ \n";
             if (file_exists($extjsTranslationFile)) {
                 $jsTranslations .= file_get_contents($extjsTranslationFile);
             } else {
                 $jsTranslations .= "console.error('Translation Error: extjs changed their lang file name again ;-(');";
             }
         }
         $poFiles = self::getPoTranslationFiles($info);
         foreach ($poFiles as $appName => $poPath) {
             if ($_appName != 'all' && $_appName != $appName) {
                 continue;
             }
             $poObject = self::po2jsObject($poPath);
             //if (! json_decode($poObject)) {
             //    $jsTranslations .= "console.err('tanslations for application $appName are broken');";
             //} else {
             $jsTranslations .= "/********************** tine translations of {$appName}**********************/ \n";
             $jsTranslations .= "Locale.Gettext.prototype._msgs['./LC_MESSAGES/{$appName}'] = new Locale.Gettext.PO({$poObject}); \n";
             //}
         }
         if (isset($cache)) {
             $cache->save($jsTranslations, $cacheId);
         }
     }
     return $jsTranslations;
 }
 /**
  * check if js or css files have changed and return all js/css as one big file or return "HTTP/1.0 304 Not Modified" if files don't have changed
  * 
  * @param string $_fileType
  * @param array $filesToWatch
  */
 protected function _deliverChangedFiles($_fileType, $filesToWatch = null)
 {
     // close session to allow other requests
     Tinebase_Session::writeClose(true);
     $config = Tinebase_Config::getInstance();
     $cacheId = null;
     $clientETag = null;
     $ifModifiedSince = null;
     if (isset($_SERVER['If_None_Match'])) {
         $clientETag = trim($_SERVER['If_None_Match'], '"');
         $ifModifiedSince = trim($_SERVER['If_Modified_Since'], '"');
     } elseif (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
         $clientETag = trim($_SERVER['HTTP_IF_NONE_MATCH'], '"');
         $ifModifiedSince = trim($_SERVER['HTTP_IF_MODIFIED_SINCE'], '"');
     }
     $filesToWatch = $filesToWatch ? $filesToWatch : $this->_getFilesToWatch($_fileType);
     if ($_fileType == 'js' && TINE20_BUILDTYPE != 'DEVELOPMENT') {
         $customJSFiles = Tinebase_Config::getInstance()->get(Tinebase_Config::FAT_CLIENT_CUSTOM_JS);
         if (!empty($customJSFiles)) {
             $filesToWatch = array_merge($filesToWatch, (array) $customJSFiles);
         }
     }
     $lastModified = $this->_getLastModified($filesToWatch);
     // use last modified time also
     $serverETag = hash('sha1', implode('', $filesToWatch) . $lastModified);
     $cache = new Zend_Cache_Frontend_File(array('master_files' => $filesToWatch));
     $cache->setBackend(Tinebase_Core::get(Tinebase_Core::CACHE)->getBackend());
     if ($clientETag && $ifModifiedSince) {
         $cacheId = __CLASS__ . "_" . __FUNCTION__ . hash('sha1', $clientETag . $ifModifiedSince);
     }
     // cache for 60 seconds
     $maxAge = 60;
     header('Cache-Control: private, max-age=' . $maxAge);
     header("Expires: " . gmdate('D, d M Y H:i:s', Tinebase_DateTime::now()->addSecond($maxAge)->getTimestamp()) . " GMT");
     // overwrite Pragma header from session
     header("Pragma: cache");
     // if the cache id is still valid, the files don't have changed on disk
     if ($clientETag == $serverETag && $cache->test($cacheId)) {
         header("Last-Modified: " . $ifModifiedSince);
         header("HTTP/1.0 304 Not Modified");
         header('Content-Length: 0');
     } else {
         // get new cacheId
         $cacheId = __CLASS__ . "_" . __FUNCTION__ . hash('sha1', $serverETag . $lastModified);
         // do we need to update the cache? maybe the client did not send an etag
         if (!$cache->test($cacheId)) {
             $cache->save(TINE20_BUILDTYPE, $cacheId, array(), null);
         }
         header("Last-Modified: " . $lastModified);
         header('Content-Type: ' . ($_fileType == 'css' ? 'text/css' : 'application/javascript'));
         header('Etag: "' . $serverETag . '"');
         flush();
         // send files to client
         foreach ($filesToWatch as $file) {
             readfile($file);
         }
     }
 }
 /**
  * get JSON from cache or new instance
  * 
  * @param array $classes for Zend_Cache_Frontend_File
  * @return Zend_Json_Server
  */
 protected static function _getServer($classes = null)
 {
     // setup cache if available
     if (is_array($classes) && Tinebase_Core::getCache()) {
         $masterFiles = array();
         $dirname = dirname(__FILE__) . '/../../';
         foreach ($classes as $class => $namespace) {
             $masterFiles[] = $dirname . str_replace('_', '/', $class) . '.php';
         }
         try {
             $cache = new Zend_Cache_Frontend_File(array('master_files' => $masterFiles, 'lifetime' => null, 'automatic_serialization' => true, 'automatic_cleaning_factor' => 0, 'write_control' => false, 'logging' => Tinebase_Core::isLogLevel(Zend_Log::DEBUG), 'logger' => Tinebase_Core::getLogger()));
             $cache->setBackend(Tinebase_Core::getCache()->getBackend());
             $cacheId = Tinebase_Helper::convertCacheId('_handle_' . sha1(Zend_Json_Encoder::encode($classes)) . '_' . (self::userIsRegistered() ? Tinebase_Core::getUser()->getId() : 'anon'));
             $server = $cache->load($cacheId);
             if ($server instanceof Zend_Json_Server) {
                 return $server;
             }
         } catch (Zend_Cache_Exception $zce) {
             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Failed to create cache. Exception: \n" . $zce);
             }
         }
     }
     $server = new Zend_Json_Server();
     $server->setAutoEmitResponse(false);
     $server->setAutoHandleExceptions(false);
     if (is_array($classes)) {
         foreach ($classes as $class => $namespace) {
             try {
                 $server->setClass($class, $namespace);
             } catch (Exception $e) {
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Failed to add JSON API for '{$class}' => '{$namespace}' Exception: \n" . $e);
                 }
             }
         }
     }
     if (self::userIsRegistered()) {
         $definitions = self::_getModelConfigMethods();
         $server->loadFunctions($definitions);
     }
     if (isset($cache)) {
         $cache->save($server, $cacheId, array(), null);
     }
     return $server;
 }