package kr.co.icontrols.iotplatform.utils;

import android.os.Handler;
import android.os.Looper;
import android.util.Base64;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import kr.co.icontrols.iotplatform.DataClass.DeviceGroupInfo;
import kr.co.icontrols.iotplatform.IotPlatformApplication;
import kr.co.icontrols.iotplatform.R;
import kr.co.icontrols.iotplatform.cognito.AppHelper;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

import static com.amazonaws.util.EncodingSchemeEnum.BASE64;
import static kr.co.icontrols.iotplatform.utils.CommonUtils.ErrorLogOutput;
import static kr.co.icontrols.iotplatform.utils.CommonUtils.WarnLogOutput;
import static kr.co.icontrols.iotplatform.utils.Constants.DEFUALT_GROUP_INDEX;

public class HttpApi {
    private static final String TAG = "HttpApi";

    public static final int HTTP_ACCEPTED = 202;
    public static final int HTTP_BAD_GATEWAY = 502;
    public static final int HTTP_BAD_METHOD = 405;
    public static final int HTTP_BAD_REQUEST = 400;
    public static final int HTTP_CLIENT_TIMEOUT = 408;
    public static final int HTTP_CONFLICT = 409;
    public static final int HTTP_CREATED = 201;
    public static final int HTTP_ENTITY_TOO_LARGE = 413;
    public static final int HTTP_FORBIDDEN = 403;
    public static final int HTTP_GATEWAY_TIMEOUT = 504;
    public static final int HTTP_GONE = 410;
    public static final int HTTP_INTERNAL_ERROR = 500;
    public static final int HTTP_LENGTH_REQUIRED = 411;
    public static final int HTTP_MOVED_PERM = 301;
    public static final int HTTP_MOVED_TEMP = 302;
    public static final int HTTP_MULT_CHOICE = 300;
    public static final int HTTP_NOT_ACCEPTABLE = 406;
    public static final int HTTP_NOT_AUTHORITATIVE = 203;
    public static final int HTTP_NOT_FOUND = 404;
    public static final int HTTP_NOT_IMPLEMENTED = 501;
    public static final int HTTP_NOT_MODIFIED = 304;
    public static final int HTTP_NO_CONTENT = 204;
    public static final int HTTP_OK = 200;
    public static final int HTTP_PARTIAL = 206;
    public static final int HTTP_PAYMENT_REQUIRED = 402;
    public static final int HTTP_PRECON_FAILED = 412;
    public static final int HTTP_PROXY_AUTH = 407;
    public static final int HTTP_REQ_TOO_LONG = 414;
    public static final int HTTP_RESET = 205;
    public static final int HTTP_SEE_OTHER = 303;
    /** @deprecated */
    @Deprecated
    public static final int HTTP_SERVER_ERROR = 500;
    public static final int HTTP_UNAUTHORIZED = 401;
    public static final int HTTP_UNAVAILABLE = 503;
    public static final int HTTP_UNSUPPORTED_TYPE = 415;
    public static final int HTTP_USE_PROXY = 305;
    public static final int HTTP_VERSION = 505;

    private static int TIMEOUT_CONNECT = 30;
    private static int TIMEOUT_WRITE = 30;
    private static int TIMEOUT_READ = 30;

    private static String URL_END_POINT = "https://1j6edvovka.execute-api.ap-northeast-2.amazonaws.com/Prod/"; //실사용 DB 주소.
    private static String URL_KAKAO_GET_ADDRESS = "https://dapi.kakao.com/v2/local/search/address.json";

    private static final int TYPE_GET = 0;
    private static final int TYPE_PUT = 1;
    private static final int TYPE_POST = 2;
    private static final int TYPE_PATCH = 3;
    private static final int TYPE_DELETE = 4;

    /**
     * OKHTTP를 통해 통신
     * @param type (GET, POST, PATCH 방식)
     * @param hasHeader (헤더 포함 유무)
     * @param url : API 주소
     * @param callback : 전송후 Callback 함수
     * @throws IOException
     */
    private static void send(final int type, final boolean hasHeader, final String url, final String json, final Callback callback) throws IOException {
        Handler mHandler = new Handler(Looper.getMainLooper());
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                String typeString = type==TYPE_GET?"GET":type==TYPE_POST?"POST":type==TYPE_PATCH?"PATCH":type==TYPE_PUT?"PUT":type==TYPE_DELETE?"DELETE":"UNKNOWN";
                ErrorLogOutput(TAG, "HTTP API START("+typeString+")\n url : " + url + "\nbody : "+ json);

                final MediaType JSON
                        = MediaType.parse("application/json; charset=utf-8");

                try {
                    final TrustManager[] trustAllCerts = new TrustManager[]{
                            new X509TrustManager() {
                                @Override
                                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
                                        throws CertificateException {
                                }

                                @Override
                                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
                                        throws CertificateException {
                                }

                                @Override
                                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                    return new java.security.cert.X509Certificate[]{};
                                }
                            }
                    };

                    // Install the all-trusting trust manager
                    final SSLContext sslContext = SSLContext.getInstance("SSL");
                    sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                    // Create an ssl socket factory with our all-trusting manager
                    final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

                    OkHttpClient client = new OkHttpClient.Builder()
                            .connectTimeout(TIMEOUT_CONNECT, TimeUnit.SECONDS)
                            .writeTimeout(TIMEOUT_WRITE, TimeUnit.SECONDS)
                            .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
                            .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
                            .hostnameVerifier(new HostnameVerifier() {
                                @Override
                                public boolean verify(String hostname, SSLSession session) {
                                    return true;
                                }
                            })
                            .build();

                    RequestBody body = RequestBody.create(JSON, json);
                    Request.Builder builder = new Request.Builder();

                    builder.url(url);

                    builder.addHeader("Accept", "application/json")
                            .addHeader("Content-Type", "application/json")
                            .addHeader("x-api-key", "C45ls6kqaU2yvjNltlmuC2qyZmEHQMRB1ixNJ6B1");

                    if(hasHeader) {
                        builder.addHeader("Authorization", "Bearer "+ AppHelper.getCurrSession().getIdToken().getJWTToken());
                    }


                    switch (type) {
                        case TYPE_PUT:
                            builder.put(body);
                            break;
                        case TYPE_POST:
                            builder.post(body);
                            break;
                        case TYPE_PATCH:
                            builder.patch(body);
                            break;
                        case TYPE_DELETE:
                            builder.delete(body);
                            break;
                        case TYPE_GET:
                            builder.get();
                            break;
                        default:
                            break;
                    }

                    Request request = builder.build();
                    client.newCall(request).enqueue(callback);
                } catch (Exception e) {
                    ErrorLogOutput(TAG,"Exception while configuring IgnoreSslCertificate " + e);
                }
            }
        }, 0);
    }

    /**
     * 사용자 - 01.회원 정보 조회
     * @param c
     * @throws IOException
     */
    public static void getUserInfo (Callback c) throws IOException {
        String url = URL_END_POINT + "user";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 사용자 - 02.회원 정보 수정
     * @param profile 프로필 이미지 uri
     * @param pushAccess 푸시메시지 설정 여부
     * @param autoUpdate 연결된 디바이스들의 자동 업데이트 설정여부
     * @param c
     * @throws IOException
     */
    public static void changeUserInfo(String profile, String nickName, String phoneNumber, boolean pushAccess, boolean autoUpdate, String pushToken, Callback c) throws IOException {
        String url = URL_END_POINT + "user";
        send(TYPE_PATCH, true, url,changeUserInfoBowlingJson(profile, nickName, phoneNumber, pushAccess, autoUpdate, pushToken),c);
    }

    private static String changeUserInfoBowlingJson(String profile, String nickName, String phoneNumber, boolean pushAccess, boolean autoUpdate, String pushToken) {
        return "{"
                + (profile.isEmpty()?"":"\"profile\":\""+profile+"\",")
                + (nickName.isEmpty()?"":"\"nickName\":\""+nickName+"\",")
                + (phoneNumber.isEmpty()?"":"\"phoneNumber\":\""+phoneNumber+"\",")
                + (pushToken.isEmpty()?"":"\"pushToken\":\""+pushToken+"\",")
                + "\"pushAccess\":"+pushAccess+","
                + "\"autoUpdate\":"+autoUpdate+"}";
    }


    public static void changeUserInfo(String profile, String nickName, String phoneNumber, String pushToken, Callback c) throws IOException {
        String url = URL_END_POINT + "user";
        send(TYPE_PATCH, true, url,changeUserInfoBowlingJson(profile, nickName, phoneNumber, pushToken),c);
    }

    private static String changeUserInfoBowlingJson(String profile, String nickName, String phoneNumber, String pushToken) {
        String jsonString = "{";
        if(!profile.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"profile\":\""+profile+"\"";
        }
        if(!nickName.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"nickName\":\""+nickName+"\"";
        }
        if(!phoneNumber.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"phoneNumber\":\""+phoneNumber+"\"";
        }
        if(!pushToken.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"pushToken\":\""+pushToken+"\"";
        }
        jsonString += "}";
        return jsonString;
    }


    /**
     * 사용자 - 03.회원 정보 검증
     * @param email 이메일
     * @param nickname 별명
     * @param phone_number 휴대폰 번호
     * @param c
     * @throws IOException
     */
    public static void isValidateUserInfo (String email, String nickname, String phone_number, Callback c) throws IOException {
        String url = URL_END_POINT + "user/validate";
        send(TYPE_POST, false, url,isValidateUserInfoBowlingJson(email, nickname, phone_number),c);
    }

    private static String isValidateUserInfoBowlingJson(String email, String nickname, String phone_number) {
        return "{\"email\":\""+email+"\","
                + "\"nickname\":\""+nickname+"\","
                + "\"phoneNumber\":\""+phone_number+"\"}";
    }


    /**
     * 사용자 - 04.회원 비밀번호 수정
     * @param uid 사용자 고유번호
     * @param password 암호화된 비밀번호
     * @param c
     * @throws IOException
     */
    public static void changeUserPassword (String uid, String password, Callback c) throws IOException {
        String url = URL_END_POINT + "user/changePassword";
        send(TYPE_PATCH, true, url,changeUserPasswordBowlingJson(uid, password),c);
    }

    private static String changeUserPasswordBowlingJson(String uid, String password) {
        return "{\"uid\":\""+uid+"\","
                + "\"password\":\""+password+"\"}";
    }

    /**
     * 사용자 - 05.인증 요청
     * @param isEmail 인증방식이 이메일인 경우
     * @param isUserConfirm 인증요청을 진행하는 시점이 User Confirm인 경우
     * @param value 인증메일을 전송할 메일 주소 또는 인증코드를 전송할 핸드폰 번호
     * @param c
     * @throws IOException
     */
    public static void requestConfirmUser (boolean isEmail, boolean isUserConfirm, String value, Callback c) throws IOException {
        String url = URL_END_POINT + "user/reqConfirm";
        send(TYPE_POST, true, url,requestConfirmUserBowlingJson(isEmail, isUserConfirm, value),c);
    }

    private static String requestConfirmUserBowlingJson(boolean isEmail, boolean isUserConfirm, String value) {
        String s_type = isEmail?"email":"“phone"; //인증진행방식 [“email”, “phone”]
        String c_case = isUserConfirm?"user_confirm":"change_password"; //인증요청을 진행하는 시점 [“user_confirm”, “change_password”]
        return "{\"sType\":\""+s_type+"\","
                + (isEmail?"\"email\":\""+value+"\",":"\"phoneNumber\":\""+value+"\",")
                + "\"cCase\":\""+c_case+"\"}";
    }


    /**
     * 사용자 - 06.회원탈퇴
     * @param uid 사용자 ID (Email)
     * @param password 비밀번호
     * @param c
     * @throws IOException
     */
    public static void deleteUserInfo (String uid, String password, Callback c) throws IOException {
        String url = URL_END_POINT + "user";
        send(TYPE_DELETE, true, url,""/*deleteUserInfoBowlingJson(uid, password)*/,c); //TODO- 문서와 JSON 실행문 상의함.
    }
    /*
    private static String deleteUserInfoBowlingJson(String uid, String password) {
        return "{\"uid\":\""+uid+"\","
                + "\"password\":\""+password+"\"}";
    }
    */

    /**
     * 사용자 - 07.사용자인증
     * @param uid 사용자 ID(회원 정보 조회 uid)
     * @param isEmail 인증방식이 이메일인 경우
     * @param isUserConfirm 인증요청을 진행하는 시점이 User Confirm인 경우
     * @param value 인증메일을 전송할 메일 주소 또는 인증코드를 전송할 핸드폰 번호
     * @param c
     * @throws IOException
     */
    public static void certificationUserInfo (String uid, boolean isEmail, boolean isUserConfirm, String value, Callback c) throws IOException {
        String url = URL_END_POINT + "activate"+"/" + uid;
        send(TYPE_POST, true, url,certificationUserInfoBowlingJson(isEmail, isUserConfirm, value),c);
    }

    private static String certificationUserInfoBowlingJson(boolean isEmail, boolean isUserConfirm, String value) {
        String s_type = isEmail?"email":"“phone"; //인증진행방식 [“email”, “phone”]
        String c_case = isUserConfirm?"user_confirm":"change_password"; //인증요청을 진행하는 시점 [“user_confirm”, “change_password”]
        return "{\"s_type\":\""+s_type+"\","
                + (isEmail?"\"email\":\""+value+"\",":"\"phoneNumber\":\""+value+"\",")
                + "\"c_case\":\""+c_case+"\"}";
    }


    /**
     * 멤버 - 01.(마스터)게스트 멤버추가 - 멤버초대
     * @param isEmail 인증방식이 이메일인 경우
     * @param value 인증메일을 전송할 메일 주소 또는 인증코드를 전송할 핸드폰 번호
     * @param c
     * @throws IOException
     */
    public static void inviteGuestForMaster (boolean isEmail, String value, Callback c) throws IOException {
        String url = URL_END_POINT + "member/guest";
        send(TYPE_POST, true, url,inviteGuestBowlingJson(isEmail, value),c);
    }

    private static String inviteGuestBowlingJson(boolean isEmail, String value) {
        return "{\"sType\":\""+(isEmail?"email":"“phone")+"\","
                + (isEmail?"\"email\":\""+value+"\"":"\"phoneNumber\":\""+value+"\"")+"}";
    }


    /**
     * 멤버 - 02.(마스터) 게스트 초대이력 조회
     * @param c
     * @throws IOException
     */
    public static void getHistoryForInviteGuest (Callback c) throws IOException {
        String url = URL_END_POINT + "member/guest/inviteHist";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 멤버 - 03.(마스터) 게스트 초대이력 삭제
     * @param hist_id 초대이력 고유아이디
     * @param c
     * @throws IOException
     */
    public static void deleteHistoryForInviteGuest (String hist_id, Callback c) throws IOException {
        String url = URL_END_POINT + "member/guest/inviteHist"+"/" + hist_id;;
        send(TYPE_DELETE, true, url,"",c);
    }

    /**
     * 멤버 - 04.(마스터) 게스트 멤버삭제
     * @param guest_id 게스트유저의 고유 id
     * @param c
     * @throws IOException
     */
    public static void deleteGuest (String guest_id, Callback c) throws IOException {
        String url = URL_END_POINT + "member/guest"+"/" + guest_id;;
        send(TYPE_DELETE, true, url,"",c);
    }

    /**
     * 멤버 - 05.(마스터) 게스트 멤버 목록 조회
     * @param c
     * @throws IOException
     */
    public static void getGuestList (Callback c) throws IOException {
        String url = URL_END_POINT + "member/guests";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 멤버 -06.(마스터) 마스터에서 탈퇴 - 마스터<->게스트 관계 해제
     * @param c
     * @throws IOException
     */
    public static void deleteMasterInfo (Callback c) throws IOException {
        String url = URL_END_POINT + "member/guests";
        send(TYPE_DELETE, true, url,"",c);
    }


    /**
     * 멤버 - 07.(게스트) 초대이력 목록 조회
     * @param c
     * @throws IOException
     */
    public static void getHistoryForInvite (Callback c) throws IOException {
        String url = URL_END_POINT + "member/inviteHist";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 멤버 - 08. (게스트) 초대 승락 / 거절
     * @param hist_id 초대 이력의 고유 아이디
     * @param isAccept 초대 응답 ( 승낙인경우 ‘yes’, 거절인경우 ‘no’ )
     * @param c
     * @throws IOException
     */
    public static void acceptToInvite (String hist_id, boolean isAccept, Callback c) throws IOException {
        String url = URL_END_POINT + "/member/inviteHist/"+hist_id+"/invited/"+(isAccept?"yes":"no");
        send(TYPE_POST, true, url,"",c);
    }

    /**
     * 멤버 - 09. (게스트) 마스터 정보 조회
     * @param c
     * @throws IOException
     */
    public static void getMasterInfo (Callback c) throws IOException {
        String url = URL_END_POINT + "member/master";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 멤버 - 10. (게스트) 멤버탈퇴 - 마스터<->게스트 관계 해제
     * @param master_id 마스터의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void deleteGuestInfo (String master_id,Callback c) throws IOException {
        String url = URL_END_POINT + "member/master"+"/"+master_id;
        send(TYPE_DELETE, true, url,"",c);
    }


    /**
     * 디바이스 그룹 - 01. 디바이스 그룹 등록
     * @param friendlyName 디바이스 그룹
     * @param icon App에 표시할 그룹별 아이콘 정보(아이콘 정보는 App과 미리 정의한 icon의 정보를 전달해야합니다.)
     * @param background App에 표시할 그룹별 배경화면 정보(배경화면 정보를 App과 미리 정의한 정보를 전달해야합니다.)
     * @param c
     * @throws IOException
     */
    public static void registerDeviceGroup (String friendlyName, String icon, String background, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups";
        send(TYPE_POST, true, url,registerDeviceGroupBowlingJson(friendlyName, icon, background),c);
    }

    private static String registerDeviceGroupBowlingJson(String friendlyName, String icon, String background) {
        return "{\"friendlyName\":\""+friendlyName+"\","
                + "\"icon\":\""+icon+"\","
                + "\"background\":\""+background+"\"}";
    }

    /**
     * 디바이스 그룹 - 02. 디바이스 그룹 조회
     * @param dgroup_id 디바이스 그룹의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void getDeviceGroup (String dgroup_id,Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups"+"/"+dgroup_id;
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 디바이스 그룹 - 03. 디바이스 그룹 수정
     * @param dgroup_id 디바이스 그룹의 고유 아이디
     * @param friendlyName 디바이스 그룹 명(기본그룹은 디바이스 그룹명을 수정할 수 없습니다.)
     * @param icon App에 표시할 그룹별 아이콘 정보(아이콘 정보는 App과 미리 정의한 icon의 정보를 전달해야합니다.)
     * @param background App에 표시할 그룹별 배경화면 정보(배경화면 정보를 App과 미리 정의한 정보를 전달해야합니다.)
     * @param c
     * @throws IOException
     */
    public static void modifyDeviceGroup (String dgroup_id, String friendlyName, String icon, String background, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups"+"/"+dgroup_id;
        send(TYPE_PATCH, true, url,modifyDeviceGroupBowlingJson(friendlyName, icon, background),c);
    }

    private static String modifyDeviceGroupBowlingJson(String friendlyName, String icon, String background) {
        String jsonString = "{";
        if(!friendlyName.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"friendlyName\":\""+friendlyName+"\"";
        }
        if(!icon.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"icon\":\""+icon+"\"";
        }
        if(!background.isEmpty()) {
            jsonString += (jsonString.length()>1?",":"")+"\"background\":\""+background+"\"";
        }
        jsonString += "}";

        return jsonString;
    }

    /**
     * 디바이스 그룹 - 04. 디바이스 그룹 삭제
     * @param dgroup_id 디바이스 그룹의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void deleteDeviceGroup (String dgroup_id, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups"+"/"+dgroup_id;
        send(TYPE_DELETE, true, url,"",c);
    }


    /**
     * 디바이스 그룹 - 05. 디바이스 그룹 목록 조회
     * @param c
     * @throws IOException
     */
    public static void getDeviceGroupList (Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups";
        send(TYPE_GET, true, url,"",c);
    }

    /***
     * 디바이스 그룹 - 06. 디바이스 그룹 목록 순서변경
     * @param list
     * @param c
     * @throws IOException
     */
    public static void changeDeviceGroupListRank (final List<DeviceGroupInfo> list, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups";
        send(TYPE_PATCH, true, url,changeDeviceGroupListRank(list),c);
    }

    private static String changeDeviceGroupListRank(final List<DeviceGroupInfo> list) {
        String jsonListString = "";
        for(int i = 0 ; i < list.size() ; i++) {
            if(list.get(i).index != DEFUALT_GROUP_INDEX) {
                if (jsonListString.length() != 0) {
                    jsonListString += ",";
                }
                jsonListString += "{\"dgroupId\":\"" + list.get(i).dgroupId + "\"" +
                        ",\"index\":" + list.get(i).index + "}";
            }
        }
        return "{\"dgroups\":["+jsonListString+"]}";
    }

    /**
     * 디바이스 그룹 - 07. 디바이스 그룹 별 디바이스 목록
     * @param dgroup_id
     * @param c
     * @throws IOException
     */
    public static void getDeviceListInDeviceGroup (String dgroup_id, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups"+"/"+dgroup_id + "/devices";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 디바이스 그룹 - 08. 디바이스 그룹에 디바이스 연결
     * @param dgroup_id 디바이스와 연결하고자 하는 디바이스 그룹의 고유 아이디
     * @param device_id 디바이스 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void connectDeviceInDeviceGroup (String dgroup_id, String device_id, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups"+"/"+dgroup_id + "/devices/"+device_id;
        send(TYPE_POST, true, url,"",c);
    }


    /**
     * 디바이스 그룹 - 09. 디바이스 그룹에 디바이스 삭제
     * @param dgroup_id 디바이스와 연결하고자 하는 디바이스 그룹의 고유 아이디
     * @param device_id 디바이스 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void deleteDeviceInDeviceGroup (String dgroup_id, String device_id, Callback c) throws IOException {
        String url = URL_END_POINT + "dgroups"+"/"+dgroup_id + "/devices/"+device_id;
        send(TYPE_DELETE, true, url,"",c);
    }

    /**
     * 디바이스 - 01. 디바이스 매핑 완료
     * @param device_id 디바이스 그룹의 고유 아이디
     * @param friendlyName 디바이스 그룹 명(기본그룹은 디바이스 그룹명을 수정할 수 없습니다.)
     * @param icon App에 표시할 그룹별 아이콘 정보(아이콘 정보는 App과 미리 정의한 icon의 정보를 전달해야합니다.)
     * @param background App에 표시할 그룹별 배경화면 정보(배경화면 정보를 App과 미리 정의한 정보를 전달해야합니다.)
     * @param c
     * @throws IOException
     */
    public static void mappingDevice (String device_id, String friendlyName, String icon, String background, Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id;
        send(TYPE_POST, true, url,mappingDeviceBowlingJson(friendlyName, icon, background),c); //TODO- 문서와 JSON 실행문 상의함.
    }

    public static void mappingDevice (String device_id, /*String friendlyName, String icon, String background,*/ Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id;
        send(TYPE_POST, true, url,""/*mappingDeviceBowlingJson(friendlyName, icon, background)*/,c); //TODO- 문서와 JSON 실행문 상의함.
    }

    private static String mappingDeviceBowlingJson(String friendlyName, String icon, String background) {
        return "{\"friendlyName\":\""+friendlyName+"\","
                + "\"icon\":\""+icon+"\","
                + "\"background\":\""+background+"\"}";
    }

    /**
     * 디바이스 - 02. 디바이스 상세정보 조회
     * @param device_id 디바이스 그룹의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void getDeviceInfo (String device_id, Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id;
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 디바이스 - 03. 디바이스 상세정보 수정
     * @param device_id 디바이스 그룹의 고유 아이디
     * @param friendlyName App에 표시할 디바이스 이름 (본인 소유의 디바이스일 경우)
     * @param c
     * @throws IOException
     */
    public static void modifyDeviceInfo (String device_id, String friendlyName, Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id;
        send(TYPE_PATCH, true, url,modifyDeviceInfoBowlingJson(friendlyName),c);
    }

    private static String modifyDeviceInfoBowlingJson(String friendlyName) {
        return "{\"friendlyName\":\""+friendlyName+"\"}";
    }

    /**
     * 디바이스 - 04. 디바이스 삭제(디바이스 초기화)
     * @param device_id 디바이스 그룹의 고유 아이디
     * friendlyName App에 표시할 디바이스 이름 (본인 소유의 디바이스일 경우)
     * @param c
     * @throws IOException
     */
    public static void deleteDevice (String device_id, /*String friendlyName,*/ Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id;
        send(TYPE_DELETE, true, url,""/*deleteDeviceBowlingJson(friendlyName)*/,c);
    }

    private static String deleteDeviceBowlingJson(String friendlyName) {
        return "{\"friendlyName\":\""+friendlyName+"\"}";
    }


    /**
     * 디바이스 - 05. 디바이스 최신 펌웨어 정보 조회
     * @param device_id 디바이스 그룹의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void getFirmwareInfoAtDevice (String device_id, Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id + "/firmware";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 디바이스 - 06. 디바이스 최신 펌웨어 업데이트
     * @param device_id 디바이스 그룹의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void updateFirmwareInfoAtDevice (String device_id, Callback c) throws IOException {
        String url = URL_END_POINT + "device"+"/"+device_id + "/firmware";
        send(TYPE_PUT, true, url,"",c);
    }

    /**
     * 디바이스 - 07. 디바이스 전체 목록 조회
     * @param c
     * @throws IOException
     */
    public static void getAllDevice (Callback c) throws IOException {
        String url = URL_END_POINT + "devices";
        send(TYPE_GET, true, url,"",c);
    }


    /**
     * HOME - 01.위치 정보 등록
     * @param latitude 위도
     * @param longitude 경도
     * @param city 도시 (ex: 경기도, 서울특별시)
     * @param district 시-구 (ex: 고양시덕양구, 용인시수지구)
     * @param town 동(ex: 성사1동, 풍덕천1동)
     * @param c
     * @throws IOException
     */
    public static void registerLocationInfo (String latitude, String longitude, String city, String district,String town, Callback c) throws IOException {
        String url = URL_END_POINT + "home/location";
        send(TYPE_POST, true, url,registerLocationInfoBowlingJson(latitude, longitude, city, district, town),c);
    }

    private static String registerLocationInfoBowlingJson(String latitude, String longitude, String city, String district,String town) {
        return "{\"latitude\":\""+latitude+"\","
                + "\"longitude\":\""+longitude+"\","
                + "\"address\":{"
                + "\"city\":\""+city+"\","
                + "\"district\":\""+district+"\","
                + "\"town\":\""+town+"\""
                +"}}";
    }

    /**
     * HOME - 02.위치 정보 조회
     * @param c
     * @throws IOException
     */
    public static void getLocationInfo (Callback c) throws IOException {
        String url = URL_END_POINT + "home/location";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * HOME - 03.위치 정보 수정
     * @param location_id 위치정보의 고유 아이디
     * @param latitude 위도
     * @param longitude 경도
     * @param city 도시 (ex: 경기도, 서울특별시)
     * @param district 시-구 (ex: 고양시덕양구, 용인시수지구)
     * @param town 동(ex: 성사1동, 풍덕천1동)
     * @param c
     * @throws IOException
     */
    public static void modifyLocationInfo (String location_id, String latitude, String longitude, String city, String district,String town, Callback c) throws IOException {
        String url = URL_END_POINT + "home/location/"+location_id;
        send(TYPE_PATCH, true, url,modifyLocationInfoBowlingJson(latitude, longitude, city, district, town),c);
    }

    private static String modifyLocationInfoBowlingJson(String latitude, String longitude, String city, String district,String town) {
        return "{\"latitude\":\""+latitude+"\","
                + "\"longitude\":\""+longitude+"\","
                + "\"address\":{"
                + "\"city\":\""+city+"\","
                + "\"district\":\""+district+"\","
                + "\"town\":\""+town+"\""
                +"}}";
    }

    /**
     * HOME - 04.위치 정보 삭제
     * @param location_id 위치정보의 고유 아이디
     * @param c
     * @throws IOException
     */
    public static void deleteLocationInfo (String location_id, Callback c) throws IOException {
        String url = URL_END_POINT + "home/location/"+location_id;
        send(TYPE_DELETE, true, url,"",c);
    }

    /**
     * HOME - 05.날씨 정보 조회
     * @param location_id 위치정보의 고유 아이디
     * @param location_id
     * @param c
     * @throws IOException
     */
    public static void getWeatherInfo (String location_id, Callback c) throws IOException {
        String url = URL_END_POINT + "/home/location/" + location_id +"/weather";
        send(TYPE_GET, true, url,"",c);
    }

    /**
     * 기타 - 01. 데이터 암호화
     * @param plainText 암호화 하고자 하는 평문 데이터
     * @param c
     * @throws IOException
     */
    public static void encryptData(String plainText, Callback c) throws IOException {
        String url = URL_END_POINT + "encrypt";
        send(TYPE_POST, true, url,encryptDataBowlingJson(plainText),c);
    }

    private static String encryptDataBowlingJson(String plainText) {
        return "{\"plainText\":\""+plainText+"\"}";
    }


    /**
     * 카카오 로컬 REST API - (검색어로 위치 정보 획득 API)
     * @param serach - 검색할 문구
     * @param c
     * @throws IOException
     */
    public static void getLocationInfo(String serach, Callback c) throws IOException {
        String url = URL_KAKAO_GET_ADDRESS + "?page=1&size=10&query=" + serach;

        ErrorLogOutput(TAG, "KAKAO HTTP API START(getLocationInfo)\n url : " + url);

        final MediaType JSON
                = MediaType.parse("application/json; charset=utf-8");

        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
                                throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
                                throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(TIMEOUT_CONNECT, TimeUnit.SECONDS)
                    .writeTimeout(TIMEOUT_WRITE, TimeUnit.SECONDS)
                    .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
                    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    })
                    .build();

            RequestBody body = RequestBody.create(JSON, "");
            Request.Builder builder = new Request.Builder();
            builder.url(url);
            builder.addHeader("Authorization", "KakaoAK " + IotPlatformApplication.getInstance().getApplicationContext().getString(R.string.kakao_rest_api_key));
            builder.get();
            Request request = builder.build();

            client.newCall(request).enqueue(c);
        } catch (Exception e) {
            ErrorLogOutput(TAG,"Exception while configuring IgnoreSslCertificate " + e);
        }
    }



    public static void appendLog(String text)
    {
        File logFile = new File("sdcard/log.file");
        if (!logFile.exists())
        {
            try
            {
                logFile.createNewFile();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        try
        {
            //BufferedWriter for performance, true to set append to file flag
            BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
            buf.append(text);
            buf.newLine();
            buf.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}
