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

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.error.IncorrectParameterException;
import com.queplix.core.integrator.security.AccessRightsManager;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.integrator.security.NoSuchGroupException;
import com.queplix.core.integrator.security.NoSuchUserException;
import com.queplix.core.integrator.security.SecurityException;
import com.queplix.core.integrator.security.User;
import com.queplix.core.integrator.security.WebLoginManager;
import com.queplix.core.integrator.security.WorkGroup;
import com.queplix.core.modules.alert.ejb.AlertManagerLocal;
import com.queplix.core.modules.alert.ejb.AlertManagerLocalHome;
import com.queplix.core.modules.alert.eql.AlertEQLAgent;
import com.queplix.core.modules.alert.utils.AlertSelectorCriteria;
import com.queplix.core.modules.config.ejb.FocusConfigManagerLocal;
import com.queplix.core.modules.config.ejb.FocusConfigManagerLocalHome;
import com.queplix.core.modules.config.jxb.Form;
import com.queplix.core.modules.config.utils.EntityHelper;
import com.queplix.core.modules.eql.CompoundKey;
import com.queplix.core.modules.eql.error.EQLException;
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.modules.jeo.gen.AlertObject;
import com.queplix.core.modules.jeo.gen.AlertObjectHandler;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.www.AbstractServlet;
import com.queplix.core.utils.www.ServletHelper;

import javax.ejb.CreateException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.SortedMap;

/**
 * <p>Helper servlet to manage alerts<p>
 * <p/>
 * <p>Returns 1 if current user has new alerts, otherwise - 0<p>
 * <strong>USAGE</strong>: <pre>GET /sys/alert/count</pre>
 * <p/>
 * <p>Create new alert(s)<p>
 * <strong>USAGE</strong>: <pre>GET /sys/alert/add?employeeId=123&message=TEST&recordId=1</pre>
 * <p><strong>Parameters</strong>:
 * <pre>     One of:
 *        toAll=true: send to all employee
 *      or..
 *        employeeId: employee id
 *      or..
 *        customerId: customer id
 *      or..
 *        workgroupId: workgroup id
 *        [tier (1,2...): workgroup tier]
 *        [toAll (true|false): send to all in workgroup or not]
 *      message: alert message
 *      severity: alert severity
 *      [form: full form name]
 *      [recordId: the unique record ID]
 *      [recordId2: the unique record composite ID]
 *      [recordId3: the unique record composite ID]
 *      [recordId4: the unique record composite ID]
 * </pre></p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:10 $
 * @see AlertEQLAgent
 */

public class AlertServlet
        extends AbstractServlet {

    // ----------------------------------------------------- methods

    //
    // Service method
    //

    public void service(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        String action = req.getPathInfo();
        if(action != null) {
            action = action.substring(1);
        } else {
            action = "";
        }

        // Perform action
        try {
            if(action.equalsIgnoreCase("count")) {
                doCountAction(req, res);
            } else if(action.equalsIgnoreCase("add")) {
                doAddAction(req, res);
            } else {
                throw new IncorrectParameterException("action", action);
            }

        } catch (SecurityException ex) {
            throw new ServletException(ex);
        }
    }

    // ----------------------------------------------------- actions

    //
    // Count alert action
    //

    private void doCountAction(HttpServletRequest req, HttpServletResponse res)
            throws ServletException,
            SecurityException,
            IOException {

        //
        // Initialization
        //

        LogonSession ls = WebLoginManager.getLogonSession(req);
        Long lastAlertId = AlertEQLAgent.getLastReadAlert(ls);

        // Search result.
        SortedMap ret;

        AlertManagerLocal local = null;
        try {
            // Create criteria.
            // Try to search one record at least.
            AlertSelectorCriteria criteria = new AlertSelectorCriteria();
            criteria.setLogonSession(ls);
            criteria.setIncomming(true);
            criteria.setPage(0);
            criteria.setPageSize(new Integer(1));
            criteria.setStartID(lastAlertId);

            // Call Alert Manager search method.
            local = getAlertManagerLocal(ls);
            ret = local.getAlerts(criteria);

        } finally {
            try {
                if(local != null) {
                    local.remove();
                }
            } catch (Exception ex) {
            }
        }

        // Print count of new alerts.
        // It must be 0 or 1.
        int count = 0;
        if(ret != null) {
            count = ret.size();
        }

        logger.DEBUG("Searching new alerts result: " + count);

        res.setContentType(ServletHelper.CONTENT_TYPE_TEXT);
        res.getWriter().print(count);
    }

    //
    // Helper method. Add alert action.
    //
    private void doAddAction(HttpServletRequest req, HttpServletResponse res)
            throws ServletException,
            SecurityException,
            IOException {

        //
        // Initialization
        //

        LogonSession ls = WebLoginManager.getLogonSession(req);

        // Alert recipients
        User recipient = null;
        WorkGroup workgroup = null;
        Integer tier = null;
        boolean toAll = false;

        String s;
        if((s = req.getParameter("employeeId")) != null) {
            //
            // Get Employee
            //
            try {
                long employeeId = Long.parseLong(s);
                recipient = loadUser(employeeId);
            } catch (NumberFormatException ex) {
                throw new GenericSystemException(
                        "Bad 'employeeId' attribute:" + s, ex);
            }

        } else if((s = req.getParameter("customerId")) != null) {
            //
            // Get Customer
            //
            try {
                long customerId = Long.parseLong(s);
                recipient = loadUser(customerId);
            } catch (NumberFormatException ex) {
                throw new GenericSystemException(
                        "Bad 'customerId' attribute:" + s, ex);
            }

        } else if((s = req.getParameter("workgroupId")) != null) {
            //
            // Get Workgroup
            //
            try {
                long workgroupId = Long.parseLong(s);
                workgroup = loadWorkgroup(workgroupId);
            } catch (NumberFormatException ex) {
                throw new GenericSystemException(
                        "Bad 'workgroupId' attribute:" + s, ex);
            }

            // get Tier
            s = req.getParameter("tier");
            if(s != null) {
                try {
                    tier = new Integer(s);
                } catch (NumberFormatException ex) {
                    throw new GenericSystemException(
                            "Bad 'tier' attribute:" + s, ex);
                }
            }

            // get toAll
            s = req.getParameter("toAll");
            if(s != null) {
                toAll = new Boolean(s).booleanValue();
            }

        } else if((s = req.getParameter("toAll")) != null &&
                new Boolean(s).booleanValue() == true) {
            //
            // Send to All. Do nothing
            //

        } else {
            throw new GenericSystemException(
                    "Please, specify recipient parameter");
        }

        // Alert message
        String message = ServletHelper.getParamAsString(req, "message");

        // Alert severity
        int severityId = ServletHelper.getParamAsInt(req, "severity");

        // Alert form
        Form form = loadForm(req.getParameter("form"));

        // Alert key
        CompoundKey recordKey = getCompoundRecordId(req);

        if(logger.getLogger().isDebugEnabled()) {
            logger.DEBUG("Try to send alert: recipient=" + recipient +
                    "; message=" + message + "; key=" + recordKey +
                    "; severityId=" + severityId + "; workgroup=" + workgroup +
                    "; tier=" + tier + "; toAll=" + toAll +
                    "; form=" + (form == null ? null:form.getName()));
        }

        //
        // Call JEO Manager.
        //

        JEOManagerLocal local = getJEOManagerLocal();
        JEObjectHandler hnd;
        try {
            hnd = local.create(ls, AlertObjectHandler.class);
        } catch (EQLException ex) {
            logger.ERROR(ex);
            throw new ServletException(ex);
        }
        AlertObject obj = (AlertObject) hnd.getJEObject();

        // Set required data.
        obj.setMessage(message);
        obj.setSeverity(severityId);

        // Set recipient.
        if(recipient != null) {
            // .. user
            obj.setRecipient_id(recipient.getUserID());
            obj.setRecipient_type(recipient.getAuthenticationType());
        } else if(workgroup != null) {
            // .. workgroup
            obj.setWorkgroup_id(workgroup.getGroupID());
            obj.setTier(tier);
            if(toAll) {
                obj.setTo_all(1);
            }
        } else {
            // .. 'To All'
            obj.setTo_all(1);
        }

        // Set Add-on data.
        if(form != null) {
            obj.setFocus_id(EntityHelper.getParentFocusName(form.getTab()));
            obj.setTab_id(form.getTab());
            obj.setForm_id(form.getName());

            int keys = recordKey.size();
            int i = 0;
            obj.setRecord_id((String) recordKey.getKey(i++));
            if(i < keys) {
                obj.setRecord_id2((String) recordKey.getKey(i++));
                if(i < keys) {
                    obj.setRecord_id3((String) recordKey.getKey(i++));
                    if(i < keys) {
                        obj.setRecord_id4((String) recordKey.getKey(i++));
                    }
                }
            }
        }

        // Commit.
        try {
            hnd.commit();
        } catch (EQLException ex) {
            logger.ERROR(ex);
            throw new ServletException(ex);
        }
    }

    // ----------------------------------------------------- private methods

    //
    // Get Form object by the name
    //

    private Form loadForm(String formName)
            throws ServletException {

        if(formName == null) {
            return null;
        }

        return getFocusConfigManagerLocal().getForm(formName);
    }

    //
    // Get employee User object
    //
    private User loadUser(long employeeId)
            throws ServletException {
        try {
            return AccessRightsManager.getUser(employeeId);
        } catch (NoSuchUserException ex) {
            throw new ServletException(ex);
        }
    }

    //
    // Get Group object
    //
    private WorkGroup loadWorkgroup(long workgroupId)
            throws ServletException {
        try {
            return AccessRightsManager.getGroup(workgroupId);
        } catch (NoSuchGroupException ex) {
            throw new ServletException(ex);
        }
    }

    //
    // Get compound record id
    //
    private CompoundKey getCompoundRecordId(HttpServletRequest req)
            throws ServletException {
        try {
            return ServletHelper.getCompoundRecordId(req);
        } catch (IncorrectParameterException ex) {
            return null;
        }
    }

    //
    // Get FocusConfigManager local interface
    //
    private FocusConfigManagerLocal getFocusConfigManagerLocal()
            throws ServletException {
        return (FocusConfigManagerLocal) getLocalObject(
                JNDINames.FocusConfigManager,
                FocusConfigManagerLocalHome.class);
    }

    //
    // Get JEO Manager local interface
    //
    private JEOManagerLocal getJEOManagerLocal()
            throws ServletException {
        return (JEOManagerLocal) getLocalObject(JNDINames.JEOManager,
                JEOManagerLocalHome.class);
    }

    //
    // Get AlertManager local interface
    //
    private AlertManagerLocal getAlertManagerLocal(LogonSession ls)
            throws ServletException {

        AlertManagerLocalHome home = (AlertManagerLocalHome)
                getLocalHome(JNDINames.AlertManager,
                        AlertManagerLocalHome.class);

        try {
            return home.create(ls);
        } catch (CreateException ex) {
            throw new GenericSystemException("Can't create AlertManager EJB.",
                    ex);
        }
    }

}
