/*
 *******************************************************************************
 * Copyright (C) 2010-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
package com.ibm.icu.dev.tool.docs;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.BitSet;
import java.util.Date;
import java.util.TreeSet;


/**
 * @author yumaoka
 *
 */
public class CollectAPI {
    private static final int MAXSTATE = APIInfo.STA_INTERNAL;

    private APIData _apidata;


    CollectAPI(String file) {
        _apidata = APIData.read(file, true);
    }

    void writeHTML(String outfile, BitSet filter) throws IOException {

        // collecting versions
        TreeSet<String> versions = new TreeSet<String>();
        for (APIInfo info : _apidata.set) {
            versions.add(info.getStatusVersion());
        }

        FileOutputStream fos = new FileOutputStream(outfile);
        PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos, "UTF-8")));

        String title = "ICU4J API Collection: " + _apidata.name;
        String note = "Contents generated by CollectAPI tool on " + new Date().toString();

        pw.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        pw.println("<html>");
        pw.println("<head>");
        pw.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
        pw.println("<title>" + title + "</title>");
        pw.println("</head>");
        pw.println("<body>");

        pw.println("<h1>" + title + "</h1>");

        for (String ver : versions) {
            boolean sawEntryForVersion = false;

            for (int state = 0; state <= MAXSTATE; state++) {
                if (!filter.get(state)) {
                    continue;
                }

                boolean firstInState = true;
                String pack = "";
                String clas = "***";  // hack - we just need a class name never used 
                boolean inList = false;

                for (APIInfo info : _apidata.set) {
                    if (!info.getStatusVersion().equals(ver)) {
                        continue;
                    }
                    if (state != info.getVal(APIInfo.STA)) {
                        continue;
                    }

                    if (!sawEntryForVersion) {
                        pw.println("<h2>Status Version: " + ver + "</h2>");
                        sawEntryForVersion = true;
                    }

                    if (firstInState) {
                        pw.println("<h3>[" + getStatusTypeName(state) + "]</h3>");
                        firstInState = false;
                    }

                    String packageName = info.getPackageName();
                    if (!packageName.equals(pack)) {
                        if (inList) {
                            pw.println("</ul>");
                            inList = false;
                        }
                        pw.println("<h4>Package: " + packageName + "</h4>");
                        pack = packageName;
                    }

                    String className = info.getClassName();
                    if (className.length() == 0) {
                        // next class
                        if (inList) {
                            pw.println("</ul>");
                            inList = false;
                        }
                        pw.print("<p><span style='color:red'>Class: </span>");
                        info.print(pw, false, true, false);
                        pw.println("</p>");
                        clas = className;
                        continue;
                    }
                    if (!className.equals(clas)) {
                        if (inList) {
                            pw.println("</ul>");
                            inList = false;
                        }
                        pw.println("<span style='color:green'>APIs: </span>" + className);
                        clas = className;
                    }

                    if (!inList) {
                        pw.println("<ul>");
                        inList = true;
                    }
                    pw.print("<li>");
                    info.print(pw, false, true, false);
                    pw.println("</li>");
                }

                if (inList) {
                    pw.println("</ul>");
                }
            }

            if (sawEntryForVersion) {
                pw.println();
                pw.println("<hr/>");
            }
        }

        pw.println("<p><i><font size=\"-1\">" + note + "</font></i></p>");

        pw.println("</body>");
        pw.println("</html>");
        pw.close();
    }

    void writeTSV(String outfile, BitSet filter) throws IOException {
        FileOutputStream fos = new FileOutputStream(outfile);
        PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos, "UTF-8")));

        for (APIInfo info : _apidata.set) {
            if (!filter.get(info.getVal(APIInfo.STA))) {
                continue;
            }
            StringBuilder buf = new StringBuilder();

            // package
            buf.append(info.getPackageName());
            buf.append("\t");

            // class
            String className = info.getClassName();
            if (className.length() == 0) {
                className = info.getName();
            }
            buf.append(className);
            buf.append("\t");

            // signature, etc
            info.format(buf, false, false, false);
            buf.append("\t");

            // status
            buf.append(APIInfo.getTypeValName(APIInfo.STA, info.getVal(APIInfo.STA)));
            buf.append("\t");

            // version
            String statusVer = info.getStatusVersion();
            if (statusVer.length() == 0) {
                statusVer = "[N/A]";
            }
            buf.append(statusVer);

            pw.println(buf.toString());
        }
        pw.close();
    }

    public static void main(String[] args) {
        String apifile = null; 
        String outfile = null;
        BitSet filter = new BitSet(MAXSTATE + 1);
        boolean isTSV = false;

        // default filter
        filter.set(APIInfo.STA_STABLE);
        filter.set(APIInfo.STA_DRAFT);
        filter.set(APIInfo.STA_DEPRECATED);

        for (int i = 0; i < args.length; i++) {
            if (args[i].equals("-f")) {
                if (i + 1 == args.length) {
                    System.out.println("Missing filter argument");
                    return;
                }
                i++;
                String[] types = args[i].split(",");
                filter.clear();
                for (String type : types) {
                    if (type.equalsIgnoreCase(getStatusTypeName(APIInfo.STA_STABLE))) {
                        filter.set(APIInfo.STA_STABLE);
                    } else if (type.equalsIgnoreCase(getStatusTypeName(APIInfo.STA_DRAFT))) {
                        filter.set(APIInfo.STA_DRAFT);
                    } else if (type.equalsIgnoreCase(getStatusTypeName(APIInfo.STA_DEPRECATED))) {
                        filter.set(APIInfo.STA_DEPRECATED);
                    } else if (type.equalsIgnoreCase(getStatusTypeName(APIInfo.STA_OBSOLETE))) {
                        filter.set(APIInfo.STA_OBSOLETE);
                    } else if (type.equalsIgnoreCase(getStatusTypeName(APIInfo.STA_INTERNAL))) {
                        filter.set(APIInfo.STA_INTERNAL);
                    } else {
                        System.out.println("Bad filter type " + type);
                        return;
                    }
                }
            } else if (args[i].equals("-o")) {
                if (i + 1 == args.length) {
                    System.out.println("Missing filter argument");
                    return;
                }
                i++;
                outfile = args[i];
            } else if (args[i].equals("-t")) {
                isTSV = true;
            } else {
                apifile = args[i];
                if (i + 1 != args.length) {
                    System.out.println("Too many arguments");
                    return;
                }
            }
        }

        if (apifile == null) {
            System.out.println("No API file specified");
            return;
        }

        CollectAPI collection = new CollectAPI(apifile);

        try {
            if (isTSV) {
                if (outfile == null) {
                    outfile = "api.tsv";
                }
                collection.writeTSV(outfile, filter);
            } else {
                if (outfile == null) {
                    outfile = "api.html";
                }
                collection.writeHTML(outfile, filter);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String getStatusTypeName(int status) {
        String name = null;
        switch (status) {
        case APIInfo.STA_STABLE:
            name = "Stable";
            break;

        case APIInfo.STA_DRAFT:
            name = "Draft";
            break;

        case APIInfo.STA_DEPRECATED:
            name = "Deprecated";
            break;

        case APIInfo.STA_OBSOLETE:
            name = "Obsolete";
            break;

        case APIInfo.STA_INTERNAL:
            name = "Internal";
            break;

        default:
            throw new IllegalArgumentException("Bad API status type " + status);
        }

        return name;
    }
}
