/**************************************************************************************************
 * Copyright 2018 Qualcomm Technologies International, Ltd.                                       *
 **************************************************************************************************/

package com.qualcomm.qti.iotcontrollersdk.controller;

import android.util.Log;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;

import com.qualcomm.qti.iotcontrollersdk.controller.interfaces.IoTCompletionCallback;
import com.qualcomm.qti.iotcontrollersdk.controller.interfaces.DiscoveryInterface;
import com.qualcomm.qti.iotcontrollersdk.allplay.resource.attributes.*;
import com.qualcomm.qti.iotcontrollersdk.allplay.resource.clients.*;
import com.qualcomm.qti.iotcontrollersdk.allplay.listeners.*;
import java.util.concurrent.atomic.AtomicInteger;
import org.iotivity.base.ObserveType;
import org.iotivity.base.OcConnectivityType;
import org.iotivity.base.OcPlatform;
import org.iotivity.base.OcPlatform.OnResourceFoundListener;
import org.iotivity.base.OcResource;
import org.iotivity.base.OcResource.OnObserveListener;
import org.iotivity.base.OcException;
import org.iotivity.base.OcRepresentation;
import org.iotivity.base.OcResource.OnPostListener;
import org.iotivity.base.OcResource.OnGetListener;
import org.iotivity.base.OcHeaderOption;


public class IoTAllPlayClient extends ControllerInterface {

    private final static String TAG = "IoTAllPlayClient";

    public enum IoTAllPlayObserveOrigin {
{% for swagger_data in swagger_objects %}
{% if "allplay" in swagger_data.type %}
{% if swagger_data.prop != 0 %}
        IoTAllPlayObserveOrigin{{swagger_data.name|class_name_syntax}},
{% endif %}
{% endif %}
{% endfor %}
    }

    public interface IoTAllPlayClientObserver {
      void onRegistration(IoTAllPlayObserveOrigin type);
      void deRegistration(IoTAllPlayObserveOrigin type);
      void onUpdate(IoTAllPlayObserveOrigin type, OcRepresentation rep);
      void onFailed(IoTAllPlayObserveOrigin type, String exception);
    }

    private TaskExecutors mExecutor;
    private IoTAllPlayClientObserver mObserver;

    /** The followings are resource clients instance variables */
{% for swagger_data in swagger_objects %}
{% if "allplay" in swagger_data.type %}
    private {{swagger_data.name|class_name_syntax}}ResourceClient {{swagger_data.name|java_instance_variable_syntax}};
{% endif %}
{% endfor %}

    /*private List<String> mDiscoveryResourceTypes;*/

    /**
     * Class constructor
     */

    public IoTAllPlayClient(final String host, final String id, DiscoveryInterface discovery, final TaskExecutors executor, long time) {

        mHost = host;
        mId = id;
        mDeviceDiscovery = discovery;
        mUriPrefix = "/qti/allplay";
        mExecutor = executor;
        mDeviceDiscoveryTime = time;
/*        mDiscoveryResourceTypes = Arrays.asList(

{% for swagger_data in swagger_objects %}
{% if "allplay" in swagger_data.type %}
                  "qti.allplay.r.{{swagger_data.name}}",
{% endif %}
{% endfor %}

                  "qti.allplay.r.mediaPlayer"
        );
*/
    }

    public void registerObserver(IoTAllPlayClientObserver observer) {
          mObserver = observer;
    }

    public synchronized String getHostName() {
        return mHost;
    }

    public synchronized String getDeviceId() {
        return mId;
    }

    @Override
    public void discoverWithCompletion(final IoTCompletionCallback callback) throws OcException {
        if(mDeviceDiscovery != null) {

            mDeviceDiscovery.findResource(mHost,/*mUriPrefix*/ OcPlatform.WELL_KNOWN_QUERY,EnumSet.of(OcConnectivityType.CT_ADAPTER_IP),
                                 new OnResourceFoundListener() {

                                   private AtomicInteger mCounter = new AtomicInteger(0);

                                   @Override
                                   public void onResourceFound(OcResource resource) {

                                      TaskExecutors.getExecutor().executeOnResourceExecutor(() -> {
                                          if (resource.getUri().contains(mUriPrefix)) {

                                              Log.d(TAG,String.format("Required resource found uri:%s, %d",
                                                          resource.getUri(),resource.getResourceTypes().size()));

                                              if(mCounter.incrementAndGet() == IoTConstants.ALLPLAY_RESOURCE_NUMBER) {
                                                Log.d(TAG,"All required resources found!");
                                                callback.onCompletion(true);
                                              }
                                          }
                                      });
                                   }

                                   @Override
                                   public void onFindResourceFailed(Throwable ex, String uri) {
                                        Log.e(TAG,String.format("Finding Resource failed:%s",uri));
                                        callback.onCompletion(false);
                                        ex.printStackTrace();
                                   }
                                 }
                             );
            }
    }

    @Override
    public void createResourceClientsForHost(String host) throws OcException {

{% for swagger_data in swagger_objects %}
{% if "allplay" in swagger_data.type %}
        {{swagger_data.name|java_instance_variable_syntax}} = new {{swagger_data.name|class_name_syntax}}ResourceClient(host);
{% if swagger_data.prop != 0 %}
        {{swagger_data.name|java_instance_variable_syntax}}.observe(ObserveType.OBSERVE.getValue(),new HashMap<>(),new OnObserveListener() {
            public void onObserveCompleted(List<OcHeaderOption> headerOptionList,
                                       OcRepresentation ocRepresentation,
                                       int sequenceNumber) {

                TaskExecutors.getExecutor().executeAllplayNotification(() -> {

                    if (OcResource.OnObserveListener.REGISTER == sequenceNumber) {
                        mObserver.onRegistration(IoTAllPlayObserveOrigin.IoTAllPlayObserveOrigin{{swagger_data.name|class_name_syntax}});
                    } else if (OcResource.OnObserveListener.MAX_SEQUENCE_NUMBER + 1 == sequenceNumber) {
                        mObserver.deRegistration(IoTAllPlayObserveOrigin.IoTAllPlayObserveOrigin{{swagger_data.name|class_name_syntax}});
                    } else if(mObserver != null) {
                        mObserver.onUpdate(IoTAllPlayObserveOrigin.IoTAllPlayObserveOrigin{{swagger_data.name|class_name_syntax}},ocRepresentation);
                    }
                 });
            }


            public void onObserveFailed(Throwable ex) {
                TaskExecutors.getExecutor().executeAllplayNotification(() -> {
                    if(mObserver != null) {
                        mObserver.onFailed(IoTAllPlayObserveOrigin.IoTAllPlayObserveOrigin{{swagger_data.name|class_name_syntax}},ex.toString());
                    }
                });
            }
        });
        mObserverList.add({{swagger_data.name|java_instance_variable_syntax}});
{% endif %}
{% endif %}
{% endfor %}

    }

    @Override
    public void stopObserving() {
        TaskExecutors.getExecutor().executeOnResourceExecutor(() -> {
            try {
{% for swagger_data in swagger_objects %}
{% if "allplay" in swagger_data.type %}
{% if swagger_data.prop != 0 %}
              {{swagger_data.name|java_instance_variable_syntax}}.stopObserving();
{% endif %}
{% endif %}
{% endfor %}
            }catch(OcException e) {
               e.printStackTrace();
            }
        });

    }

{% set isForIoTSys = [False] %}
{% for swagger_data in swagger_objects %}
{% if "allplay" in swagger_data.type %}
{% include "controller_method.java.jinja2" %}
{% endif %}
{% endfor %}
}
