/*
 * Copyright (c) 2016 Oracle and/or its affiliates.  All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL).  See the LICENSE file in the root
 * directory for license terms.  You may choose either license, or both.
 */

package com.oracle.iot.sample.enterpriseclientsample;

import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.oracle.iot.sample.R;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import oracle.iot.client.DeviceModel;
import oracle.iot.client.enterprise.Device;
import oracle.iot.client.enterprise.EnterpriseClient;
import oracle.iot.client.enterprise.VirtualDevice;

public class IBeaconSensorActivity extends Activity {
    private static final String ERROR_TAG = "IOT_ERROR";
    private static final String MSG_TAG = "IOT";
    private static final String MSSI_ATTRIBUTE = "ora_txPower";
    private static final String RSSI_ATTRIBUTE = "ora_rssi";
    private VirtualDevice vDevice;
    TextView currentMSSI;
    TextView currentRSSI;
    TextView uuid;
    TextView major;
    TextView minor;
    Context context;
    String deviceId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ibeacon_sensor);
        EnterpriseClientUtil util = EnterpriseClientUtil.getInstance(this);
        util.setCurrentContext(this);
        deviceId = util.getSelectedDeviceToMonitor().device.getId();
        util.getSelectedDeviceToMonitor().device.getValue(Device.Field.MANUFACTURER);
        TextView deviceNameTV = (TextView)findViewById(R.id.deviceTitle);
        deviceNameTV.setText(deviceId);
        currentMSSI = (TextView)findViewById(R.id.mssiValue);
        currentRSSI = (TextView)findViewById(R.id.rssiValue);
        uuid = (TextView)findViewById(R.id.uuid);
        major = (TextView)findViewById(R.id.majorNumber);
        minor = (TextView)findViewById(R.id.minorNumber);
        Map<String, String> metadata = util.getSelectedDeviceToMonitor().device.getMetadata();
        String uuidNum = metadata.get("UUID");
        String majorNum = metadata.get("major");
        String minorNum = metadata.get("minor");
        uuid.setText("UUID : " + (uuidNum!=null?uuidNum:""));
        major.setText( "Major: " + (majorNum!=null?majorNum:""));
        minor.setText( "Minor: " + (minorNum!=null?minorNum:""));

        final SensorOperation sensorThread = new SensorOperation(getApplicationContext());
        sensorThread.execute(this);
    }

    private class SensorOperation extends AsyncTask<Context, String, Void> {
        EnterpriseClient client;
        String mssi;
        String rssi;
        DeviceModel deviceModel = null;
        String modelUrn = null;

        public SensorOperation (Context mContext){
            context = mContext;
            mssi = "-62";
            rssi = "-62";
        }

        @Override
        protected Void doInBackground(Context... params) {
            try {
                client = EnterpriseClientUtil.getInstance(null).getECL();
            }catch(Exception e){
                vDevice = null;
                publishProgress("No valid device Id!");
                return null;
            }
            if (deviceId == null) {
                vDevice = null;
                publishProgress("No valid device Id!");
                return null;
            }

            try {
                modelUrn = EnterpriseClientUtil.getInstance(null).getSelectedDeviceToMonitor().deviceModel.urn;
                deviceModel = client.getDeviceModel(modelUrn);
                vDevice = client.createVirtualDevice(deviceId, deviceModel);
                setupHandlers(vDevice);
            } catch (Exception e) {
                Log.d(ERROR_TAG, e.getMessage());
            }

            return null;
        }

        @Override
            protected void onProgressUpdate(String... s) {
            if(vDevice == null) {
                return;
            }
            try {
                if(s[0].contains("onChange")) {
                    mssi = vDevice.get(MSSI_ATTRIBUTE).toString();
                    rssi = vDevice.get(RSSI_ATTRIBUTE).toString();
                    currentMSSI.setText(mssi.trim());
                    currentRSSI.setText(rssi.trim());
                    Log.d(MSG_TAG, "MSSI -> " + mssi);
                    Log.d(MSG_TAG, "RSSI -> " + rssi);
                }
            } catch (Exception e) {
                Log.d(ERROR_TAG, e.getMessage());
            }
        }

        AtomicBoolean breakWaitLoop = new AtomicBoolean(false);

        private void setupHandlers(VirtualDevice device) {
            device.setOnChange(new VirtualDevice.ChangeCallback<VirtualDevice>() {
                public void onChange(VirtualDevice.ChangeEvent<VirtualDevice> event) {
                    VirtualDevice virtualDevice = event.getVirtualDevice();
                    StringBuilder msg = new StringBuilder(new Date().toString());
                    msg.append(": ");
                    msg.append(virtualDevice.getEndpointId());
                    msg.append(" : onChange : ");
                    boolean first = true;
                    VirtualDevice.NamedValue<?> namedValue = event.getNamedValue();
                    while (namedValue != null) {
                        String attributeName = namedValue.getName();
                        Object attributeValue = namedValue.getValue();

                        if (!first) {
                            msg.append(',');
                        } else {
                            first = false;
                        }

                        msg.append('\"');
                        msg.append(attributeName);
                        msg.append("\"=");
                        msg.append(String.valueOf(attributeValue));

                        namedValue = namedValue.next();
                    }

                    Log.d(MSG_TAG, msg.toString());
                    publishProgress(msg.toString());
                }
            });

            device.setOnError(
                    new VirtualDevice.ErrorCallback<VirtualDevice>() {
                        public void onError(VirtualDevice.ErrorEvent event) {
                            VirtualDevice device = (VirtualDevice)event.getVirtualDevice();
                            StringBuilder msg = new StringBuilder(new Date().toString() + " : onError : " +
                                    device.getEndpointId() + " : \"" + event.getMessage());

                            // Normally some error processing would go here,
                            // but since this a sample, notify the main thread
                            // to end the sample.
                            breakWaitLoop.set(true);

                            publishProgress(msg.toString());
                        }
                    });
        }
    }
}
