/*
 * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.cms.ui.workflow;

import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.util.Assert;
import com.arsdigita.util.GraphSet;
import com.arsdigita.util.Graphs;
import com.arsdigita.workflow.simple.Task;
import com.arsdigita.workflow.simple.TaskCollection;
import com.arsdigita.workflow.simple.Workflow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;

class TaskTableModelBuilder extends AbstractTableModelBuilder {
    public static final String versionId =
        "$Id: //cms/dev/src/com/arsdigita/cms/ui/workflow/TaskTableModelBuilder.java#10 $" +
        "$Author: dennis $" +
        "$DateTime: 2004/04/07 16:07:11 $";

    private static final Logger s_log = Logger.getLogger
        (TaskTableModelBuilder.class);

    private final WorkflowRequestLocal m_workflow;

    TaskTableModelBuilder(final WorkflowRequestLocal workflow) {
        m_workflow = workflow;
    }

    public final TableModel makeModel(final Table table,
                                      final PageState state) {
        s_log.debug("Creating a new table model for the current request");

        return new Model(m_workflow.getWorkflow(state));
    }

    private static class Model implements TableModel {
        private Task m_task;
        private Iterator m_tasks;
        private Map m_dependencies = new HashMap();

        private Model(final Workflow workflow) {
            TaskCollection tc = workflow.getTaskCollection();
            GraphSet g = new GraphSet();
            while (tc.next()) {
                Task t = tc.getTask();
                final TaskCollection deps = t.getRequiredTasks();
                final StringBuffer buffer = new StringBuffer();
                while (deps.next()) {
                    Task dep = deps.getTask();
                    g.addEdge(t, dep, null);
                    buffer.append(dep.getLabel() + ", ");
                }

                final int len = buffer.length();
                if (len >= 2) {
                    buffer.setLength(len - 2);
                } else {
                    g.addNode(t);
                }
                deps.close();
                m_dependencies.put(t, buffer.toString());
            }

            List tasks = new ArrayList();
	outer:
            while (g.nodeCount() > 0) {
                List l = Graphs.getSinkNodes(g);
                for (Iterator it = l.iterator(); it.hasNext(); ) {
                    Task t = (Task) it.next();
                    tasks.add(t);
                    g.removeNode(t);
                    continue outer;
                }
                // break loop if no nodes removed
                s_log.error("found possible loop in tasks for " + workflow);
                break;
            }
            Assert.assertEquals(workflow.getTaskCount(), tasks.size());
            m_tasks = tasks.iterator();
        }

        public final int getColumnCount() {
            return 4;
        }

        public final boolean nextRow() {
            if (m_tasks.hasNext()) {
                m_task = (Task) m_tasks.next();
                return true;
            } else {
                return false;
            }
        }

        public final Object getKeyAt(final int column) {
            return m_task.getID();
        }

        public final Object getElementAt(final int column) {
            switch (column) {
            case 0:
                return m_task.getLabel();
            case 1:
                return m_task.getDescription();
            case 2:
                return m_dependencies.get(m_task);
            case 3:
                return m_task.getStateString();
            default:
                throw new IllegalStateException();
            }
        }
    }
}
