/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import org.clearsilver.HDF;

import java.util.ArrayList;

public class NavTree {

    public static void writeNavTree(String dir) {
        ArrayList<Node> children = new ArrayList();
        for (PackageInfo pkg: DroidDoc.choosePackages()) {
            children.add(makePackageNode(pkg));
        }
        Node node = new Node("Reference", dir + "packages.html", children, null);

        StringBuilder buf = new StringBuilder();
        if (false) {
            // if you want a root node
            buf.append("[");
            node.render(buf);
            buf.append("]");
        } else {
            // if you don't want a root node
            node.renderChildren(buf);
        }

        HDF data = DroidDoc.makeHDF();
        data.setValue("reference_tree", buf.toString());
        ClearPage.write(data, "navtree_data.cs", "navtree_data.js");
    }

    private static Node makePackageNode(PackageInfo pkg) {
        ArrayList<Node> children = new ArrayList();

        children.add(new Node("Description", pkg.fullDescriptionHtmlPage(), null, null));

        addClassNodes(children, "Interfaces", pkg.interfaces());
        addClassNodes(children, "Classes", pkg.ordinaryClasses());
        addClassNodes(children, "Enums", pkg.enums());
        addClassNodes(children, "Exceptions", pkg.exceptions());
        addClassNodes(children, "Errors", pkg.errors());

        return new Node(pkg.name(), pkg.htmlPage(), children, pkg.getSince());
    }

    private static void addClassNodes(ArrayList<Node> parent, String label, ClassInfo[] classes) {
        ArrayList<Node> children = new ArrayList();

        for (ClassInfo cl: classes) {
            if (cl.checkLevel()) {
                children.add(new Node(cl.name(), cl.htmlPage(), null, cl.getSince()));
            }
        }

        if (children.size() > 0) {
            parent.add(new Node(label, null, children, null));
        }
    }

    private static class Node {
        private String mLabel;
        private String mLink;
        ArrayList<Node> mChildren;
        private String mSince;

        Node(String label, String link, ArrayList<Node> children, String since) {
            mLabel = label;
            mLink = link;
            mChildren = children;
            mSince = since;
        }

        static void renderString(StringBuilder buf, String s) {
            if (s == null) {
                buf.append("null");
            } else {
                buf.append('"');
                final int N = s.length();
                for (int i=0; i<N; i++) {
                    char c = s.charAt(i);
                    if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
                        buf.append(c);
                    } else {
                        buf.append("\\u");
                        for (int j=0; i<4; i++) {
                            char x = (char)(c & 0x000f);
                            if (x > 10) {
                                x = (char)(x - 10 + 'a');
                            } else {
                                x = (char)(x + '0');
                            }
                            buf.append(x);
                            c >>= 4;
                        }
                    }
                }
                buf.append('"');
            }
        }

        void renderChildren(StringBuilder buf) {
            ArrayList<Node> list = mChildren;
            if (list == null || list.size() == 0) {
                // We output null for no children.  That way empty lists here can just
                // be a byproduct of how we generate the lists.
                buf.append("null");
            } else {
                buf.append("[ ");
                final int N = list.size();
                for (int i=0; i<N; i++) {
                    list.get(i).render(buf);
                    if (i != N-1) {
                        buf.append(", ");
                    }
                }
                buf.append(" ]\n");
            }
        }

        void render(StringBuilder buf) {
            buf.append("[ ");
            renderString(buf, mLabel);
            buf.append(", ");
            renderString(buf, mLink);
            buf.append(", ");
            renderChildren(buf);
            buf.append(", ");
            renderString(buf, mSince);
            buf.append(" ]");
        }
    }
}
