import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import org.roller.presentation.pagecache.rollercache.LRUCacheHandler;

/**
 * RFC 3229 "feed" instance manipulation - difference computation
 */
public class FeedDiff {

    /**
     * Return the current string with the entries which are also present
     * in the original removed.
     */
    public static String diff(String original, String current, String element) {

        // entry delimiters
        String open  = "<"  + element + ">";
        String close = "</" + element + ">";

        // parse the original feed into entries, adding each to the HashSet
        HashSet entries = new HashSet();
        int cursor = original.length();
        while (cursor > 0) {

            int right = original.lastIndexOf(close, cursor);
            if (right == -1) break;

            int left = original.lastIndexOf(open, right);
            if (left == -1) break;

            right += close.length();
            cursor = left - 1;

            entries.add(original.substring(left, right));
        }

        // parse the current feed into entries, removing any which are
        // present in the HashSet 
        StringBuffer result = new StringBuffer(current);
        cursor = current.length();
        while (cursor > 0) {

            int right = current.lastIndexOf(close, cursor);
            if (right == -1) break;

            int left = current.lastIndexOf(open, right);
            if (left == -1) break;

            right += close.length();
            cursor = left - 1;

            // if this entry is in the original HashSet, remove it from the result
            if (entries.contains(current.substring(left, right))) {

                // also remove any preceeding whitespace
                while (cursor>=0 && Character.isWhitespace(current.charAt(cursor))) {
                    cursor--;
                }

                // remove the entry from the result
                result.delete(cursor, right-1);
            }
        }

        // return result
        return new String(result);
    }

    /**
     * Compute a hash for the specified content
     */
    public static String hash(String content) {
        try{

            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(content.getBytes());
            return LRUCacheHandler.toBase64(md.digest()).replace('/', '_');

        } catch (java.security.NoSuchAlgorithmException e) {
            // should never happen
            return null;
        }
    }


    /**
     * Parse If-None-Match headers
     */
    public static Set parse(String header) {
       HashSet result = new HashSet();

       StringTokenizer st = new StringTokenizer(header, ",");
       while(st.hasMoreTokens()){
           String tag = (String)st.nextToken().trim();
           if (tag.startsWith("W/")) tag=tag.substring(2);
           if (tag.startsWith("\"") && tag.endsWith("\"")) {
               tag=tag.substring(1,tag.length()-1);
           }
           result.add(tag);
       }

       return result;
    }

    /**
     * Main program, useful for testing diff and hash functions
     */
    public static void main(String[] args) throws Exception {
        if (args.length != 3) {
            System.err.println("Usage: java FeedDiff original current element");
            System.exit(8);
        }

        // read original into a string
        File file = new File(args[0]);
        byte[] bytes = new byte[(int)file.length()];
        (new FileInputStream(file)).read(bytes, 0, bytes.length);
        String original = new String(bytes);

        // read current into a string
        file = new File(args[1]);
        bytes = new byte[(int)file.length()];
        (new FileInputStream(file)).read(bytes, 0, bytes.length);
        String current = new String(bytes);

        // print diff
        System.out.println("ETag: " + hash(current));
        System.out.println();
        System.out.println(diff(original, current, args[2]));
    }

}

