/*
 * Copyright (c) 2013 Cinnober Financial Technology AB, Stockholm,
 * Sweden. All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Cinnober Financial Technology AB, Stockholm, Sweden. You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Cinnober.
 *
 * Cinnober makes no representations or warranties about the suitability
 * of the software, either expressed or implied, including, but not limited
 * to, the implied warranties of merchantibility, fitness for a particular
 * purpose, or non-infringement. Cinnober shall not be liable for any
 * damages suffered by licensee as a result of using, modifying, or
 * distributing this software or its derivatives.
 */
package com.cinnober.msgcodec.javadoc;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.cinnober.msgcodec.anot.Name;
import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doclet;
import com.sun.javadoc.RootDoc;

/**
 * The doc annotation doclet extracts javadoc comments for groups and fields,
 * and writes them in the Java properties format. The properties are printed to the file specified by
 * the -output &lt;file&gt; option.
 * The documentation is stored in the annotation named <em>doc</em>.
 *
 * <p>The entire class documentation is used for groups.
 *
 * <p>For fields, the comment of the get method is used, excluding the first sentence. The following
 * pattern for documenting fields is recommended:
 * <pre>
 * /** Returns foo.
 *  * The semantics of foo is explained here.
 *  * {@literal @}return foo
 *  *{@literal /}
 * public String getFoo() { ... }
 *
 * /** Set foo.
 *  * {@literal @}param foo the foo to set
 *  *{@literal /}
 * public void setFoo(String foo) { ... }
 * </pre>
 *
 * <p>Usage:<br>
 * <code>java -doclet com.cinnober.msgcodec.javadoc.DocAnnotationDoclet ...</code>
 *
 *
 * @author mikael.brannstrom
 * @see com.cinnober.msgcodec.Annotations#toProperties()
 */
public class DocAnnotationDoclet extends Doclet {
    public static boolean start(RootDoc root) {
        File outputFile = findOutputFileOption(root.options());
        if (!outputFile.getParentFile().exists()) {
            outputFile.getParentFile().mkdirs();
        }
        System.out.println("output=" + outputFile.getAbsolutePath());

        // build
        Map<String, GroupDefDoc> groupsByName = new HashMap<>();
        Map<String, String> groupNameByClassName = new HashMap<>();
        for (ClassDoc classDoc : root.classes()) {
            GroupDefDoc group = new GroupDefDoc(classDoc);
            groupsByName.put(group.getName(), group);
            groupNameByClassName.put(group.getClassName(), group.getName());
        }

        // doc properties

        // TODO: patch {@link ...} tags so that JavaClass is replaced with GroupName.
        // i.e. use groupNameByClassName

        String docAnnotatationName = "doc";
        Properties properties = new Properties();
        for (GroupDefDoc group : groupsByName.values()) {
            group.addDoc(properties, docAnnotatationName);
        }

        try {
            OutputStream out = new FileOutputStream(outputFile);
            properties.store(out, "Doc annotations generated by " + DocAnnotationDoclet.class.getName());
            out.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return true;
    }

    public static String getNameAnnotation(AnnotationDesc[] annotations, String defaultName) {
        for (AnnotationDesc annot : annotations) {
            if (annot.annotationType().qualifiedName().equals(Name.class.getName())) {
                return (String) annot.elementValues()[0].value().value();
            }
        }
        return defaultName;
    }

    private static File findOutputFileOption(String[][] options) {
        for (String[] option : options) {
            if (option[0].equals("-output")) {
                return new File(option[1]);
            }
        }
        return new File("annotations.properties");
    }

    public static int optionLength(String option) {
        switch (option) {
        case "-output": // file>
            return 2;
        default:
            // gradle fix. Until I know how to disable standard doclet options we need to recognize them
            return standardDocletOptionLength(option);
        }
    }
    public static int standardDocletOptionLength(String option) {
        switch (option) {
        case "-d": // <directory>
            return 2;
        case "-use": //
            return 1;
        case "-version": //
            return 1;
        case "-author": //
            return 1;
        case "-docfilessubdirs": //
            return 1;
        case "-splitindex": //
            return 1;
        case "-windowtitle": // <text>
            return 2;
        case "-doctitle": // <html-code>
            return 2;
        case "-header": // <html-code>
            return 2;
        case "-footer": // <html-code>
            return 2;
        case "-top": //    <html-code>
            return 2;
        case "-bottom": // <html-code>
            return 2;
        case "-link": // <url>
            return 1;
        case "-linkoffline": // <url> <url2>
            return 3;
        case "-excludedocfilessubdir": // <name1>:..
            return 2;
        case "-group": // <name> <p1>:<p2>..
            return 3;
        case "-nocomment": //
            return 1;
        case "-nodeprecated": //
            return 1;
        case "-noqualifier": // <name1>:<name2>:...
            return 2;
        case "-nosince": //
            return 1;
        case "-notimestamp": //
            return 1;
        case "-nodeprecatedlist": //
            return 1;
        case "-notree": //
            return 1;
        case "-noindex": //
            return 1;
        case "-nohelp": //
            return 1;
        case "-nonavbar": //
            return 1;
        case "-serialwarn": //
            return 1;
        case "-tag": // <name>:<locations>:<header>
            return 2;
        case "-taglet": // path
            return 2;
        case "-tagletpath": // path
            return 2;
        case "-Xdocrootparent": // <url>
            return 2;
        case "-charset": // <charset>
            return 2;
        case "-helpfile": // <file>
            return 2;
        case "-linksource": //
            return 1;
        case "-sourcetab": // <tab length>
            return 2;
        case "-keywords": //
            return 1;
        case "-stylesheetfile": // <path>
            return 2;
        case "-docencoding": // <name>
            return 2;
        default:
            return 0;
        }
    }

}

@@ -2487,16 +2487,18 @@
         
+//
 System.o

Do not print to stdout