import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import org.sablecc.sablecc.expander.Expander;

public class SvnWebifier2 {
    final static String NL = System.getProperty("line.separator");
    
    private final Expander expander;
    private final Set revisions = new TreeSet();
    private final TreeMap shortLogs = new TreeMap();
    private final TreeMap directories = new TreeMap();
    
    public static void main(String[] args) throws Exception {
	SvnWebifier2 sw = new SvnWebifier2();
	sw.loadRevs();
	sw.createLogs();
	sw.loadDirectories();
	sw.loadAll();
	sw.createIndices();
    }
    
    private SvnWebifier2() throws Exception {
	expander = new Expander(new InputStreamReader(getClass().getResourceAsStream("template.html")));
    }
    
    private void loadRevs() throws Exception {
	BufferedReader in = new BufferedReader(new FileReader("revs"));
	try {
	    String line;
	    while ((line = in.readLine()) != null) {
		Integer revision = new Integer(line);
		revisions.add(revision);
	    }
	} finally {
	    in.close();
	}
    }
    
    private void createLogs() throws Exception {
	BufferedReader in = new BufferedReader(new FileReader("logs"));
	try {
	    //------------------------------------------------------------------------
	    String line = in.readLine();
	    
	    while ((line = in.readLine()) != null) {
		StringBuffer fullLog = new StringBuffer();
		
		//rREV | AUTH | DATE TIME TZ (DAY, DOM M Y) | NUMLINES lines
		
		StringTokenizer st = new StringTokenizer(line, "|");

		Integer revision = new Integer (st.nextToken().trim().substring(1));
		String author = st.nextToken().trim();
		String date = st.nextToken().trim();
		st.nextToken(" ");
		int lines = Integer.parseInt(st.nextToken(" "));

		String shortLog = "";
		
		//
		line = in.readLine();
		
		for (int i = 0; i < lines; i++) {
		    line = in.readLine();
		    fullLog.append(line);
		    fullLog.append(NL);
		    
		    if(i == 0) {
			shortLog = line;
		    }			
		}
		
		//------------------------------------------------------------------------
		line = in.readLine();
		
		if(revisions.contains(revision)) {
		    shortLogs.put(revision, new ShortLog(revision, author, date, shortLog));
		    
		    Expander.Expansion expansion = expander.new Expansion(new FileWriter("log" + revision + ".txt"), "log");
		    
		    TreeMap args = new TreeMap();
		    args.put("content", fullLog);
		    expansion.applyMacro("logcontent", args);
		    expansion.done();
		}
	    }
	} finally {
	    in.close();
	}
    }
    
    private void loadDirectories() throws Exception {
	BufferedReader in = new BufferedReader(new FileReader("directories"));
	try {
	    String line;
	    while ((line = in.readLine()) != null) {
		directories.put(line, new Directory(line));
	    }
	} finally {
	    in.close();
	}
    }
    
    private void loadAll() throws Exception {
	BufferedReader in = new BufferedReader(new FileReader("all"));
	try {
	    String line;
	    while ((line = in.readLine()) != null) {
		StringTokenizer st = new StringTokenizer(line, " ");
		String name = st.nextToken();
		Integer revision = new Integer(st.nextToken());
		Directory dir = (Directory) directories.get(name);

		if (dir != null) {
		    dir.revision = revision;
		    int index = name.lastIndexOf('/');
		    if(index != -1) {
			Directory parent = (Directory) directories.get(name.substring(0, index));
			parent.directories.add(dir);
		    }
		} else {
		    Directory parent = (Directory) directories.get(name.substring(0, name.lastIndexOf('/')));
		    parent.files.add(new File (name, revision));
		}
	    }
	} finally {
	    in.close();
	}
    }
    
    private void createIndices() throws Exception {
	for (Iterator i = directories.entrySet().iterator(); i.hasNext(); ) {
	    Directory dir = (Directory) ((Map.Entry) i.next()).getValue();

	    if (dir.revision == null) {
		continue;
	    }

	    int filenum = dir.files.size();
	    int dirnum = dir.directories.size();

	    boolean darkdir = false;
	    boolean darkfile = false;

	    String path;
	    if (dir.fullName.length() > 11) {
		path = dir.fullName.substring(11);
	    } else {
		path = "";
	    }

	    Expander.Expansion expansion;
	    
	    if (path.equals("")) {
		expansion = expander.new Expansion(new FileWriter("index.html"), "main");
	    } else {
		new java.io.File(path).mkdir();
		expansion = expander.new Expansion(new FileWriter(path + "/index.html"), "main");
	    }
	
	    {
		TreeMap args = new TreeMap();
		args.put("path", "/" + path);
		expansion.applyMacro("title", args);
	    }
	
	    if(path.equals("")) {
		TreeMap args = new TreeMap();
		expansion.applyMacro("nouplink", args);
	    } else {
		TreeMap args = new TreeMap();
		expansion.applyMacro("uplink", args);
	    }
	
	    for (Iterator j = dir.directories.iterator(); j.hasNext();) {
		Directory child = (Directory) j.next();
		
		TreeMap args = new TreeMap();
		args.put("name", child.shortName);
		args.put("link", child.shortName);
		args.put("version", child.revision.toString());
		
		ShortLog shortLog = (ShortLog) shortLogs.get(child.revision);
		args.put("date", shortLog.date);
		args.put("author", shortLog.author);
		args.put("log", shortLog.shortLog);
		args.put("loglink", dir.rootPath + "log" + shortLog.revision + ".txt");
		if (darkdir) {
		    expansion.applyMacro("darkdir", args);
		} else {
		    expansion.applyMacro("paledir", args);
		}
		darkdir = !darkdir;
	    }

	    for (Iterator j = dir.files.iterator(); j.hasNext();) {
		File child = (File) j.next();
		
		TreeMap args = new TreeMap();
		args.put("name", child.shortName);
		args.put("link", dir.rootPath + child.fullName);
		args.put("version", child.revision.toString());
		
		ShortLog shortLog = (ShortLog) shortLogs.get(child.revision);
		args.put("date", shortLog.date);
		args.put("author", shortLog.author);
		args.put("log", shortLog.shortLog);
		args.put("loglink", dir.rootPath + "log" + shortLog.revision + ".txt");
		if (darkdir) {
		    expansion.applyMacro("darkfile", args);
		} else {
		    expansion.applyMacro("palefile", args);
		}
		darkdir = !darkdir;
	    }

	    {
		TreeMap args = new TreeMap();
		args.put("path", "/" + path);
		args.put("dirnum", "" + dirnum);
		args.put("filenum", "" + filenum);
		expansion.applyMacro("body", args);
	    }
	    
	    expansion.done();
	}
    }

    private static class ShortLog {
	Integer revision;
	String author;
	String date;
	String shortLog;
	
	ShortLog(Integer revision, String author, String date, String shortLog) {
	    this.revision = revision;
	    this.author = author;
	    this.date = date;
	    this.shortLog = shortLog;
	}
    }

    private static class Directory implements Comparable {
	String fullName;
	String shortName;
	String rootPath = "";
	Integer revision;
	TreeSet directories = new TreeSet();
	TreeSet files = new TreeSet();
	
	Directory(String fullName) {
	    this.fullName = fullName;
	    int index = fullName.lastIndexOf('/');
	    if (index == -1) {
		this.shortName = "";
	    } else {
		this.shortName = fullName.substring(index + 1);
		int count = 0;
		int length = fullName.length();
		for (int i = 0; i < length; i++) {
		    if (fullName.charAt(i) == '/') {
			rootPath += "../";
		    }
		}
	    }
	}
	
	public int compareTo(Object o) {
	    Directory dir = (Directory) o;
	    return fullName.compareTo(dir.fullName);
	}
    }
    
    private static class File implements Comparable {
	String fullName;
	String shortName;
	Integer revision;
	
	File(String fullName, Integer revision) {
	    this.fullName = fullName;
	    this.revision = revision;
	    int index = fullName.lastIndexOf('/');
	    this.shortName = fullName.substring(index + 1);
	}
    
	public int compareTo(Object o) {
	    File file = (File) o;
	    return fullName.compareTo(file.fullName);
	}
    }
}
