package org.incava.doctorj;

import java.util.Iterator;
import java.util.List;
import org.incava.analysis.Report;
import org.incava.java.*;
import org.incava.log.Log;


/**
 * Analyzes Javadoc and code for methods.
 */
public class MethodDocAnalyzer extends FunctionDocAnalyzer
{
    public final static String MSG_RETURN_WITHOUT_DESCRIPTION = "@return without description.";

    public final static String MSG_RETURN_FOR_VOID_METHOD = "@return for method returning void";

    public final static String MSG_RETURN_TYPE_USED = "@return refers to method return type";
    
    private ASTMethodDeclaration method;
    
    public MethodDocAnalyzer(Report r, ASTMethodDeclaration method)
    {
        super(r, method);
        this.method = method;
    }

    public String getItemType() 
    {
        return "method";
    }

    protected void checkJavadoc(JavadocNode javadoc)
    {
        Log.log("javadoc: " + javadoc);

        super.checkJavadoc(javadoc);

        if (javadoc != null) {
            JavadocTaggedNode[] taggedComments = javadoc.getTaggedComments();
            for (int ti = 0; ti < taggedComments.length; ++ti) {
                JavadocTag tag = taggedComments[ti].getTag();
                Log.log("checking tag: " + tag);
                if (tag.text.equals(JavadocTags.RETURN)) {
                    ASTResultType resType = (ASTResultType)method.jjtGetChild(0);
                    Log.log("result type: " + resType);
                    Token resTkn = resType.getFirstToken();
                    Log.log("resTkn: " + resTkn.kind);
                    
                    if (resTkn.kind == Java14ParserConstants.VOID) {
                        addViolation(MSG_RETURN_FOR_VOID_METHOD, tag.start, tag.end);
                    }
                    else {
                        JavadocElement tgt = taggedComments[ti].getTarget();
                        if (tgt == null) {
                            if (isCheckable(method, CHKLVL_TAG_CONTENT)) {
                                addViolation(MSG_RETURN_WITHOUT_DESCRIPTION, tag.start, tag.end);
                            }
                        }
                        else {
                            String text = tgt.text;
                            Log.log("text: '" + text + "'");
                            if (text.equals(resTkn.image)) {
                                addViolation(MSG_RETURN_TYPE_USED, tgt.start, tgt.end);
                            }
                        }
                    }
                }
            }
        }        
    }

    /**
     * Returns the parameter list for the method.
     */
    protected ASTFormalParameters getParameterList()
    {
        ASTMethodDeclarator md = (ASTMethodDeclarator)method.jjtGetChild(1);
        return (ASTFormalParameters)md.jjtGetChild(0);
    }

    /**
     * Returns the valid tags, as strings, for methods.
     */
    protected List getValidTags()
    {
        return JavadocTags.getValidMethodTags();
    }

    /**
     * Adds a violation for a method, with the violation pointing to the method
     * name.
     */
    protected void addUndocumentedViolation(String desc)
    {
        // first item (token) in method declarator

        SimpleNode declaration = (SimpleNode)method.jjtGetChild(1);
        Token name = (Token)declaration.getChildren().get(0);
        Log.log("name: " + name);
        addViolation(desc, name);
    }

}
