package basics.internet;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;

public class RobotRules
{
private static RobotRules               me      = null;
private static int                      MAXSIZE = 1000;
private HashMap<String, RuleEvalutator> cache   = null;

public static boolean allow(URL url, String path)
{
   RuleEvalutator checker = getCache().getRobotRuleChecker(url);
   return !checker.isAccessDenied(path);
}

private RobotRules()
{
   cache = new HashMap<String, RuleEvalutator>();
}

private static RobotRules getCache()
{
   if(me == null)
   {
      me = new RobotRules();
   }
   return me;
}

private synchronized RuleEvalutator getRobotRuleChecker(URL url)
{
   RuleEvalutator rc = null;
   String robotfile = getRobotsTextFilepath(url);
   if(cache.containsKey(robotfile))
   {
      rc = (RuleEvalutator)cache.get(robotfile);
   }
   else
   {
      rc = new RuleEvalutator(readUrl(robotfile));
      addToCache(robotfile, rc);
   }
   return rc;
}

public static String getRobotsTextFilepath(URL url)
{
   StringBuffer sb = new StringBuffer();
   sb.append(url.getProtocol());
   sb.append("://");
   sb.append(url.getAuthority());
   sb.append("/robots.txt");
   return sb.toString();
}

private synchronized void addToCache(String url, RuleEvalutator rrc)
{
   if(!(cache.size() < MAXSIZE))
   {
      String k = cache.keySet().iterator().next();
      cache.remove(k);
   }
   cache.put(url, rrc);
}

private String readUrl(String urlString)
{
   URL url = null;
   URLConnection connection = null;
   BufferedReader oBReader = null;
   // Log.debug("Reading: " + urlString);
   StringBuffer sb = new StringBuffer();
   try
   {
      url = new URL(urlString);
      // open the connection and prepare it to POST
      connection = url.openConnection();
      //      OsUtl.trace(urlString);
      connection.setDoOutput(false);
      connection.setDoInput(true);
      connection.setAllowUserInteraction(false);
      // Read the response
      oBReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
      String sOutput = null;
      while((sOutput = oBReader.readLine()) != null)
      {
         sb.append(sOutput);
         sb.append("\n");
      }
      oBReader.close();
   }
   catch(Exception e)
   {
      //      OsUtl.trace("NOT FOUND: " + url.toString());
   }
   return sb.toString();
}
}

class RuleEvalutator
{
private String  robotRules    = null;
// private boolean idle = true;
private boolean folderAllowed = true;
private boolean fileAllowed   = true;

RuleEvalutator(String rules)
{
   this.robotRules = rules == null ? "" : rules;
}

boolean isAccessDenied(String docPath)
{
   // Log.debug("Checking: " + docPath);
   String [] a = robotRules.split("\n");
   for(int x = 0; x < a.length; x++)
   {
      String r = a[x];
      if(r == null)
      {
         r = "";
      }
      else
      {
         r = r.trim();
      }
      if(r.length() > 0 && !r.startsWith("#"))
      {
         String [] buffer = r.split(" ");
         String tmp = r.toLowerCase();
         // Log.debug((x+1) + ".) " + a[x]);
         if(tmp.startsWith("user-agent:"))
         {
            agentLine(buffer.length > 1 ? buffer[1] : "");
         }
         else
            if(tmp.startsWith("disallow:"))
            {
               disallowLine(buffer.length > 1 ? buffer[1] : "", docPath);
            }
            else
               if(tmp.startsWith("allow:"))
               {
                  allowLine(buffer.length > 1 ? buffer[1] : "", docPath);
               }
      }
   }
   if(fileAllowed)
   {
      //      OsUtl.trace(docPath + " is allowed.");
      return false;
   }
   else
   {
      //      OsUtl.trace(docPath + " is forbidden.");
      return true;
   }
}

/**
 * prueft ob wir gemeint sein koennen
 */
private void agentLine(String agent)
{
   // idle = true;
   agent = agent.trim();
   // if (agent.equals("*")) idle = false;
}

private void disallowLine(String disallow, String docPath)
{
   disallow = disallow.trim();
   // Log.debug("DA Rule: " + disallow + " DOC:" + docPath);
   if(disallow.equals("/"))
   {
      folderAllowed = false;
      fileAllowed = false;
      // Log.debug("Nothing allowed!");
   }
   else
   {
      if(isFile(disallow))
      {
         if(disallow.equals(docPath))
         {
            fileAllowed = false;
            // Log.debug("This File may not be accessed: " + disallow);
         }
         // idle = false; //ab jetzt anweisungen verwerten!
      }
      else
      // is a folder
      {
         if(disallow.equals(docPath))
         {
            folderAllowed = false;
            // Log.debug("This Folder may not be accessed: " + disallow);
         }
         else
         // subfolder?
         {
            if(docPath.length() > disallow.length())
            {
               String dp = docPath.substring(0, disallow.length());
               if(disallow.equals(dp))
               {
                  folderAllowed = false;
                  // Log.debug("This Folder may not be accessed: " + disallow);
               }
            }
         }
      }
   }
}

private void allowLine(String allow, String docPath)
{
   allow = allow.trim();
   // Log.debug("Allow Rule: " + allow + " DOC:" + docPath);
   if(allow.equals("/"))
   {
      folderAllowed = true;
      fileAllowed = true;
      // Log.debug("Nothing allowed!");
   }
   else
   {
      if(isFile(allow))
      {
         if(allow.equals(docPath))
         {
            fileAllowed = true;
            // Log.debug("This File may be accessed: " + allow);
         }
         // idle = false; //ab jetzt anweisungen verwerten!
      }
      else
      // is a folder
      {
         if(allow.equals(docPath))
         {
            folderAllowed = true;
            // Log.debug("This Folder may be accessed: " + allow);
         }
         else
         // subfolder?
         {
            if(docPath.length() > allow.length())
            {
               String dp = docPath.substring(0, allow.length());
               if(allow.equals(dp))
               {
                  folderAllowed = true;
                  // Log.debug("This Folder may be accessed: " + allow);
               }
            }
         }
      }
   }
}

private boolean isFile(String test)
{
   // is file?
   int dotPos = test.lastIndexOf(".");
   int slashPos = test.lastIndexOf("/");
   return(dotPos > slashPos);
}
}
