/*
 * Copyright (c) 2016, 2017 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.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.AlignmentSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;

import oracle.iot.client.DeviceModel;
import oracle.iot.client.enterprise.Device;
import oracle.iot.client.enterprise.EnterpriseClient;
import oracle.iot.client.enterprise.Pageable;
import oracle.iot.client.enterprise.UserAuthenticationException;
import oracle.iot.client.enterprise.VirtualDevice;
import com.oracle.iot.sample.R;

public class DeviceListActivity extends Activity {
    public enum DeviceType {
        TEMPERATURE("temperature"),
        HUMIDITY("humidity"),
        IBEACON("ibeacon"),
        EDDYSTONE("eddystone"),
        CAMERA("camera");

        final String alias;
        DeviceType(String alias) {
            this.alias = alias;
        }

        public String alias() {
            return this.alias;
        }
    }
    ArrayList<DeviceListItem> devices = new ArrayList<DeviceListItem>();
    DeviceListAdapter dataAdapter = null;
    Context context;
    private static final String HUMIDITY_ATTRIBUTE_NAME = "humidity";
    private static final String TEMPERATURE_ATTRIBUTE_NAME = "temp";
    private static final String IBEACON_ATTRIBUTE_NAME = "ora_rssi";
    private static final String EDDYSTONE_ATTRIBUTE_NAME = "ora_rssi";
    private static final String IMAGE_TIME_ATTRIBUTE_NAME = "imageTime";
    DeviceType deviceType;
    String sensorAttribute;
    private ECLDeviceListTask eclTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_device_list);
        context  = this;
        EnterpriseClientUtil util = EnterpriseClientUtil.getInstance(context);
        TextView heading = (TextView) findViewById(R.id.deviceTitle);
        TextView listHeader = (TextView) findViewById(R.id.listHeader);
        listHeader.setText("  Device ID");
        TextView listHeader2 = (TextView) findViewById(R.id.listHeader2);
        if (util.getDM().urn.contains(DeviceType.TEMPERATURE.alias())) {
            deviceType = DeviceType.TEMPERATURE;
            heading.setText("Temperature Sensors");
            sensorAttribute = TEMPERATURE_ATTRIBUTE_NAME;
            listHeader2.setText("Temperature      ");
        } else if (util.getDM().urn.contains(DeviceType.HUMIDITY.alias())){
            deviceType = DeviceType.HUMIDITY;
            heading.setText("Humidity Sensors");
            sensorAttribute = HUMIDITY_ATTRIBUTE_NAME;
            listHeader2.setText("Humidity      ");
        } else if (util.getDM().urn.contains(DeviceType.IBEACON.alias())){
            deviceType = DeviceType.IBEACON;
            heading.setText("iBeacon Sensors");
            sensorAttribute = IBEACON_ATTRIBUTE_NAME;
            listHeader2.setText("RSSI      ");
        } else if (util.getDM().urn.contains(DeviceType.EDDYSTONE.alias())){
            deviceType = DeviceType.EDDYSTONE;
            heading.setText("Eddystone Sensors");
            sensorAttribute = EDDYSTONE_ATTRIBUTE_NAME;
            listHeader2.setText("RSSI      ");
        } else if (util.getDM().urn.contains(DeviceType.CAMERA.alias())){
            deviceType = DeviceType.CAMERA;
            heading.setText("Camera Sensors");
            sensorAttribute = IMAGE_TIME_ATTRIBUTE_NAME;
            listHeader2.setText("Image Time    ");
        }
        util.setCurrentContext(context);
        eclTask = new ECLDeviceListTask();
        eclTask.execute(this);
    }

    private class ECLDeviceListTask extends AsyncTask<Context, String, Void> {

        private static final String ERROR_TAG = "IOT_ERROR";
        boolean updatingSensorList = true;

        @Override
        protected Void doInBackground(Context... params) {
            getDevices();
            return null;
        }

        public void getDevices() {
            // use enterprise client to get active devices
            try {
                EnterpriseClient client = EnterpriseClientUtil.getInstance(null).getECL();
                DeviceModelLineItem dm = EnterpriseClientUtil.getInstance(null).getDM();
                Pageable<Device> tmpDevices = null;
                // get active devices

                tmpDevices = client.getActiveDevices(dm.urn);
                while (tmpDevices.hasMore()) {
                    try {
                        tmpDevices.next();
                    } catch (java.util.NoSuchElementException e) {
                        break;
                    }
                    for (Device d: tmpDevices.elements()) {
                        try {
                            DeviceListItem dli = new DeviceListItem();
                            dli.device = d;
                            dli.deviceModel = dm;
                            dli.deviceType = deviceType;
                            DeviceModel deviceModel = client.getDeviceModel(dm.urn);
                            VirtualDevice vDevice = client.createVirtualDevice(d.getId(), deviceModel);

                            if (vDevice.get(sensorAttribute) == null)
                                dli.currentValue = "";
                            else
                                dli.currentValue = vDevice.get(sensorAttribute).toString();
                            setupHandlers(vDevice, d.getId());
                            devices.add(dli);
                        } catch (IllegalArgumentException e) {
                            Log.d(ERROR_TAG, e.getMessage());
                        }
                    }
                }
                updatingSensorList=false;
                publishProgress();
                if (!this.isCancelled()){
                    Thread.sleep(1000);
                    publishProgress();
                }
                return;
            } catch (UserAuthenticationException uae){
                Log.d(ERROR_TAG, uae.getMessage());
                uae.printStackTrace();
            } catch (IOException e) {
                Log.d(ERROR_TAG, e.getMessage());
                e.printStackTrace();
            } catch (GeneralSecurityException e) {
                Log.d(ERROR_TAG, e.getMessage());
                e.printStackTrace();
            } catch(InterruptedException ie){

            }
        }

        private void setupHandlers(VirtualDevice device,
                                   final String endpointId) {
            device.setOnChange(new VirtualDevice.ChangeCallback<VirtualDevice>() {
                public void onChange(VirtualDevice.ChangeEvent<VirtualDevice> event) {
                    while (updatingSensorList){};
                    VirtualDevice.NamedValue<?> namedValue = event.getNamedValue();
                    while (namedValue != null) {
                        String attributeName = namedValue.getName();
                        Object attributeValue = namedValue.getValue();
                        if (deviceType == DeviceType.HUMIDITY && attributeName.equals(HUMIDITY_ATTRIBUTE_NAME)){
                            for(int i=0;i<devices.size();i++){
                                DeviceListItem temp = devices.get(i);
                                if (temp.device.getId().equals(endpointId)){
                                    temp.currentValue=((Integer)attributeValue).toString();
                                    devices.set(i,temp);
                                }
                            }
                            break;
                        } else if( deviceType == DeviceType.TEMPERATURE && attributeName.equals(TEMPERATURE_ATTRIBUTE_NAME)){
                            for(int i=0;i<devices.size();i++){
                                DeviceListItem temp = devices.get(i);
                                if (temp.device.getId().equals(endpointId)){
                                    temp.currentValue=((Double)attributeValue).toString();
                                    devices.set(i,temp);
                                }

                            }                            
                            break;
                        } else if( deviceType == DeviceType.EDDYSTONE && attributeName.equals(EDDYSTONE_ATTRIBUTE_NAME)){
                            for(int i=0;i<devices.size();i++){
                                DeviceListItem temp = devices.get(i);
                                if (temp.device.getId().equals(endpointId)){
                                    temp.currentValue=((Double)attributeValue).toString();
                                    devices.set(i,temp);
                                }

                            }
                            break;
                        } else if( deviceType == DeviceType.IBEACON && attributeName.equals(IBEACON_ATTRIBUTE_NAME)){
                            for(int i=0;i<devices.size();i++){
                                DeviceListItem temp = devices.get(i);
                                if (temp.device.getId().equals(endpointId)){
                                    temp.currentValue=((Double)attributeValue).toString();
                                    devices.set(i,temp);
                                }
                            }
                            break;
                        } else if( deviceType == DeviceType.CAMERA && attributeName.equals(IMAGE_TIME_ATTRIBUTE_NAME)){
                            for(int i=0;i<devices.size();i++){
                                DeviceListItem temp = devices.get(i);
                                if (temp.device.getId().equals(endpointId)){
                                    temp.currentValue=attributeValue.toString();
                                    devices.set(i,temp);
                                }
                            }
                            break;
                        }

                        namedValue = namedValue.next();
                    }
                    publishProgress();
                }
            });
        }

        @Override
        protected void onProgressUpdate(String... s) {
            dataAdapter = new DeviceListAdapter(context,
                    R.layout.device_list_line_item, devices);
            ListView listView = (ListView) findViewById(R.id.deviceList);
            // Assign adapter to ListView
            listView.setAdapter(dataAdapter);
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                public void onItemClick(AdapterView<?> parent, View view,
                                        int position, long id) {
                    DeviceListItem dli = (DeviceListItem) parent.getItemAtPosition(position);
                    EnterpriseClientUtil.getInstance(null).setSelectedDeviceToMonitor(dli);
                }
            });

        }
    }
    private class DeviceListAdapter extends ArrayAdapter<DeviceListItem> {

        private ArrayList<DeviceListItem> deviceList;

        public DeviceListAdapter(Context context, int textViewResourceId,
                                 ArrayList<DeviceListItem> dmList) {
            super(context, textViewResourceId, dmList);
            deviceList = new ArrayList<DeviceListItem>();
            deviceList.addAll(dmList);
        }

        private class ViewHolder {
            TextView name;

        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            DeviceListAdapter.ViewHolder holder = null;

            if (convertView == null) {
                LayoutInflater vi = (LayoutInflater)getSystemService(
                        Context.LAYOUT_INFLATER_SERVICE);
                convertView = vi.inflate(R.layout.device_list_line_item, null);

                holder = new DeviceListAdapter.ViewHolder();
                holder.name = (TextView) convertView.findViewById(R.id.deviceName);
                convertView.setTag(holder);

                holder.name.setOnClickListener( new View.OnClickListener() {
                    public void onClick(View v) {
                        TextView tv = (TextView) v ;
                        DeviceListItem sensor = (DeviceListItem)tv.getTag();
                        EnterpriseClientUtil.getInstance(null).setSelectedDeviceToMonitor(sensor);
                        Intent intent;
                        switch (sensor.deviceType) {
                            case TEMPERATURE:
                                // start monitoring temperature sensor activity
                                intent = new Intent(context, TemperatureSensorActivity.class);
                                break;
                            case HUMIDITY:
                                // start monitoring humidity sensor activity
                                intent = new Intent(context, HumiditySensorActivity.class);
                                break;
                            case IBEACON:
                                // start monitoring iBeacon sensor activity
                                intent = new Intent(context, IBeaconSensorActivity.class);
                                break;
                            case EDDYSTONE:
                                // start monitoring Eddystone sensor activity
                                intent = new Intent(context, EddystoneSensorActivity.class);
                                break;
                            case CAMERA:
                                // start monitoring Camera sensor activity
                                intent = new Intent(context, MotionActivatedCameraSensorActivity.class);
                                break;
                            default:
                                return;
                        }
                        startActivity(intent);
                    }
                });
            }
            else {
                holder = (DeviceListAdapter.ViewHolder) convertView.getTag();
            }

            DeviceListItem deviceListItem = devices.get(position);
            String currentValue = deviceListItem.currentValue;
            String deviceID = deviceListItem.device.getId();
            while(deviceID.length()<15)
                deviceID +=" ";
            switch (deviceType) {
                case TEMPERATURE:
                    if (!(currentValue.length() != 4))
                        currentValue += " ";
                    currentValue = " " + currentValue + (char) 0x00B0 + "C";
                    break;
                case HUMIDITY:
                    currentValue +="%";
                    break;
            }
            while (currentValue.length() < 5)
                currentValue = " " + currentValue;

            if (deviceID.length() > 15) {
                deviceID += "\n";
                currentValue += " >";
                SpannableString styledText = new SpannableString(deviceID + currentValue);
                styledText.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE), deviceID.length(), deviceID.length() + currentValue.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                holder.name.setText(styledText);
            } else {
                holder.name.setText( deviceID+ "      " + currentValue + "     " + ">");
            }
            holder.name.setTag(deviceListItem);
            return convertView;
        }
    }

    @Override
    public void onPause(){
        super.onPause();
        eclTask.cancel(true);
    }
}
