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

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.jxb.entity.Efield;
import com.queplix.core.jxb.entity.Entity;
import com.queplix.core.modules.config.ejb.CustomConfigManagerLocal;
import com.queplix.core.modules.config.ejb.CustomConfigManagerLocalHome;
import com.queplix.core.modules.config.jxb.CustomField;
import com.queplix.core.modules.config.utils.EntityHelper;
import com.queplix.core.modules.eql.EQLERes;
import com.queplix.core.modules.eql.EQLNullObject;
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.error.EQLException;
import com.queplix.core.modules.eql.error.UserQueryParseException;
import com.queplix.core.modules.jeo.JEObjectHandler;
import com.queplix.core.modules.jeo.ejb.JEOManagerLocal;
import com.queplix.core.modules.jeo.ejb.JEOManagerLocalHome;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.async.ASyncObject;
import com.queplix.core.utils.async.ASyncRequest;
import com.queplix.core.utils.cache.CacheObjectManager;
import com.queplix.core.utils.log.AbstractLogger;

import java.io.Serializable;

/**
 * Base class for all entity update handlers.
 *
 * @author [ALB] Baranov L. Andrey
 * @author [ONZ] Oleg N. Zhovtanyuk
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:32 $
 */

public abstract class EntityUpdate
        extends AbstractLogger
        implements Serializable, ASyncObject {

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

    /**
     * Update status: Continue update process
     */
    public static final int CONTINUE = 0;

    /**
     * Update status: Skip update record process
     */
    public static final int SKIP_RECORD = 1;

    /**
     * Update status: Skip entire update process
     */
    public static final int SKIP_ALL = 2;

    // Empty values (for convenience).
    protected static final String EMPTY_VALUE = StringHelper.EMPTY_VALUE;
    protected static final byte EMPTY_NUMBER = StringHelper.EMPTY_NUMBER;

    /**
     * Value object for an asynchronous update request.
     */
    public static final ASyncRequest UPDATE_REQUEST_FLAG
            = new EntityUpdateAsyncRequest(0);

    /**
     * Value object for an asynchronous delete request.
     */
    public static final ASyncRequest DELETE_REQUEST_FLAG
            = new EntityUpdateAsyncRequest(1);

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

    // Update data object.
    private EntityUpdateObject euo;

    // ============================================== Update scripts API methods

    /**
     * After-new handler.
     *
     * @throws EQLException
     */
    public void afterNew()
            throws EQLException {
    }

    /**
     * Before-update handler.
     *
     * @return update status
     * @throws EQLException
     */
    public int beforeUpdate()
            throws EQLException {
        return CONTINUE;
    }

    /**
     * After-update handler.
     *
     * @throws EQLException
     */
    public void afterUpdate()
            throws EQLException {
    }

    /**
     * Custom update handler.
     *
     * @return update status
     * @throws EQLException
     */
    public int update()
            throws EQLException {
        return CONTINUE;
    }

    /**
     * Before-delete handler.
     *
     * @return update status
     * @throws EQLException
     */
    public int beforeDelete()
            throws EQLException {
        return CONTINUE;
    }

    /**
     * Delete handler.
     *
     * @return update status
     * @throws EQLException
     */
    public int delete()
            throws EQLException {
        return CONTINUE;
    }

    /**
     * After-delete handler.
     *
     * @throws EQLException
     */
    public void afterDelete()
            throws EQLException {
    }

    /**
     * Make async process.
     *
     * @param request async request
     */
    public final void process(ASyncRequest request) {

        // Check request.
        if(request == null) {
            throw new NullPointerException("Got NULL request");
        }

        // Update / delete switch.
        if(request.equals(UPDATE_REQUEST_FLAG)) {
            try {
                afterUpdate();
            } catch (EQLException ex) {
                throw new GenericSystemException(ex);
            }
        } else if(request.equals(DELETE_REQUEST_FLAG)) {
            try {
                afterDelete();
            } catch (EQLException ex) {
                throw new GenericSystemException(ex);
            }
        } else {
            throw new IllegalStateException("Unknown request type");
        }
    }

    // Get string.
    public String toString() {
        return "euo=" + euo;
    }

    // ========================================================== Helper methods

    /**
     * Checks for add / update mode.
     *
     * @return true for add mode
     */
    protected boolean isNew() {
        return euo.getRecord().isNew();
    }

    /**
     * EntityUpdateObject getter.
     *
     * @return EntityUpdateObject
     */
    protected final EntityUpdateObject getEUO() {
        return euo;
    }

    /**
     * EntityUpdateObject setter.
     *
     * @param euo EntityUpdateObject
     */
    protected final void setEUO(EntityUpdateObject euo) {
        this.euo = euo;
    }

    /**
     * Cache Object Manager EJB getter.
     *
     * @return Cache Object Manager reference
     */
    protected CacheObjectManager getCOM() {
        return euo.getSession().getCOM();
    }

    /**
     * Gets the user logon session.
     *
     * @return user logon session
     */
    protected LogonSession getLogonSession() {
        return euo.getSession().getLogonSession();
    }

    /**
     * Get EQLResCell by the name. If cell not found create new with NULL object.
     *
     * @param name cell name
     * @return EQLResCell object
     */
    protected EQLResCell getCell(String name) {

        Entity entity = euo.getEntity();
        Efield field = EntityHelper.getEfield(name, entity);
        EQLReqField reqField = new EQLReqField(entity, field);

        // Get EQLResCell from EQLResRecord. Create, if not found.
        EQLResRecord resRecord = euo.getRecord();
        EQLResCell resCell = resRecord.getResCell(reqField);
        if(resCell == null) {
            resCell = new EQLResCell(reqField, EQLNullObject.getInstance());
            resRecord.insertData(resCell);
        }

        // Ok.
        return resCell;

    }

    /**
     * Gets a JEO handler for current record.
     *
     * @param hndClass JEO handler class
     * @return JEObjectHandler object
     */
    protected JEObjectHandler getJEOHandler(Class hndClass) {
        JEOManagerLocal jeoManager = (JEOManagerLocal)
                getCOM().getLocalObject(JNDINames.JEOManager,
                        JEOManagerLocalHome.class);
        return getJEOHandler(jeoManager, hndClass);
    }

    /**
     * Gets a JEO handler for current record.
     *
     * @param jeoManager JEO Manager EJB reference
     * @param hndClass   JEO handler class
     * @return JEObjectHandler object
     */
    protected JEObjectHandler getJEOHandler(JEOManagerLocal jeoManager,
                                            Class hndClass) {
        LogonSession ls = euo.getSession().getLogonSession();
        EQLERes res = euo.getResponse();
        EQLResRecord resRecord = euo.getRecord();
        return jeoManager.getJEO(ls, res, resRecord, hndClass);
    }

    /**
     * Gets the entity field old value.
     * If the value was not changed, returns its current (new) value.
     *
     * @param fieldName entity field name
     * @return object with the field old value
     */
    protected Object getOldValue(String fieldName) {
        return getCell(fieldName).getOldEQLObject().getObject();
    }

    /**
     * Gets the entity field new value.
     *
     * @param fieldName entity field name
     * @return object with the field new value
     */
    protected Object getNewValue(String fieldName) {
        return getCell(fieldName).getEQLObject().getObject();
    }

    /**
     * Check if a field is changed.
     *
     * @param name entity field name
     * @return <b>true</b> if the field is changed
     */
    protected boolean isValueChanged(String name) {
        return getCell(name).isValueChanged();
    }

    /**
     * Checks the string for emptiness.
     *
     * @param str given string
     * @return true for <code>null</code> or empty string
     */
    protected boolean isEmpty(String str) {
        return StringHelper.isEmpty(str);
    }

    /**
     * Checks the chars for emptiness.
     *
     * @param cc given array of chars
     * @return true for <code>null</code> or empty char array
     */
    protected boolean isEmpty(char[] cc) {
        return StringHelper.isEmpty(cc);
    }

    /**
     * Compares two strings.
     * Makes no difference between the null values and empty strings.
     *
     * @param s1 First string.
     * @param s2 Second string.
     * @return true, if the strings are equal.
     */
    protected boolean cmp(String s1, String s2) {
        return StringHelper.cmp(s1, s2);
    }

    /**
     * Throws UserQueryParseException exception.
     *
     * @param fieldName Efield name
     * @param value     incorrect field value
     * @param comments  optional comment
     * @throws UserQueryParseException
     */
    protected void throwUserQueryParseException(String fieldName,
                                                String value,
                                                String comments)
            throws UserQueryParseException {

        Entity entity = euo.getEntity();
        String entityName = entity.getName();
        String langID = euo.getSession().getLogonSession().getUser()
                .getLangID();

        CustomConfigManagerLocal customManager =
                (CustomConfigManagerLocal) getCOM().getLocalObject(
                        JNDINames.CustomConfigManager,
                        CustomConfigManagerLocalHome.class);

        CustomField customField = customManager.getLocalizedCustomField(langID,
                entityName, fieldName);
        String caption = customField.getCaption();

        throw new UserQueryParseException(value, entityName, caption, comments);
    }

    /*
     * No javadoc
     * @see #throwUserQueryParseException(String,String,String)
     */
    protected void throwUserQueryParseException(String fieldName, String value)
            throws UserQueryParseException {
        throwUserQueryParseException(fieldName, value, null);
    }

    // ============================================================= Inner class

    /**
     * Special async request.
     *
     * @author [ALB] Baranov Andrey
     * @author [ONZ] Oleg N. Zhovtanyuk
     * @version 1.0
     */
    public static class EntityUpdateAsyncRequest
            implements ASyncRequest {

        private int i;

        private EntityUpdateAsyncRequest(int i) {
            this.i = i;
        }

        public int hashCode() {
            return i;
        }

        public boolean equals(Object o) {
            return (o instanceof EntityUpdateAsyncRequest) &&
                    (i == ((EntityUpdateAsyncRequest) o).i);
        }
    }
}
