package huffman;

import java.util.*;

/**
 * This class tests the existence of required methods for assignment 3, that is, it
 * checks whether the methods have the correct names and input types. This does not
 * check the method has the correct behavoir, or whether it even properly executes
 * - it just checks the existence and correct naming of methods. It also does not
 * check whether methods are labelled correctly as private or public, you should make
 * sure of that yourself.
 * 
 * You have to compile this inside the huffman package, and run this class. Missing
 * methods or wrong types will be reported as missing methods. Correct output will
 * look like this:

class huffman.CharCode: found constructor with arguments [char].
class huffman.CharCode: found method getChar.
class huffman.CharCode: found method setFrequency.
class huffman.CharCode: found method getFrequency.
class huffman.CharCode: found method setCodeWord.
class huffman.CharCode: found method toString.
class huffman.CharCode: found method getCharAsString.
class huffman.HuffmanNode: found constructor with arguments [class huffman.CharCode].
class huffman.HuffmanNode: found constructor with arguments [class huffman.HuffmanNode, class huffman.HuffmanNode].
class huffman.HuffmanNode: found method getLeft.
class huffman.HuffmanNode: found method getRight.
class huffman.HuffmanNode: found method getFrequency.
class huffman.HuffmanNode: found method isLeaf.
class huffman.HuffmanNode: found method getCharCode.
class huffman.HuffmanNode: found method compareTo.
class huffman.HuffmanTree: found field charCode.
class huffman.HuffmanTree: found field root.
class huffman.HuffmanTree: found method fillInFrequencies.
class huffman.HuffmanTree: found method buildHuffmanTree.
class huffman.HuffmanTree: found method fillInCodeWords.
class huffman.HuffmanTree: found constructor with arguments [class java.lang.String].
class huffman.HuffmanTree: found method printFrequencies.
class huffman.HuffmanTree: found method printTree.
class huffman.HuffmanTree: found method printTable.
class huffman.HuffmanTree: found method encodeChar.
class huffman.HuffmanTree: found method encodeString.
class huffman.HuffmanTree: found method decodeChar.
class huffman.HuffmanTree: found method decodeString.
class huffman.HuffmanTree: found method getNumChars.
class huffman.HuffmanTree: found method getNumChars.
class huffman.HuffmanTree: found method getCompressedDataSize.
class huffman.HuffmanTree: found method getMinCodeWordLength.
class huffman.HuffmanTree: found method getMaxCodeWordLength.
class huffman.HuffmanTree: found method toBitSequence.
class huffman.HuffmanTree: found constructor with arguments [class huffman.BitSequence].
class huffman.HuffmanTree: found method getCompressedHeaderSize.
 */
public class TestSignatures {

    /**
     * @param args
     */
    public static void main(String[] args) throws NoSuchMethodException {

        //*** Test CharCode *************************************************************
        findConstructor(CharCode.class,char.class);
        findMethod(CharCode.class,char.class, "getChar");
        findMethod(CharCode.class,void.class, "setFrequency", int.class);
        findMethod(CharCode.class,int.class, "getFrequency");
        findMethod(CharCode.class,void.class, "setCodeWord", BitSequence.class);
        findMethod(CharCode.class,String.class, "toString");
        findMethod(CharCode.class,String.class, "getCharAsString");
        
        
        //*** Test HuffmanNode **********************************************************
        findConstructor(HuffmanNode.class,CharCode.class);
        findConstructor(HuffmanNode.class,HuffmanNode.class,HuffmanNode.class);
        findMethod(HuffmanNode.class,HuffmanNode.class, "getLeft");
        findMethod(HuffmanNode.class,HuffmanNode.class, "getRight");
        findMethod(HuffmanNode.class,int.class, "getFrequency");
        findMethod(HuffmanNode.class,boolean.class, "isLeaf");
        findMethod(HuffmanNode.class,CharCode.class, "getCharCode");
        findMethod(HuffmanNode.class,int.class, "compareTo", HuffmanNode.class);

        
        //*** Test HuffmanTree **********************************************************
        findField(HuffmanTree.class,"charCode",CharCode[].class);
        findField(HuffmanTree.class,"root",HuffmanNode.class);
        findMethod(HuffmanTree.class,void.class,"fillInFrequencies",String.class);
        findMethod(HuffmanTree.class,void.class,"buildHuffmanTree");
        findMethod(HuffmanTree.class,void.class,"fillInCodeWords",BitSequence.class,HuffmanNode.class);
        findConstructor(HuffmanTree.class,String.class);
        findMethod(HuffmanTree.class,void.class,"printFrequencies");
        findMethod(HuffmanTree.class,void.class,"printTree");
        findMethod(HuffmanTree.class,void.class,"printTable");
        findMethod(HuffmanTree.class,BitSequence.class,"encodeChar",char.class);
        findMethod(HuffmanTree.class,BitSequence.class,"encodeString",String.class);
        findMethod(HuffmanTree.class,char.class,"decodeChar",BitSequence.class);
        findMethod(HuffmanTree.class,String.class,"decodeString",BitSequence.class,int.class);
        findMethod(HuffmanTree.class,int.class,"getNumChars");
        findMethod(HuffmanTree.class,int.class,"getNumChars");
        findMethod(HuffmanTree.class,int.class,"getCompressedDataSize");
        findMethod(HuffmanTree.class,int.class,"getMinCodeWordLength");
        findMethod(HuffmanTree.class,int.class,"getMaxCodeWordLength");
        findMethod(HuffmanTree.class,BitSequence.class,"toBitSequence");
        findConstructor(HuffmanTree.class,BitSequence.class);
        findMethod(HuffmanTree.class,int.class,"getCompressedHeaderSize");
    }
    
    
    
    /**
     * checks whether a method with the given name exists in the given class, with the
     * given argument and return types.
     * If the method is not found, an error message is printed.
     * If the method is found, a message is printed as well
     */
    public static void findMethod(Class<?> aClass,Class<?> returnType,String name,Class<?>... argTypes){
        try {
            if (aClass.getDeclaredMethod(name, argTypes).getReturnType().isInstance(returnType)) 
                throw new NoSuchMethodException(); //throw no such method if the return type doesn't match
            System.out.println(aClass+": found method "+name+".");
        } catch (NoSuchMethodException e){
            System.err.println("error: "+aClass+": method "+name+" with argument types "+Arrays.asList(argTypes)
                    +" and return type ["+returnType+"] not found.");
        }
    }
    
    
    /**
     * checks whether a constructor with the given name exists in the given class, with the
     * given argument and return types.
     * If the constructor is not found, an error message is printed.
     * If the constructor is found, a message is printed as well
     */
    public static void findConstructor(Class<?> aClass,Class<?>... argTypes){
        try {
            aClass.getDeclaredConstructor(argTypes);
            System.out.println(aClass+": found constructor with arguments "+Arrays.asList(argTypes)+".");
        } catch (NoSuchMethodException e){
            System.err.println("error: "+aClass+": constructor with argument types "+Arrays.asList(argTypes)
                    +" not found");
        }
    }

    
    /**
     * checks whether a field with the given name exists in the given class, with the
     * given argument and return types.
     * If the field is not found, an error message is printed.
     * If the field is found, a message is printed as well
     */
    public static void findField(Class<?> aClass,String name,Class<?> type){
        try {
            if (aClass.getDeclaredField(name).getType().isInstance(type))
                throw new NoSuchFieldException(); //throw no such field if the return type doesn't match
            System.out.println(aClass+": found field "+name+".");
        } catch (NoSuchFieldException e){
            System.err.println("error: "+aClass+": field "+name+" with type "+type+" not found.");
        }
    }
    
}


