package org.mandarax.xkb;
/*
 * Copyright (C) 1999-2004 <a href="mailto:mandarax@jbdietrich.com">Jens Dietrich</a>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URL;
import org.apache.log4j.Category;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.mandarax.kernel.KnowledgeBase;

/**
 * Manager for managing drivers and adding support like xml data source access
 * via writers and readers, streams, urls and files.
 * <br>
 * Changed in version 1.9: output uses "pretty printing".
 * <br>
 * <strong>Important Note:</strong>In version 2.2 the similar ZKB framework has been added. In the long term
 * ZKB will replace XKB! For details, see the <code>org.mandarax.zkb</code> package.
 * @author <A HREF="mailto:mandarax@jbdietrich.com">Jens Dietrich</A>
 * @version 3.3.1 <9 August 2004>
 * @since 1.4
 */
public class XKBManager {

    private SAXBuilder saxBuilder = null;
    private boolean    validate   = false;
    private Category   LOG        = null;
    private XKBDriver  driver     = null;
    /**
     * Constructor.
     */
    public XKBManager() {
        super ();
    }

    /**
     * Exports a knowledge base to a file.
     * @param kb a knowledge base
     * @param target a file
     * @throws an XKBException is thrown if export fails
     */
    public void exportKnowledgeBase(File target, KnowledgeBase kb) throws XKBException {
        try {
            Writer writer = new FileWriter (target);
            exportKnowledgeBase (writer, kb);
            writer.close ();
        } catch(IOException x) {
            throw new XKBException (x.getMessage ());
        }
    }

    /**
     * Exports a knowledge base to an output stream.
     * @param kb a knowledge base
     * @param target an output stream
     * @throws an XKBException is thrown if export fails
     */
    public void exportKnowledgeBase(OutputStream target, KnowledgeBase kb) throws XKBException {
        if(driver == null) throw new XKBException ("Cannot export knowledge base without driver");

        try {
            Document doc = driver.exportKnowledgeBase (kb);

            // com.mdcs.joi.Inspector.inspect(doc);
            XMLOutputter xmlOut         = new XMLOutputter (Format.getPrettyFormat());
            String       stringifiedXML = xmlOut.outputString (doc);
            // xmlOut.output (stringifiedXML, System.out);
            xmlOut.output (doc, target);
        } catch(IOException x) {
            throw new XKBException (x.getMessage (),x);
        }
    }

    /**
     * Exports a knowledge base to a writer.
     * @param kb a knowledge base
     * @param target a writer
     * @throws an XKBException is thrown if export fails
     */
    public void exportKnowledgeBase(Writer target, KnowledgeBase kb) throws XKBException {
        if(driver == null) {
            throw new XKBException ("Cannot export knowledge base without driver");
        }
        try {
            Document doc = driver.exportKnowledgeBase (kb);
            (new XMLOutputter (Format.getPrettyFormat())).output (doc, target);
        } catch(IOException x) {
            throw new XKBException (x.getMessage (),x);
        }
    }

    /**
     * Get the document from the data sorce.
     * @return a document
     * @param File the data source
     */
    protected Document getDocument(File data) throws XKBException {
        if(data == null) throw new XKBException ("Cannot build document from null");
        try {
            return getSAXBuilder ().build (data);
        } 
        catch(JDOMException x) {
        	throw new XKBException (x.getMessage (),x);
        }
        catch(IOException x) {
        	throw new XKBException (x.getMessage (),x);
        }
    }

    /**
     * Get the document from the data sorce.
     * @return a document
     * @param InputStream the data source
     */
    protected Document getDocument(InputStream data) throws XKBException {
        if(data == null) {
            throw new XKBException ("Cannot build document from null");
        }

        try {
            return getSAXBuilder ().build (data);
        } 
        catch(JDOMException x) {
            throw new XKBException (x.getMessage (),x);
        }
        catch(IOException x) {
            throw new XKBException (x.getMessage (),x);
        }
    }

    /**
     * Get the document from the data sorce.
     * @return a document
     * @param URL the data source
     */
    protected Document getDocument(URL data) throws XKBException {
        if(data == null) {
            throw new XKBException ("Cannot build document from null");
        }

        try {
            return getSAXBuilder ().build (data);
        } 
        catch(JDOMException x) {
            throw new XKBException (x.getMessage (),x);
        }
        catch(IOException x) {
            throw new XKBException (x.getMessage (),x);
        }
    }

    /**
     * Get the SAX builder.
     * @return the SAX builder
     */
    private SAXBuilder getSAXBuilder() {
        if(saxBuilder == null) {
            saxBuilder = new SAXBuilder (validate);
        }

        return saxBuilder;
    }

    /**
     * Import a knowledge base from a file source.
     * @return a knowledge base
     * @param source a file
     * @throws an XKBException is thrown if import fails
     */
    public KnowledgeBase importKnowledgeBase(File source)
            throws XKBException {
        if(driver == null) {
            throw new XKBException (
                "Cannot import knowledge base without driver");
        } else {
            return driver.importKnowledgeBase (getDocument (source));
        }
    }

    /**
     * Import a knowledge base from an input stream source.
     * @return a knowledge base
     * @param source an input stream
     * @throws an XKBException is thrown if import fails
     */
    public KnowledgeBase importKnowledgeBase(InputStream source)
            throws XKBException {
        if(driver == null) {
            throw new XKBException (
                "Cannot import knowledge base without driver");
        } else {
            return driver.importKnowledgeBase (getDocument (source));
        }
    }

    /**
     * Import a knowledge base from a url source.
     * @return a knowledge base
     * @param source a url
     * @throws an XKBException is thrown if import fails
     */
    public KnowledgeBase importKnowledgeBase(URL source) throws XKBException {
        if(driver == null) {
            throw new XKBException (
                "Cannot import knowledge base without driver");
        } else {
            return driver.importKnowledgeBase (getDocument (source));
        }
    }


    /**
     * Set a new driver.
     * @param aDriver a driver
     */
    public void setDriver(XKBDriver aDriver) {
        driver = aDriver;
    }

    /**
     * Set the SAX builder. E.g., here we can set a special XML parser.
     * Note that validation of the builder and validation set here could become inconsistent!
     * @param builder a SAX builder
     */
    public void setSAXBuilder(SAXBuilder builder) {
        saxBuilder = builder;
    }
}
