package org.iotivity.bridge.homeserver;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;

import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.util.Pair;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.icontrols.service.control.ILightControlService;
import com.icontrols.service.control.ILightControlServiceCallback;

import org.iotivity.OCCoreRes;
import org.iotivity.OCEndpoint;
import org.iotivity.OCQos;
import org.iotivity.OCUuid;
import org.iotivity.OCUuidUtil;
import org.iotivity.bridge.homeserver.handler.client.DeviceDiscoveryHandler;
import org.iotivity.bridge.homeserver.handler.client.GetCommonResponseHandler;
import org.iotivity.bridge.homeserver.handler.client.GetLightResponseHandler;
import org.iotivity.bridge.homeserver.handler.client.Post2LightResponseHandler;
import org.iotivity.bridge.homeserver.handler.client.PostLightResponseHandler;
import org.iotivity.bridge.homeserver.handler.client.ResourceDetailsHelper;
import org.iotivity.bridge.homeserver.model.Bridge;
import org.iotivity.bridge.homeserver.model.Light;
import org.iotivity.bridge.homeserver.utils.Utils;
import org.iotivity.oc.OcCborEncoder;
import org.iotivity.oc.OcRemoteDevice;
import org.iotivity.oc.OcRemoteResource;
import org.iotivity.oc.OcUtils;

import java.util.ArrayList;
import java.util.HashMap;

public class BridgeServerActivity extends AppCompatActivity {

    private static final String TAG = BridgeServerActivity.class.getSimpleName();

    private Button discoverDevicesButton;
    private ListView listView;

    private AdapterView.OnItemClickListener resourceItemClickListener;
    private AdapterView.OnItemLongClickListener resourceItemLongClickListener ;
    private ArrayAdapter<OcRemoteResource> resourceArrayAdapter;

    private AdapterView.OnItemClickListener deviceItemClickListener;
    private ArrayAdapter<OcRemoteDevice> deviceArrayAdapter;

    ArrayList<OcRemoteDevice> deviceList = new ArrayList<OcRemoteDevice>();
    private final Object arrayAdapterSync = new Object();

    private TextView mConsoleTextView;
    private ScrollView mScrollView;

    private RemoteServiceConnection remoteConn ;
    private LocalServiceConnection localConn ;
    private IBridgeService remoteBinder = null ;                    // Remote Service Binder
    private BridgeService.LocalServiceBinder localBinder = null ;   // Local Service Binder
    private BridgeService bridgeService = null ;
    private BridgeServer bridgeServer = null ;

    public BridgeService getBridgeService() {
        return bridgeService ;
    }
    public BridgeServer getBridgeServer() {
        return bridgeServer ;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        createContent();

        if (savedInstanceState == null) {
            // start first time only
            //bridgeServer = new BridgeServer(this);

            // start Service
            Intent intent = new Intent( BridgeServerActivity.this, BridgeService.class );
            startService(intent);

            // Local Service Bind
            localConn = new LocalServiceConnection();
            bindService(intent, localConn, Context.BIND_AUTO_CREATE);

            // Bridge Service Remote Bind
            remoteConn = new RemoteServiceConnection();
            Intent rIntent = new Intent();
            rIntent.setClassName("org.iotivity.bridge.homeserver", "org.iotivity.bridge.homeserver.BridgeService");
            rIntent.setAction(IBridgeService.class.getName());
            bindService(rIntent, remoteConn, Context.BIND_AUTO_CREATE);

        }
    }

    @Override
    protected void onDestroy() {

        this.unbindBridgeService();

        super.onDestroy();

        //Log.d(TAG, "Service Process will be killed : service pid = " + service_pid + ", application pid = " + Process.myPid());
        // Bridge Service and Application Process Kill
        //android.os.Process.killProcess(service_pid);

        //or

        //Log.d(TAG, "System.exit() will be called");
        //System.runFinalizersOnExit(true);
        //System.exit(0);
    }

    private void unbindBridgeService() {

        // Unregister Remote Client Callback
        if (remoteBinder != null) {
            try {
                remoteBinder.unregisterActivityCallback(aCallback);
                remoteBinder.unregisterBridgeServiceCallback(sCallback);
                Log.d(TAG, "unregister Remote Client Callback()");
            } catch (RemoteException e) {
                // There is nothing special we need to do if the service
                // has crashed.
            }
        }

        // Unbind Service
        if(localBinder!=null) {
            unbindService(localConn);
            localBinder = null;
        }
        if(remoteBinder!=null) {
            unbindService(remoteConn);
            remoteBinder = null ;
        }
        Log.d(TAG, "unbindServices()");

    }

    private void stopBridgeService() {

        // unbind Service
        unbindBridgeService();

        // stop Service
        Intent intent = new Intent( BridgeServerActivity.this, BridgeService.class );
        stopService(intent);
        Log.d(TAG, "stopService()");
    }

    class RemoteServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            Log.d(TAG, "onServiceConnected ComponentName=" + name + ", IBinder=" + service.toString());
            if (service instanceof IBridgeService.Stub) {

                remoteBinder = IBridgeService.Stub.asInterface(service);

                try {
                    remoteBinder.registerActivityCallback(aCallback);
                    remoteBinder.registerBridgeServiceCallback(sCallback);
                } catch (RemoteException ex) {
                    Log.e(TAG, "Register Callbacks", ex);
                    // In this case the service has crashed before we could even
                    // do anything with it; we can count on soon being
                    // disconnected (and then reconnected if it can be restarted)
                    // so there is no need to do anything here.
                }

                Toast.makeText(BridgeServerActivity.this, "Bridge Remote Service Connected",
                        Toast.LENGTH_SHORT).show();

            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

            Log.d(TAG, "onServiceDisconnected ComponentName=" + name + ", IBinder=" + remoteBinder.toString());
            remoteBinder = null;
            Toast.makeText(BridgeServerActivity.this, "Bridge Remote Service Disconnected",
                    Toast.LENGTH_SHORT).show();

        }

    }

    class LocalServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            Log.d(TAG, "onServiceConnected ComponentName=" + name + ", IBinder=" + service.toString());
            if (service instanceof BridgeService.LocalServiceBinder) {

                localBinder = (BridgeService.LocalServiceBinder) service;
                bridgeService = localBinder.getService();
                bridgeServer = bridgeService.getBridgeServer();
                Toast.makeText(BridgeServerActivity.this, "Bridge Local Service Connected",
                        Toast.LENGTH_SHORT).show();

            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

            Log.d(TAG, "onServiceDisconnected ComponentName=" + name + ", IBinder=" + localBinder.toString());

            localBinder = null;
            bridgeService = null;
            bridgeServer = null;

            Toast.makeText(BridgeServerActivity.this, "Bridge Local Service Disconnected",
                    Toast.LENGTH_SHORT).show();

        }
    }

    private IBridgeActivityCallback aCallback = new IBridgeActivityCallback.Stub() {
        /**
         * This is called by the remote service regularly to tell us about
         * new values.  Note that IPC calls are dispatched through a thread
         * pool running in each process, so the code executing here will
         * NOT be running in our main thread like most other things -- so,
         * to update the UI, we need to use a Handler to hop over there.
         */
        @Override
        public void onLogPrintLineReceived() throws RemoteException {
            printLine();
        }

        @Override
        public void onLogMessageReceived(String msg) throws RemoteException {
            msg(msg);
        }

        @Override
        public void onDeviceDiscovered() throws RemoteException {

            runOnUiThread(new Runnable() {
                public void run() {
                    synchronized (arrayAdapterSync) {
                        deviceArrayAdapter.setNotifyOnChange(false);
                        if(bridgeServer!=null) {
                            deviceArrayAdapter.clear();
                            deviceArrayAdapter.addAll(bridgeServer.getPairwisedDevices());
                        }
                        deviceArrayAdapter.setNotifyOnChange(true);
                    }
                    deviceArrayAdapter.notifyDataSetChanged();
                }
            });

        }

    };

    private IBridgeServiceCallback sCallback = new IBridgeServiceCallback.Stub() {
        /**
         * This is called by the remote service regularly to tell us about
         * new values.  Note that IPC calls are dispatched through a thread
         * pool running in each process, so the code executing here will
         * NOT be running in our main thread like most other things -- so,
         * to update the UI, we need to use a Handler to hop over there.
         */

        @Override
        public void onResultReceived(int result_code, String result_data) throws RemoteException {
            msg("result_code="+result_code + ", result_data="+result_data );
            printLine();
        }
    };

    /*private static final int BUMP_MSG = 1;

    private Handler mHandler = new Handler() {
        @Override public void handleMessage(Message msg) {
            switch (msg.what) {
                case BUMP_MSG:
                    msg("Received from service: " + msg.arg1);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

    };
*/
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.actionbar_actions, menu) ;
        return true ;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_bridge_reset:
                // TODO : do some action like start Activity or show Dialog
            {
                AlertDialog.Builder resetBridgeDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                resetBridgeDialogBuilder.setTitle(getString(R.string.resetBridge));
                resetBridgeDialogBuilder.setMessage(getString(R.string.resetBridgeMessage));

                resetBridgeDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if(bridgeServer!=null) bridgeServer.resetBridgeServer();
                    }
                });

                resetBridgeDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                });

                Dialog resebridgeDialog = resetBridgeDialogBuilder.create();
                resebridgeDialog.show();
                return true;
            }

            case R.id.action_vods_reset:
                // TODO : do some action like start Activity or show Dialog
                {
                    AlertDialog.Builder resetVodsDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                    resetVodsDialogBuilder.setTitle(getString(R.string.resetVods));
                    resetVodsDialogBuilder.setMessage(getString(R.string.resetVodsMessage));

                    resetVodsDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if(bridgeServer!=null) bridgeServer.resetVirtualOCFDevices();
                        }
                    });

                    resetVodsDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    });

                    Dialog resetVodsDialog = resetVodsDialogBuilder.create();
                    resetVodsDialog.show();
                    return true;
            }
            case R.id.action_bridgeservice_stop : {

                AlertDialog.Builder stopServiceDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                stopServiceDialogBuilder.setTitle(getString(R.string.stopBridgeService));
                stopServiceDialogBuilder.setMessage(getString(R.string.stopBridgeMessage));

                stopServiceDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // Stop Bridge Service
                        stopBridgeService();
                    }
                });

                stopServiceDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                });

                Dialog stopServiceDialog = stopServiceDialogBuilder.create();
                stopServiceDialog.show();
                return true;

            }
            case R.id.action_bridgeservice_kill : {

                AlertDialog.Builder killServiceDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                killServiceDialogBuilder.setTitle(getString(R.string.killBridgeService));
                killServiceDialogBuilder.setMessage(getString(R.string.killBridgeMessage));

                killServiceDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // kill Bridge Service
                        stopBridgeService();
                        Log.d(TAG, "System.exit() will be called");
                        System.runFinalizersOnExit(true);
                        System.exit(0);
                    }
                });

                killServiceDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                });

                Dialog killServiceDialog = killServiceDialogBuilder.create();
                killServiceDialog.show();
                return true;

            }
            default :
                return super.onOptionsItemSelected(item) ;
        }
    }

    private void createContent() {

        mConsoleTextView = (TextView) findViewById(R.id.consoleTextView);
        mConsoleTextView.setMovementMethod(new ScrollingMovementMethod());
        mScrollView = (ScrollView) findViewById(R.id.scrollView);
        mScrollView.fullScroll(View.FOCUS_DOWN);

        resourceItemClickListener = new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                OcRemoteResource resource = resourceArrayAdapter.getItem((int) id);
                if (resource != null) {
                    AlertDialog.Builder resourceDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                    resourceDialogBuilder.setTitle(resource.getAnchor() + resource.getUri());

                    ListView resourceDetailsListView = new ListView(BridgeServerActivity.this);
                    final ArrayList<HashMap<String, String>> resourceDetailsList = new ArrayList<>();
                    final SimpleAdapter resourceDetailsAdapter = new SimpleAdapter(BridgeServerActivity.this,
                            resourceDetailsList, R.layout.resource_multi_line,
                            new String[]{"line1", "line2", "line3", "line4"},
                            new int[]{R.id.line_1, R.id.line_2, R.id.line_3, R.id.line_4});

                    resourceDetailsListView.setAdapter(resourceDetailsAdapter);
                    resourceDetailsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                            // TODO :
                            Log.d(TAG, "resourceDetailsListView clicked!!");
                        }
                    });
                    resourceDialogBuilder.setView(resourceDetailsListView);

                    ResourceDetailsHelper.buildResourceDetails(resource, resourceDetailsList);

                    Dialog resourceDialog = resourceDialogBuilder.create();
                    resourceDialog.show();

                } else {
                    Log.w(TAG, "Resource not found in list");
                }
            }
        };

        resourceItemLongClickListener = new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                // TODO :

                Log.d(TAG, "resourceItemLongClickListener clicked!!");
                OcRemoteDevice device = null ;
                if(view.getTag()!=null && view.getTag() instanceof OcRemoteDevice) {
                    device = (OcRemoteDevice) view.getTag();
                    Log.d(TAG, "getTag() OcRemoteDevice = " + device.getName());
                }

                OcRemoteResource resource = resourceArrayAdapter.getItem((int) id);
                if (resource != null) {
                    if (Utils.containsList(resource.getTypes(), Light.RT_BINARYSWITCH) ||   // Light Switch(Switch Binary) resource and
                            Utils.containsList(resource.getTypes(), Light.RT_DIMMING)) {    // Dimming Control resource

                        OCEndpoint ep = Utils.getCoapsEndpoint(resource.getEndpoints());
                        Log.d(TAG, "Get Light Request by Client : Endpoint = " + OcUtils.endpointToString(ep) +", Uri = "+resource.getUri());

                        Light res_light = new Light(device.getName());
                        GetLightResponseHandler responseHandler = new GetLightResponseHandler(BridgeServerActivity.this, resource, new Light());
                        OcUtils.doGet(resource.getUri(), ep, null, responseHandler, OCQos.LOW_QOS);
                    }
                    else { // Common Get Response
                        GetCommonResponseHandler responseHandler = new GetCommonResponseHandler(BridgeServerActivity.this, resource);
                        OcUtils.doGet(resource.getUri(), Utils.getCoapsEndpoint(resource.getEndpoints()), null, responseHandler, OCQos.LOW_QOS);
                    }
                }
                return true;
            }
        };

        deviceItemClickListener = new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                final OcRemoteDevice device = deviceArrayAdapter.getItem((int) id);
                if (device != null) {
                    AlertDialog.Builder discoverResourcesDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                    discoverResourcesDialogBuilder.setTitle(R.string.discoveredResources);

                    ListView resourceListView = new ListView(BridgeServerActivity.this);
                    resourceListView.setTag(device); // temporary device on view.setTag
                    final ArrayList<OcRemoteResource> resourceArrayList = new ArrayList<OcRemoteResource>();
                    resourceArrayAdapter = new ArrayAdapter(BridgeServerActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, resourceArrayList) {
                        @Override
                        public View getView(int position, View convertView, ViewGroup parent) {
                            View view = super.getView(position, convertView, parent);
                            TextView text1 = (TextView) view.findViewById(android.R.id.text1);

                            view.setTag(device);
                            OcRemoteResource resource = resourceArrayAdapter.getItem(position);
                            if (resource != null) {
                                text1.setText(resource.getAnchor() + resource.getUri());
                            }
                            return view;
                        }
                    };
                    resourceListView.setAdapter(resourceArrayAdapter);
                    resourceListView.setOnItemClickListener(resourceItemClickListener);
                    resourceListView.setOnItemLongClickListener(resourceItemLongClickListener);
                    discoverResourcesDialogBuilder.setView(resourceListView);

                    resourceArrayAdapter.setNotifyOnChange(false);
                    for (OcRemoteResource resource : device.getResources()) {
                        if(Utils.isAccessableByPairwisedClient(resource.getTypes())) {
                            resourceArrayAdapter.add(resource);
                        }
                    }
                    resourceArrayAdapter.setNotifyOnChange(true);
                    resourceArrayAdapter.notifyDataSetChanged();

                    Dialog discoverResourcesDialog = discoverResourcesDialogBuilder.create();
                    discoverResourcesDialog.show();

                } else {
                    Log.w(TAG, "Uuid not found in list");
                }
            }
        };

        discoverDevicesButton = (Button) findViewById(R.id.discover_devices_button);
        discoverDevicesButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                deviceArrayAdapter.setNotifyOnChange(false);
                deviceArrayAdapter.clear();
                deviceArrayAdapter.setNotifyOnChange(true);

                if(bridgeService!=null) {
                    bridgeService.clearPairwisedDevices();
                    bridgeService.loadPairwisedDeviceUUIDs();
                }

                new Thread(new Runnable() {
                    public void run() {

                        OCUuid bridge_di = OCCoreRes.getDeviceId(Bridge.BRIDGE_INDEX);
                        if (!OcUtils.discoverAllDevices(new DeviceDiscoveryHandler(bridgeService, bridge_di))) {
                            final String msg = "Failed to discover devices";
                            Log.d(TAG, msg);
                            runOnUiThread(new Runnable() {
                                public void run() {
                                    Toast.makeText(BridgeServerActivity.this, msg, Toast.LENGTH_LONG).show();
                                }
                            });
                        }
                    }
                }).start();
            }
        });

        deviceArrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_2, android.R.id.text1, deviceList) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                TextView text1 = (TextView) view.findViewById(android.R.id.text1);
                TextView text2 = (TextView) view.findViewById(android.R.id.text2);

                OcRemoteDevice device = deviceArrayAdapter.getItem(position);
                if (device != null) {
                    text1.setText(OCUuidUtil.uuidToString(device.getDeviceId()));
                    text2.setText("\t" + device.getName());
                }
                return view;
            }
        };

        listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(deviceArrayAdapter);
        listView.setOnItemClickListener(deviceItemClickListener);
        listView.setFocusable(true);
        listView.setFocusableInTouchMode(true);
        listView.setItemsCanFocus(true);
    }

    public void addDevice(final OcRemoteDevice device) {

        runOnUiThread(new Runnable() {
            public void run() {
                synchronized (arrayAdapterSync) {
                    deviceArrayAdapter.setNotifyOnChange(false);
                    deviceArrayAdapter.add(device);
                    deviceArrayAdapter.setNotifyOnChange(true);
                }
                deviceArrayAdapter.notifyDataSetChanged();
            }
        });
    }

    public void msg(final String text) {
        runOnUiThread(new Runnable() {
            public void run() {
                mConsoleTextView.append("\n");
                mConsoleTextView.append(text);
                mScrollView.fullScroll(View.FOCUS_DOWN);
            }
        });
        Log.i(TAG, text);
    }

    public void printLine() {
        msg("------------------------------------------------------------------------");
    }

    public void showErrorDialog(final String title, final String msg) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                alertDialogBuilder.setTitle(title);
                alertDialogBuilder.setMessage(msg);

                alertDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });

                Dialog errorDialog = alertDialogBuilder.create();
                errorDialog.show();
            }
        });
    }

    public void showResultDialog(final String title, final String msg) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                alertDialogBuilder.setTitle(title);
                alertDialogBuilder.setMessage(msg);

                alertDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });

                Dialog errorDialog = alertDialogBuilder.create();
                errorDialog.show();
            }
        });
    }

    public void showPropertiesDialog(final String title, final ArrayList<Pair<String, Object>> props, final OcRemoteResource resource) {

        runOnUiThread(new Runnable() {
            public void run() {

                AlertDialog.Builder propertyDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                propertyDialogBuilder.setTitle(title);

                ListView propertyDetailsListView = new ListView(BridgeServerActivity.this);
                final ArrayAdapter propertyArrayAdapter = new ArrayAdapter(BridgeServerActivity.this,
                        android.R.layout.simple_list_item_1, android.R.id.text1, props) {
                    @Override
                    public View getView(int position, View convertView, ViewGroup parent) {
                        View view = super.getView(position, convertView, parent);
                        TextView text1 = (TextView) view.findViewById(android.R.id.text1);


                        Pair<String, Object> prop = (Pair<String, Object>) this.getItem(position);
                        if (prop != null) {
                            text1.setText(prop.first + " = "+ prop.second);
                        }
                        return view;
                    }
                };
                propertyDetailsListView.setAdapter(propertyArrayAdapter);
                propertyDetailsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        // TODO :
                        Log.d(TAG, "propertyDetailsListView position["+position+"] clicked!!");
                        final Pair<String, Object> property = (Pair<String, Object>)propertyArrayAdapter.getItem(position);
                        AlertDialog.Builder postputDialogBuilder = new AlertDialog.Builder(BridgeServerActivity.this);
                        postputDialogBuilder.setTitle("Post/Put value of " + property.first);
                        postputDialogBuilder.setMessage("Do you want to change the value of this property \""+property.first+"\" ?");

                        final EditText ed_value = new EditText(BridgeServerActivity.this) ;
                        ed_value.setText(property.second.toString());
                        postputDialogBuilder.setView(ed_value);
                        postputDialogBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String value = ed_value.getText().toString();
                                Log.d(TAG, "Edit box value = " + value + ", type = " + property.second);

                                // post/put
                                OcRemoteDevice device = findRemoteDevice(resource);
                                Light res_light = new Light(device.getName());
                                PostLightResponseHandler putLight = new PostLightResponseHandler(BridgeServerActivity.this, resource, res_light);
                                if (OcUtils.initPost(resource.getUri(), Utils.getCoapsEndpoint(resource.getEndpoints()), null, putLight, OCQos.LOW_QOS)) {
                                    OcCborEncoder root = OcCborEncoder.createOcCborEncoder(OcCborEncoder.EncoderType.ROOT);
                                    if(property.second instanceof Boolean) {
                                        Log.d(TAG, "type = " + Boolean.class.toString());
                                        root.setBoolean(property.first, Boolean.parseBoolean(value));
                                    } else if(property.second instanceof Integer) {
                                        Log.d(TAG, "type = " + Integer.class.toString());
                                        root.setLong(property.first, Integer.parseInt(value));
                                    } else if(property.second instanceof Long) {
                                        Log.d(TAG, "type = " + Long.class.toString());
                                        root.setLong(property.first, Long.parseLong(value));
                                    } else if(property.second instanceof Double) {
                                        Log.d(TAG, "type = " + Double.class.toString());
                                        root.setDouble(property.first, Double.parseDouble(value));
                                    } else if(property.second instanceof String) {
                                        Log.d(TAG, "type = " + String.class.toString());
                                        root.setTextString(property.first, value);
                                    }
                                    root.done();

                                    if (OcUtils.doPost()) {
                                        BridgeServerActivity.this.msg("\tSent Post request");
                                    } else {
                                        BridgeServerActivity.this.msg("\tCould not send Post request");
                                    }
                                } else {
                                    BridgeServerActivity.this.msg("\tCould not init Post request");
                                }
                                BridgeServerActivity.this.printLine();
                            }
                        });
                        postputDialogBuilder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        });

                        Dialog postputDialog = postputDialogBuilder.create();
                        postputDialog.show();

                    }
                });
                propertyDialogBuilder.setView(propertyDetailsListView);
                propertyDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });

                Dialog propertyDialog = propertyDialogBuilder.create();
                propertyDialog.show();
            }
        });

    }

    private OcRemoteDevice findRemoteDevice(OcRemoteResource current_resource) {
        for (OcRemoteDevice device : deviceList) {
            for(OcRemoteResource resource : device.getResources()) {
                if(resource.equals(current_resource)) return device ;
            }
        }
        return null ;
    }

}
