/* Begin ReWriter.java file */
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.util.Comparator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

/* This class "rewrites" itself when its rewriteSelf() method is called; it randomly changes its name, its 
 * method names, its attribute names, and its comments */
public class ReWriter {

    /* This attribute stores the symbols used in java operators / programs; these must be separated from methods
     * and attributes for the renaming to take place; fortunately, java ignores whitespace so even as strange as
     * method . runit ( abc ) may look, it is perfectly legal */
    String ops = ".[]()+-!*;,/%<>=&^|~?:";
    // note that backslash (\) and quotes (',") are omitted

    /* This attribute stores a StringCompare comparator */
    StringCompare sc = new StringCompare();

    /* This attribute stores the original names of the methods and fields being mapped */
    String originals[] = null;

    /* This attribute stores the new names of the methods and fields being mapped */
    String nameMaps[] = null;

    /* The main method */
    public static void main(String[] args) {
        ReWriter rw = new ReWriter();
        rw.rewriteSelf();
    }

    /* This method returns a replacement for the input String guaranteed to be unique among all inputs; in reality, 
     * a much more complex random mapping would be used */
    public String nameMap(String iName) {
        if (iName.compareTo("main") != 0) {
            return iName + "_xxx";
        } else {
            return "main";
        }
    } // mapName ()

    /* This method surrounds operators with white space for the rewriter */
    String spaceOutOperators(String st) {
        int j = 0;
        for (int i = 0; i < st.length(); i++) {
            if (ops.indexOf(st.charAt(i)) >= 0) {
                j = i + 1;
                while ((j < st.length()) && (ops.indexOf(st.charAt(j)) >= 0)) {
                    j++;
                }
                st = st.substring(0, i) + " " + st.substring(i, j) + " " + st.substring(j);
                i = j;
            }
        }
        return st;
    } // spaceOutOperators ( String )

    /* This method rewrites the given class */
    public void rewrite(Class c) {
        try {
            // get the method and field references
            Method[] m = c.getDeclaredMethods();
            Field[] f = c.getDeclaredFields();
            // create a map of the class, method, and field names
            int nummaps = m.length + f.length + 1;
            originals = new String[nummaps];
            nameMaps = new String[nummaps];
            // store the class name and map name
            originals[0] = c.getName();
            // store the method names
            for (int i = 0; i < m.length; i++) {
                originals[1 + i] = m[i].getName();
            }
            // store the field names
            for (int i = 0; i < f.length; i++) {
                originals[1 + m.length + i] = f[i].getName();
            }
            // sort the array
            Arrays.sort(originals, sc);
            // map the names
            for (int i = 0; i < nummaps; i++) {
                nameMaps[i] = nameMap(originals[i]);
            }
            // Load the input file
            String cName = c.getName() + ".java";
            BufferedReader br = new BufferedReader(new FileReader(cName));
            ArrayList al = new ArrayList();
            int loc = 0;
            al.add(0, " ");
            while (al.get((al.size() - 1)) != null) {
                al.add(br.readLine());
            }
            br.close();
            al.trimToSize();
            //tokenize it; search for class, method , & field names; replace with nameMaps; output
            String oName = nameMaps[Arrays.binarySearch(originals, c.getName(), sc)] + ".java";
            PrintWriter pw = new PrintWriter(new FileOutputStream(oName), true);
            StringTokenizer st = null;
            String tken = null;
            int pos = -1;
            String tmp = null;
            ops.trim();
            for (int i = 1; i < al.size(); i++) {
                if (al.get(i) != null) {
                    tmp = (String)(al.get(i));
                    tmp = spaceOutOperators(tmp);
                    st = new StringTokenizer(tmp);
                    while (st.hasMoreTokens()) {
                        tken = st.nextToken();
                        pos = Arrays.binarySearch(originals, tken, se);
                        if (pos >= 0) {
                            pw.print(nameMaps[pos] + " ");
                        } else {
                            pw.print(tken + " ");
                        }
                    } // whilte more tokens on line
                    pw.println();
                } // if there is a line to process
            } // while more lines in file
            pw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    } // rewrite (Class)

    /* This method rewrites this class  */
    public void rewriteSelf() {
        rewrite(this.getClass());
    } // rewriteSelf()
} // Rewriter

class StringCompare implements Comparator {
    public int compare(Object s1, Object s2) {
        return ((String)(s1)).compareTo(((String)(s2)));
    }

} //StringCompare

/* End ReWriter.java file */