void SubscriberImpl::startDeliveryWithFilter(const std::string& topic,
                                             const std::string& subscriberId,
                                             const MessageHandlerCallbackPtr& callback,
                                             const ClientMessageFilterPtr& filter) {
  if (0 == filter.get()) {
    throw NullMessageFilterException();
  }
  if (0 == callback.get()) {
    throw NullMessageHandlerException();
  }

  TopicSubscriber t(topic, subscriberId);

  // Get the subscriber channel handler
  SubscriberClientChannelHandlerPtr handler =
    channelManager->getSubscriptionChannelHandler(t);

  if (handler.get() == 0) {
    LOG4CXX_ERROR(logger, "Trying to start deliver on a non existant handler topic = "
                          << topic << ", subscriber = " << subscriberId);
    throw NotSubscribedException();
  }

  handler->startDelivery(t, callback, filter);
}
/* static */ void SubscriberConsumeCallback::timerComplete(const SubscriberClientChannelHandlerPtr handler, 
							   const PubSubResponsePtr m, 
							   const boost::system::error_code& error) {
  if (error) {
    return;
  }
  handler->messageReceived(handler->getChannel(), m);
}
bool SubscriberImpl::hasSubscription(const std::string& topic, const std::string& subscriberId) {
  TopicSubscriber ts(topic, subscriberId);
  // Get the subscriber channel handler
  SubscriberClientChannelHandlerPtr handler =
    channelManager->getSubscriptionChannelHandler(ts);
  if (!handler.get()) {
    return false;
  }
  return handler->hasSubscription(ts);
}
void SubscriberImpl::stopDelivery(const std::string& topic, const std::string& subscriberId) {
  TopicSubscriber t(topic, subscriberId);
  
  boost::shared_lock<boost::shared_mutex> lock(topicsubscriber2handler_lock);
  SubscriberClientChannelHandlerPtr handler = topicsubscriber2handler[t];

  if (handler.get() == 0) {
    LOG4CXX_ERROR(logger, "Trying to start deliver on a non existant handler topic = " << topic << ", subscriber = " << subscriberId);
  }
  handler->stopDelivery();
}
void SubscriberImpl::stopDelivery(const std::string& topic, const std::string& subscriberId) {
  TopicSubscriber t(topic, subscriberId);

  // Get the subscriber channel handler
  SubscriberClientChannelHandlerPtr handler =
    channelManager->getSubscriptionChannelHandler(t);

  if (handler.get() == 0) {
    LOG4CXX_ERROR(logger, "Trying to stop deliver on a non existant handler topic = "
                          << topic << ", subscriber = " << subscriberId);
    throw NotSubscribedException();
  }
  handler->stopDelivery(t);
}
void SubscriberImpl::closeSubscription(const std::string& topic, const std::string& subscriberId) {
  LOG4CXX_DEBUG(logger, "closeSubscription (" << topic << ",  " << subscriberId << ")");

  TopicSubscriber t(topic, subscriberId);

  SubscriberClientChannelHandlerPtr handler;
  {
    boost::lock_guard<boost::shared_mutex> lock(topicsubscriber2handler_lock);
    handler = topicsubscriber2handler[t];
    topicsubscriber2handler.erase(t);
  }
  
  if (handler.get() != 0) {
    handler->close();
  }
}
void SubscriberImpl::doSubscribe(const DuplexChannelPtr& channel, const PubSubDataPtr& data, const SubscriberClientChannelHandlerPtr& handler) {
  channel->storeTransaction(data);

  OperationCallbackPtr writecb(new SubscriberWriteCallback(client, data));
  channel->writeRequest(data->getRequest(), writecb);

  boost::lock_guard<boost::shared_mutex> lock(topicsubscriber2handler_lock);
  TopicSubscriber t(data->getTopic(), data->getSubscriberId());
  SubscriberClientChannelHandlerPtr oldhandler = topicsubscriber2handler[t];
  if (oldhandler != NULL) {
    oldhandler->handoverDelivery(handler);
  }
  topicsubscriber2handler[t] = handler;
  
  LOG4CXX_DEBUG(logger, "Set topic subscriber for topic(" << data->getTopic() << ") subscriberId(" << data->getSubscriberId() << ") to " << handler.get() << " topicsubscriber2topic(" << &topicsubscriber2handler << ")");
}
void SubscriberImpl::consume(const std::string& topic, const std::string& subscriberId,
                             const MessageSeqId& messageSeqId) {
  TopicSubscriber t(topic, subscriberId);

  // Get the subscriber channel handler
  SubscriberClientChannelHandlerPtr handler =
    channelManager->getSubscriptionChannelHandler(t);

  if (handler.get() == 0) {
    LOG4CXX_ERROR(logger, "Cannot consume. No subscription channel handler found for topic ("
                          << topic << ") subscriberId(" << subscriberId << ").");
    return;
  }

  handler->consume(t, messageSeqId);
}
/*static*/ void SubscriberClientChannelHandler::reconnectTimerComplete(const SubscriberClientChannelHandlerPtr handler,
								       const DuplexChannelPtr channel, const std::exception e, 
								       const boost::system::error_code& error) {
  if (error) {
    return;
  }
  handler->should_wait = false;
  handler->channelDisconnected(channel, e);
}
void SubscriberImpl::consume(const std::string& topic, const std::string& subscriberId, const MessageSeqId& messageSeqId) {
  TopicSubscriber t(topic, subscriberId);
  
  boost::shared_lock<boost::shared_mutex> lock(topicsubscriber2handler_lock);
  SubscriberClientChannelHandlerPtr handler = topicsubscriber2handler[t];

  if (handler.get() == 0) {
    LOG4CXX_ERROR(logger, "Cannot consume. Bad handler for topic(" << topic << ") subscriberId(" << subscriberId << ") topicsubscriber2topic(" << &topicsubscriber2handler << ")");
    return;
  }

  DuplexChannelPtr channel = handler->getChannel();
  if (channel.get() == 0) {
    LOG4CXX_ERROR(logger, "Trying to consume a message on a topic/subscriber pair that don't have a channel. Something fishy going on. Topic: " << topic << " SubscriberId: " << subscriberId << " MessageSeqId: " << messageSeqId.localcomponent());
  }
  
  PubSubDataPtr data = PubSubData::forConsumeRequest(client->counter().next(), subscriberId, topic, messageSeqId);  
  OperationCallbackPtr writecb(new ConsumeWriteCallback(client, data));
  channel->writeRequest(data->getRequest(), writecb);
}
void SubscriberClientChannelHandler::handoverDelivery(const SubscriberClientChannelHandlerPtr& newHandler) {
  LOG4CXX_DEBUG(logger, "Messages in queue " << queue.size());
  MessageHandlerCallbackPtr handler = this->handler;
  stopDelivery(); // resets old handler
  newHandler->startDelivery(handler);
}