/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.activemq.bugs;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.InitialContext;

import org.apache.activemq.broker.BrokerService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AMQ2084Test {

   private static final Logger LOG = LoggerFactory.getLogger(AMQ2084Test.class);
   BrokerService broker;
   CountDownLatch qreceived;
   String connectionUri;

   @Before
   public void startBroker() throws Exception {
      broker = new BrokerService();
      broker.setPersistent(false);
      connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString();
      broker.start();

      qreceived = new CountDownLatch(1);
   }

   @After
   public void stopBroker() throws Exception {
      if (broker != null) {
         broker.stop();
      }
   }

   public void listenQueue(final String queueName, final String selectors) {
      try {
         Properties props = new Properties();
         props.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
         props.put("java.naming.provider.url", connectionUri);
         props.put("queue.queueName", queueName);

         javax.naming.Context ctx = new InitialContext(props);
         QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
         QueueConnection conn = factory.createQueueConnection();
         final Queue queue = (Queue) ctx.lookup("queueName");
         QueueSession session = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
         QueueReceiver receiver = session.createReceiver(queue, selectors);
         System.out.println("Message Selector: " + receiver.getMessageSelector());
         receiver.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
               try {
                  if (message instanceof TextMessage) {
                     TextMessage txtMsg = (TextMessage) message;
                     String msg = txtMsg.getText();
                     LOG.info("Queue Message Received: " + queueName + " - " + msg);
                     qreceived.countDown();

                  }
                  message.acknowledge();
               }
               catch (Throwable e) {
                  e.printStackTrace();
               }
            }
         });
         conn.start();
      }
      catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void listenTopic(final String topicName, final String selectors) {
      try {
         Properties props = new Properties();
         props.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
         props.put("java.naming.provider.url", connectionUri);
         props.put("topic.topicName", topicName);

         javax.naming.Context ctx = new InitialContext(props);
         TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("ConnectionFactory");
         TopicConnection conn = factory.createTopicConnection();
         final Topic topic = (Topic) ctx.lookup("topicName");
         TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
         TopicSubscriber receiver = session.createSubscriber(topic, selectors, false);

         receiver.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
               try {
                  if (message instanceof TextMessage) {
                     TextMessage txtMsg = (TextMessage) message;
                     String msg = txtMsg.getText();
                     LOG.info("Topic Message Received: " + topicName + " - " + msg);
                  }
                  message.acknowledge();
               }
               catch (Exception e) {
                  e.printStackTrace();
               }
            }
         });
         conn.start();
      }
      catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void publish(String topicName, String message) {
      try {
         Properties props = new Properties();
         props.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
         props.put("java.naming.provider.url", connectionUri);
         props.put("topic.topicName", topicName);
         javax.naming.Context ctx = new InitialContext(props);
         TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("ConnectionFactory");
         TopicConnection conn = factory.createTopicConnection();
         Topic topic = (Topic) ctx.lookup("topicName");
         TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
         TopicPublisher publisher = session.createPublisher(topic);
         if (message != null) {
            Message msg = session.createTextMessage(message);
            publisher.send(msg);
         }
      }
      catch (Exception e) {
         e.printStackTrace();
      }
   }

   @Test
   public void tryXpathSelectorMatch() throws Exception {
      String xPath = "XPATH '//books//book[@lang=''en'']'";
      listenQueue("Consumer.Sample.VirtualTopic.TestXpath", xPath);
      publish("VirtualTopic.TestXpath", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><books><book lang=\"en\">ABC</book></books>");
      assertTrue("topic received: ", qreceived.await(20, TimeUnit.SECONDS));
   }

   @Test
   public void tryXpathSelectorNoMatch() throws Exception {
      String xPath = "XPATH '//books//book[@lang=''es'']'";
      listenQueue("Consumer.Sample.VirtualTopic.TestXpath", xPath);
      publish("VirtualTopic.TestXpath", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><books><book lang=\"en\">ABC</book></books>");
      assertFalse("topic did not receive unmatched", qreceived.await(5, TimeUnit.SECONDS));
   }

}
