/**
 * Copyright 2004-2010 DFKI GmbH.
 * All Rights Reserved.  Use is subject to license terms.
 *
 * Permission is hereby granted, free of charge, to use and distribute
 * this software and its documentation without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of this work, and to
 * permit persons to whom this work is furnished to do so, subject to
 * the following conditions:
 *
 * 1. The code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 * 2. Any modifications must be clearly marked as such.
 * 3. Original authors' names are not deleted.
 * 4. The authors' names are not used to endorse or promote products
 *    derived from this software without specific prior written
 *    permission.
 *
 * DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE
 * CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 * THIS SOFTWARE.
 */

import de.dfki.lt.mary.client.MaryClient;

/* ActiveMQ stuff */

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import javax.jms.DeliveryMode;

//import com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl;

import org.apache.activemq.ActiveMQConnectionFactory;



/**
 * Mary client with activeMQ message receiving/sending capabilities
 * @author Alexis Heloir, heavily based on Marc Marc Schr&ouml;der client
 * and activeMQ Topic Listener/Publisher
 */
public class MaryClientUser implements MessageListener {

    /* openMary stuff */
    private Connection connection;
    private MessageProducer publisher;
    private Session session;
    private int count;
    private long start;
    private Topic topic;
    private MaryReader maryReader;
    ByteArrayOutputStream speechDurationStream = new ByteArrayOutputStream();
    ByteArrayOutputStream wavStream = new ByteArrayOutputStream();
    private MaryClient mary;

    /* activeMQ stuff */
    private String url = "tcp://localhost:61616";
    private String inputType = "SSML";
    private String outputType = "AUDIO";
    private String audioType = "WAVE";
    private String defaultVoiceName = "hmm-slt";
    

    private Integer msgID;

    
    public static void main(String[] argv) {
     MaryClientUser l = new MaryClientUser();
     String[] unknown = CommandLineSupport.setOptions(l, argv);
     if (unknown.length > 0) {
       System.out.println("Unknown options: " + Arrays.toString(unknown));
       System.exit(-1);
     }
     l.run();
    }

    /**
     * setting up openMary socket connexions and registering to the activeMQ running broker 
     */
    public void run() {
        try {
            maryReader = new MaryReader();

            ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
            connection = factory.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic("elvish");

            MessageConsumer consumer = session.createConsumer(topic, "ELVISH_SCOPE = 'elvish' AND MESSAGE_PREFIX = 'RemoteSpeechCmd'");
            consumer.setMessageListener(this);
            System.out.println("Waiting for messages...");
            
            connection.start();

            publisher = session.createProducer(topic);
            publisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            System.out.println("Ready to send messages...");

            /* a remote OpenMary server (hopefully running) */ 
            //String serverHost = System.getProperty("server.host", "cling.dfki.uni-sb.de");
            /* an OpenMary server which is running on your machine */ 
            String serverHost = System.getProperty("server.host", "localhost");
            int serverPort = Integer.getInteger("server.port", 59125).intValue();
            mary = new MaryClient(serverHost, serverPort);
            System.out.println("Connexion to openMary server established...");
            
        } catch (Exception e) {
            System.out.println("Caught: " + e);
            e.printStackTrace();
        }
    }


    private static boolean checkText(Message m, String s) {
        try {
            return m instanceof TextMessage && ((TextMessage)m).getText().equals(s);
        } catch (JMSException e) {
            e.printStackTrace(System.out);
            return false;
        }
    }

    public void onMessage(Message message)
    {
        if (checkText(message, "SHUTDOWN")) {
            try {
                connection.close();
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        } else if (checkText(message, "REPORT")) {
            // send a report:
            try {
                long time = System.currentTimeMillis() - start;
                String msg = "Received " + count + " in " + time + "ms";
                publisher.send(session.createTextMessage(msg));
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
            count = 0;
        } else {
              try {
                String textToPronounce = ((TextMessage)message).getText();
                textToPronounce = textToPronounce.replace("RemoteSpeechCmd speak ", "");
                String character = (textToPronounce.split(" "))[0];
                textToPronounce = textToPronounce.replace(character + " ","");
                String uttID = (textToPronounce.split(" "))[0];
                textToPronounce = textToPronounce.replaceFirst(uttID + " ", "");
                String voiceName = (textToPronounce.split(" "))[0];
                textToPronounce = textToPronounce.replace(voiceName + " ","");
                String filename = (textToPronounce.split(" "))[0];
                textToPronounce = textToPronounce.replace(filename + " ","");

                msgID = new Integer(uttID);

                mary.process(textToPronounce, inputType, outputType, audioType,defaultVoiceName, wavStream);
                File audioFile = new File(filename);
                FileOutputStream audioFileStream = new FileOutputStream(audioFile);
                audioFileStream.write(wavStream.toByteArray());
                audioFileStream.close();
                wavStream.reset();
                
                mary.process(textToPronounce, inputType, "DURATIONS_EN", audioType,defaultVoiceName, speechDurationStream);
                ByteArrayInputStream ba = new ByteArrayInputStream(speechDurationStream.toByteArray());
                speechDurationStream.reset();

                String amqMessage = new String("RemoteSpeechReply " + character + " " + uttID + " OK: " + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<speak>\n<soundFile name=\"");
                amqMessage = amqMessage + audioFile.getAbsolutePath();
                amqMessage = amqMessage + "\"/> ";
                // convert the OpenMary xml into smartBody VHuman remote speech message 
                amqMessage = amqMessage + maryReader.readMary(ba);
                amqMessage = amqMessage +" </speak>";
                Message sendMessage = session.createTextMessage( amqMessage  );
                sendMessage.setStringProperty( "ELVISH_SCOPE" , "elvish");
                sendMessage.setStringProperty( "MESSAGE_PREFIX" , "RemoteSpeechReply");
                sendMessage.setStringProperty( "RemoteSpeechReply" , character + " " + uttID + " OK: " + "<?xml version=\"1.0\" encoding=\"UTF-8\"?><act><bml>troulala</bml></act>" );
                publisher.send(sendMessage);
            } catch (Exception e) {
                System.out.println("Caught: " + e);
                e.printStackTrace();
            }
        }
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

