/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (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.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.queplix.core.modules.inbox.utils;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.modules.inbox.Account;
import com.queplix.core.modules.inbox.jxb.ErrorFilter;
import com.queplix.core.modules.inbox.jxb.Filter;
import com.queplix.core.modules.inbox.jxb.InboxConfig;
import com.queplix.core.modules.inbox.jxb.Provider;
import com.queplix.core.modules.inbox.utils.log.SystemLogPublisher;
import com.queplix.core.utils.dao.AbstractPropertyFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The class presents Inbox property factory.
 *
 * @author Firstname LastName
 * @since 8 Dec 2006
 */
public final class InboxPropertyFactory
        extends AbstractPropertyFactory {

    // ================================================================= Constants

    // Single instance.
    private static final InboxPropertyFactory o = new InboxPropertyFactory();

    // Config file name.
    private static final String CONFIG_FILE = "inbox.xml";

    // ================================================================= Fields

    // XML inbox config
    private InboxConfig inboxConfig;

    // Map of com.queplix.core.modules.inbox.jxb.Provider objects
    private Map providerMap;
    // Map of Class objects for different InboxProvider.
    private Map providerClassMap;

    // Map of com.queplix.core.modules.inbox.jxb.Filter objects
    private Map filterMap;
    // Map of Class objects for different MailFilter.
    private Map filterClassMap;
    // Map of filter name in execution order.
    private List filterNameList;

    // Error filter class.
    private Class errFilterClass;

    // Account DAO.
    private AccountDAO accountDAO;

    // InboxMsgBuilder class.
    private Class msgBuilderClass;

    // ================================================================= Constructor

    // Constructor - blocks direct instantiation.

    private InboxPropertyFactory() {

        // XML config initialization
        inboxConfig = (InboxConfig) loadSysPropertiesAsObject(CONFIG_FILE,
                InboxConfig.class);

        //
        // Initialization
        //

        // 1. Inbox providers.

        providerMap = new HashMap();
        providerClassMap = new HashMap();

        int providerSize = inboxConfig.getProviders().getProviderCount();
        for(int i = 0; i < providerSize; i++) {
            Provider provider = inboxConfig.getProviders().getProvider(i);

            providerMap.put(provider.getName(), provider);
            providerClassMap.put(provider.getName(), initClass(
                    provider.getClassName()));
        }

        // 2. Inbox filters.

        filterMap = new HashMap();
        filterClassMap = new HashMap();
        filterNameList = new ArrayList();

        int filterSize = inboxConfig.getFilters().getFilterCount();
        for(int i = 0; i < filterSize; i++) {
            Filter filter = inboxConfig.getFilters().getFilter(i);

            filterMap.put(filter.getName(), filter);
            filterClassMap.put(filter.getName(), initClass(
                    filter.getClassName()));
            filterNameList.add(filter.getName());
        }

        // .. error filter
        ErrorFilter filter = inboxConfig.getFilters().getErrorFilter();
        errFilterClass = initClass(filter.getClassName());

        // 3. DAOs.

        // account
        accountDAO = (AccountDAO) initObject(
                inboxConfig.getAccountConfig().getDao().getClassName(),
                inboxConfig.getAccountConfig().getDao().getParam());

        // 4. Other classes.

        // message builder
        msgBuilderClass = initClass(inboxConfig.getMessageBuilderClassName());
    }

    // ================================================================= Static methods

    /**
     * Get single instance
     *
     * @return InboxPropertyFactory object
     */
    public static InboxPropertyFactory getInstance() {
        return o;
    }

    // ================================================================= Public methods

    /**
     * Gets provider class
     *
     * @param name provider name
     * @return class
     */
    public Class getInboxProviderClass(String name) {

        Class clazz = (Class) providerClassMap.get(name);
        if(clazz == null) {
            throw new IllegalStateException(
                    "Cannot get InboxProvider class for name: " + name);
        }

        return clazz;
    }

    /**
     * Gets error filter class
     *
     * @return class
     */
    public Class getErrorMailFilterClass() {

        if(errFilterClass == null) {
            throw new IllegalStateException("Cannot get error class");
        }

        return errFilterClass;
    }


    /**
     * Gets filter class
     *
     * @param name filter name
     * @return class
     */
    public Class getMailFilterClass(String name) {

        Class clazz = (Class) filterClassMap.get(name);
        if(clazz == null) {
            throw new IllegalStateException(
                    "Cannot get MailFilter class for name: " + name);
        }

        return clazz;
    }

    /**
     * Gets filter names.
     *
     * @return List
     */
    public List getMailFilterNames() {
        return Collections.unmodifiableList(filterNameList);
    }

    /**
     * Instantiates the account DAO
     *
     * @return AccountDAO
     */
    public AccountDAO getAccountDAO() {
        if(accountDAO == null) {
            throw new GenericSystemException("Can't get account DAO");
        }

        return accountDAO;
    }

    /**
     * Gets message builder class
     *
     * @return Class
     */
    public Class getMessageBuilderClass() {
        if(msgBuilderClass == null) {
            throw new GenericSystemException("Can't get message builder class");
        }

        return msgBuilderClass;
    }

    /**
     * Instantiates new object - InboxPluggableModule.
     *
     * @param clazz   Class
     * @param account Account
     * @param logName String
     * @return InboxPluggableModule
     */
    public InboxPluggableModule getInstance(Class clazz, Account account,
                                            String logName,
                                            SystemLogPublisher publisher) {

        // Checking.
        if(clazz == null) {
            throw new NullPointerException(
                    "InboxPropertyFactory#getInstance: 'clazz' is NULL");
        }
        if(account == null) {
            throw new NullPointerException(
                    "InboxPropertyFactory#getInstance: 'account' is NULL");
        }
        if(logName == null) {
            throw new NullPointerException(
                    "InboxPropertyFactory#getInstance: 'logName' is NULL");
        }

        // Instantiating InboxPluggableModule.
        InboxPluggableModule o;
        try {
            o = (InboxPluggableModule) clazz.newInstance();
        } catch (Exception ex) {
            ERROR(ex);
            throw new GenericSystemException(
                    "Cannot instantiate AbstractInboxPluggableModule. " +
                            "Class: " + clazz.getName(), ex);
        }
        o.setAccount(account);
        o.setLogName(logName);
        o.setLogPublisher(publisher);
        return o;
    } // getInstance(Class, Account, String) : InboxPluggableModule
}
