/*
Copyright (C) 2000-2010  Ministere de la culture et de la communication (France), AJLSM
See LICENCE file
 */
package fr.gouv.culture.sdx.repository;

import fr.gouv.culture.sdx.document.Document;
import fr.gouv.culture.sdx.document.ParsableDocument;
import fr.gouv.culture.sdx.exception.SDXException;
import fr.gouv.culture.sdx.exception.SDXExceptionCode;
import fr.gouv.culture.sdx.utils.AbstractSdxObject;
import fr.gouv.culture.sdx.utils.Utilities;
import fr.gouv.culture.sdx.utils.logging.LoggingUtils;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.cocoon.xml.XMLConsumer;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

/**
 * A basic implementation of a repository.
 *
 * <p>
 * This abstract implementation handles the super.getLog(), the id and null operations
 * for connections.
 */
public abstract class AbstractRepository extends AbstractSdxObject implements Repository {

    /**True if this is a default repository for an application. */
    protected boolean isDefault;
    /**String representation of the "repository" attribute name "read-only".*/
//  FIXME : private field never used locally [MP]
    private final String ATTRIBUTE_READ_ONLY = "read-only";

    /**Loads base configuration common to all repositories.
     *@param configuration   The configuration object
     *
     * The parameter required are an id for the repository, an optional attribute
     * indicating if the repository is the default within a document base is also handled
     * but the default if not specified will be false.
     *
     * @param   configuration   The configuration for this repository (based on a xml file).
     *
     *<p> Sample configuration entry:
     *<p>&lt;sdx:repository sdx:type = "FS" sdx:id = "myRepoId" baseDirectory = "baseDirName" depth = "2" extent = "50"/>
     *@see #documented_application.xconf we should link to this in the future when we have better documentation capabilities
     *
     *@throws ConfigurationException
     */
    protected void loadBaseConfiguration(Configuration configuration) throws ConfigurationException {
        super.configure(configuration);
        isDefault = (configuration.getAttributeAsBoolean(Repository.ConfigurationNode.DEFAULT, false));
    }

    /** Releases a previously opened connection.
     *
     * This does nothing in this abstract class.
     *
     *	@param	c	The connection to release.
     */
    public void releaseConnection(RepositoryConnection c) throws SDXException {
        //   if (c != null) c.optimize();
    }

    public boolean isDefault() {
        return this.isDefault;
    }

    /**Does param checks for subclasses
     * @throws SDXException
     */
    public void delete(Document doc, RepositoryConnection c) throws SDXException {
        Utilities.checkDocument(super.getLog(), doc);
        this.checkConnection(c);
    }

    /**Does param checks for subclasses
     * @throws SDXException
     */
    public void add(Document doc, RepositoryConnection c) throws SDXException {
        Utilities.checkDocument(super.getLog(), doc);
        this.checkConnection(c);
    }

    /**Does param checks for subclasses
     *
     *  @param	doc		    The document to read.
     *	@param	encoding	Should be <code> null</code>  as not verified here, but in subClasses with checkEncoding() method.
     *	@param	c		    A connection to the repository.
     * @throws SDXException
     */
    public InputStream openStream(Document doc, String encoding, RepositoryConnection c) throws SDXException {
        //ensuring we have a valid object
        Utilities.checkDocument(super.getLog(), doc);
        //verifying the encoding, if not valid we use a default, see checkEncoding() for details
        encoding = checkEncoding(encoding);
        this.checkConnection(c);
        return null;
    }

    /**Does param checks for subclasses
     *@throws SDXException
     */
    public void get(Document doc, OutputStream os, RepositoryConnection c) throws SDXException {
        Utilities.checkDocument(super.getLog(), doc);
        Utilities.checkOutputStream(super.getLog(), os);
        this.checkConnection(c);
    }

    /**Does param checks for subclasses
     * @throws SDXException
     */
    public void toSAX(ParsableDocument doc, XMLConsumer consumer, RepositoryConnection c) throws SDXException {
        Utilities.checkDocument(super.getLog(), doc);
        Utilities.checkXmlConsumer(super.getLog(), consumer);
        this.checkConnection(c);
    }

    /**Sets the isDefault flag for the repository*/
    public void setIsDefault(boolean b) {
        this.isDefault = b;
    }

    /**Verifies an encoding string,
     * if not supported by JVM default is used, UTF-8.
     *
     * @param encoding
     * @return
     */
    protected String checkEncoding(String encoding) throws SDXException {
        String defaultEncoding = DEFAULT_ENCODING;
        if (Utilities.checkString(encoding)) {
            //verifying the given encoding
            try {
                //TODOException?:will this work, just encoding a string, how to verify the encoding by the JVM see javadocs for System
                defaultEncoding.getBytes(encoding);
                return encoding;
            } catch (UnsupportedEncodingException e) {
                //logging exception
                LoggingUtils.logException(super.getLog(), e);
                //trying the default
                try {
                    defaultEncoding.getBytes(defaultEncoding);
                    //logging info for using default locale
                    //TODORefactor: the string to a class field or TODOException
                    LoggingUtils.logInfo(super.getLog(), "Using the default encoding: " + defaultEncoding);
                    return defaultEncoding;
                } catch (UnsupportedEncodingException e1) {
                    String[] args = new String[2];
                    args[0] = defaultEncoding;
                    args[1] = e1.getMessage();
                    throw new SDXException(super.getLog(), SDXExceptionCode.ERROR_DEFAULT_ENCODING, args, null);
                }

            }
        } else {
            //log message that we are using the defaultEncoding
            return defaultEncoding;
        }

    }

    public void checkConnection(RepositoryConnection c) throws SDXException {
        if (c == null) {
            String[] args = new String[1];
            args[0] = this.getId();
            throw new SDXException(super.getLog(), SDXExceptionCode.ERROR_CONNECTION_NULL, args, null);
        }
    }

    public void optimize() throws SDXException {
    }

    protected String getClassNameSuffix() {
        return Repository.CLASS_NAME_SUFFIX;
    }

}
