/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.app.xmlui.aspect.xmlworkflow.admin;

import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.log4j.Logger;
import org.dspace.app.util.Util;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.ContextUtil;
import org.dspace.app.xmlui.utils.UIException;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.*;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.handle.HandleManager;
import org.dspace.xmlworkflow.WorkflowConfigurationException;
import org.dspace.xmlworkflow.WorkflowFactory;
import org.dspace.xmlworkflow.state.Step;
import org.dspace.xmlworkflow.state.Workflow;
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.sql.SQLException;
import java.util.*;

/**
 * A transformer that renders all xmlworkflow items
 * and allows for the admin to either delete them or send
 * them back to the submitter
 *
 * @author Bram De Schouwer (bram.deschouwer at dot com)
 * @author Kevin Van de Velde (kevin at atmire dot com)
 * @author Ben Bosman (ben at atmire dot com)
 * @author Mark Diggory (markd at atmire dot com)
 */
public class WorkflowOverviewTransformer extends AbstractDSpaceTransformer {


    private static final Logger log = Logger.getLogger(WorkflowOverviewTransformer.class);
    private static final int[] RESULTS_PER_PAGE_PROGRESSION = {5, 10, 20, 40, 60, 80, 100};


    private static final Message T_dspace_home =
        message("xmlui.general.dspace_home");

    private static final Message T_trail =
        message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.trail");

    private static final Message T_title =
        message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.title");
    private static final Message T_go = message("xmlui.general.go");
    private static final Message T_head = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.title");
    
    private static final Message T_search_column1 = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.search_column1");
    private static final Message T_search_column2 = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.search_column2");
    private static final Message T_search_column3 = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.search_column3");
    private static final Message T_search_column4 = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.search_column4");
    private static final Message T_search_column5 = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.search_column5");
    private static final Message T_button_back_to_submitter = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.button.submit_submitter");
    private static final Message T_button_delete = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.button.submit_delete");
    private static final Message T_no_results = message("xmlui.XMLWorkflow.WorkflowOverviewTransformer.button.no_results");


    /**
     * Add Page metadata.
     */
    public void addPageMeta(PageMeta pageMeta) throws WingException, SQLException
    {
        pageMeta.addMetadata("title").addContent(T_title);
        pageMeta.addTrailLink(contextPath + "/", T_dspace_home);

        pageMeta.addTrail().addContent(T_trail);
    }


    public void addBody(Body body) throws SAXException, WingException, SQLException, IOException, AuthorizeException {
        Context context = ContextUtil.obtainContext(ObjectModelHelper.getRequest(objectModel));
        if(!AuthorizeManager.isAdmin(context)){
            throw new AuthorizeException();
        }
        
        Division div = body.addInteractiveDivision("xmlworkflowoverview", contextPath + "/admin/xmlworkflowoverview", Division.METHOD_POST, "primary");
        this.buildSearchResultsDivision(div);
    }


    /**
     * Attach a division to the given search division named "search-results"
     * which contains results for this search query.
     *
     * @param div The division to contain the results division.
     */
    protected void buildSearchResultsDivision(Division div)
            throws IOException, SQLException, WingException, AuthorizeException {
        int pageSize = getParameterRpp();
        int page = getParameterPage();
        try {
            Request request = ObjectModelHelper.getRequest(objectModel);
            int collectionIdFilter = Util.getIntParameter(request, "filter_collection");

            XmlWorkflowItem[] results = XmlWorkflowItem.findAllInCollection(context, page, pageSize, collectionIdFilter);
            Para para = div.addPara("result-query", "result-query");

            int hitCount = XmlWorkflowItem.countAllInCollection(context, collectionIdFilter);
            para.addContent(message("").parameterize("", hitCount));


            div.setHead(T_head);
            this.buildSearchControls(div);

            Division resultsDiv = div.addDivision("search-results", "primary");

            if (hitCount > 0) {
                // Pagination variables.
                int firstItemIndex = ((page - 1) * pageSize) + 1;
                int lastItemIndex = (page - 1) * pageSize + results.length;
                if (hitCount < lastItemIndex) {
                    lastItemIndex = hitCount;
                }
                int pagesTotal = ((hitCount - 1) / pageSize) + 1;
                Map<String, String> parameters = new HashMap<String, String>();
                parameters.put("page", "{pageNum}");
                String pageURLMask = generateURL(parameters);

                resultsDiv.setMaskedPagination(hitCount, firstItemIndex,
                        lastItemIndex, page, pagesTotal, pageURLMask);


                // Look for any items in the result set.
                Table table = resultsDiv.addTable("workflow-item-overview-table", results.length + 1, 5);

                Row headerRow = table.addRow(Row.ROLE_HEADER);
                headerRow.addCellContent(T_search_column1);
                headerRow.addCellContent(T_search_column2);
                headerRow.addCellContent(T_search_column3);
                headerRow.addCellContent(T_search_column4);
                headerRow.addCellContent(T_search_column5);


                for (XmlWorkflowItem wfi : results) {
                    Item item = wfi.getItem();
                    Row itemRow = table.addRow();

                    java.util.List<PoolTask> pooltasks = PoolTask.find(context,wfi);
                    java.util.List<ClaimedTask> claimedtasks = ClaimedTask.find(context, wfi);

                    Message state = message("xmlui.XMLWorkflow.step.unknown");
                    for(PoolTask task: pooltasks){
                        Workflow wf = WorkflowFactory.getWorkflow(wfi.getCollection());
                        Step step = wf.getStep(task.getStepID());
                        state = message("xmlui.XMLWorkflow." + wf.getID() + "." + step.getId());
                    }
                    for(ClaimedTask task: claimedtasks){
                        Workflow wf = WorkflowFactory.getWorkflow(wfi.getCollection());
                        Step step = wf.getStep(task.getStepID());
                        state = message("xmlui.XMLWorkflow." + wf.getID() + "." + step.getId());
                    }


                    //Column 0 task Checkbox to delete
                    itemRow.addCell().addCheckBox("workflow_id").addOption(wfi.getID());

                    //Column 1 task Step
                    itemRow.addCellContent(state);
                    //Column 2 Item name
                    itemRow.addCell().addXref(request.getContextPath() + "/admin/display-workflowItem?wfiId=" +wfi.getID(), item.getName() );
                    //Column 3 collection
                    itemRow.addCell().addXref(HandleManager.resolveToURL(context, wfi.getCollection().getHandle()), wfi.getCollection().getName());
                    //Column 4 submitter
                    itemRow.addCell().addXref("mailto:" + wfi.getSubmitter().getEmail(), wfi.getSubmitter().getFullName());



                }

                Para buttonsPara = resultsDiv.addPara();
                buttonsPara.addButton("submit_submitter").setValue(T_button_back_to_submitter);
                buttonsPara.addButton("submit_delete").setValue(T_button_delete);

            } else {
                resultsDiv.addPara(T_no_results);
            }
        } catch (WorkflowConfigurationException e) {
            log.error(LogManager.getHeader(context, "Error while displaying the admin workflow overview page", ""), e);
        }
    }


    protected int getParameterPage() {
        try {
            return Integer.parseInt(ObjectModelHelper.getRequest(objectModel).getParameter("page"));
        }
        catch (Exception e) {
            return 1;
        }
    }

    protected int getParameterRpp() {
        try {
            return Integer.parseInt(ObjectModelHelper.getRequest(objectModel).getParameter("rpp"));
        }
        catch (Exception e) {
            return 10;
        }
    }

    protected int getParameterSortBy() {
        try {
            return Integer.parseInt(ObjectModelHelper.getRequest(objectModel).getParameter("sort_by"));
        }
        catch (Exception e) {
            return 0;
        }
    }

    protected String getParameterOrder() {
        String s = ObjectModelHelper.getRequest(objectModel).getParameter("order");
        return s != null ? s : "DESC";
    }


    /**
     * Generate a url to the simple search url.
     */
    protected String generateURL(Map<String, String> parameters)
            throws UIException {
        if (parameters.get("page") == null) {
            parameters.put("page", String.valueOf(getParameterPage()));
        }

        if (parameters.get("rpp") == null) {
            parameters.put("rpp", String.valueOf(getParameterRpp()));
        }
        if(parameters.get("filter_collection")== null) {
            parameters.put("filter_collection", ObjectModelHelper.getRequest(objectModel).getParameter("filter_collection"));
        }

        return super.generateURL("xmlworkflowoverview", parameters);
    }

    protected void buildSearchControls(Division div)
            throws WingException, SQLException {

        Request request = ObjectModelHelper.getRequest(objectModel);
        Table controlsTable = div.addTable("search-controls", 1, 3);
        Row controlsRow = controlsTable.addRow(Row.ROLE_DATA);

        // Create a control for the number of records to display
        Cell rppCell = controlsRow.addCell();
        rppCell.addContent("pagesize");
        Select rppSelect = rppCell.addSelect("rpp");
        for (int i : RESULTS_PER_PAGE_PROGRESSION) {
            rppSelect.addOption((i == getParameterRpp()), i, Integer.toString(i));
        }

        Cell filterCell = controlsRow.addCell();

        // Create a drop down of the different sort columns available
        int selectedCollectionId = Util.getIntParameter(request, "filter_collection");
        filterCell.addContent("Collection filter:");
        Select sortSelect = filterCell.addSelect("filter_collection");
        sortSelect.addOption(-1 == selectedCollectionId,-1, "None");
        Collection[] collections = Collection.findAll(context);
        for (Collection collection : collections) {
            sortSelect.addOption(collection.getID() == selectedCollectionId, collection.getID(), collection.getName());
        }

        controlsRow.addCell().addButton("submit_search_controls").setValue(T_go);
    }

}
