/*******************************************************************************
 * Copyright (c) 2006, 2018 IBM Corporation and others.
 * 
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - Jeff Briggs, Henry Hughes, Ryan Morse
 *******************************************************************************/

package org.eclipse.linuxtools.systemtap.structures;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.linuxtools.internal.systemtap.structures.Localization;
import org.eclipse.linuxtools.profiling.launch.IRemoteFileProxy;
import org.eclipse.linuxtools.profiling.launch.RemoteProxyManager;

public class KernelSourceTree {
    public TreeNode getTree() {
        return kernelTree;
    }

    /**
     * Builds the kernel tree from file parameter direct and stores the excluded string array.
     *
     * @param direct The file to include into the tree.
     * @param excluded The string array to store as excluded.
     */
    public void buildKernelTree(String direct, String[] excluded) {
        if (direct == null || direct.isEmpty()){
            kernelTree = null;
            return;
        }
        try {
            URI locationURI = new URI(direct);
            IRemoteFileProxy proxy = RemoteProxyManager.getInstance().getFileProxy(locationURI);
            this.buildKernelTree(locationURI, excluded, proxy, null);
        } catch (URISyntaxException e) {
            kernelTree = null;
        } catch (CoreException e) {
            kernelTree = null;
        }
    }

    /**
     * Builds the kernel tree from file parameter direct and stores the excluded string array.
     *
     * @param locationURI The URI to include into the tree.
     * @param excluded The string array to store as excluded.
     * @param proxy The proxy to be used to get the remote files
     * @param monitor a progress monitor for this operation. Can be null.
     * @throws CoreException If traversing the tree fails.
     *
     * @since 1.1
     */
    public void buildKernelTree(URI locationURI, String[] excluded, IRemoteFileProxy proxy, IProgressMonitor monitor) throws CoreException {
        if (excluded != null){
            this.excluded = Arrays.copyOf(excluded, excluded.length);
        }
        IFileStore fs = proxy.getResource(locationURI.getPath());
        if (fs == null) {
            kernelTree = null;
        } else {
            kernelTree = new TreeNode(fs, fs.getName(), false);
            addLevel(kernelTree, monitor);
        }
    }

    /**
     * Adds a level to the kernel source tree.
     *
     * @param top The top of the tree to add a level to.
     * @throws CoreException
     */
    private void addLevel(TreeNode top, IProgressMonitor monitor) throws CoreException {
        boolean add;
        TreeNode current;
        IFileStore fs = (IFileStore)top.getData();
        IFileStore[] fsList = null;
        fsList = fs.childStores(EFS.NONE, new NullProgressMonitor());
        if (monitor != null) {
            monitor.beginTask(Localization.getString("ReadingKernelSourceTree"), 100); //$NON-NLS-1$
        }
        CCodeFileFilter filter = new CCodeFileFilter();
        for (IFileStore fsChildren : fsList) {
            add = true;
            boolean isDir = fsChildren.fetchInfo().isDirectory();
            if (!filter.accept(fsChildren.getName(), isDir)) {
                continue;
            }

            for(int j=0; j<excluded.length; j++) {
                if(fsChildren.getName().equals(excluded[j].substring(0, excluded[j].length()-1)) && isDir) {
                    add = false;
                    break;
                }
            }
            if(add) {
                current = new TreeNode(fsChildren, fsChildren.getName(), !isDir);
                top.add(current);
                if(isDir) {
                    addLevel(top.getChildAt(top.getChildCount()-1), null);
                    if(0 == current.getChildCount()) {
                        top.remove(top.getChildCount()-1);
                    }
                }
            }
            if (monitor != null) {
                monitor.worked(1);
            }
        }
        top.sortLevel();
    }

    public void dispose() {
        kernelTree = null;
    }

    private TreeNode kernelTree;
    private String[] excluded = new String[0];
}
