package com.ntels.kneet.v3.common.websocket;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Handler;
import android.os.Message;

import com.koushikdutta.async.http.AsyncHttpClient;
import com.koushikdutta.async.http.WebSocket;
import com.ntels.kneet.v3.common.AppConfig;
import com.ntels.kneet.v3.common.Constants;
import com.ntels.kneet.v3.common.util.LogUtil;
import com.ntels.kneet.v3.common.util.Util;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Semaphore;

/**
 * 1. ClassName :   WebSocketService
 * 2. FileName  :   WebSocketService.java
 * 3. Package   :   com.ntels.kneet.v3.common.websocket
 * 4. Date      :   2016-06-08
 * 5. Author    :   aaron
 * 6. Comment   :   Initialize
 */
public class WebSocketService extends Service {
    public static final int WEBSOCKET_CONNECT_TIMEOUT = 0;
    public static final int WEBSOCKET_CLIENT_AUTH = 1;

    private static final String TAG = WebSocketService.class.getSimpleName();
    private static final int TIMEOUT = 20;
    private AppConfig appConfig;
    private WebSocket webSocket = null;
    private Semaphore semaphore = null;
    private ArrayList<onWebSocketResponse> webSocketResponses = new ArrayList<onWebSocketResponse>();
    private final IBinder binder = new WebSocketBinder();
    private Util util = new Util();

    public WebSocketService() {
    }

    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch ( msg.what ) {
                case WEBSOCKET_CONNECT_TIMEOUT:
                    LogUtil.i(TAG, "WebSocket Time out");
                    break;
                case WEBSOCKET_CLIENT_AUTH:
                    send(Constants.WEBSOCKET_SEND_AUTH);
                    break;
            }
            return false;
        }
    });

    @Override
    public void onCreate() {
        super.onCreate();
        appConfig = (AppConfig) this.getApplicationContext();
    }

    /**
     * WebSocket Listener 추가
     *
     * @param webSocketResponse : WebSocket 데이터를 전달받을 리스너 객체
     */
    public void addWebSocketResponse(onWebSocketResponse webSocketResponse) {
        this.webSocketResponses.add(webSocketResponse);
    }

    public void removeWebSocketResponse(onWebSocketResponse webSocketResponse) {
        this.webSocketResponses.remove(webSocketResponse);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /**
     * WebSocket 연결
     *
     */
    public void webSocketConnect() {
        String url = Constants.URL_SERVICE_HUB_V3_DEV + "/" + appConfig.getsSelect_Servicehub_App_Id();

        if ( !appConfig.getSelect_Homegrp_Id().equals("") ) {
            url = url + "/" + appConfig.getSelect_Homegrp_Id();
        }

        LogUtil.i(TAG, "WebSocket URL : " + url);

        AsyncHttpClient.getDefaultInstance().websocket(url, null, new AsyncHttpClient.WebSocketConnectCallback() {
            @Override
            public void onCompleted(Exception ex, WebSocket ws) {
                if ( ex != null ) {
                    LogUtil.i(TAG, "WebSocket Exception : " + ex.getMessage());
                    appConfig.setbWebSocketConn(false);
                    return;
                }
                LogUtil.i(TAG, "onCompleted");
                appConfig.setbWebSocketConn(true);
                ws.setStringCallback(new WebSocket.StringCallback() {
                    @Override
                    public void onStringAvailable(final String message) {
                        LogUtil.i(TAG, "WebSocket Response : " + message);
                        if ( checkBasicStatus(message) ) { return; }

                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                if ( webSocketResponses.size() > 0 ) {
                                    for ( onWebSocketResponse wsr : webSocketResponses ) {
                                        wsr.onWebSocketResponse(message);
                                    }
                                }
                            }
                        });
                    }
                });
                webSocket = ws;
                // WebSocket Client 인증 수행
                handler.sendEmptyMessage(WEBSOCKET_CLIENT_AUTH);
            }
        });
    }

    public void webSocketClose() {
        webSocket.close();
        webSocket = null;
        webSocketResponses.clear();
        appConfig.setbWebSocketConn(false);
    }

    /**
     * device online/connect 상태 및 client 인증 결과는 리스너로 전달 없이 바로 값 저장
     *
     * @param message : WebSocket으로 전달받은 json 데이터 스트링
     * @return : 리스너로 결과 전달할지 말지 여부
     */
    private boolean checkBasicStatus(String message) {
        try {
            JSONObject jsonObject = new JSONObject(message);
            if ( jsonObject.get(Constants.WEBSOCKET_KEY_MESSAGE_TYPE).equals(Constants.WEBSOCKET_TYPE_CONN) ) {
                appConfig.setsSelect_Homegrp_Homehub_Conn_State(util.null2string(jsonObject.get(Constants.WEBSOCKET_KEY_DEVICE_CONN)));
                return true;
            } else if ( jsonObject.get(Constants.WEBSOCKET_KEY_MESSAGE_TYPE).equals(Constants.WEBSOCKET_TYPE_AUTH) ) {
                appConfig.setbWebSocketAuth(util.null2string(jsonObject.get(Constants.WEBSOCKET_KEY_RESULT_CODE)).equals("00") ? true : false);
                return true;
            } else if ( jsonObject.get(Constants.WEBSOCKET_KEY_MESSAGE_TYPE).equals(Constants.WEBSOCKET_TYPE_DEVICE_CONTENT) ) {
                String onlineStatus = ((JSONObject) jsonObject.get(Constants.WEBSOCKET_KEY_CONTENT_VALUE)).getString(Constants.WEBSOCKET_KEY_ONLINE);
                if ( onlineStatus.equalsIgnoreCase("ON") ) {
                    appConfig.setsSelect_Homegrp_Homehub_Dongle_State("ON");
                    appConfig.setsSelect_Homegrp_Homehub_Conn_State("connect");
                } else {
                    appConfig.setsSelect_Homegrp_Homehub_Dongle_State("OFF");
                    appConfig.setsSelect_Homegrp_Homehub_Conn_State("connect");
                }
                return true;
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * WebSocket 연결 상태 체크
     *
     * @return : true - 연결됨, false - 연결안됨
     */
    public boolean isWebSocketConnected() {
        return webSocket == null ? false : true;
    }

    public void send(int apiId) {
        if ( !isWebSocketConnected() ) {
            if ( webSocketResponses.size() > 0 ) {
                for ( onWebSocketResponse wsr : webSocketResponses ) {
                    wsr.onWebSocketError("error");
                }
            }
            return;
        }

        WebSocketSender webSocketSender = new WebSocketSender(webSocket, handler);
        switch (apiId) {
            case Constants.WEBSOCKET_SEND_AUTH:
                webSocketSender.send_client_auth();
                break;
        }
    }

    public void send(int apiId, HashMap<String, Object>hmParams) {
        if ( !isWebSocketConnected() ) {
            if ( webSocketResponses.size() > 0 ) {
                for ( onWebSocketResponse wsr : webSocketResponses ) {
                    wsr.onWebSocketError("error");
                }
            }
            return;
        }

        WebSocketSender webSocketSender = new WebSocketSender(webSocket, handler);
        switch (apiId) {
            case Constants.WEBSOCKET_SEND_AUTH:
                break;
            case Constants.WEBSOCKET_SEND_DEVICE_REGISTER:
                webSocketSender.send_device_register(hmParams);
                break;
            case Constants.WEBSOCKET_SEND_DEVICE_DELETE:
                webSocketSender.send_device_delete(hmParams);
                break;
            case Constants.WEBSOCKET_SEND_NODE_COMMAND:
                webSocketSender.send_node_command(hmParams);
                break;

        }
    }

    public void send(int apiId, String sJsonParam) {
        if ( !isWebSocketConnected() ) {
            if ( webSocketResponses.size() > 0 ) {
                for ( onWebSocketResponse wsr : webSocketResponses ) {
                    wsr.onWebSocketError("error");
                }
            }
            return;
        }

        WebSocketSender webSocketSender = new WebSocketSender(webSocket, handler);
        switch (apiId) {
            case Constants.WEBSOCKET_SEND_AUTH:
                break;
        }
    }

    public class WebSocketBinder extends Binder {
        public WebSocketService getService() {
            return WebSocketService.this;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if ( !isWebSocketConnected() ) {
            webSocketConnect();
        }
        return START_STICKY;
    }
}
