import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;

class Lister
{

  public Lister(String[] constructors, String[] methods, String[] fields) {

    listClasses(constructors, methods, fields);
  }

  /**
   * center the frame on screen.
   */
  public static void centerScreen(JFrame frame) {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height)
    {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width)
    {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
  }


	/** List all classes in a new Frame
	 * @param constructors The array containing all available constructors.
	 * @param methods      The array containing all available methods.
	 * @param fields       The array containing all available fields.
	 * @return 0.
	 */
	public static int listClasses(String[] constructors, String[] methods, String[] fields) {

    // ImageIcon icon = new ImageIcon(System.getProperty("user.dir") + System.getProperty("file.separator") + "cube.gif");

		JTabbedPane tp = new JTabbedPane();

		// Now add the different tabs:
		tp.addTab("Constructors", null, makeTablePanel(createConstructors(constructors)), "Available Constructors");
		tp.setSelectedIndex(0);
		tp.addTab("Methods", null, makeTablePanel(createMethods(methods)), "Available methods");
		tp.addTab("Fields", null, makeTablePanel(createFields(fields)), "Available variables");
		tp.addTab("About", null, createAbout(), "Contribution");

		// Now create a frame and put the JTabbedPane into it:
		final JFrame frame = new JFrame("Class Lister");
		frame.addWindowListener(new WindowAdapter() {
			 public void windowClosing(WindowEvent e) {
				// DO UNDER NO CIRCUMSTANCE USE System.exit(0) !!!
				// It shuts down the JVM !!!!
				// System.exit(0);
					frame.setVisible(false);
					frame.dispose();
					// Do a manuel garbage collect
					System.gc();
				}
		 });
		frame.getContentPane().add(tp, BorderLayout.CENTER);
		frame.setSize(640, 400);
		centerScreen(frame);
		frame.setVisible(true);
		frame.toFront();

		return(0);
	}

  /**
   * @param table The table that is to be equipped with a ScrollPane.
   * @return a JScrollPane (implicitely casted to Component)
   */
  protected static Component makeTablePanel(JTable table) {

    TableColumn column = null;
    for (int i = 0; i < table.getColumnCount(); i++) {
      column = table.getColumnModel().getColumn(i);
      column.sizeWidthToFit();
    }

    //TableSorter sorter = new TableSorter(table);
    //JTable sTable = new JTable(sorter);
    //sorter.addMouseListenerToHeaderInTable(sTable);
    JScrollPane scrollPane = new JScrollPane(table);
    return scrollPane;
  }

  /**
   * return the access specifier
   */
  private static String getAccessSpecifier(String input) {
   String toSearch;
   if (input.indexOf("(") > -1) {
     toSearch = input.substring(0, input.indexOf("("));
   } else {
     toSearch = input;
   }
   if (toSearch.indexOf("public") > -1) return "public";
   if (toSearch.indexOf("protected") > -1) return "protected";
   if (toSearch.indexOf("private") > -1) return "private";
   return "";
  }

  /**
   * return the qualifier
   */
  private static String getQualifier(String input) {
   String toSearch = input.substring(0, input.indexOf("("));
   if (toSearch.indexOf("synchronized") > -1) return "synchronized";
   return "";
  }

  /**
   * return the access
   */
  private static String getAccess(String input) {
   String toSearch;
   if (input.indexOf("(") > -1) {
     toSearch = input.substring(0, input.indexOf("("));
   } else {
     toSearch = input;
   }
   if (toSearch.indexOf("static") > -1) return "static";
   if (toSearch.indexOf("abstract") > -1) return "abstract";
   return "";
  }

  /**
   * return the existence of native
   */
  private static String getNative(String input) {
   String toSearch = input.substring(0, input.indexOf("("));
   if (toSearch.indexOf("native") > -1) return "native";
   return "";
  }

  /**
   * return the existence of final
   */
  private static String getFinal(String input) {
   String toSearch = input.substring(0, input.indexOf("("));
   if (toSearch.indexOf("final") > -1) return "final";
   return "";
  }

  /**
   * return the return type
   */
  private static String getReturnType(String input) {
    //boolean _debug =true;

   int where = input.indexOf("(");
   String subStr;
   String retType;

   if (where > -1) {
     subStr = input.substring(0, where);
   } else {
     subStr = input;
   }

   if (subStr.length() > 0) {
     String[] toSearch = subStr.split(" ", 10); // just bigger than the maximum.
     retType = toSearch[toSearch.length-2];
   }
   else
     retType = "";

   if (_debug) System.out.println("getReturnType : " + retType);
   return retType;
  }


  /**
   * return the Classname of the method
   */
  private static String getMethodClass(String input) {
   //boolean _debug =true;
   int where = input.indexOf("(");
   String subStr = input.substring(0, where);
   if (_debug) System.out.println("getMethodClass : " + subStr);
   String[] toSearch = subStr.split(" ", 10); // just bigger than the maximum.
   String retType = toSearch[toSearch.length-1];

   if (retType.lastIndexOf(".") > -1) {
     retType = retType.substring(0,retType.lastIndexOf("."));
   }
   if (_debug) System.out.println("getMethodClass : " + retType);
   return retType;
  }

  /**
   * return the Methodname of the method
   */
  private static String getMethodName(String input) {
   //boolean _debug =true;

   int where = input.indexOf("(");
   String subStr;
   if (where > -1) {
     subStr = input.substring(0, where);
   } else {
     subStr = input;
   }

   String[] toSearch = subStr.split(" ", 10); // just bigger than the maximum.
   String retType = toSearch[toSearch.length-1];

   retType = retType.substring(retType.lastIndexOf(".")+1);

   if (_debug) System.out.println("getMethodName : " + retType);
   return retType;
  }

  /**
   * return the Methodname of the method
   */
  private static String getArguments(String input) {
   //boolean _debug =true;
   String retType = input.substring(input.indexOf("(")+1,input.indexOf(")"));

   if (_debug) System.out.println(retType);
   return retType;
  }

  /**
   * return the throws of the method
   */
  private static String getThrows(String input) {
   //boolean _debug =true;
   String retType = input.substring(input.indexOf(")")+1);
   if (retType.indexOf("throws") > -1) {
     retType = retType.substring(retType.indexOf("throws")+7);
   } else
    retType = "";
   if (_debug) System.out.println(retType);
   return retType;
  }


	/** creates a JTable according to the input
	 * @param columnNames The descriptions of the rows
	 * @param rows The content of the rows
	 * @param toDo If 0, create a table according to the method(s).<br/>
     *             If 1, create a table according to the constructor(s).<br/>
     *             If 2, create a table according to the field(s).<br/>
	 * @return a complete table
	 */
	static JTable createTable(String[] columnNames, String[] rows, int toDo) {
    Object[][] data;
    String row[];
    //boolean _debug = true;

    if (_debug) System.out.println("createTable : Start =================");

    if (toDo == 0) {
      // Create data fields for the contents:
      data = new Object[rows.length][10];

      for (int i = 0; i < rows.length; i++) {
        if (_debug) System.out.println("createTable : Method : " + rows[i]);
        String[] newRow = {"","","","","","","","","",""};
        newRow[0] = getAccessSpecifier(rows[i]);
        newRow[1] = getAccess(rows[i]);
        newRow[2] = getReturnType(rows[i]);
        newRow[3] = getMethodClass(rows[i]);
        newRow[4] = getMethodName(rows[i]);
        newRow[5] = getArguments(rows[i]);
        newRow[6] = getThrows(rows[i]);
        newRow[7] = getQualifier(rows[i]);
        newRow[8] = getFinal(rows[i]);
        newRow[9] = getNative(rows[i]);

        data[i] = newRow;
      }

    } else if (toDo == 1) {

      // Create data fields for the contents:
      data = new Object[rows.length][3];

      for (int i = 0; i < rows.length; i++) {
        String[] newRow = {"", "", ""};
        newRow[0] = getAccessSpecifier(rows[i]);
        newRow[1] = getMethodName(rows[i]);
        newRow[2] = getArguments(rows[i]);
        data[i] = newRow;
      }
    } else {
      // Create data fields for the contents:
      data = new Object[rows.length][3];

      for (int i = 0; i < rows.length; i++) {
        String[] newRow = {"", "", ""};
        newRow[0] = getAccessSpecifier(rows[i]);
        newRow[1] = getReturnType(rows[i]);
        newRow[2] = getMethodName(rows[i]);
        data[i] = newRow;
      }
    }

    if (_debug) System.out.println("createTable : End   =================");

    return new JTable(data, columnNames);
  }

  /** Show all available methods in a list.
   * @param constructors The array containing all available methods.
   * @return a JTable containing the methods.
   */
  static JTable createMethods(String[] methods) {
    String[] columnNamesM = {"Access specifier", "Access", "Return Type",
                             "Class","Name", "Arguments", "Throws", "Qualifier", "final", "native" };


    return createTable(columnNamesM, methods, 0);
  }

  /** Show all available constructors in a list.
   * @param constructors The array containing all available constructors.
   * @return a JTable containing the constructors.
   */
  static JTable createConstructors(String[] constructors) {
    String[] columnNamesC = {"Access specifier", "Name", "Arguments"};

    return createTable(columnNamesC, constructors, 1);
  }

  /** Show all available fields in a list.
   * @param constructors The array containing all available fields.
   * @return a Component containing the fields.
   */
  static JTable createFields(String[] fields) {
    String[] columnNamesF = {"Access specifier", "Access", "Name"};
    return createTable(columnNamesF, fields, 2);
  }

  /** Show some information about the Creator of the class.
   * @return a Component containing the fields.
   */
  static JPanel createAbout() {
    ImageIcon icon1 = new ImageIcon(System.getProperty("user.dir") + System.getProperty("file.separator") + "SciFace.gif");
    ImageIcon icon2 = new ImageIcon(System.getProperty("user.dir") + System.getProperty("file.separator") + "MuPAD.gif");
    JPanel panel = new JPanel(false);

    JLabel filler1 = new JLabel("Created by Jörn Maas", icon1, JLabel.CENTER);
    //filler1.setHorizontalAlignment(JLabel.CENTER);
    JLabel filler2 = new JLabel("(c) 2003 by MuPAD", icon2, JLabel.CENTER);
    //filler2.setHorizontalAlignment(JLabel.CENTER);
    //JLabel filler3 = new JLabel();

    panel.setLayout(new GridLayout(3, 1));
    panel.add(filler1);
    panel.add(filler2);
    //panel.add(filler3);

    return panel;
  }

  public static void main(String[] args) {
/*
    String constructors[] = { "public Prog()", "Prog(int)" };
    String methods[] = {"public javax.swing.JFrame Prog.returnOnlyJFrame()",
   "public static int[][] Prog.returnDoubleArrayInteger()",
   "public char[] Prog.returnSingleArrayChar()",
   "public short[] Prog.returnSingleArrayShort(short[])",
   "public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException",
   "public boolean Prog.returnBoolean(boolean)",
   "public static java.math.BigDecimal Prog.returnBigDecimalFromDoubleArrayBigDecimal(java.math.BigDecimal[][])",
   "public boolean java.lang.Object.equals(java.lang.Object)",
   "public double[] Prog.returnSingleArrayDouble(double[])",
   "public static int Prog.numberIntTest(byte,boolean)",
   "public static long Prog.numberTest(short,boolean)",
   "public static char Prog.returnCharFromTripleArrayChar(char[][][])",
   "public java.math.BigInteger Prog.returnBigInteger()",
   "public boolean Prog.returnBoolean()",
   "public static java.lang.String Prog.returnStringFromSingleArrayString(java.lang.String[])",
   "public char[] Prog.returnSingleArrayChar(char[])",
   "public static byte Prog.returnByteFromSingleArrayByte(byte[])",
   "public byte[] Prog.returnSingleArrayByte()",
   "public int Prog.returnInt(int)",
   "public native int java.lang.Object.hashCode()",
   "public final void java.lang.Object.wait() throws java.lang.InterruptedException",
   "public static int[] Prog.returnSingleArrayInteger()",
   "public float Prog.returnFloat()",
   "public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException",
   "public java.math.BigInteger Prog.returnBigInteger(java.math.BigInteger)",
   "public int Prog.returnInt()",
   "public static int Prog.key()",
   "public static java.math.BigDecimal Prog.returnBigDecimalFromSingleArrayBigDecimal(java.math.BigDecimal[])",
   "public boolean[] Prog.returnSingleArrayBoolean(boolean[])",
   "public static int Prog.numberIntTest(int,boolean)",
   "public static int[][][][] Prog.returnQuadArrayInteger()",
   "public final native void java.lang.Object.notify()",
   "public static short Prog.returnShortFromDoubleArrayShort(short[][])",
   "public long Prog.returnLong(long)",
   "public static boolean Prog.returnBooleanFromDoubleArrayBoolean(boolean[][])",
   "public static java.math.BigInteger Prog.returnBigIntegerFromDoubleArrayBigInteger(java.math.BigInteger[][])",
   "public java.math.BigInteger[] Prog.returnSingleArrayBigInteger()",
   "public boolean[] Prog.returnSingleArrayBoolean()",
   "public java.lang.String Prog.returnString()",
   "public int[] Prog.returnSingleArrayInt(int[])",
   "public static int Prog.numberIntTest(short,boolean)",
   "public java.math.BigDecimal Prog.returnBigDecimal()",
   "public java.lang.String Prog.getObjecttoString(java.lang.Object)",
   "public static double Prog.returnDoubleFromDoubleArrayDouble(double[][])",
   "public java.math.BigInteger[] Prog.returnSingleArrayBigInteger(java.math.BigInteger[])",
   "public float[] Prog.returnSingleArrayFloat()",
   "public final native java.lang.Class java.lang.Object.getClass()",
   "public int[] Prog.returnSingleArrayInt()",
   "public static java.math.BigInteger Prog.numberTest(java.math.BigInteger,boolean)",
   "public java.lang.String Prog.getFrameName(java.awt.Frame)",
   "public static void Prog.systemExit()",
   "public static int[][][] Prog.returnTripleArrayInteger()",
   "public static long Prog.returnLongFromDoubleArrayLong(long[][])",
   "public java.lang.String Prog.returnString(java.lang.String)",
   "public static int Prog.allEntries()",
   "public static float Prog.returnFloatFromDoubleArrayFloat(float[][])",
   "public static int Prog.callBack(java.lang.String[])",
   "public static short Prog.returnShortFromSingleArrayShort(short[])",
   "public static char Prog.returnCharFromDoubleArrayChar(char[][])",
   "public static java.math.BigInteger Prog.returnBigIntegerFromSingleArrayBigInteger(java.math.BigInteger[])",
   "public static int Prog.returnIntFromDoubleArrayInt(int[][])",
   "public long[] Prog.returnSingleArrayLong(long[])",
   "public static double Prog.numberTest(double,boolean)",
   "public short Prog.returnShort()",
   "public java.lang.String java.lang.Object.toString()",
   "public static void Prog.main(java.lang.String[])",
   "public static long Prog.numberTest(long,boolean)",
   "public float Prog.returnFloat(float)",
   "public java.lang.String Prog.getAppletName(java.applet.Applet)",
   "public java.lang.String[] Prog.returnSingleArrayString()",
   "public double Prog.returnDouble()",
   "private void Prog.testSpecifier3()",
   "public java.lang.String Prog.getObjectName(java.lang.Object)",
   "public static boolean Prog.returnBooleanFromSingleArrayBoolean(boolean[], boolean)",
   "public static double Prog.returnDoubleFromSingleArrayDouble(double[])",
   "public byte Prog.returnByte(byte)",
   "public long Prog.returnLong()",
   "public java.math.BigDecimal[] Prog.returnSingleArrayBigDecimal()",
   "public java.math.BigDecimal Prog.returnBigDecimal(java.math.BigDecimal)",
   "public char Prog.returnChar()",
   "public static long Prog.returnLongFromSingleArrayLong(long[])",
   "public static long Prog.numberTest(byte,boolean)",
   "public short Prog.returnShort(short)",
   "public java.lang.String Prog.getNull(java.applet.Applet)",
   "public static java.lang.String Prog.callbackTest()",
   "public static float Prog.returnFloatFromSingleArrayFloat(float[])",
   "public java.lang.String[] Prog.returnSingleArrayString(java.lang.String[])",
   "public java.awt.Frame Prog.returnOnlyFrame()",
   "public static char Prog.returnCharFromSingleArrayChar(char[])",
   "public static int Prog.returnIntFromSingleArrayInt(int[])",
   "public static java.math.BigDecimal Prog.numberTest(java.math.BigDecimal,boolean)",
   "public double Prog.returnDouble(double)",
   "protected void Prog.testSpecifier2()",
   "public short[] Prog.returnSingleArrayShort()",
   "public float[] Prog.returnSingleArrayFloat(float[])",
   "public static double Prog.numberTest(float,boolean)",
   "public static int[][][][][] Prog.returnQuintArrayInteger()",
   "public static long Prog.numberTest(int,boolean)",
   "public byte Prog.returnByte()",
   "public char Prog.returnChar(char)",
   "public final native void java.lang.Object.notifyAll()",
   "public synchronized final native static String calcMuPAD(String query)",
   "public java.applet.Applet Prog.returnOnlyApplet()",
   "public static java.lang.String Prog.returnStringFromDoubleArrayString(java.lang.String[][])",
   "public static boolean Prog.returnBooleanFromTripleArrayBoolean(boolean[][][])",
   "public byte[] Prog.returnSingleArrayByte(byte[])",
   "public double[] Prog.returnSingleArrayDouble()",
   "public static byte Prog.returnByteFromDoubleArrayByte(byte[][])",
   "public java.math.BigDecimal[] Prog.returnSingleArrayBigDecimal(java.math.BigDecimal[])",
   "public long[] Prog.returnSingleArrayLong()",
   "void Prog.testSpecifier1()"
};
    String fields[] = {"protected java.lang.String Prog.po_stringVariable",
   "private short Prog.pr_shortVariable",
   "public static char Prog.pu_satic_charVariable",
   "private double Prog.pr_doubleVariable",
   "private long Prog.pr_longVariable",
   "byte Prog.pa_byteVariable",
   "private char Prog.pr_charVariable",
   "protected short Prog.po_shortVariable",
   "protected double Prog.po_doubleVariable",
   "float Prog.pa_floatVariable",
   "public float Prog.pu_floatVariable",
   "protected long Prog.po_longVariable",
   "public int Prog.pu_intVariable",
   "protected char Prog.po_charVariable",
   "private byte Prog.pr_byteVariable",
   "int Prog.pa_intVariable",
   "double Prog.pa_doubleVariable",
   "public java.lang.String Prog.pu_stringVariable",
   "protected static java.lang.String Prog.po_static_stringVariable",
   "protected byte Prog.po_byteVariable",
   "java.lang.String Prog.pa_stringVariable",
   "long Prog.pa_longVariable",
   "char Prog.pa_charVariable",
   "private static double Prog.pr_static_doubleVariable",
   "boolean Prog._debug",
   "private float Prog.pr_floatVariable",
   "public short Prog.pu_shortVariable",
   "private int Prog.pr_intVariable",
   "public double Prog.pu_doubleVariable",
   "java.awt.Frame Prog.hallo",
   "short Prog.pa_shortVariable",
   "public long Prog.pu_longVariable",
   "public char Prog.pu_charVariable",
   "protected float Prog.po_floatVariable",
   "protected int Prog.po_intVariable",
   "private java.lang.String Prog.pr_stringVariable",
   "public byte Prog.pu_byteVariable"
};
    listClasses(constructors, methods, fields);
*/
  }

	static boolean _debug = false;

}
