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

import com.queplix.core.integrator.security.AccessRightsManager;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.integrator.security.WebLoginManager;
import com.queplix.core.jxb.entity.Entity;
import com.queplix.core.modules.eql.EQLEReq;
import com.queplix.core.modules.eql.EQLObject;
import com.queplix.core.modules.eql.EQLReq;
import com.queplix.core.modules.eql.EQLReqSelect;
import com.queplix.core.modules.eql.EQLRes;
import com.queplix.core.modules.eql.EQLResMetaData;
import com.queplix.core.modules.eql.EQLResRecord;
import com.queplix.core.modules.eql.EQLSql;
import com.queplix.core.modules.eql.ejb.EQLManagerLocal;
import com.queplix.core.modules.eql.ejb.EQLManagerLocalHome;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.SystemHelper;
import com.queplix.core.utils.www.AbstractServlet;

import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * Executes any EQL queries.
 *
 * @author Andrey L. Baranov [ALB]
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:34 $
 */

public class EqlServlet
        extends AbstractServlet {

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

    private static final int MAX_RECORDS = 200;

    // ===================================================== Servlet API methods

    /* (non-Javadoc)
     * @see HTTPServlet#service(HttpServletRequest, HttpServletResponse)
     */

    public void service(HttpServletRequest request,
                        HttpServletResponse response)
            throws ServletException, IOException {

        // Check if the servlet is run from the localhost
        if(!request.getRemoteAddr().equalsIgnoreCase("127.0.0.1")) {
            throw new ServletException("Cannot use this servlet.");
        }

        // Check permissions.
        if(SystemHelper.isProductionMode()) {
            // [TN] {
            // check availability in production mode
            if(!new Boolean(this.getInitParameter("allowInProductionMode"))
                    .booleanValue()) {
                throw new ServletException(
                        "Cannot use this servlet in production mode");
            }
            // [TN] }
        }

        // Get parameters.
        String eql = request.getParameter("eql");
        if(eql == null) {
            eql = "";
        }

        String page = request.getParameter("page");
        if(page == null) {
            page = "0";
        }

        String pageSize = request.getParameter("pageSize");
//        if( pageSize == null ) {
//            pageSize = "20";
//        }

        String metaData = request.getParameter("metaData");
        if(metaData == null) {
            metaData = "";
        }

        String typeS = request.getParameter("type");
        if(typeS == null) {
            typeS = "select";
        }
        boolean isSelectMode = typeS.equalsIgnoreCase("select");
        boolean isAggregateMode = typeS.equalsIgnoreCase("aggregate");
        boolean isNewMode = typeS.equalsIgnoreCase("new");

        // Initialization
        LogonSession ls = null;
        String result = null;

        // Log in.
        try {
            ls = WebLoginManager.getLogonSession(request);
        } catch (Exception ex1) {
            ls = AccessRightsManager.getSystemLogonSession();
        }

        if(!StringHelper.isEmpty(eql)) {
            String fullEQL;
            if(isSelectMode) {
//                fullEQL = "SELECT /* page=" + page + ", pageSize=" + pageSize + ", " + metaData + " */ " + eql;
                fullEQL = "SELECT /* page=" + page;
                if(!StringHelper.isEmpty(pageSize)) {
                    fullEQL += ", pageSize=" + pageSize;
                }

                if(!StringHelper.isEmpty(metaData)) {
                    fullEQL += ", " + metaData;
                }

                fullEQL += " */ " + eql;
            } else if(isAggregateMode) {
                fullEQL = "AGGREGATE " + eql;
            } else {
                fullEQL = "NEW " + eql;
            }
            result = executeQuery(ls, fullEQL);
        } else {
            result = "<b>EMPTY</b>";
        }

        // Set HTTP headers.
        response.setContentType("text/html");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        // Print data.
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<body>");
        out.println("<form method=post action=eql>");
        out.println("<table border=0 cellspacing=4 cellpadding=0  width=800>");
        out.println("<tr>");
        out.println("<td><input type=radio name=type value=select "
                + (isSelectMode ? "checked":"") + "/></td>");
        out.println("<td align=left width='100%'>");
        out.println("<label><b>SELECT /* page=</b></label>");
        out.println("<input name=page type=text size=5 maxlength=10 value=\""
                + page + "\"/>");
        out.println("<label><b>,</b></label>");
        out.println("<label><b>pageSize=</b></label>");
        out.println(
                "<input name=pageSize type=text size=5 maxlength=10 value=\""
                        + (pageSize != null ? pageSize:"") + "\"/>");
        out.println("<label><b>,</b></label>");
        out.println("<input name=metaData type=text size=50 value=\""
                + (metaData != null ? metaData:"") + "\"/>");
        out.println("<label><b>*/</b></label>");
        out.println("</td>");
        out.println("</tr>");
        out.println("<tr>");
        out.println(
                "<td><input type=radio name=type value=aggregate "
                        + (isAggregateMode ? "checked":"")
                        + "/></td>");
        out.println("<td align=left>");
        out.println("<label><b>AGGREGATE</b></label>");
        out.println("</td>");
        out.println("</tr>");
        out.println("<tr>");
        out.println("<td><input type=radio name=type value=new "
                + (isNewMode ? "checked":"") + "/></td>");
        out.println("<td align=left>");
        out.println("<label><b>NEW</b></label>");
        out.println("</td>");
        out.println("</tr>");
        out.println(
                "<tr><td colspan=2 style=width:100%><textarea name=eql style=width:100%;height:300>");
        out.println(eql);
        out.println("</textarea></td></tr>");
        out.println("<tr><td><input type=submit value=Go></td></tr>");
        out.println("<tr><td colspan=2 style=width:100%>");
        out.println(result);
        out.println("</td></tr>");
        out.println("</table>");
        out.println("</form>");
        out.println("</body>");
        out.println("</html>");
    }

    // ========================================================= Private methods

    // Executes the given EQL query.

    private String executeQuery(LogonSession ls, String eql) {

        // Initialization.
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        StringBuffer sb = new StringBuffer();

        try {

            InitialContext context = new InitialContext();
            EQLManagerLocalHome home = (EQLManagerLocalHome) context.lookup(
                    JNDINames.EQLManager);
            EQLManagerLocal eqlManager = home.create();

            EQLRes res = eqlManager.select(ls, eql);

            EQLResMetaData metaData = res.getMetaData();
            EQLReq req = metaData.getReq();
            Entity baseEntity = null;
            if(req instanceof EQLEReq) {
                baseEntity = ((EQLEReq) req).getEntity();
            }

            if(baseEntity != null) {
                sb.append("<br><label>");
                sb.append("Base entity: ").append(baseEntity.getName());
                sb.append("</label><br>");
            }
            sb.append("<br><label><pre>").append("EQL: ").append(
                    StringHelper.escape(eql.trim())).append(
                    "</pre></label><br>");
            EQLSql eqlSql = metaData.getEQLSql();
            if(eqlSql != null) {
                sb.append("<br><label><pre>").append("SQL: ").append(
                        StringHelper.escape((eqlSql.getMainSql() == null) ? ""
                                :eqlSql.getMainSql().trim())).append(
                        "</pre></label><br>");
                for(int i = 0; i < eqlSql.datasetEqlSqlSize(); i++) {
                    EQLSql _eqlSql = eqlSql.getDatasetEqlSql(i);
                    sb.append("<br><label>");
                    sb.append(" Dataset [" + i + "] SQL: ").append((
                            _eqlSql.getMainSql() == null) ? ""
                            :_eqlSql.getMainSql());
                    sb.append("</label><br>");
                }
            }
            sb.append("<br><br>");
            sb.append(buildTable(res));

        } catch (Exception ex) {
            ex.printStackTrace();
            sb = new StringBuffer();
            sb.append(
                    "<textarea style=\"width:100%;height:300\" name=\"error\">");
            sb.append(StringHelper.escape(ex.getMessage())).append(
                    "</textarea>");
        }

        return sb.toString();

    }

    // Builds the HTML table for data.
    private static String buildTable(EQLRes res) {

        StringBuffer sb = new StringBuffer();

        EQLResMetaData metaData = res.getMetaData();
        EQLReq req = metaData.getReq();
        EQLSql eqlSql = metaData.getEQLSql();

        int size = res.size();
        if(size > 0) {
            sb.append("<table border=\"1\"><tr>");
            EQLReqSelect reqSelect = req.getSelect();
            int selsize = reqSelect.size();
            for(int i = 0; i < selsize; i++) {
                String id = reqSelect.getAttr(i).getId();
                sb.append("<td><b>").append(id).append("</b></td>");
            }
            if(eqlSql != null) {
                for(int i = 0; i < eqlSql.datasetEqlSqlSize(); i++) {
                    String id = "[dataset" + i + "]";
                    sb.append("<td><b>").append(id).append("</b></td>");
                }
            }
            sb.append("</tr>");

            for(int i = 0; i < size; i++) {
                sb.append("<tr>");
                EQLResRecord record = res.getRecord(i);
                int recsize = record.size();
                for(int j = 0; j < recsize; j++) {
                    EQLObject obj = record.getEQLObject(j);
                    EQLObject listObj = record.getEQLListObject(j);

                    Object o;
                    if(listObj != null) {
                        o = listObj.getObject();
                    } else {
                        o = obj.getObject();
                    }

                    sb.append("<td>");

                    if(o instanceof char[]) {
                        sb.append("<pre>");
                        sb.append(StringHelper.escape(new String((char[]) o)));
                        sb.append("</pre>");
                    } else {
                        sb.append(StringHelper.escape("" + o));
                    }

                    sb.append("</td>");
                }
                if(eqlSql != null) {
                    for(int j = 0; j < eqlSql.datasetEqlSqlSize(); j++) {
                        EQLRes datasetRes = record.getDRes(j);
                        sb.append("<td>");
                        sb.append(buildTable(datasetRes));
                        sb.append("</td>");
                    }
                }
                sb.append("</tr>");
            }
            sb.append("</table>");

        } else {
            sb.append("<textarea style=\"width:100%\" name=\"empty\">");
            sb.append("No result set...").append("</textarea>");
        }

        return sb.toString();
    }
}
