package baf.guide;
import java.io.*;
import java.util.*;
import baf.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
/** Items form the core of the Guide. Subclasses include Game, Author,
* and so on - anything that has its own page and can serve as the
* basis of an index. Items are customarily read from a text file
* marked up with lines beginning with colons in a manner that I
* really should document somewhere.
*/
public abstract class Item implements Comparable {
static final String basedir = "/home/httpd/html/if/raw";
static final String baseurl = "/if/data/items";
public String filename;
public String url;
public String rawname;
public String name;
static String toc = "/if/index.html";
protected String sortString = null;
long lastModified = 0;
Properties attributes = new Properties();
public static String nameToUrl(String s) {
s = s.replace(' ', '_');
if (s.indexOf(';') != -1) s = s.replace(';', ',');
if (s.indexOf('&') != -1) s = s.replace('&', '+');
// There are several other unsafe characters, but they're
// unlikely to be used.
// '&' *should* be a safe character, but isn't.
return s;
}
public static String urlToName(String s) {
s = s.replace('_', ' ');
if (s.indexOf(',') != -1) s = s.replace(',', ';');
if (s.indexOf('+') != -1) s = s.replace('+', '&');
return s;
}
static Hashtable byPath = new Hashtable();
public static synchronized Item forPath(String path) throws IOException {
Item item = (Item)byPath.get(path);
// If it's out of date, forget you ever saw it.
if (item != null) {
File f = new File(basedir+path);
if (f.lastModified() > item.lastModified) item = null;
}
if (item == null) {
if (path.startsWith("/games/")) item = new Game(path);
else if (path.startsWith("/authors/")) item = new Author(path);
else if (path.startsWith("/years/")) item = new Year(path);
else if (path.startsWith("/devsys/")) item = new Devsys(path);
else if (path.startsWith("/platforms/")) item = new Platform(path);
else if (path.startsWith("/genres/")) item = new Genre(path);
else if (path.startsWith("/lingvoj/")) item = new Language(path);
else if (path.startsWith("/ratings/")) item = new Rating(path);
else if (path.startsWith("/chron/")) item = new Chron(path);
else throw new IllegalArgumentException();
byPath.put(path, item);
}
return item;
}
/** Creates a new Item.
* @param path The (relative) path to the data file
*/
public Item(String path) throws IOException {
rawname = path.substring(path.indexOf('/', 1)+1);
name = urlToName(rawname);
sortString = name.toLowerCase();
filename = basedir + path;
url = baseurl + path;
try {
lastModified = new File(filename).lastModified();
BufferedReader f = new BufferedReader(new FileReader(filename));
String line;
while ((line = f.readLine()) != null) {
if (line.length() > 0 && line.charAt(0) == ':') {
char c = line.charAt(1);
if (!Character.isWhitespace(c)) {
StringTokenizer st = new StringTokenizer(line);
String tag = st.nextToken();
String value = st.nextToken("").trim();
// Chron tags get parsed specially
if (c == 'c') {
StringTokenizer dt = new StringTokenizer(value, "/ ");
String month = dt.nextToken();
String day = dt.nextToken();
String year = dt.nextToken();
value = year + ((month.length()==1)? ".0" : ".") + month;
}
attributes.put(tag, value);
}
}
}
f.close();
} catch (FileNotFoundException e) {
// It's OK to not have a data file. It just means that this is a blank
// item, existing solely because of references from other items.
// (ie, an Author with no contact info).
}
}
public String toString() {
return name;
}
/** Returns a string suitable for displaying in an alphabetical index.
*/
public String getListingString() {
return toString();
}
/** Returns the key by which this Item is referred to in files
*/
public String getRefString() {
return name;
}
/** Returns a string suitable for alphabetical comparisons.
*/
public final String getSortString() {
return sortString;
}
/** The method for the "Comparable" interface
*/
public int compareTo(Object o) {
Item i = (Item)o;
return getSortString().compareTo(i.getSortString());
}
/** Crucial! Crucial!
*/
public boolean equals(Object o) {
return o != null && o instanceof Item &&
((Item)o).filename.equals(filename);
}
/** This may be used by the servlet's getLastModified method.
*/
public long getLastModified() throws IOException {
Game.update();
if (lastModified >= Game.globalLastModified) return lastModified;
else return Game.globalLastModified;
}
/** Returns the URL for the page detailing this Item
*/
public String getURL() {
return url;
}
/** Inserts a hotlink in the output stream.
* @param out The output stream
* @param loc The URL to link to
* @param txt The visible text of the hotlink
*/
protected static void hotlink(ServletOutputStream out, String loc, String txt)
throws IOException {
out.print("");
out.print(txt);
out.print("");
}
/** Insterts into the output stream a link to this item.
*/
void hotlink(ServletOutputStream out, String txt) throws IOException {
hotlink(out, url, txt);
}
/** Inserts into the output stream a link to this item.
* Uses the item's name as the visible text.
*/
void hotlink(ServletOutputStream out) throws IOException {
hotlink(out, url, name);
}
/** Prints a standard beginning to HTML pages in the Guide.
*/
public static final void header(ServletOutputStream out,
String title, String desc, Index index, Item current) throws IOException {
out.print("\n");
out.print(title);
out.print("\n\n");
if (index != null) {
out.print("\n");
}
out.print("");
navigation(out, index, current);
out.print("
\n");
}
public static final void header(ServletOutputStream out,
String title, String desc) throws IOException {
header(out, title, desc, null, null);
}
public void header(ServletOutputStream out) throws IOException {
header(out, name, getDescription(), Index.forTag(getTag()), this);
}
/** Prints a standard ending to HTML pages in the Guide.
*/
public static final void footer(ServletOutputStream out) throws IOException {
out.print("\n
\nBaf's Guide to the Interactive Fiction Archive
\n");
out.print("Copyright © 1998 ");
hotlink(out, "http://www.wurb.com/~carl/", "Carl Muckenhoupt");
out.print(" - ");
hotlink(out, "mailto:carl@wurb.com", "carl@wurb.com");
out.print("