/**
 * Copyright (c) Summa-tech.com
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * FilterGettersAndSetters.java
 * 
 * Takes as piped input the output from the JavaNCSS command below, and filters out all getters and
 * setters in order to more accurately calculate the average code complexity of a given system.
 * Without filtering getters and setters, the code complexity could look artificially low,
 * especially for a system with a large domain model or a great number of DTOs. In these cases, the
 * code complexity numbers would be less meaningingful, and comparing to other systems would be
 * apples to oranges.
 * 
 * CMD> javancss -function -recursive 
 * 
 * After filtering out the getters and setters, it re-calculates the average CCN, average Javadoc,
 * and max CCN.
 * 
 * @author Benjamin Northrop, Summa 2009
 */
public class FilterGettersAndSetters {

    /** Regular expression patterns for getter and setter methods. */
    private final static Pattern getter = Pattern.compile("\\Aget[a-zA-z,\\d]*");
    private final static Pattern setter = Pattern.compile("\\Aset[a-zA-z,\\d]");

    /**
     * Main method, taking piped input the output from the JavaNCSS command.
     */
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        String line = null;
        int totalCcn = 0;
        int totalJavadoc = 0;
        int count = 0;
        try {

            while ((line = reader.readLine()) != null) {
                StringTokenizer tokenizer = new StringTokenizer(line);
                String[] columns = splitLine(tokenizer);

                try {
                    int ccn = Integer.parseInt(columns[2]);
                    int javadoc = Integer.parseInt(columns[3]);

                    /*
                     * Methods are fully qualified, so split by the '.' and find the last token
                     * which will be the method.
                     */
                    String method = columns[4];
                    String[] tokens = method.split("\\.");
                    String methodName = tokens[tokens.length - 1];
                    Matcher getterMatcher = getter.matcher(methodName);
                    Matcher setterMatcher = setter.matcher(methodName);

                    /*
                     * If it's a getter or setter and the complexity is 1 (i.e. a simple
                     * getter/setter), then just continue (i.e. filter it out).
                     */
                    if ((getterMatcher.find() || setterMatcher.find()) && ccn == 1) {
                        continue;
                    }

                    totalCcn += ccn;
                    totalJavadoc += javadoc;
                    count++;

                } catch (Exception e) {
                    /*
                     * Ignore the exception, since may be a header and footer line, and not a normal
                     * row of data.
                     */
                }
            }

        } finally {
            if (reader != null) {
                reader.close();
            }
        }

        /*
         * Calculate the average CCN and Javadoc and print the output.
         */
        double averageCcn = (double) totalCcn / (double) count;
        double averageJavadoc = (double) totalJavadoc / (double) count;
        System.out.println("Total CCN: " + totalCcn);
        System.out.println("Average CCN: :" + averageCcn);
        System.out.println("Total Javadoc: " + totalJavadoc);
        System.out.println("Average Javadoc: :" + averageJavadoc);
    }

    /**
     * Split the output line from JavaNCSS. Expects exactly 5 columns of data, for function number,
     * NCSS, CCN, Javadoc, and method name.
     */
    private static String[] splitLine(StringTokenizer tokenizer) {
        int i = 0;
        String columns[] = new String[5];
        while (tokenizer.hasMoreElements()) {
            String column = tokenizer.nextToken();
            if (i < 6) {
                columns[i] = column;
            }
            i++;
        }
        return columns;
    }
}