package org.jgroups.demos;

import org.jgroups.Global;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.ReceiverAdapter;
import org.jgroups.conf.ConfiguratorFactory;
import org.jgroups.conf.ProtocolConfiguration;
import org.jgroups.conf.ProtocolStackConfigurator;
import org.jgroups.util.Util;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Simple pub-sub program using a shared transport: every topic creates a new channel
 * @author bela
 * @since 3.0
 */
public class PubSub {
    final Map<String,JChannel> topics=new HashMap<String,JChannel>();


    void start(String props) throws Exception {
        System.out.println("\n========== PubSub instance started =========");
        System.out.println("Valid commands are:");
        System.out.println("subscribe <topic>");
        System.out.println("unsubscribe <topic>");
        System.out.println("exit");
        System.out.println("print (prints all topics)");
        System.out.println("<topic>: <message>\n\n");

        System.out.println("Example");
        System.out.println("subscribe one\nsubscribe two\none: hello world\n\n");
        for(;;) {
            System.out.print("> ");
            String line=Util.readLine(System.in).trim();
            if(line.startsWith("subscribe")) {
                final String topic=line.substring("subscribe".length()).trim();
                if(!topics.containsKey(topic)) {
                    // we need to make sure "singleton_name" is set in the transport
                    JChannel ch=createSharedChannel("pubsub", props);
                    ch.setReceiver(new ReceiverAdapter() {
                        public void receive(Message msg) {
                            System.out.println("[" + topic + "] << " + msg.getObject());
                        }
                    });
                    ch.connect(topic);
                    topics.put(topic, ch);
                    System.out.println("subscribed to topic \"" + topic + "\"; current subscriptions: " + topics.keySet());
                }
                continue;
            }
            if(line.startsWith("unsubscribe")) {
                final String topic=line.substring("unsubscribe".length()).trim();
                JChannel ch=topics.remove(topic);
                if(ch == null) {
                    System.err.println("Topic \"" + topic + "\" not found");
                    continue;
                }
                Util.close(ch);
                System.out.println("unsubscribed from topic \"" + topic + "\"; current subscriptions: " + topics.keySet());
                continue;
            }
            if(line.startsWith("exit"))
                break;
            if(line.startsWith("print")) {
                System.out.println("topics: " + topics.keySet());
                continue;
            }
            int index=line.indexOf(":");
            if(index == -1) {
                // post to all topics
                for(JChannel ch: topics.values()) {
                    Message msg=new Message(null, null, line);
                    ch.send(msg);
                }
                continue;
            }
            String topic=line.substring(0, index).trim();
            String message=line.substring(index).trim();
            JChannel ch=topics.get(topic);
            if(ch == null) {
                System.err.println("sending to topic \"" + topic + "\" failed as topic doesn't exist, subscribe first");
                continue;
            }
            Message msg=new Message(null, null, message);
            ch.send(msg);
        }
        for(JChannel ch: topics.values())
            Util.close(ch);
    }

    private static JChannel createSharedChannel(String singleton_name, String props) throws Exception {
        ProtocolStackConfigurator config=ConfiguratorFactory.getStackConfigurator(props);
        List<ProtocolConfiguration> protocols=config.getProtocolStack();
        ProtocolConfiguration transport=protocols.get(0);
        transport.getProperties().put(Global.SINGLETON_NAME, singleton_name);
        return new JChannel(config);
    }

    
    public static void main(final String[] args) throws Exception {
        String props=null;
        for(int i=0; i < args.length; i++) {
            if(args[i].equals("-props")) {
                props=args[++i];
                continue;
            }
            help();
            return;
        }

        new PubSub().start(props);
    }


    protected static void help() {
        System.out.println("PubSub [-props props]");
        System.out.println("Valid commands are:");
        System.out.println("subscribe <topic>");
        System.out.println("unsubscribe <topic>");
        System.out.println("exit");
        System.out.println("print (prints all topics)");
        System.out.println("<topic>: <message>\n\n");

        System.out.println("Example");
        System.out.println("subscribe one\nsubscribe two\none: hello world");
    }




}
