/*
 * File:     CorpusDatabaseImpl.java
 * Project:  MPI Linguistic Application
 * Date:     03 April 2006
 *
 * Copyright (C) 2001-2006  Max Planck Institute for Psycholinguistics
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package mpi.eudico.server.corpora.clomimpl.abstr;

import mpi.eudico.server.corpora.clom.Corpus;
import mpi.eudico.server.corpora.clom.CorpusDatabase;
import mpi.eudico.server.corpora.clom.ToolDatabase;

import mpi.eudico.server.corpora.util.DataTreeNode;

import mpi.eudico.server.util.ServerConfiguration;

import mpi.eudico.tool.ToolCondition;

// Feb 8 2000 Markus Sessions: ShoeboxCompositeCorpus was removed, bring it back
// Feb 8 2000 Markus Sessions: GestureCorpus was removed, bring it back
import java.io.File;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;


/**
 * CorpusDatabaseImpl allows only one instance that constitutes the entry point
 * for all requests on Corpora on the EUDICO server. It is implemented as a
 * 'Singleton' to make sure that there can only exist one instance. This
 * instance is created during startup of the server and lasts until the server
 * is shut down.
 *
 * @author Hennie Brugman
 * @author Albert Russel
 * @version 10-Jun-1999
 * @version Aug 2005 Identity removed
 */
public class CorpusDatabaseImpl implements CorpusDatabase {
    /** The reference to the only implementation of CorpusDatabaseImpl. */
    private static CorpusDatabaseImpl cdi;
    private String name;

    /** Holds a reference to each component Corpus. */
    private Vector corpora;

    /** Holds a list of all available Identities. */
    private Set identities;

    /**
     * Instantiates objects for all component Corpora. This constructor is
     * declared private because it may only be called from the Instance()
     * method, not from any user code.
     *
     */
    private CorpusDatabaseImpl() {
        name = "Eudico Database";
        corpora = new Vector();

        try {
            File[] corpusList = (new File(ServerConfiguration.CORPUS_DIRECTORY)).listFiles();

            if (corpusList != null) {
                // check for each sub directory if it contains a known corpus.
                for (int i = 0; i < corpusList.length; i++) {
                    // check if the sub directory contains the cgn.

                    /*
                    if (corpusList[i].getName().equals("cgn")) {
                        // The CGN gets instantiated as a CompositeCorpus with a name
                        // a path and this DataBase as parent.
                        String corpusPath = corpusList[i].getAbsolutePath() +
                            File.separator + "annot";
                        corpora.add(new CGNCompositeCorpus(
                                "Corpus Gesproken Nederlands", corpusPath, this));
                    }
                    */
                    /*                   if (corpusList[i].getName().equals("dobes")) {
                                           String corpusPath = corpusList[i].getAbsolutePath() +
                                               File.separator + "dobes";
                                           corpora.add(new DobesCompositeCorpus(
                                                   "Dobes preview corpus", corpusPath, this));
                                       } */

                    // check if the gesture database is supported
                    //if (corpusList[i].getName().equals("gesture")) {
                    //    corpora.add(GestureCorpus.Instance());
                    //}
                    // check if the sub directory contains chat formatted corpora.
                    if (corpusList[i].getName().equals("childes") ||
                            corpusList[i].getName().equals("chat")) {
                        System.out.println("");
                        System.out.println("   CHAT corpus found ------");
                        System.out.println("");

                        //                       DirectoryTree tree = new LocalDirectoryTree(corpusList[i]);
                        //                       corpora.add(new CHATCompositeCorpus(
                        //                               "CHAT formatted corpora", this, tree));
                    }
                }
            } else {
                System.err.println("CorpusDatabaseImpl:No corpora found in " +
                    ServerConfiguration.CORPUS_DIRECTORY);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        identities = new HashSet();
    }

    /**
     * Takes the role of a constructor, implements the 'Singleton' design
     * pattern. Instance() either creates this classes' only instance or
     * return it if it is already created.
     *
     * @return the classes' only instance
     *
     */
    public static CorpusDatabaseImpl Instance() {
        if (cdi == null) {
            cdi = new CorpusDatabaseImpl();
        }

        return cdi;
    }

    /**
     * Returns the corpora available.
     *
     * @return the available corpora
     *
     */
    public Vector getCorpora() {
        Vector visibleCorpora = new Vector();

        Iterator iter = corpora.iterator();

        while (iter.hasNext()) {
            //System.out.println("CorpusDatabaseImpl:getCorpora: " + ((Corpus)corpora.get(0)).getName() );
            Corpus corp = (Corpus) iter.next();

            visibleCorpora.add(corp);
        }

        return visibleCorpora;
    }

    /**
     * Prints statistics of component Corpora to the EUDICO server's console.
     * <code>printStatistics</code> is recursively called on the Corpus
     * hierarchy.
     *
     */
    public void printStatistics() {
        System.out.println("Statistics for database: " + name);
        System.out.println("-->Current Identities:");

        Iterator iter = identities.iterator();

        while (iter.hasNext()) {
            System.out.println("   -->" + iter.next());
        }

        Iterator iter2 = corpora.iterator();

        while (iter2.hasNext()) {
            ((Corpus) iter2.next()).printStatistics();
        }
    }

    /**
     * Forces the EUDICO server VM to do a Garbage Collect. Is made available
     * for testing purposes only.
     *
     */
    public void collectGarbage() {
        System.gc();
    }

    /**
     * Gives the name of the whole database: "Eudico database".
     *
     * @return the database name
     *
     */
    public String getNodeName() {
        return name;
    }

    /**
     * Gives the name of the whole database: "Eudico database".
     *
     * @return the database name
     *
     */
    public String getName() {
        return name;
    }

    /**
     * No MetaData is available at the top level ???
     *
     * @return DOCUMENT ME!
     */
    public Vector getMetaData() {
        return null;
    }

    /**
     * No MetaData is available at the top level ???
     *
     * @return DOCUMENT ME!
     */
    public boolean hasMetaData() {
        return false;
    }

    /**
     * Everbody has access to top level
     *
     * @return DOCUMENT ME!
     */
    /**
     * CorpusDatabaseImpl is never a leaf node in the tree of Corpora,
     * therefore 'false' is always returned.
     *
     * @return return value is always 'false'
     *
     */
    public boolean isTreeViewableLeaf() {
        return false;
    }

    /**
     * Gives all children of this node in the tree of corpora, in this case all
     * component top level Corpora in the Eudico database.
     *
     *
     * @return a list of child objects, in this case Corpora
     *!
     */
    public Vector getChildren() {
        return getCorpora();
    }

    // ToolAdministrator interface methods

    /**
     * Give all Tools that are applicable to a data object in the Corpus
     * hierarchy. For CorpusDatabase there are in this version no such Tools.
     *
     * @return ask the ToolDatabase.
     *
     */
    public Vector getAvailableTools() {
        return ToolDatabaseImpl.Instance().getAvailableTools(this);
    }

    /**
     * Returns true if this ToolAdministrator meets the condition specified in
     * the argument.
     *
     * @param theCondition DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     */
    public boolean checkToolCondition(ToolCondition theCondition) {
        return false;
    }

    // DataTreeNode interface method

    /**
     * Returns the parent in the Corpus data object hierarchy, in this case
     * null, because CorpusDatabase is the root of the tree.
     *
     * @return a null DataTreeNode reference
     *
     */
    public DataTreeNode getParent() {
        return null; // is the root of the tree
    }

    /**
     * Removes a child in the Corpus data hierarchy by deleting the reference
     * to the child. The garbage collector will then do the actual deletion.
     * Children for CorpusDatabase are Corpora. For the moment, a
     * CorpusDatabase' children are kept alive all during the server's life
     * time, so removeChild does nothing.
     *
     * @param theChild the child to be deleted
     *
     */
    public void removeChild(DataTreeNode theChild) {
    }

    /**
     * Returns the single instance of the ToolDatabase.
     *
     * @return DOCUMENT ME!
     *
     */
    public ToolDatabase getToolDatabase() {
        return ToolDatabaseImpl.Instance();
    }
}
