/*
 * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.packaging;

import com.arsdigita.db.*;
import com.arsdigita.persistence.*;
import com.arsdigita.persistence.metadata.*;
import com.arsdigita.persistence.pdl.*;
import com.arsdigita.kernel.*;
import com.arsdigita.util.*;
import com.arsdigita.util.parameter.*;
import com.arsdigita.runtime.*;
import com.arsdigita.runtime.Initializer;
import com.arsdigita.loader.*;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Set;

import org.apache.log4j.Logger;

/**
 * Loader
 *
 * @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
 * @version $Revision: #12 $ $Date: 2004/04/07 $
 **/

class Loader {

    private static final Logger s_log = Logger.getLogger(Loader.class);

    public final static String versionId = "$Id: //core-platform/dev/src/com/arsdigita/packaging/Loader.java#12 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    private static final String INIT = "com.arsdigita.runtime.Initializer";

    public static Loader get(String pkg) {
        ClassLoader ldr = Loader.class.getClassLoader();
        InputStream is = ldr.getResourceAsStream(pkg + ".load");
        if (is == null) { return null; }
        LoaderInfo info = new LoaderInfo(is);
        try { is.close(); }
        catch (IOException e) { throw new UncheckedWrapperException(e); }
        return new Loader(pkg, info, Checklist.get(pkg));
    }

    private String m_key;
    private LoaderInfo m_info;
    private Checklist m_checks;
    private List m_scripts;

    public Loader(String key, LoaderInfo info, Checklist checks) {
        m_key = key;
        m_info = info;
        m_checks = checks;
        m_scripts = new ArrayList();
        for (Iterator it = m_info.getDataScripts().iterator();
             it.hasNext(); ) {
            String script = (String) it.next();
            m_scripts.add(Classes.newInstance(script));
        }
    }

    public String getKey() {
        return m_key;
    }

    public LoaderInfo getInfo() {
        return m_info;
    }

    public List getScripts() {
        return m_scripts;
    }

    public boolean checkSchema() {
        if (m_checks == null) {
            return true;
        } else {
            return m_checks.run
                (Checklist.SCHEMA, new ScriptContext(null, null));
        }
    }

    public void loadSchema(Connection conn) {
        int db = DbHelper.getDatabase(conn);
        String dir = DbHelper.getDatabaseDirectory(db);
        List scripts = m_info.getSchemaScripts();
        for (Iterator it = scripts.iterator(); it.hasNext(); ) {
            String script = (String) it.next();
            s_log.info("Loading schema for " + script);
            PackageLoader.load(conn, script + "/" + dir + "-create.sql");
        }
    }

    public boolean checkData(Session ssn) {
        if (m_checks == null) {
            return true;
        } else {
            return m_checks.run(Checklist.DATA, new ScriptContext(ssn, null));
        }
    }

    public void loadData(Session ssn, ParameterLoader loader) {
        final List inits = m_info.getProvidedInitializers();
        CompoundInitializer ini = new CompoundInitializer();
        for (Iterator it = inits.iterator(); it.hasNext(); ) {
            String init = (String) it.next();
            s_log.info("Running initializer " + init);
            ini.add((Initializer) Classes.newInstance(init));
        }
        Startup.run(ssn, ini);

        TransactionContext txn = ssn.getTransactionContext();
        txn.beginTxn();

        final ScriptContext ctx = new ScriptContext(ssn, loader);
        new KernelExcursion() {
            protected void excurse() {
                setEffectiveParty(Kernel.getSystemParty());
                for (Iterator it = m_scripts.iterator(); it.hasNext(); ) {
                    Script script = (Script) it.next();
                    s_log.info("Running data loader " + script.getClass().getName());
                    script.run(ctx);
                }
            }
        }.run();

        if (txn.inTxn()) {
            txn.commitTxn();
        }
    }

    public void loadInits(final Session ssn) {
        final TransactionContext txn = ssn.getTransactionContext();
        txn.beginTxn();

        final List inits = m_info.getProvidedInitializers();
        final List required = m_info.getRequiredInitializers();
        for (Iterator it = inits.iterator(); it.hasNext(); ) {
            String init = (String) it.next();
            DataObject dataobject = ssn.create(new OID(INIT, init));
            DataAssociation da = (DataAssociation)dataobject.get("requirements");
            for (Iterator reqit = required.iterator(); reqit.hasNext(); ) {
                String reqinit = (String) reqit.next();
                da.add(ssn.retrieve(new OID(INIT, reqinit)));
            }
        }

        if (txn.inTxn()) {
            txn.commitTxn();
        }
    }

    Set getRequired() {
        Set result = new HashSet();
        result.addAll(m_info.getRequiredTables());
        result.addAll(m_info.getRequiredInitializers());
        result.addAll(m_info.getRequiredPackages());
        return result;
    }

    Set getProvided() {
        Set result = new HashSet();
        result.addAll(m_info.getProvidedTables());
        result.addAll(m_info.getProvidedInitializers());
        result.add(m_key);
        return result;
    }

    public String toString() {
        return "<loader for " + m_key + ">";
    }

}
