content: /*
   * 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.camel.component.pubnub.example;
  
  import java.security.SecureRandom;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.concurrent.ConcurrentHashMap;
  
  import com.pubnub.api.models.consumer.pubsub.PNMessageResult;
  import org.apache.camel.EndpointInject;
  import org.apache.camel.ProducerTemplate;
  import org.apache.camel.builder.RouteBuilder;
  import org.apache.camel.component.pubnub.PubNubConstants;
  import org.apache.camel.main.Main;
  
  import static org.apache.camel.component.pubnub.PubNubConstants.OPERATION;
  import static org.apache.camel.component.pubnub.PubNubConstants.UUID;
  import static org.apache.camel.component.pubnub.example.PubNubExampleConstants.PUBNUB_PUBLISH_KEY;
  import static org.apache.camel.component.pubnub.example.PubNubExampleConstants.PUBNUB_SUBSCRIBE_KEY;
  
  public final class PubNubSensor2Example {
  
      private PubNubSensor2Example() {
      }
  
      public static void main(String[] args) throws Exception {
          Main main = new Main();
          main.configure().addRoutesBuilder(new PubsubRoute());
          main.configure().addRoutesBuilder(new SimulatedDeviceEventGeneratorRoute());
          main.run();
      }
  
      static class SimulatedDeviceEventGeneratorRoute extends RouteBuilder {
          private final String deviceEP
                  = "pubnub:iot?uuid=device2&publishKey=" + PUBNUB_PUBLISH_KEY + "&subscribeKey=" + PUBNUB_SUBSCRIBE_KEY;
          private final String devicePrivateEP = "pubnub:device2private?uuid=device2&publishKey=" + PUBNUB_PUBLISH_KEY
                                                 + "&subscribeKey=" + PUBNUB_SUBSCRIBE_KEY;
  
          @Override
          public void configure() {
              from("timer:device2").routeId("device-event-route")
                      .bean(PubNubSensor2Example.EventGeneratorBean.class, "getRandomEvent('device2')")
                      .to(deviceEP);
  
              from(devicePrivateEP)
                      .routeId("device-unicast-route")
                      .log("Message from master to device2 : ${body}");
          }
      }
  
      static class PubsubRoute extends RouteBuilder {
          private static String masterEP
                  = "pubnub:iot?uuid=master&subscribeKey=" + PUBNUB_SUBSCRIBE_KEY + "&publishKey=" + PUBNUB_PUBLISH_KEY;
          private static Map<String, String> devices = new ConcurrentHashMap<>();
  
          @Override
          public void configure() {
              from(masterEP)
                      .routeId("master-route")
                      .bean(PubNubSensor2Example.PubsubRoute.DataProcessorBean.class, "doSomethingInteresting(${body})")
                      .log("${body} headers : ${headers}").to("mock:result");
  
              //TODO Could remote control device to turn on/off sensor measurement
              from("timer:master?delay=15000&period=5000").routeId("unicast2device-route")
                      .setHeader(PubNubConstants.CHANNEL,
                              method(PubNubSensor2Example.PubsubRoute.DataProcessorBean.class, "getUnicastChannelOfDevice()"))
                      .setBody(constant("Hello device"))
                      .to(masterEP);
          }
  
          public static class DataProcessorBean {
              @EndpointInject("pubnub:iot?uuid=master&subscribeKey=" + PUBNUB_SUBSCRIBE_KEY)
              private static ProducerTemplate template;
  
              public static String getUnicastChannelOfDevice() {
                  // just get the first channel
                  return devices.values().iterator().next();
              }
  
              public static void doSomethingInteresting(PNMessageResult message) {
                  String deviceUUID;
                  deviceUUID = message.getPublisher();
                  if (devices.get(deviceUUID) == null) {
                      Map<String, Object> headers = new HashMap<>();
                      headers.put(OPERATION, "WHERENOW");
                      headers.put(UUID, deviceUUID);
                      @SuppressWarnings("unchecked")
                      java.util.List<String> channels = (java.util.List<String>) template.requestBodyAndHeaders(null, headers);
                      devices.put(deviceUUID, channels.get(0));
                  }
              }
          }
      }
  
      record DeviceWeatherInfo(String device, int humidity, int temperature) {
  
          private static SecureRandom rand = new SecureRandom();
  
          public DeviceWeatherInfo(String device) {
              this(device, rand.nextInt(100), rand.nextInt(40));
          }
      }
  
      public static class EventGeneratorBean {
          public static DeviceWeatherInfo getRandomEvent(String device) {
              return new DeviceWeatherInfo(device);
          }
      }
  }
  