/**
   * Called from AsteriskServerImpl whenever a new entry appears in a queue.
   *
   * @param event the JoinEvent received
   */
  void handleJoinEvent(JoinEvent event) {
    final AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());
    final AsteriskChannelImpl channel = channelManager.getChannelImplByName(event.getChannel());

    if (queue == null) {
      logger.error("Ignored JoinEvent for unknown queue " + event.getQueue());
      return;
    }
    if (channel == null) {
      logger.error("Ignored JoinEvent for unknown channel " + event.getChannel());
      return;
    }

    if (queue.getEntry(event.getChannel()) != null) {
      logger.error(
          "Ignored duplicate queue entry in queue "
              + event.getQueue()
              + " for channel "
              + event.getChannel());
      return;
    }

    // Asterisk gives us an initial position but doesn't tell us when he shifts the others
    // We won't use this data for ordering until there is a appropriate event in AMI.
    // (and refreshing the whole queue is too intensive and suffers incoherencies
    // due to asynchronous shift that leaves holes if requested too fast)
    int reportedPosition = event.getPosition();

    queue.createNewEntry(channel, reportedPosition, event.getDateReceived());
  }
  /**
   * Called from AsteriskServerImpl whenever an enty leaves a queue.
   *
   * @param event - the LeaveEvent received
   */
  void handleLeaveEvent(LeaveEvent event) {
    final AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());
    final AsteriskChannelImpl channel = channelManager.getChannelImplByName(event.getChannel());

    if (queue == null) {
      logger.error("Ignored LeaveEvent for unknown queue " + event.getQueue());
      return;
    }
    if (channel == null) {
      logger.error("Ignored LeaveEvent for unknown channel " + event.getChannel());
      return;
    }

    final AsteriskQueueEntryImpl existingQueueEntry = queue.getEntry(event.getChannel());
    if (existingQueueEntry == null) {
      logger.error(
          "Ignored leave event for non existing queue entry in queue "
              + event.getQueue()
              + " for channel "
              + event.getChannel());
      return;
    }

    queue.removeEntry(existingQueueEntry, event.getDateReceived());
  }
  /**
   * Called during initialization to populate the members of the queues.
   *
   * @param event the QueueMemberEvent received
   */
  private void handleQueueMemberEvent(QueueMemberEvent event) {
    final AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());
    if (queue == null) {
      logger.error("Ignored QueueEntryEvent for unknown queue " + event.getQueue());
      return;
    }

    AsteriskQueueMemberImpl member = queue.getMember(event.getLocation());
    if (member == null) {
      member =
          new AsteriskQueueMemberImpl(
              server,
              queue,
              event.getLocation(),
              QueueMemberState.valueOf(event.getStatus()),
              event.getPaused(),
              event.getPenalty(),
              event.getMembership(),
              event.getCallsTaken(),
              event.getLastCall());

      queue.addMember(member);
    } else {
      if (member.stateChanged(QueueMemberState.valueOf(event.getStatus()))
          | member.pausedChanged(event.getPaused())
          | member.penaltyChanged(event.getPenalty())
          | member.callsTakenChanged(event.getCallsTaken())
          | member.lastCallChanged(event.getLastCall())) {
        queue.stampLastUpdate();
      }
    }
  }
 void disconnected() {
   synchronized (queuesLRU) {
     for (AsteriskQueueImpl queue : queuesLRU.values()) {
       queue.cancelServiceLevelTimer();
     }
     queuesLRU.clear();
   }
 }
  void handleQueueMemberPenaltyEvent(QueueMemberPenaltyEvent event) {
    AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());

    if (queue == null) {
      logger.error("Ignored QueueMemberStatusEvent for unknown queue " + event.getQueue());
      return;
    }

    AsteriskQueueMemberImpl member = queue.getMemberByLocation(event.getLocation());
    if (member == null) {
      logger.error("Ignored QueueMemberStatusEvent for unknown member " + event.getLocation());
      return;
    }

    member.penaltyChanged(event.getPenalty());
  }
  /**
   * Challange a QueueMemberRemovedEvent.
   *
   * @param event - the generated QueueMemberRemovedEvent.
   */
  public void handleQueueMemberRemovedEvent(QueueMemberRemovedEvent event) {
    final AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());
    if (queue == null) {
      logger.error("Ignored QueueMemberRemovedEvent for unknown queue " + event.getQueue());
      return;
    }

    final AsteriskQueueMemberImpl member = queue.getMember(event.getLocation());
    if (member == null) {
      logger.error(
          "Ignored QueueMemberRemovedEvent for unknown agent name: "
              + event.getMemberName()
              + " location: "
              + event.getLocation()
              + " queue: "
              + event.getQueue());
      return;
    }

    queue.removeMember(member);
  }
  public List<AsteriskQueue> getQueuesUpdatedAfter(Date date) {
    refreshQueuesIfForced();

    List<AsteriskQueue> copy = new ArrayList<AsteriskQueue>();
    synchronized (queuesLRU) {
      List<Entry<String, AsteriskQueueImpl>> list =
          new ArrayList<Entry<String, AsteriskQueueImpl>>(queuesLRU.entrySet());
      ListIterator<Entry<String, AsteriskQueueImpl>> iter = list.listIterator(list.size());

      Entry<String, AsteriskQueueImpl> entry;
      while (iter.hasPrevious()) {
        entry = iter.previous();
        AsteriskQueueImpl astQueue = entry.getValue();
        if (astQueue.getLastUpdateMillis() <= date.getTime()) {
          break;
        }
        copy.add(astQueue);
      }
    }

    return copy;
  }
  /**
   * Challange a QueueMemberStatusEvent. Called from AsteriskServerImpl whenever a member state
   * changes.
   *
   * @param event that was triggered by Asterisk server.
   */
  void handleQueueMemberStatusEvent(QueueMemberStatusEvent event) {
    AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());

    if (queue == null) {
      logger.error("Ignored QueueMemberStatusEvent for unknown queue " + event.getQueue());
      return;
    }

    AsteriskQueueMemberImpl member = queue.getMemberByLocation(event.getLocation());
    if (member == null) {
      logger.error("Ignored QueueMemberStatusEvent for unknown member " + event.getLocation());
      return;
    }

    updateQueue(queue.getName());

    member.stateChanged(QueueMemberState.valueOf(event.getStatus()));
    member.penaltyChanged(event.getPenalty());
    member.lastCallChanged(event.getLastCall());
    member.callsTakenChanged(event.getCallsTaken());

    queue.fireMemberStateChanged(member);
  }
  /**
   * Challange a QueueMemberAddedEvent.
   *
   * @param event - the generated QueueMemberAddedEvent.
   */
  public void handleQueueMemberAddedEvent(QueueMemberAddedEvent event) {
    final AsteriskQueueImpl queue = getInternalQueueByName(event.getQueue());
    if (queue == null) {
      logger.error("Ignored QueueMemberAddedEvent for unknown queue " + event.getQueue());
      return;
    }

    AsteriskQueueMemberImpl member = queue.getMember(event.getLocation());
    if (member == null) {
      member =
          new AsteriskQueueMemberImpl(
              server,
              queue,
              event.getLocation(),
              QueueMemberState.valueOf(event.getStatus()),
              event.getPaused(),
              event.getPenalty(),
              event.getMembership(),
              event.getCallsTaken(),
              event.getLastCall());
    }

    queue.addMember(member);
  }
  /**
   * Called during initialization to populate the list of queues.
   *
   * @param event the event received
   */
  private void handleQueueParamsEvent(QueueParamsEvent event) {
    AsteriskQueueImpl queue;

    final String name = event.getQueue();
    final Integer max = event.getMax();
    final String strategy = event.getStrategy();
    final Integer serviceLevel = event.getServiceLevel();
    final Integer weight = event.getWeight();
    final Integer calls = event.getCalls();
    final Integer holdTime = event.getHoldTime();
    final Integer talkTime = event.getTalkTime();
    final Integer completed = event.getCompleted();
    final Integer abandoned = event.getAbandoned();
    final Double serviceLevelPerf = event.getServiceLevelPerf();

    queue = getInternalQueueByName(name);

    if (queue == null) {
      queue =
          new AsteriskQueueImpl(
              server,
              name,
              max,
              strategy,
              serviceLevel,
              weight,
              calls,
              holdTime,
              talkTime,
              completed,
              abandoned,
              serviceLevelPerf);
      logger.info("Adding new queue " + queue);
      addQueue(queue);
    } else {
      // We should never reach that code as this method is only called for initialization
      // So the queue should never be in the queues list
      synchronized (queue) {
        synchronized (queuesLRU) {
          if (queue.setMax(max)
              | queue.setServiceLevel(serviceLevel)
              | queue.setWeight(weight)
              | queue.setCalls(calls)
              | queue.setHoldTime(holdTime)
              | queue.setTalkTime(talkTime)
              | queue.setCompleted(completed)
              | queue.setAbandoned(abandoned)
              | queue.setServiceLevelPerf(serviceLevelPerf)) {

            queuesLRU.remove(queue.getName());
            queuesLRU.put(queue.getName(), queue);
          }
        }
      }
    }
  }
 /**
  * Adds a queue to the internal map, keyed by name.
  *
  * @param queue the AsteriskQueueImpl to be added
  */
 private void addQueue(AsteriskQueueImpl queue) {
   synchronized (queuesLRU) {
     queuesLRU.put(queue.getName(), queue);
   }
 }