/**
 *
 * Copyright 2003-2007 Jive Software.
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.jivesoftware.smackx.workgroup.agent;

import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

import org.jivesoftware.smackx.workgroup.QueueUser;

import org.jxmpp.jid.parts.Resourcepart;

/**
 * A queue in a workgroup, which is a pool of agents that are routed  a specific type of
 * chat request.
 */
public class WorkgroupQueue {

    private Resourcepart name;
    private Status status = Status.CLOSED;

    private int averageWaitTime = -1;
    private Date oldestEntry = null;
    private Set<QueueUser> users = Collections.emptySet();

    private int maxChats = 0;
    private int currentChats = 0;

    /**
     * Creates a new workgroup queue instance.
     *
     * @param name the name of the queue.
     */
    WorkgroupQueue(Resourcepart name) {
        this.name = name;
    }

    /**
     * Returns the name of the queue.
     *
     * @return the name of the queue.
     */
    public Resourcepart getName() {
        return name;
    }

    /**
     * Returns the status of the queue.
     *
     * @return the status of the queue.
     */
    public Status getStatus() {
        return status;
    }

    void setStatus(Status status) {
        this.status = status;
    }

    /**
     * Returns the number of users waiting in the queue waiting to be routed to
     * an agent.
     *
     * @return the number of users waiting in the queue.
     */
    public int getUserCount() {
        if (users == null) {
            return 0;
        }
        return users.size();
    }

    /**
     * Returns an Iterator for the users in the queue waiting to be routed to
     * an agent (QueueUser instances).
     *
     * @return an Iterator for the users waiting in the queue.
     */
    public Iterator<QueueUser> getUsers() {
        if (users == null) {
            return new HashSet<QueueUser>().iterator();
        }
        return Collections.unmodifiableSet(users).iterator();
    }

    void setUsers(Set<QueueUser> users) {
        this.users = users;
    }

    /**
     * Returns the average amount of time users wait in the queue before being
     * routed to an agent. If average wait time info isn't available, -1 will
     * be returned.
     *
     * @return the average wait time
     */
    public int getAverageWaitTime() {
        return averageWaitTime;
    }

    void setAverageWaitTime(int averageTime) {
        this.averageWaitTime = averageTime;
    }

    /**
     * Returns the date of the oldest request waiting in the queue. If there
     * are no requests waiting to be routed, this method will return <tt>null</tt>.
     *
     * @return the date of the oldest request in the queue.
     */
    public Date getOldestEntry() {
        return oldestEntry;
    }

    void setOldestEntry(Date oldestEntry) {
        this.oldestEntry = oldestEntry;
    }

    /**
     * Returns the maximum number of simultaneous chats the queue can handle.
     *
     * @return the max number of chats the queue can handle.
     */
    public int getMaxChats() {
        return maxChats;
    }

    void setMaxChats(int maxChats) {
        this.maxChats = maxChats;
    }

    /**
     * Returns the current number of active chat sessions in the queue.
     *
     * @return the current number of active chat sessions in the queue.
     */
    public int getCurrentChats() {
        return currentChats;
    }

    void setCurrentChats(int currentChats) {
        this.currentChats = currentChats;
    }

    /**
     * A class to represent the status of the workgroup. The possible values are:
     *
     * <ul>
     *      <li>WorkgroupQueue.Status.OPEN -- the queue is active and accepting new chat requests.
     *      <li>WorkgroupQueue.Status.ACTIVE -- the queue is active but NOT accepting new chat
     *          requests.
     *      <li>WorkgroupQueue.Status.CLOSED -- the queue is NOT active and NOT accepting new
     *          chat requests.
     * </ul>
     */
    public static final class Status {

        /**
         * The queue is active and accepting new chat requests.
         */
        public static final Status OPEN = new Status("open");

        /**
         * The queue is active but NOT accepting new chat requests. This state might
         * occur when the workgroup has closed because regular support hours have closed,
         * but there are still several requests left in the queue.
         */
        public static final Status ACTIVE = new Status("active");

        /**
         * The queue is NOT active and NOT accepting new chat requests.
         */
        public static final Status CLOSED = new Status("closed");

        /**
         * Converts a String into the corresponding status. Valid String values
         * that can be converted to a status are: "open", "active", and "closed".
         *
         * @param type the String value to covert.
         * @return the corresponding Type.
         */
        public static Status fromString(String type) {
            if (type == null) {
                return null;
            }
            type = type.toLowerCase(Locale.US);
            if (OPEN.toString().equals(type)) {
                return OPEN;
            }
            else if (ACTIVE.toString().equals(type)) {
                return ACTIVE;
            }
            else if (CLOSED.toString().equals(type)) {
                return CLOSED;
            }
            else {
                return null;
            }
        }

        private String value;

        private Status(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return value;
        }
    }
}
