/*
 * 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.eqlext.ejb;

import com.queplix.core.error.ErrorHelper;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.jxb.entity.Efield;
import com.queplix.core.modules.eql.CompoundKey;
import com.queplix.core.modules.eql.EQLReqField;
import com.queplix.core.modules.eql.EQLResCell;
import com.queplix.core.modules.eql.EQLResRecord;
import com.queplix.core.modules.eql.ejb.AbstractEQLSupportedEJB;
import com.queplix.core.modules.eql.error.EQLException;
import com.queplix.core.modules.eqlext.GetRecordsRes;
import com.queplix.core.modules.eqlext.actions.AbstractSRAction;
import com.queplix.core.modules.eqlext.actions.ActionContext;
import com.queplix.core.modules.eqlext.actions.GRAction;
import com.queplix.core.modules.eqlext.actions.UpdateSRAction;
import com.queplix.core.modules.eqlext.jxb.sr.ExtSreqs;
import com.queplix.core.modules.eqlext.jxb.sr.Sreq;
import com.queplix.core.modules.eqlext.jxb.sr.types.TodoSType;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.xml.XMLHelper;

import java.io.PrintWriter;
import java.io.Reader;
import java.util.Properties;

/**
 * <p>Set records session EJB</p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:39 $
 */

public class SetRecordsEJB
        extends AbstractEQLSupportedEJB {

    // ------------------ PUBLIC METHODS ---------------------

    /**
     * Initialize bean
     */
    public void ejbCreate() {
        INFO("SetRecordsEJB created - " + hashCode());
    }

    /**
     * Executes set records procedure.
     *
     * @param sreq request object
     * @param ls   logon session
     * @return GetRecordsRes object
     * @throws EQLException on EQL errors
     */
    public GetRecordsRes process(Sreq sreq, LogonSession ls)
            throws EQLException {

        // Initialization.
        long time = System.currentTimeMillis();
        GetRecordsRes res = null;

        try {
            // Do process.
            UpdateSRAction sra = doProcess(sreq, ls);

            // If Sreq 'getresponse' attribute = true
            // And if operation was not DELETE ->
            // Get first record again.
            if(sreq.getGetresponse().booleanValue() &&
                    sreq.getSreqRecord(0).getTodo().getType() != TodoSType
                            .DELETE_TYPE) {
                String entityName = sra.getEntity().getName();

                // Pkey could be changed within update operation - reread it.
                CompoundKey compoundKey = getCompoundKey(
                        sra.getEQLRes().getRecord(0));

                /** @todo set to 'false' when they fix client-side logic */
                Properties prop = new Properties();
                prop.setProperty(GRAction.IGNORE_SEND_ON_REQ_PARAM, "true");
                res = getGetRecordsLocal().process(entityName,
                        compoundKey,
                        prop,
                        ls);
            }

        } catch (EQLException ex) {
            throw ex;
        } catch (Throwable t) {
            ErrorHelper.throwSystemException(t, this);
        }

        // Ok.
        if(getLogger().isDebugEnabled()) {
            DEBUG("SetRecords EJB completed. Time (ms) = " + (
                    System.currentTimeMillis() - time));
        }
        return res;

    }

    /**
     * Execute set records procedure
     *
     * @param in  Reader object to read Sreq request
     * @param out PrintWriter object to write Ress response
     * @param sc  security config
     * @throws EQLException
     */
    public void process(Reader in, PrintWriter out, LogonSession sc)
            throws EQLException {

        long time = System.currentTimeMillis();

        // Deserialize request.
        Sreq sreq = (Sreq) XMLHelper.getParsedObject(Sreq.class, in);

        if(getLogger().isDebugEnabled()) {
            DEBUG("SetRecords request:");
            DEBUG("*******************");
            DEBUG(new String(XMLHelper.writeObject(sreq)));
            DEBUG("*******************");
        }

        try {
            // do process
            UpdateSRAction sra = doProcess(sreq, sc);

            // If Sreq 'getresponse' attribute = true
            // And if operation was not DELETE ->
            // Get first record again.
            if(sreq.getGetresponse().booleanValue() &&
                    sreq.getSreqRecord(0).getTodo().getType() != TodoSType
                            .DELETE_TYPE) {
                String entityName = sra.getEntity().getName();

                int records = sreq.getSreqRecordCount();
                CompoundKey[] compoundKeys = new CompoundKey[records];

                for(int i = 0; i < records; i++) {
                    // Pkey could be changed within update operation - reread it.
                    compoundKeys[i] = getCompoundKey(sra.getEQLRes().getRecord(
                            i));
                    if(compoundKeys[i].size() == 0) {
                        throw new NullPointerException(
                                "Cannot find key to re-read #" +
                                        i + " record after update");
                    }
                }

                Properties prop = new Properties();
                prop.setProperty(GRAction.IGNORE_SEND_ON_REQ_PARAM, "true");
                getGetRecordsLocal().process(entityName,
                        entityName,
                        compoundKeys,
                        prop,
                        out,
                        sc);
            }

        } catch (EQLException ex) {
            throw ex;

        } catch (Throwable t) {
            ErrorHelper.throwSystemException(t, this);
        }

        if(getLogger().isDebugEnabled()) {
            DEBUG("...setRecords completed time(ms)=" + (
                    System.currentTimeMillis() - time));
        }
    }

    /**
     * Execute extended set records procedure
     *
     * @param in Reader object to read ExtSreqs request
     * @param sc security config
     * @throws EQLException
     */
    public void extProcess(Reader in, LogonSession sc)
            throws EQLException {

        long time = System.currentTimeMillis();

        // Deserialize request.
        ExtSreqs extSreqs = (ExtSreqs) XMLHelper.getParsedObject(ExtSreqs.class,
                in);

        if(getLogger().isDebugEnabled()) {
            DEBUG("ExtSetRecords request:");
            DEBUG("*-*-*-*-*-*-*-*-*-*");
            DEBUG(new String(XMLHelper.writeObject(extSreqs)));
            DEBUG("*-*-*-*-*-*-*-*-*-*");
        }

        try {
            int size = extSreqs.getSreqCount();

            // Make changes
            for(int i = 0; i < size; i++) {
                Sreq sreq = extSreqs.getSreq(i);
                doProcess(sreq, sc);
            }

        } catch (EQLException ex) {
            throw ex;

        } catch (Throwable t) {
            ErrorHelper.throwSystemException(t, this);
        }

        if(getLogger().isDebugEnabled()) {
            DEBUG("...ext setRecords completed time(ms)=" + (
                    System.currentTimeMillis() - time));
        }

    }

    // ------------------ PRIVATE METHODS --------------------

    //
    // Do process
    //

    private UpdateSRAction doProcess(Sreq sreq, LogonSession sc)
            throws EQLException {

        // create context
        ActionContext ctx = new ActionContext(sc,
                getEntityViewConfigManager(),
                getFocusConfigManager(),
                getCustomConfigManager(),
                getEQLManager(),
                getUserPropertyManager());

        // Ok.
        return AbstractSRAction.process(ctx, sreq);
    }

    //
    // Initalize CompoundKey from EQLResRecord object
    //
    private CompoundKey getCompoundKey(EQLResRecord resRecord) {

        CompoundKey compoundKey = new CompoundKey();

        for(int i = 0; i < resRecord.size(); i++) {
            EQLResCell resCell = resRecord.getResCell(i);
            EQLReqField reqField = resCell.getReqField();
            Efield field = reqField.getField();
            boolean isPkey = field.getPkey().booleanValue();
            if(isPkey) {
                compoundKey.addKey(resCell.getEQLObject().getObject());
            }
        }

        return compoundKey;
    }

    //
    // Get GetRecords local interface
    //
    private GetRecordsLocal getGetRecordsLocal() {
        return (GetRecordsLocal) getLocalObject(JNDINames.GetRecords,
                GetRecordsLocalHome.class);
    }
}
