/*
 * Copyright (c) 2015. Ncomz. All Rights Reserved
 */

package com.ntels.onecable.view.things;

import com.android.volley.NetworkResponse;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.ntels.onecable.R;
import com.ntels.onecable.common.Constants;
import com.ntels.onecable.common.c_interface.OnDataSendToReslut;
import com.ntels.onecable.common.http.HttpSend;
import com.ntels.onecable.common.netatmo.NetatmoHttpClientImpl;
import com.ntels.onecable.common.util.Dlog;
import com.ntels.onecable.common.util.LogUtil;
import com.ntels.onecable.common.util.Util;
import com.ntels.onecable.common.widget.CustomActivity;
import com.ntels.onecable.view.dialog.CustomDialog;

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

import android.app.Activity;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.MediaController;
import android.widget.VideoView;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;

import static com.ntels.onecable.common.http.Response.OK;

/**
 * <pre>
 * 1. ClassName :   ThingsDeviceNetatmoCameraDetail
 * 2. FileName  :   ThingsDeviceNetatmoCameraDetail.java
 * 3. Package   :   com.ntels.onecable.view.things
 * 4. Date      :   2016-11-25
 * 5. Author    :   aaron
 * 6. Comment   :   Initialize
 * </pre>
 */
public class ThingsDeviceNetatmoCameraDetail extends CustomActivity implements View.OnClickListener,
        CustomDialog.OnMsgAlterToResult {

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

    /*통신 관련*/
    private int mType = 0;
    private static final int MSG_COM_P_NETATMO_REFRESH_TOKEN = 1;
    private static final int MSG_COM_P_NETATMO_HOMEDATA = 2;
    private static final int MSG_COM_G_NETATMO_COMMAND_PING = 3;

    private static final int CAMERAVIEW_DELAY_MILLIS = 100;
    private static final int DEFAULT_ANIMATION_DURATION = 800;
    private static final int DEFAULT_ANIMATION_TIMEOUT = 15000;

    /*공통*/
    private Activity mActivity;
    private Util mUtil = new Util();
    private CustomDialog mCustomDialog = new CustomDialog();
    private VideoView mCameraView = null;
    private String mRefreshToken = "";
    private NetatmoHttpClientImpl mNetatmoHttpClientImpl = null;
    private boolean mIsLoading = false;
    private Animation mLoadingAnimation;
    private String mCameraId = "";
    private String mCameraUrl = "";
    private String mLocalCameraUrl = "";
    private boolean mIsLocalPing = false;
    private String mCameraOnOff = "";
    private String mOnlineState = "";

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        mActivity = ThingsDeviceNetatmoCameraDetail.this;
        mCustomDialog.setOnMsgAlterToResultEvent(this);
        mNetatmoHttpClientImpl = new NetatmoHttpClientImpl(this);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        View viewToLoad = LayoutInflater.from(mActivity).inflate(
                R.layout.things_device_netatmo_camera_detail, null);
        this.setContentView(viewToLoad);

        if (getIntent() != null) {
            mRefreshToken = getIntent().getStringExtra(Constants.EXTRA_REFRESH_TOKEN);
            mCameraId = getIntent().getStringExtra(Constants.EXTRA_CAMERA_ID);
            mCameraOnOff = getIntent().getStringExtra(Constants.EXTRA_CAMERA_ON_OFF);
            mOnlineState = getIntent().getStringExtra(Constants.EXTRA_ONLNIE_STATE);
        }
        mUtil.getView(mActivity, R.id.btnClose).setOnClickListener(this);
        LogUtil.i(TAG, "Camera share : " + mCameraOnOff);
        if ("OFF".equals(mOnlineState) || "OFF".equals(mCameraOnOff)) {
            mUtil.getView(mActivity, R.id.llOff).setVisibility(View.VISIBLE);
        } else {
            startLoading();
        }
    }

    @Override
    public void onClick(View view) {
        LogUtil.i(TAG, "onClick!!");
        switch (view.getId()) {
            case R.id.btnClose:
                onBackPressed();
                break;

            default:
                break;
        }
    }

    @Override
    public void resultCustomDialogResponse(int msgId, int btnResult) {

        switch (msgId) {

            case Constants.MSG807:
                if (btnResult == 1) {
                    if (mType == MSG_COM_P_NETATMO_REFRESH_TOKEN) {
                        startLoading();
                    } else {
                        comHandler.sendEmptyMessageDelayed(mType, Constants.HANDLER_DELAY_MILLIS);
                    }
                }
                break;
            case Constants.MSG000:
            case Constants.MSG916:
            case Constants.MSG919:
            case Constants.MSG920:
                onBackPressed();
                break;

            default:
                break;
        }
    }

    /**
     * UI display.
     */
    private void setDisp() {
        if (mIsLoading) {
            mLoadingAnimation.cancel();
        }
        mCameraView = (VideoView) findViewById(R.id.vvCameraView);
        MediaController mc = new MediaController(this);
        mc.setAnchorView(mCameraView);
        mc.setMediaPlayer(mCameraView);
        LogUtil.i(TAG, "mCameraUrl : " + mCameraUrl);
        mCameraView.setVideoURI(Uri.parse(mCameraUrl));
        mCameraView.setMediaController(mc);
        mCameraView.requestFocus();
        mCameraView.postInvalidateDelayed(CAMERAVIEW_DELAY_MILLIS);
        mCameraView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mp.setVolume(1.0f, 1.0f);
                mCameraView.start();
            }
        });
        mCameraView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                LogUtil.i(TAG, "what : " + what + ", extra : " + extra);
                return true;
            }
        });
    }

    /**
     * 사용자 넷타모 access token을 갱신한다.
     */
    private void refreshToken() {

        if (null == mRefreshToken || "" == mRefreshToken) {
            if (mIsLoading) {
                mLoadingAnimation.cancel();
            }
            mCustomDialog.msgAlert(mActivity, Constants.MSG920);
            return;
        }
        mNetatmoHttpClientImpl.refreshToken(mRefreshToken,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        JSONObject jsonObject;
                        try {
                            jsonObject = new JSONObject(response);
                            mNetatmoHttpClientImpl.processOAuthResponse(jsonObject);
                            comHandler.sendEmptyMessageDelayed(MSG_COM_P_NETATMO_HOMEDATA,
                                    Constants.HANDLER_DELAY_MILLIS);
                        } catch (JSONException ex) {
                            ex.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {

                    @Override
                    public void onErrorResponse(VolleyError error) {
                        LogUtil.e("errorRefreshToken", error.toString());
                        if (mIsLoading) {
                            mLoadingAnimation.cancel();
                        }
                        LogUtil.e(TAG, error.toString());
                        String errorMessage = null;

                        NetworkResponse response = error.networkResponse;
                        if (response != null && response.data != null) {
                            try {
                                errorMessage = new JSONObject(
                                        new String(response.data, "UTF-8")).getString("error");
                            } catch (UnsupportedEncodingException ex) {
                                ex.printStackTrace();
                            } catch (JSONException ex) {
                                ex.printStackTrace();
                            }
                            LogUtil.e(TAG, errorMessage);
                            if (null != errorMessage) {
                                if ("invalid_grant".equals(errorMessage)) {
                                    mCustomDialog.msgAlert(mActivity, Constants.MSG919);
                                } else {
                                    mCustomDialog.msgAlert(mActivity, Constants.MSG000,
                                            errorMessage);
                                }
                            }
                        }
                    }
                }
        );
    }

    /**
     * 넷타모 사용자 계정에 있는 카메라 정보를 읽어온다.
     */
    private void netatmoHomeData() {

        mNetatmoHttpClientImpl.getHomeData(
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        JSONObject jsonObject;
                        try {
                            jsonObject = new JSONObject(response);
                            LogUtil.i(TAG, "Homedata response : " + jsonObject.toString());
                            ArrayList<HashMap<String, Object>> alCameraList =
                                    mNetatmoHttpClientImpl.parseNetatmoCamera(jsonObject);
                            processCurrentCameraUrl(alCameraList);
                        } catch (JSONException ex) {
                            ex.printStackTrace();
                            if (mIsLoading) {
                                mLoadingAnimation.cancel();
                            }
                            mCustomDialog.msgAlert(mActivity, Constants.MSG807);
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.e(TAG, error.toString());
                        if (mIsLoading) {
                            mLoadingAnimation.cancel();
                        }
                        mCustomDialog.msgAlert(mActivity, Constants.MSG807);
                    }
                }
        );

    }

    /**
     * 로딩 애니메이션 시작.
     */
    private void startLoading() {
        mIsLoading = true;
        mLoadingAnimation = AnimationUtils.loadAnimation(mActivity, R.anim.progress_anim);
        mLoadingAnimation.setDuration(DEFAULT_ANIMATION_DURATION);
        mLoadingAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                LogUtil.i(TAG, "onAnimationStart");
                comHandler.sendEmptyMessageDelayed(MSG_COM_P_NETATMO_REFRESH_TOKEN,
                        Constants.HANDLER_DELAY_MILLIS);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mLoadingAnimation.cancel();
                    }
                }, DEFAULT_ANIMATION_TIMEOUT);
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                LogUtil.i(TAG, "onAnimationEnd");
                mIsLoading = false;
                mUtil.getImageView(mActivity, R.id.ivLoadingProgress).clearAnimation();
                mUtil.getImageView(mActivity, R.id.ivLoadingProgress).setVisibility(View.GONE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                LogUtil.i(TAG, "onAnimationRepeat");
            }
        });
        mUtil.getImageView(mActivity, R.id.ivLoadingProgress).bringToFront();
        mUtil.getImageView(mActivity, R.id.ivLoadingProgress).setVisibility(View.VISIBLE);
        mUtil.getImageView(mActivity, R.id.ivLoadingProgress).startAnimation(mLoadingAnimation);
    }

    /**
     * 카메라 재생 Url 셋팅.
     *
     * @param cameras 카메라 정보
     */
    private void processCurrentCameraUrl(ArrayList<HashMap<String, Object>> cameras) {
        for (HashMap<String, Object> hmCamera : cameras) {
            if (hmCamera.get("id").equals(mCameraId)) {
                if (hmCamera.get("status").equals("disconnected")) {
                    mCustomDialog.msgAlert(mActivity, Constants.MSG916);
                    return;
                }
                mCameraUrl = mUtil.null2string(hmCamera.get("vpn_url"));
                if (((Boolean) hmCamera.get("is_local")).booleanValue()) {
                    comHandler.sendEmptyMessageDelayed(MSG_COM_G_NETATMO_COMMAND_PING,
                            Constants.HANDLER_DELAY_MILLIS);
                } else {
                    mCameraUrl += "/live/index.m3u8";
                    setDisp();
                }
                break;
            }
        }
    }

    /**
     * 네타모 카메라의 로컬 IP Address를 조회한다.
     */
    private void sendGetCloudNetatmoCommandPing() {
        String cameraUrl = "";
        try {
            HttpSend httpSend;

            httpSend = new HttpSend(mActivity, !mIsLoading);

            httpSend.setOnDataSendToReslutEvent(new OnDataSendToReslut() {
                @Override
                public void resultResponse(com.ntels.onecable.common.http.Response result) {

                    resultGetCloudNetamoCommandPing(result);
                }
            });
            if (mIsLocalPing) {
                cameraUrl = mLocalCameraUrl;
            } else {
                cameraUrl = this.mCameraUrl;
            }

            httpSend.G_cloud_netatmo_command_ping(cameraUrl);
        } catch (Exception ex) {
            ex.printStackTrace();
            mCustomDialog.msgAlert(mActivity, Constants.MSG807);
        }
    }

    /**
     * 네타모 카메라의 로컬 IP Address를 조회 결과.
     *
     * @param result 결과 data
     */
    private void resultGetCloudNetamoCommandPing(com.ntels.onecable.common.http.Response result) {

        try {
            if (result.getStatusCode() == OK) {
                HashMap<String, Object> hmMap = mUtil.jsonToMap(result.getContent());
                if (hmMap.size() > 0) {
                    if (!mIsLocalPing) {
                        // vpn_url로 ping을 날렸을때 local_url이 결과로 오면
                        // 다시 local_url로 ping을 날린다.
                        mIsLocalPing = true;
                        mLocalCameraUrl = mUtil.null2string(hmMap.get(Constants.KEY_LOCAL_URL));
                        comHandler.sendEmptyMessageDelayed(MSG_COM_G_NETATMO_COMMAND_PING,
                                Constants.HANDLER_DELAY_MILLIS);
                    } else {
                        // local_url로 ping을 날려 같은 local_url이 결과로 오는지 확인되면 vpn_url
                        // 뒤에 /live/index_local.m3u8를 붙인다.
                        mIsLocalPing = false;
                        mCameraUrl += "/live/index_local.m3u8";
                        setDisp();
                    }
                }
            } else {
                JSONObject joResult = new JSONObject(result.getContent());
                Dlog.v(joResult.toString());
                if (mIsLoading) {
                    mLoadingAnimation.cancel();
                }
            }
        } catch (Exception ex) {
            if (mIsLoading) {
                mLoadingAnimation.cancel();
            }
            ex.printStackTrace();
            // TODO : 에러 처리 추가
            if (mIsLocalPing) {
                // is_local true이지만 같은 local network에 있지 않을때는 vpn_url로 영상 플레이
                mIsLocalPing = false;
                mCameraUrl += "/live/index.m3u8";
                setDisp();
            } else {
                mCustomDialog.msgAlert(mActivity, Constants.MSG807);
            }
        }
    }

    Handler comHandler = new Handler(new IncomingHandlerCallBack());

    /**
     * 서버 요청 핸들러.
     */
    class IncomingHandlerCallBack implements Handler.Callback {

        @Override
        public boolean handleMessage(Message msg) {

            mType = msg.what;
            switch (msg.what) {
                case MSG_COM_P_NETATMO_REFRESH_TOKEN:
                    refreshToken();
                    break;
                case MSG_COM_P_NETATMO_HOMEDATA:
                    netatmoHomeData();
                    break;
                case MSG_COM_G_NETATMO_COMMAND_PING:
                    sendGetCloudNetatmoCommandPing();
                    break;

                default:
                    break;
            }
            return true;
        }
    }

}
