package jp.odakyu.toiletsignage.task;

import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;

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

import java.io.DataOutputStream;
import java.io.IOException;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimerTask;

import jp.odakyu.toiletsignage.connection.NtpServerConnection;
import jp.odakyu.toiletsignage.connection.ToiletServerConnection;
import jp.odakyu.toiletsignage.constants.ToiletConstants;
import jp.odakyu.toiletsignage.info.ToiletInfo;
import jp.odakyu.toiletsignage.json.ResultToiletJson;
import jp.odakyu.toiletsignage.json.USBToiletDefaultJson;
import jp.odakyu.toiletsignage.log.Logger;
import jp.odakyu.toiletsignage.util.DateTimeFormat;
import jp.odakyu.toiletsignage.util.DateTimeUtil;

/**
 * Created by agentec on 2017/12/11.
 */

public class UpdateToiletInfoTask extends TimerTask {
    private static final String TAG = "UpdateToiletInfoTask";
    private static final int TWO_THOUSAND_YEARS = 2000;
    private int errorCount = 0;
    private Context applicationContext;
    private ToiletInfo toiletInfo;

    public UpdateToiletInfoTask(Context context){
        applicationContext = context;
        toiletInfo = ToiletInfo.getInstance();
    }

    /**
     * 実際トイレサーバから10秒ごとに情報を取得するタスク実行
     */
    @Override
    public void run() {
        Logger.i(TAG, "Thread Start");
        boolean isNetworkConnect = true;
        //インターネット接続チェック
        if (isNetworkAvailable(applicationContext)) {
            ArrayList<USBToiletDefaultJson> toiletInfoArray = toiletInfo.getToiletDefaultJsonArray();
            boolean isError = false;
            boolean isNtpServerCheck = false;
            for (USBToiletDefaultJson toiletDefaultJson : toiletInfoArray) {
                try {
                    if(!isNtpServerCheck) {
                        synchronizingNtpServerDate();
                        isNtpServerCheck = true;
                    }

                    String jsonString = ToiletServerConnection.connectionToiletServer(toiletDefaultJson.getToiletId());
                    if (jsonString == null) {
                        Logger.w(TAG, "json object null jsonString");
                        isError = true;
                        break;
                    }

                    JSONObject jsonObject = new JSONObject(jsonString);

                    ArrayList<ResultToiletJson> resultToiletJsonArray = new ArrayList<>();
                    JSONArray jsonArray = jsonObject.getJSONArray(ResultToiletJson.KEY_RESULT);
                    Logger.d(TAG, "jsonArray.length = " + jsonArray.length());
                    for (int i = 0; i < jsonArray.length(); i++) {
                        ResultToiletJson resultToiletJson = new ResultToiletJson((JSONObject) jsonArray.get(i));
                        resultToiletJsonArray.add(resultToiletJson);
                    }

                    ToiletInfo.getInstance().setResultToiletJsonMap(toiletDefaultJson.getToiletId(), resultToiletJsonArray);
                } catch (Exception e) {
                    Logger.e(TAG, e.getLocalizedMessage(), e);
                    isError = true;
                    break;
                }
            }
            if (isError) {
                errorCount++;
            } else {
                errorCount = 0;
            }
        } else {
            errorCount++;
            isNetworkConnect = false;
        }

        //Broadcast送信
        Intent intent = new Intent(ToiletInfo.NAME_CONNTENT_FINISH);
        intent.putExtra(ToiletConstants.KEY_ERROR_COUNT, errorCount);
        intent.putExtra(ToiletConstants.KEY_NETWORK_CONNECT, isNetworkConnect);
        applicationContext.sendBroadcast(intent);

        Logger.d(TAG, "Thread End");
    }

    /**
     * インターネット（Wifi）チェック
     * @param context Application Context
     * @return internet check
     */
    private boolean isNetworkAvailable(Context context) {
        final ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
        return connectivityManager.getActiveNetworkInfo() != null && connectivityManager.getActiveNetworkInfo().isConnected();
    }

    /**
     * 端末時刻が異常かチェック（2000年未満）
     * @return
     */
    private boolean isAbnormalYear() {
        int currentYear = Integer.parseInt(DateTimeUtil.toStringInTimeZone(new Date(), DateTimeFormat.yyyy, "UTC"));
        return currentYear < TWO_THOUSAND_YEARS;
    }

    /**
     * NTPサーバーの時刻を取得し、端末時刻にセット
     * @throws IOException
     */
    private void synchronizingNtpServerDate() throws IOException, JSONException {
        if(isAbnormalYear()) {
            String jsonString = NtpServerConnection.connectionNtpServer();
            JSONObject jsonObject = new JSONObject(jsonString);
            Long ntpTimeMillis = (long) ((Double) jsonObject.get("st") * 1000);

            String cmd = "date " + DateTimeUtil.toString(new Timestamp(ntpTimeMillis), DateTimeFormat.MMDDHHmmyyyyss__colon);

            Logger.d(TAG,"Current Date : " + DateTimeUtil.toString(DateTimeUtil.getCurrentDate(), DateTimeFormat.yyyyMMddHHmmss_slash));
            Logger.d(TAG, "Command=%s, NtpDate=%s", cmd, DateTimeUtil.toString(new Timestamp(ntpTimeMillis), DateTimeFormat.yyyyMMddHHmmss_slash));
            runAsRoot(cmd);
        }
    }

    /**
     * Root化端末のコマンド実行
     *
     * @param cmd
     * @throws IOException
     */
    private void runAsRoot(String cmd) {
        try {
            Process process = Runtime.getRuntime().exec("su");

            DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream());
            dataOutputStream.writeBytes(cmd+"\n");

            dataOutputStream.writeBytes("exit\n");
            dataOutputStream.flush();
        } catch (IOException e) {
            Logger.w(TAG, "runAsRoot error.");
            //何も処理しない
        }
    }

    /*
    //実際「google.com」に影響があるが確認が取れてないので未使用
    private boolean isInternetAvailable() {
        try {
            final InetAddress address = InetAddress.getByName("google.com");
            return !address.equals("");
        } catch (UnknownHostException e) {
            // Log error
            e.printStackTrace();
        }
        return false;
    }
    */
}
