# Source: jala/code/RemoteContent.js

    //
    // Jala Project [http://opensvn.csie.org/traccgi/jala]
    //
    // Copyright 2004 ORF Online und Teletext GmbH
    //
    // Licensed under the Apache License, Version 2.0 (the ``License'');
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //    http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an ``AS IS'' BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    //
    // $Revision$
    // $LastChangedBy$
    // $LastChangedDate$
    // $HeadURL$
    //

    /**
     * @fileoverview Fields and methods of the jala.RemoteContent class.
     */

    // HelmaLib dependencies
    app.addRepository("modules/core/String.js");
    app.addRepository("modules/core/Object.js");
    app.addRepository("modules/core/Date.js");
    app.addRepository("modules/helma/Http.js");

    // Define the global namespace for Jala modules
    if (!global.jala) {
       global.jala = {};
    }

    /**
     * Construct a new remote content handler.
     * @class API to define, fetch and update content
     * from a remote site.
     * @param {String} url The URL string of the remote site.
     * @param {Integer} method The method to retrieve the remote content.
     * @param {File} storage The cache directory.
     * @returns A new remote content handler.
     * @extends helma.Http
     * @constructor
     */
    jala.RemoteContent = function(url, method, storage) {
       if (typeof PropertyMgr == "undefined")
          var PropertyMgr = {};

       var NULLSTR = "";
       var key = url.md5();
       var fname = key + jala.RemoteContent.SUFFIX;
       var cache;
       method = (method != null ? method.toLowerCase() : null);

       // depending on the method argument the instance
       // becomes extent of the appropriate remote client
       switch (method) {
          case jala.RemoteContent.XMLRPC:
             break;
          default:
             helma.Http.call(this);
             break;
       }

       if (!storage) {
          storage = jala.RemoteContent.CACHEDIR;
          if (!storage.exists() || !storage.isDirectory())
             storage.mkdir(storage.getAbsolutePath());
       }

       var getCache = function() {
          switch (storage.constructor) {
             case HopObject:
                cache = storage;
                break;

             case PropertyMgr:
                cache = storage.getAll();
                break;

             default:
                var f = new File(storage, fname);
                cache = f.exists() ? Xml.read(f) : new HopObject();
          }
          return cache;
       };

       var setCache = function() {
          cache.url = url;
          cache.method = method;
          if (!cache.interval) {
             cache.interval = Date.ONEHOUR;
          }
          cache.lastUpdate = new Date();
          cache = cache.clone(new HopObject());

          switch (storage.constructor) {
             case HopObject:
                for (var i in cache)
                   storage[i] = cache[i];
                break;

             case PropertyMgr:
                storage.setAll(cache);
                break;

             default:
                var f = new File(storage, fname);
                Xml.write(cache, f);
          }
          return;
       };

       cache = getCache();

       /**
        * Set the interval the remote content's
        * cache is bound to be updated.
        * @param {Number} interval The interval value in milliseconds.
        */
       this.setInterval = function(interval) {
          cache.interval = parseInt(interval, 10);
          return;
       };

       /**
        * Get an arbitrary property of the remote content.
        * @param {String} key The name of the property.
        * @returns The value of the property.
        */
       this.get = function(key) {
          return cache[key];
       }

       /**
        * Get all available property names.
        * @returns The list of property names.
        * @type Array
        */
       this.getKeys = function() {
          var keys = [];
          for (var i in cache) {
             keys.push(i);
          }
          return keys.sort();
       };

       /**
        * Tests whether the remote content needs to be updated.
        * @returns True if the remote content needs to be updated.
        * @type Boolean
        */
       this.needsUpdate = function() {
          if (!cache.lastUpdate) {
             return true;
          } else {
             var max = new Date() - cache.interval;
             if (max - cache.lastUpdate > 0) {
                return true;
             }
          }
          return false;
       };

       /**
        * Get the updated and cached remote content.
        * @returns The content as retrieved from the remote site.
        * @type String
        */
       this.update = function() {
          app.debug("[jala.RemoteContent] Retrieving " + url);
          var result;
          switch (method) {
             case jala.RemoteContent.XMLRPC:
                break;
             default:
                result = this.getUrl(url, cache.lastModified || cache.eTag);
                if (result.code != 200 && cache.content) {
                   // preserve the content received before
                   result.content = cache.content;
                }
                result.interval = cache.interval;
                cache = result;
          }
          setCache();
          return cache.content;
       };

       /**
        * Flushes (empties) the cached remote content.
        */
       this.clear = function() {
          switch (storage.constructor) {
             case HopObject:
                for (var i in storage)
                   delete storage[i];
                break;

             case PropertyMgr:
                storage.reset();
                break;

             default:
                var f = new File(storage, fname);
                f.remove();
          }
          return;
       };

       /**
        * Get a string representation of the remote content.
        * @returns The remote content as string.
        * @type String
        */
       this.toString = function() {
          return cache.content || NULLSTR;
       };

       /**
        * Get the value of the remote content.
        * @returns The remote content including response header data.
        * @type Object
        */
       this.valueOf = function() {
          return cache;
       };

       return this;
    };

    /**
     * A constant representing the HTTP retrieval method.
     * @type int
     * @final
     */
    jala.RemoteContent.HTTP = 1;

    /**
     * A constant representing the XML-RPC retrieval method.
     * @type int
     * @final
     */
    jala.RemoteContent.XMLRPC = 2;

    /**
     * The default name of the cache directory.
     * @type String
     * @final
     */
    jala.RemoteContent.SUFFIX = ".cache";

    /**
     * The default cache directory.
     * @type File
     * @final
     */
    jala.RemoteContent.CACHEDIR = new File(app.dir, jala.RemoteContent.SUFFIX);

    /**
     * Remove all remote content from a file-based cache.
     * @param {File} cache An optional target directory.
     */
    jala.RemoteContent.flush = function(cache) {
       jala.RemoteContent.forEach(function(rc) {
          rc.clear();
          return;
       });
       return;
    };

    /**
     * Apply a custom method on all remote content in a file-based cache.
     * @param {Function} callback The callback method to be executed
     * for each remote content file.
     * @param {File} cache An optional target directory.
     */
    jala.RemoteContent.forEach = function(callback, cache) {
       if (!cache)
          cache = jala.RemoteContent.CACHEDIR;
       var f, rc;
       var files = cache.list();
       for (var i in files) {
          f = new File(cache, files[i]);
          if (!files[i].endsWith(jala.RemoteContent.SUFFIX))
             continue;
          rc = new jala.RemoteContent(Xml.read(f).url);
          if (callback && callback.constructor == Function)
             callback(rc);
       }
       return;
    };

    /**
     * Apply a custom method on all remote content in a file-based cache.
     * @param {Function} callback The callback method to be executed
     * for each remote content file.
     * @param {File} cache An optional target directory.
     * @deprecated Use {@link #forEach} instead.
     */
    jala.RemoteContent.exec = function() {
       jala.RemoteContent.forEach.apply(this, arguments);
    };