package com.atlassian.confluence.extra.workflow;

import com.atlassian.user.User;

import java.util.*;

import bucket.user.UserAccessor;
import bucket.container.ContainerManager;

/**
 * Created by IntelliJ IDEA.
 * User: Tomd
 * Date: 3/05/2005
 * Time: 17:52:00
 * To change this template use File | Settings | File Templates.
 */
public class DefaultWorkflowType implements WorkflowType
{
    private String name;
    private Map operationsMap = new HashMap();
    private List triggers = new ArrayList();


    private String description;
    private Map stateMap = new HashMap();
    private State notStarted;
    private Set participatingGroups = new HashSet();
    private String[] roles;
    private Collection actionTypes;
    private Collection triggerTypes;
    private UserAccessor userAccessor;

    public DefaultWorkflowType(String name, String description, List states, List operations, List triggers, List groups, List roles, List actionTypes, List triggerTypes)
    {
        this(name,
                description,
                (State[]) states.toArray(new State[states.size()]),
                (Operation[]) operations.toArray(new Operation[operations.size()]),
                (Trigger[]) triggers.toArray(new Trigger[triggers.size()]),
                (String[]) groups.toArray(new String[groups.size()]),
                (String[]) roles.toArray(new String[roles.size()]),
                (ActionType[]) actionTypes.toArray(new ActionType[actionTypes.size()]),
                (TriggerType[]) triggerTypes.toArray(new TriggerType[triggerTypes.size()])
        );
    }

    public DefaultWorkflowType(String name, String description, State[] states, Operation[] operations, Trigger[] triggers,
                               String[] groups, String[] roles, ActionType[] actionTypes, TriggerType[] triggerTypes)
    {
        this.name = name;
        this.description = description;
        for (int i = 0; i < operations.length; ++i)
        {
            operationsMap.put(operations[i].getName(), operations[i]);
        }
        operationsMap.put(PageViewOperation.OPERATION_NAME, new PageViewOperation());
        operationsMap.put(PageEditOperation.OPERATION_NAME, new PageEditOperation());
        this.triggers = new ArrayList(Arrays.asList(triggers));
        for (int i = 0; i < triggers.length; ++i)
        {
            ((Trigger) this.triggers.get(i)).setOwner(this);
            ((Trigger) this.triggers.get(i)).setId(i);
        }
        for (int i = 0; i < states.length; ++i)
        {
            stateMap.put(states[i].getId(), states[i]);
        }
        this.notStarted = new State(name, "NOT_STARTED", "Workflow Not Started", null);
        stateMap.put(notStarted.getId(), notStarted);
        participatingGroups.addAll(Arrays.asList(groups));
        this.roles = roles;
        this.actionTypes = Arrays.asList(actionTypes);
        this.triggerTypes = Arrays.asList(triggerTypes);
    }

    public String getName()
    {
        return name;
    }

    public Map getAvailableOperations(WorkflowClient client, User user)
    {
        Map ops = new HashMap();
        State currentState = client.getState();
        if (currentState.equals(notStarted))
        {
            ops.put("init", new DefaultOperation(new Condition[]{}, "init", "Start Workflow"));
        }
        else
        {
            for (Iterator i = operationsMap.values().iterator(); i.hasNext();)
            {
                Operation o = (Operation) i.next();
                if (o.availableToUserAndClient(user, client))
                {
                    ops.put(o.getName(), o);
                }
            }
        }
        return ops;
    }

    public void deleteOperation(String name)
    {
        operationsMap.remove(name);
    }

    public void addOperation(Operation operation)
    {
        operationsMap.put(operation.getName(), operation);
    }

    public void operationPerformed(Operation op, WorkflowClient client, User user)
    {
        for (int i = 0; i < triggers.size(); ++i)
        {
            ((Trigger) triggers.get(i)).clientDidOperation(op, client, user);
        }
    }

    public String getDescription()
    {
        return description;
    }

    public void setDescription(String description)
    {
        this.description = description;
    }

    public State getStateById(String stateId)
    {
        return (State) stateMap.get(stateId);
    }

    public boolean isUserParticipating(User user)
    {
        for (Iterator i = getUserAccessor().getGroups(user).iterator(); i.hasNext();)
        {
            String g = (String) i.next();
            if (participatingGroups.contains(g))
            {
                return true;
            }
        }
        return false;
    }

    private UserAccessor getUserAccessor()
    {
        if (userAccessor == null)
            userAccessor = (UserAccessor) ContainerManager.getComponent("userAccessor");

        return userAccessor;
    }

    public List getInitActions()
    {
        return getInitTrigger().getActions();
    }

    public Trigger getInitTrigger()
    {
        for (int i = 0; i < triggers.size(); ++i)
        {
            if (triggers.get(i) instanceof SingleEventTrigger)
            {
                SingleEventTrigger set = (SingleEventTrigger) triggers.get(i);
                if (set.getEvent().equals("init"))
                {
                    return set;
                }
            }
        }
        return null;
    }

    public Collection getNonInitOperations()
    {
        return operationsMap.values();
    }

    public List getNonInitTriggers()
    {
        List l = new ArrayList();
        for (int i = 0; i < triggers.size(); ++i)
        {
            if (!(triggers.get(i) instanceof SingleEventTrigger) || ((SingleEventTrigger) triggers.get(i)).getEvent() == null || !((SingleEventTrigger) triggers.get(i)).getEvent().equals("init"))
            {
                l.add(triggers.get(i));
            }
        }
        return l;
    }

    public List getTriggers()
    {
        return triggers;
    }

    public void deleteTrigger(int id)
    {
        triggers.remove(id);
        for (int i = 0; i < triggers.size(); ++i)
        {
            Trigger t = (Trigger) triggers.get(i);
            t.setId(i);
        }
    }

    public void addTrigger(Trigger trigger)
    {
        triggers.add(trigger);
        trigger.setId(triggers.size() - 1);
        trigger.setOwner(this);
    }

    public Collection getTriggerTypes()
    {
        return triggerTypes;
    }

    public Trigger getTriggerById(int id)
    {
        for (int i = 0; i < triggers.size(); ++i)
        {
            if (((Trigger) triggers.get(i)).getId() == id)
            {
                return (Trigger) triggers.get(i);
            }
        }
        return null;
    }


    public Operation getOperationByName(String name)
    {
        return (Operation) operationsMap.get(name);
    }

    public Collection getStates()
    {
        return stateMap.values();
    }

    public Collection getRoles()
    {
        return Arrays.asList(roles);
    }

    public Collection getGroups()
    {
        return participatingGroups;
    }

    public Collection getActionTypes()
    {
        return actionTypes;
    }
}
