/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *     "Apache Jetspeed" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache" or
 *    "Apache Jetspeed", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package org.apache.jetspeed.cache.disk;

//jetspeed
import org.apache.jetspeed.util.*;

//standard java stuff
import java.io.*;
import java.net.*;
import java.util.*;

//turbine
import org.apache.turbine.util.*;
import org.apache.turbine.services.servlet.TurbineServlet;
import org.apache.jetspeed.services.resources.JetspeedResources;

/**
   <p>
   Misc utils for managing the disk cache.
   </p>

   <p>
   This tries to separate URLs into three categories:
       <ul>
           <li>
           Virtual: URLs which are contructored such as: /test/test.xml
           </li>

           <li>
           Local: URLs which are contructored such as: http://localhost/test/test.xml
           </li>

           <li>
           Remote: URLs which are contructored such as: http://REMOTE.SERVER/test/test.xml
           </li>
           
       </ul>
   </p>
   
   @see DiskCache
   @author <A HREF="mailto:burton@apache.org">Kevin A. Burton</A>
   @version $Id: DiskCacheUtils.java,v 1.17 2001/09/13 17:52:18 sgala Exp $
*/
public class DiskCacheUtils {

    /**
    Used to determine if a given URL should be cached.  This prevents people 
    from trying to cache documents that aren't supported.  http and ftp should
    fit almost any situation.
    */
    public final static String[] VALID_PROTOCOLS = { "http", "ftp" };
    
    /**
    Stores the protocols which sould be recognized as local
    */
    private static Vector localprotocols = JetspeedResources.getVector("diskcache.localprotocols");

    private static String hostName = "localhost";
    static {
        try {
            hostName = java.net.InetAddress.getLocalHost().getHostName();
        } catch (Throwable t) {}
        if (localprotocols.size()==0) { // default values, if key is not defined
            localprotocols.add("file");
        }
    }
    
    /**
    Give an full url:  http://www.cnn.com/test
    
    just return the virutal portion:  /test
    */
    public static String getVirtual( String url ) {
        
        //strip off the begining of the URL if necessary:
        
        int begin = 0;
        
        if ( url.indexOf(":/") != -1 ) {
            begin = url.indexOf( ":/" ) + 2;
        }
        
        if ( begin > 0 ) {
            url = url.substring( begin, url.length() );
        }
        
        url = url.substring( url.indexOf("/"), url.length() );
        
        
        return url;
    }
    
    /**
       Given a virtual URL, resolve it to a local URL:
    
       Ex: /test.xml  -> http://localhost:80/test.xml
    */
    public static String getLocalURL( String virtual ) {

     //if this virtual URL is actually a local, return it directly.
        if ( virtual != null &&
             isLocal( virtual ) &&
             virtual.indexOf("/") != 0 ) {
            return virtual;
        }

        if ( isVirtual( virtual ) == false ) {
            throw new IllegalArgumentException( "The URL specifies is not a virtual URL: " + virtual );
        }
                
        String url = TurbineServlet.getResource( virtual ).toString();
        
        return url;
    }

    /**
       Return true if this URL is virtual.

       EX: /tmp/test.xml
     */
    public static boolean isVirtual( String url ) {

        if ( url.indexOf( "/" ) == 0 ) {
            return true;
        } 

        return false;
    }
    
    /**
    Return true if this URL is on the local server.
    */
    public static boolean isLocal( String url ) {


        /*
          If the URL is virtual, return true:

          EX: /test/test.xml
              
         */
        
        if ( url != null && url.length() > 1 ) {

            if ( ( url.indexOf( ":/" ) == -1 ) ) {
                //this must be a local URL because it is virtual "/test/test.xml"
                return true;
            }


        /*
          ok... perform two more tests.  if the URL is on the local server.. or on
          localhost then return true
          
          EX: http://localhost
              http://server.domain
         */
            if ( ( url.indexOf( "http://localhost" ) == 0 ) || 
                 ( url.indexOf( "http://127.0.0.1" ) == 0 ) || 
                 ( url.indexOf( "http://" + hostName ) == 0 ) ||

           // RL: using EngineContext doesn't work because the serverName
           // and serverPort is a request-based information.
           // We should either fix EngineContext to use a config property
           // or remove it altogether and find something that always works !
        
             /* ( url.indexOf( EngineContext.getInstance().getServerScheme() +
                            "://" + 
                            EngineContext.getInstance().getServerName() ) == 0 ) */
                    ( false )
                 ) {
                return true;
            }
            
            /* SH Testing local protocols also */
            if (localprotocols!=null) {
                Enumeration en = localprotocols.elements();
                while(en.hasMoreElements()) {
                    String protocol = (String)en.nextElement()+":";
                    if ( url.indexOf(protocol) != -1 ) 
                    {
                        return true;
                    }
                }
            }

        }
        return false;
    }
    
    /**
    Return true if this URL is NOT on the local server.
    */
    public static boolean isRemote( String url ) {
        return ! isLocal( url );
    }
    
    /**
    Return true if this url is in the cache.
    @see DiskCache#isCached( String )
    */
    public static boolean isCached( DiskCache instance, 
                                    String url ) {
     
    /*         if ( isLocal( url ) ) {
               //SGP: I think we should not cache local urls
               return false;
               }*/
                
    //         return DiskCacheUtils.getFile( instance, url ).exists();
         return instance.isCached(url);
    }

    /**
    @see DiskCacheUtils#isCached( DiskCache, String )
    */
    public static boolean isCached( String url ) {
        return isCached( JetspeedDiskCache.getInstance(), url );
    }
    
    /**
    Return true if the given URL should be cached or not.
    */
    public static boolean isCacheable( String url ) {

        for (int i = 0; i < VALID_PROTOCOLS.length;++i) {

            String uri = VALID_PROTOCOLS[i] + ":/";

            if (url.length() >= uri.length() &&
        url.substring(0, uri.length() ).equals( uri ) ) {
                return isRemote( url ); //SGP was true
            }

        }
        return false;
    }
    
    /**
       Given a URL, determine what the filename would be within the cache.  Note 
       that this doesn't return a URL just a path to where it would be stored 
       locally.
    */
    public static File getFile( DiskCache instance, 
                                String url ) {

      String file = URIEncoder.encode( url );

      file = instance.getRoot() + "/" + file;

      return new File( file );
      
    }

    /**
       Given a url and an disk cache instance, determine what the correct URL for this
       cache entry for the remote URL would be.
     */
    public static String getFileURL( DiskCache instance,
                                     String url ) {

        URL fileURL = null;
        
        try {
            fileURL = DiskCacheUtils.getFile( instance, url ).toURL();
        } catch (MalformedURLException e) {
            // what can we do in this case ?
            Log.error(e);
            return null;
        }
        
        return fileURL.toString();
        
    }
    
}

