/*
 * 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.eql.parser;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.jxb.entity.Entity;
import com.queplix.core.modules.config.utils.EntitySchema;
import com.queplix.core.modules.config.utils.EntitySchemaFactory;
import com.queplix.core.modules.eql.EQLEReq;
import com.queplix.core.modules.eql.EQLERes;
import com.queplix.core.modules.eql.EQLReq;
import com.queplix.core.modules.eql.EQLRes;
import com.queplix.core.modules.eql.jxb.eqlagent.Binding;
import com.queplix.core.modules.eql.jxb.eqlagent.Eqlagent;
import com.queplix.core.modules.eql.jxb.eqlagent.Eqlagents;
import com.queplix.core.modules.eql.jxb.eqlagent.Property;
import com.queplix.core.utils.dao.AbstractPropertyFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * EQL agent factory.
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.2 $ $Date: 2005/10/26 14:03:51 $
 */

public final class EQLAgentFactory
        extends AbstractPropertyFactory {

    // =================================================== Constants and fields

    // Single instance.
    private static final EQLAgentFactory o = new EQLAgentFactory();
    // Config file name.
    private static final String CONFIG_FILE = "eqlagent.xml";

    private Map map = new HashMap();

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

    private EQLAgentFactory() {
        try {

            // Init EqlAgent XML config.
            Eqlagents eqlagents = (Eqlagents) loadSysPropertiesAsObject(
                    CONFIG_FILE, Eqlagents.class);

            // Init map of EqlAgent objects for each binding element.
            for(int i = 0; i < eqlagents.getEqlagentCount(); i++) {
                Eqlagent eqlagent = eqlagents.getEqlagent(i);
                String name = eqlagent.getName();
                String className = eqlagent.getEqlagentclass();
                Binding[] bindings = eqlagent.getBinding();
                Property[] properties = eqlagent.getProperty();

                for(int j = 0; j < bindings.length; j++) {
                    Binding binding = bindings[j];
                    String bindSchemaName = binding.getEntityschema();

                    INFO("Try to init EqlAgent: " + name + ", class: "
                            + className +
                            ", binding: " + bindSchemaName);

                    // .. getting entity schema
                    EntitySchema schema = EntitySchemaFactory.getInstance().get(
                            bindSchemaName);

                    // .. create new object
                    EQLAgent eqlAgent = (EQLAgent) Class.forName(className)
                            .newInstance();

                    // .. set schema and property
                    eqlAgent.init(schema, properties);

                    // .. remember reference
                    map.put(bindSchemaName, eqlAgent);
                }
            }

        } catch (Exception e) {
            ERROR(e);
            throw new GenericSystemException(
                    "Cannot init Eqlagents: " + e.getMessage(), e);
        }
    }

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

    /**
     * EQL agent instance getter.
     *
     * @param req EQLReq object
     * @return EQL Agent object
     */
    public EQLAgent getEQLAgent(EQLReq req) {

        Entity baseEntity;
        if(req instanceof EQLEReq) {
            // take schema name from the base entity
            baseEntity = ((EQLEReq) req).getEntity();
        } else {
            // take schema name from the entity of the first field in request
            baseEntity = req.getSelect().getAttr(0).getReqField().getReqEntity()
                    .getEntity();
        }

        return getEQLAgent(baseEntity);
    }

    /**
     * EQL agent instance getter.
     *
     * @param res EQLRes object
     * @return EQL Agent object
     */
    public EQLAgent getEQLAgent(EQLRes res) {
        if(res instanceof EQLERes) {
            // take schema name from the base entity
            return getEQLAgent(((EQLERes) res).getEntity());
        } else {
            // take schema name from the request
            return getEQLAgent(res.getMetaData().getReq());
        }
    }

    /**
     * EQL agent instance getter.
     *
     * @param entity Entity object
     * @return EQL Agent object
     */
    public EQLAgent getEQLAgent(Entity entity) {
        String schemaName = entity.getDbschema();
        EntitySchema schema = EntitySchemaFactory.getInstance().get(schemaName);
        EQLAgent agent = (EQLAgent) map.get(schema.getSchemaName());
        if(agent == null) {
            throw new GenericSystemException(
                    "Cannot get EQLAgent by the schema name '" + schemaName
                            + "'");
        }
        return agent;
    }

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

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