package com.xypower.mpmaster;

import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.PowerManager;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Base64;

import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.FileUploader;
import com.xypower.common.HttpRequest;
import com.xypower.common.InetAddressUtils;
import com.xypower.common.JSONUtils;
import com.xypower.common.MD5Util;
import com.xypower.common.MicroPhotoContext;
import com.xypower.common.ThermalInfoUtil;
import com.xypower.common.ZipUtils;

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

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class AppMaster {

    private static String TAG = "MPLOG";
    private MpMasterService mService;
    private String mMasterUrl;
    private String mCmdid;
    private boolean mBundleWithMpApp;
    private PowerManager.WakeLock mWakelock;

    public static final String CMD_REBOOT_APP = "cmd_reboot_app";
    public static final String CMD_REBOOT_MASTER = "cmd_reboot_mpmaster";
    public static final String CMD_REBOOT_DEV = "yw_cmd_android_reboot";
    public static final String CMD_UPGRADE = "upgrade";
    public static final String CMD_UPLOAD_LOGS = "yw_cmd_upload_i1_zip_log";
    public static final String CMD_SET_CMA = "i1_cmd_set_i1_server_ip_port";
    public static final String CMD_SET_MNTN = "i1_cmd_set_xy_yw_ip_port";
    public static final String CMD_SET_APP_HB = "i1_cmd_set_i1_heart_beat_time";
    public static final String CMD_UPDATE_CONFIG = "upd_cfg";
    public static final String CMD_PULL_FILE = "pull_files";
    public static final String CMD_PUSH_FILE = "push_file";
    public static final String CMD_DELETE_FILE = "del_file";
    public static final String CMD_HOT_SPOT = "yw_cmd_hot_spot";
    public static final String CMD_ENABLE_GPS = "yw_cmd_enable_gps";
    public static final String CMD_ENABLE_OTG = "yw_cmd_enable_otg";
    public static final String CMD_UPD_OTA = "yw_upd_ota";

    public static final String CMD_IMPORT_PUB_KEY = "imp_pub_key";

    public AppMaster(MpMasterService service, String masterUrl, String cmdid, boolean bundleWithMpApp) {

        mService = service;
        mMasterUrl = masterUrl;
        mCmdid = cmdid;
        mBundleWithMpApp = bundleWithMpApp;
        mWakelock = null;

        if (!mBundleWithMpApp) {
            int aa = 0;
        }

        try {
            PowerManager powerManager = (PowerManager) service.getSystemService(Context.POWER_SERVICE);
            mWakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "com.xypower.mpmaster:MpMaster");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    protected void finalize() {
        try {
            if (mWakelock != null) {
                mWakelock.setReferenceCounted(false);
                mWakelock.release();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            mWakelock = null;
        }
        mService = null;
    }

    private long getBootTime() {
        return (System.currentTimeMillis() - SystemClock.elapsedRealtimeNanos() / 1000000) / 1000;
    }

    public void start() {

        new Thread(new Runnable() {

            void sleep(long ms) {
                try {
                    Thread.sleep(ms);
                } catch (Exception ex) {
                }
            }

            @Override
            public void run() {

                final boolean separateNetwork = mService.isSeparateNetwork();
                boolean simcardSwitched = false;

                if (separateNetwork) {
                    try {
                        ConnectivityManager connectivityManager = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
                        Network previousNetwork = connectivityManager.getActiveNetwork();
                        String previousNetworkStr = previousNetwork == null ? "" : previousNetwork.toString();

                        mService.selectSimCard(2);
                        simcardSwitched = true;
                        sleep(100);

                        boolean connected = false;

                        for (int idx = 0; idx < 8; idx++) {
                            Network network = connectivityManager.getActiveNetwork();
                            if (!network.equals(previousNetwork)) {
                                mService.logger.info("Network Changed from " + previousNetworkStr + " to " + network.toString());
                                break;
                            }

                            sleep(1000);
                        }

                        try {
                            runImpl();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        } finally {
                            try {
                                if (simcardSwitched && !mService.isMntnMode()) {
                                    mService.selectSimCard(1);
                                }
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    } finally {
                        try {
                            if (simcardSwitched && !mService.isMntnMode()) {
                                mService.selectSimCard(1);
                            }
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                } else {
                    try {
                        runImpl();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }).start();
    }

    private void runImpl() {
        String masterUrl = mMasterUrl;

        if (TextUtils.isEmpty(masterUrl)) {
            return;
        }

        HttpURLConnection httpURLConnection = null;
        InputStream inputStream = null;
        Date now = new Date();
        now.setHours(0);
        now.setMinutes(0);
        now.setSeconds(0);

        long startTime = now.getTime() / 1000;
        long endTime = startTime + 86400 - 1;

        try {
            if (masterUrl.indexOf('?') != -1) {
                masterUrl += "&" + MicroPhotoContext.MASTER_URL_CMDID + "=" + URLEncoder.encode(mCmdid, "UTF-8");
            } else {
                masterUrl += "?" + MicroPhotoContext.MASTER_URL_CMDID + "=" + URLEncoder.encode(mCmdid, "UTF-8");
            }
            URL url = new URL(masterUrl);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setConnectTimeout(15000);
            httpURLConnection.setReadTimeout(15000);
            httpURLConnection.setRequestMethod("POST");
            // httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);

            httpURLConnection.setRequestProperty("Accept-Cmds", "Multiple");

            List<Pair<String, String>> postParams = new ArrayList<>();
            postParams.add(new Pair<String, String>("id", mCmdid));
            postParams.add(new Pair<String, String>("XyDev", "1"));
            if (mBundleWithMpApp) {
                postParams.add(new Pair<String, String>("bundled", "1"));
            }
            postParams.add(new Pair<String, String>("bootTime", Long.toString(getBootTime())));
            postParams.add(new Pair<String, String>("i1Version", mService.getMpAppVersion()));
            postParams.add(new Pair<String, String>("oid", mService.getSerialNo()));
            postParams.add(new Pair<String, String>("maintainVersion", mService.getMasterAppVersion()));

            postParams.add(new Pair<String, String>("firmware", MpMasterService.getSystemProperty("ro.custom.ota.version")));

            postParams.add(new Pair<String, String>("signalLevel1", Integer.toString(MpMasterService.getSignalLevel(1))));
            postParams.add(new Pair<String, String>("signalLevel2", Integer.toString(MpMasterService.getSignalLevel(2))));

            // SysApi.
            postParams.add(new Pair<String, String>("simcard1", mService.getIccid(1)));
            // if (mService.isSeparateNetwork()) {
            postParams.add(new Pair<String, String>("simcard2", mService.getIccid(2)));
            // }

            postParams.add(new Pair<String, String>("freeROM", getFreeROM()));

            buildStats(startTime, postParams);

            try {
                MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(mService);
                if (appConfig != null) {
                    postParams.add(new Pair<String, String>("heartbeatDuration", Integer.toString(appConfig.heartbeat)));
                    postParams.add(new Pair<String, String>("cma", appConfig.server + ":" + Integer.toString(appConfig.port)));
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            try {
                postParams.add(new Pair<String, String>("mainBoardTmp", ThermalInfoUtil.getCPUTermperature()));
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            try {
                String battery = getBatteryVoltage() + "V/" + getChargingBatteryVoltage() + "V";
                postParams.add(new Pair<String, String>("battery", battery));
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            // postParams(httpURLConnection.getOutputStream(), postParams);
            buildParams(httpURLConnection.getOutputStream(), postParams);
            httpURLConnection.connect();
            inputStream = httpURLConnection.getInputStream();

            int responseCode = httpURLConnection.getResponseCode();

            if (responseCode == HttpURLConnection.HTTP_OK) {
                //在子线程中不能操作UI线程，通过handler在UI线程中进行操作
                // handler.sendEmptyMessage(0x00);
                String response = convertStreamToString(inputStream);
                process(response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void buildStats(long startTime, List<Pair<String, String>> stats) {

        try {
            /*
            struct MP_STATS
            {
                int hb;
                int hbAck;
                int scheduledCount;
                int takingTimes;
                int succeededPhotos;
                int failedPhotos;
                int failedTimes;
                int uploaded;
                int devReboots;
                int appReboots;
            };
            */

            int[] items = MpMasterService.getStats(startTime);
            if (items == null || items.length < 12) {
                return;
            }

            stats.add(new Pair<String, String>("numberOfHb", Integer.toString(items[0])));
            stats.add(new Pair<String, String>("numberOfHbAck", Integer.toString(items[1])));

            stats.add(new Pair<String, String>("recv", Integer.toString(items[2])));
            stats.add(new Pair<String, String>("photoTimes", Integer.toString(items[3])));
            stats.add(new Pair<String, String>("success", Integer.toString(items[4])));
            stats.add(new Pair<String, String>("failure", Integer.toString(items[5])));
            stats.add(new Pair<String, String>("failedTimes", Integer.toString(items[6])));
            stats.add(new Pair<String, String>("uploads", Integer.toString(items[7])));

            stats.add(new Pair<String, String>("uploads", Integer.toString(items[7])));


            if (items[8] > 0) {
                stats.add(new Pair<String, String>("rebootTimes", Integer.toString(items[8])));
            }

            if (items[9] > 0) {
                stats.add(new Pair<String, String>("i1RebootTimes", Integer.toString(items[9])));
            }

            if (items[10] > 0) {
                stats.add(new Pair<String, String>("rebootTimesWk", Integer.toString(items[10])));
            }

            if (items[11] > 0) {
                stats.add(new Pair<String, String>("i1RebootTimesWk", Integer.toString(items[11])));
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private String getBatteryVoltage() {
        int val = 0;
        for (int idx = 0; idx < 3; idx++) {
            val = MpMasterService.getInt(115);
            if (val > 0) {
                return Integer.toString(val / 1000) + "." + Integer.toString((val % 1000) / 100);
            }
        }

        return "";
    }

    private String getChargingBatteryVoltage() {
        int val = 0;
        for (int idx = 0; idx < 3; idx++) {
            val = MpMasterService.getInt(112);
            if (val > 0) {
                return Integer.toString(val / 1000) + "." + Integer.toString((val % 1000) / 100);
            }
        }

        return "";
    }

    private String getImei(int number) {
        return (number == 1) ? SysApi.getImei(mService) : SysApi.getImei2(mService);
    }

    private String getFreeROM() {
        long[] flashInfo = SysApi.getFlashInfo();
        if (flashInfo != null && flashInfo.length > 1) {
            double fd = (double)(flashInfo[1] * 100) / (double)flashInfo[0];
            return Integer.toString((int)fd) + "%";
        }
        return "";
    }

    private void process(String content) {
        if (TextUtils.isEmpty(content)) {
            return;
        }

        try {
            mService.logger.info(content);

            JSONObject jsonObject = new JSONObject(content);
            int isUpgrade = jsonObject.optInt("isUpgrade", 0);
            String url = jsonObject.optString("url", null);
            long cid = jsonObject.optLong("cid", 0);

            int mntnMode = jsonObject.optInt("yw", 0);
            int quickHbMode = jsonObject.optInt("kxt", 0);

            mService.setMntnMode(mntnMode != 0, quickHbMode != 0);

            if (isUpgrade == 1 && !TextUtils.isEmpty(url)) {
                upgradeApp(cid, "upgrade", url);
            }

            processCmd(cid, jsonObject);

            JSONArray cmdObjects = jsonObject.optJSONArray("cmds");

            if (cmdObjects != null) {
                int cnt = cmdObjects.length();
                for (int idx = 0; idx < cnt; idx++) {
                    JSONObject cmdObject = cmdObjects.getJSONObject(idx);
                    if (cmdObject != null) {
                        processCmd(cid, cmdObject);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void sendResult(long cid, int result, String action, String content) {
        String url = mMasterUrl;
        try {
            if (!url.endsWith("/")) {
                url += "/";
            }
            url += "status/?";
            url += MicroPhotoContext.MASTER_URL_CMDID + "=" + URLEncoder.encode(mCmdid, "UTF-8") +
                    "&cid=" + Long.toString(cid) +
                    "&res=" + Integer.toString(result) + "&act=" + URLEncoder.encode(action, "UTF-8") +
                    "&content=" + URLEncoder.encode(content, "UTF-8");
            HttpRequest.get(url);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void processCmd(long cid, JSONObject jsonObject) {
        String cmd = jsonObject.optString("cmd", "");

        if (TextUtils.equals(cmd, CMD_REBOOT_DEV)) {
            mService.logger.warning("Recv Reset Cmd");
            SysApi.reboot(mService.getApplicationContext());
        } else if (TextUtils.equals(cmd, CMD_UPLOAD_LOGS)) {
            String url = jsonObject.optString("url", null);
            mService.logger.warning("Recv Upload Log" + url);
            int noSpecData = jsonObject.optInt("noSpecData", 0);
            uploadLogs(url, noSpecData == 0);
            uploadMasterLogs(url);
        } else if (TextUtils.equals(cmd, CMD_SET_CMA)) {
            String ip = jsonObject.optString("value_str", null);
            int port = jsonObject.optInt("value_int", 0);
            mService.logger.warning("Recv Set CMA Cmd: " + (TextUtils.isEmpty(ip) ? "" : ip) + " port=" + Integer.toString(port));
            updateCma(ip, port);
        } else if (TextUtils.equals(cmd, CMD_SET_MNTN)) {
            String ip = jsonObject.optString("value_str", null);
            int port = jsonObject.optInt("value_int", 0);
            mService.logger.warning("Recv Set Mntn Cmd: " + (TextUtils.isEmpty(ip) ? "" : ip) + " port=" + Integer.toString(port));
            String newUrl = buildMntnServer(ip, port);
            if (newUrl != null) {
                mService.updateMntn(newUrl);
            }
        } else if (TextUtils.equals(cmd, CMD_UPDATE_CONFIG)) {
            JSONArray jsonConfigs = null;
            try {
                jsonConfigs = jsonObject.getJSONArray("configs");
                String path = jsonObject.optString("path", null);
                String fileName = jsonObject.optString("fileName", null);

                mService.logger.warning("Recv Update Config: " + path + " " + fileName);

                if (jsonConfigs != null) {

                    for (int idx = 0; idx < jsonConfigs.length(); idx++) {
                        JSONObject jsonConfig = jsonConfigs.getJSONObject(idx);
                        String configName = jsonConfig.optString("name", null);
                        int fieldType = jsonConfig.optInt("type", 0);
                        Object val = jsonConfig.opt("value");

                        updateConfig(path, fileName, configName, fieldType, val);
                    }

                    String packageName = jsonObject.optString("packageName", null);
                    if (packageName != null) {
                        MicroPhotoContext.restartApp(mService.getApplicationContext(), packageName);
                    }
                }
            } catch (Exception ex) {
            }
        } else if (TextUtils.equals(cmd, CMD_PUSH_FILE)) {

            String path = jsonObject.optString("path", null);
            String content = jsonObject.optString("content", null);
            mService.logger.warning("Recv Push File: " + path);

            File file = new File(path);
            File parentPath = file.getParentFile();
            if (!parentPath.exists()) {
                parentPath.mkdirs();
            }

            byte[] data = null;
            try {
                data = Base64.decode(content, Base64.DEFAULT);
            } catch (Exception ex) {
            }

            if (data != null) {
                OutputStream outputStream = null;
                try {
                    outputStream = new FileOutputStream(file);
                    outputStream.write(data);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (Exception ex) {
                        }
                    }
                }
            }
        } else if (TextUtils.equals(cmd, CMD_HOT_SPOT)) {
            int enable = jsonObject.optInt("enable", 1);
            String name = jsonObject.optString("name", "XYMP");
            mService.logger.warning("Recv EN HotSpot: " + name + "=" + enable);
            if (enable != 0) {
                SysApi.openHotSpot(mService.getApplicationContext());
            } else {
                SysApi.closeHotSpot(mService.getApplicationContext());
            }
        } else if (TextUtils.equals(cmd, CMD_ENABLE_GPS)) {
            int enable = jsonObject.optInt("enable", 1);
            mService.logger.warning("Recv EN GPS: " + enable);
            SysApi.enableGps(mService.getApplicationContext(), (enable != 0));
        } else if (TextUtils.equals(cmd, CMD_ENABLE_OTG)) {
            int enable = jsonObject.optInt("enable", 1);
            mService.logger.warning("Recv EN OTG: " + enable);
            SysApi.setOtgState((enable != 0));
        }  else if (TextUtils.equals(cmd, CMD_PULL_FILE)) {
            pullFiles(jsonObject);
        }  else if (TextUtils.equals(cmd, CMD_DELETE_FILE)) {

            String path = jsonObject.optString("path", null);
            mService.logger.warning("Recv Del File: " + path);
            deleteFile(path);
        } else if (TextUtils.equals(cmd, CMD_IMPORT_PUB_KEY)) {

        } else if (TextUtils.equals(cmd, CMD_UPD_OTA)) {
            String url = jsonObject.optString("url", null);
            String fileName = jsonObject.optString("fileName", null);
            String md5 = jsonObject.optString("md5", null);
            mService.logger.warning("Recv Update OTA: " + url + " " + fileName);
            if (!TextUtils.isEmpty(url)) {
                upgradeOta(cid, cmd, url, fileName, md5);
            }
        }
    }

    private void importPublicKey(JSONObject jsonObject) {
        String content = jsonObject.optString("pubkey", null);
        String md5 = jsonObject.optString("md5", null);

        File path = new File(MicroPhotoContext.buildAppDir(mService.getApplicationContext()) + "keys/");
        if (!path.exists()) {
            path.mkdirs();
        }

        File file = new File(path, "pubkey.cert");

        byte[] data = null;
        try {
            data = Base64.decode(content, Base64.DEFAULT);
        } catch (Exception ex) {
        }

        if (data != null) {

            if (TextUtils.equals(MD5Util.md5(data), md5)) {
                OutputStream outputStream = null;
                try {
                    outputStream = new FileOutputStream(file);
                    outputStream.write(data);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (Exception ex) {
                        }
                    }
                }

                Intent intent = new Intent(MpMasterService.ACTION_IMP_PUBKRY);
                intent.putExtra("path", file.getAbsolutePath());
                intent.putExtra("md5", md5);
                intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP);
                mService.getApplicationContext().sendBroadcast(intent);
            }
        }
    }

    private void pullFiles(JSONObject jsonObject) {
        try {
            JSONArray jsonPaths = jsonObject.optJSONArray("paths");
            if (jsonPaths != null && jsonPaths.length() > 0) {
                // String[] path = jsonObject.optString("path", null);

                List<String> paths = new ArrayList<>();
                for (int idx = 0; idx < jsonPaths.length(); idx++) {
                    String path = jsonPaths.optString(idx);
                    if (path != null) {
                        paths.add(path);
                    }
                }

                String url = jsonObject.optString("url", null);
                mService.logger.warning("Recv Pull File: " + url);
                if (url != null && !paths.isEmpty()) {
                    uploadFiles(url, paths);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void deleteFile(String path) {
        try {
            File file = new File(path);
            if (file.exists() && file.isFile()) {
                file.delete();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private boolean updateConfig(String path, String fileName, String name, int fieldType, Object val) {

        if (name == null) {
            return false;
        }

        File configFile = new File(Environment.getExternalStorageDirectory(), path);
        if (!configFile.exists()) {
            if (val == null) {
                // Should delete the config field
                return true;
            }

            configFile.mkdirs();
        }

        configFile = new File(configFile, fileName);
        if (!configFile.exists() && val == null) {
            return true;
        }

        JSONObject jsonObject = JSONUtils.loadJson(configFile.getAbsolutePath());
        if (jsonObject == null) {
            if (val == null) {
                return true;
            }
            jsonObject = new JSONObject();
        }

        if (!JSONUtils.updateJsonProperty(jsonObject, name, fieldType, val)) {
            return false;
        }

        return JSONUtils.saveJson(configFile.getAbsolutePath(), jsonObject);
    }

    private String buildMntnServer(String server, int port) {
        if (TextUtils.isEmpty(server) && port == 0) {
            return null;
        }

        String url = null;
        if (server.startsWith("http://") || server.startsWith("https://")) {
            url = server;
        } else {
            if ((InetAddressUtils.isIPv4Address(server) || InetAddressUtils.isIPv6Address(server)) && port > 0) {
                url = "http://" + server + ":" + Integer.toString(port) + "/";
            }
        }

        return url;
    }

    private boolean updateCma(String ip, int port) {
        if ((InetAddressUtils.isIPv4Address(ip) && InetAddressUtils.isIPv6Address(ip)) || port <= 0) {
            return false;
        }

        MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(mService.getApplicationContext());

        if (TextUtils.equals(ip, appConfig.server) && port == appConfig.port) {
            return true;
        }

        appConfig.server = ip;
        appConfig.port = port;

        MicroPhotoContext.saveMpAppConfig(mService.getApplicationContext(), appConfig);

        MicroPhotoContext.restartMpApp(mService.getApplicationContext());

        return true;
    }

    private void upgradeApp(long cid, String action, String url) {

        mService.logger.warning("Recv Upgrade Cmd: url=" + url);

        FileDownloader dl = new FileDownloader();
        File path = new File(MicroPhotoContext.buildAppDir(mService.getApplicationContext()), "packages");
        if (!path.exists()) {
            path.mkdirs();
        }

        File file = new File(path, "app.apk");
        if (file.exists()) {
            file.delete();
        }
        String apkPath = file.getAbsolutePath();
        if (dl.download(url, apkPath)) {
            sendResult(cid, 1, action, action + ":" + mCmdid);
            Context context = mService.getApplicationContext();
            mService.logger.info("Upgrade APP: " + url);

            SysApi.installApk(context, apkPath, context.getPackageName(), true);
        } else {
            mService.logger.warning("Failed to Download:" + url);
        }
    }

    private void upgradeOta(long cid, String action, String url, String fileName, String md5) {

        mService.logger.warning("Recv Upgrade OTA: url=" + url);

        FileDownloader dl = new FileDownloader();
        File path = new File(MicroPhotoContext.buildAppDir(mService.getApplicationContext()), "ota");
        if (!path.exists()) {
            path.mkdirs();
        }

        File file = new File(path, fileName == null ? "ota.zip" : fileName);
        if (file.exists()) {
            file.delete();
        }
        String otaPath = file.getAbsolutePath();
        if (dl.download(url, otaPath)) {
            sendResult(cid, 1, action, action + ":" + mCmdid);
            Context context = mService.getApplicationContext();
            mService.logger.info("Upgrade OTA: " + url);

            SysApi.installOTA(context, context.getPackageName(), otaPath);
        } else {
            mService.logger.warning("Failed to Download:" + url);
        }
    }

    private void uploadLogs(String url, final boolean includingSpecData) {
        String appDir = mService.buildAppDir();

        try {

            long ts = System.currentTimeMillis();//long now = android.os.SystemClock.uptimeMillis();
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            Date dt = new Date(ts);

            final String fileName = mCmdid + "_" + format.format(dt) + ".zip";
            final File file = File.createTempFile(fileName, null, new File(appDir));
            if (file == null) {
                return;
            }

            final String mpAppDir = MicroPhotoContext.buildMpAppDir(mService.getApplicationContext());
            final File logDir = new File(mpAppDir + "logs" + File.separator);
            if (!logDir.exists()) {
                return;
            }

            ZipUtils.Filter filter = new ZipUtils.Filter() {
                @Override
                public boolean match(String fileName) {
                    if (!fileName.endsWith(".txt")) {
                        return false;
                    }
                    if (!includingSpecData && fileName.startsWith("specdata")) {
                        return false;
                    }
                    return true;
                }
            };
            ZipUtils.ZipFolder(logDir, file, filter);

            if (!file.exists()) {
                return;
            }

            FileUploader fileUploader = new FileUploader(url);
            fileUploader.addFilePart("file", file, fileName, "application/x-zip-compressed");

            String response = fileUploader.finish();
            if (response != null) {

            }
        } catch (Exception ex) {

        }
    }

    private void uploadMasterLogs(String url) {
        String appDir = mService.buildAppDir();

        try {

            long ts = System.currentTimeMillis();//long now = android.os.SystemClock.uptimeMillis();
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            Date dt = new Date(ts);

            final String fileName = mCmdid + "_mst_" + format.format(dt) + ".zip";
            final File file = File.createTempFile(fileName, null, new File(appDir));
            if (file == null) {
                return;
            }

            final String mpAppDir = MicroPhotoContext.buildMasterAppDir(mService.getApplicationContext());
            final File logDir = new File(mpAppDir + "logs" + File.separator);
            if (!logDir.exists()) {
                return;
            }

            ZipUtils.Filter filter = new ZipUtils.Filter() {
                @Override
                public boolean match(String fileName) {
                    return fileName.endsWith(".txt");
                }
            };
            ZipUtils.ZipFolder(logDir, file, filter);

            if (!file.exists()) {
                return;
            }

            FileUploader fileUploader = new FileUploader(url);
            fileUploader.addFilePart("file", file, fileName, "application/x-zip-compressed");

            String response = fileUploader.finish();
            if (response != null) {

            }
        } catch (Exception ex) {

        }
    }

    private void uploadLogs(String url, String tempPath, String path, String ext, String uploadFileName) {

        try {

            final File pathFile = new File(path);
            if (!pathFile.exists()) {
                return;
            }

            final File file = File.createTempFile(uploadFileName, null, new File(tempPath));
            if (file == null) {
                return;
            }

            ZipUtils.ZipFolder(pathFile, file, null);

            if (!file.exists()) {
                return;
            }

            FileUploader fileUploader = new FileUploader(url);
            fileUploader.addFilePart("file", file, uploadFileName, "application/x-zip-compressed");

            String response = fileUploader.finish();
            if (response != null) {

            }
        } catch (Exception ex) {

        }
    }

    private void uploadFiles(String url, List<String> paths) {
        String appDir = mService.buildAppDir();

        try {

            long ts = System.currentTimeMillis();//long now = android.os.SystemClock.uptimeMillis();
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            Date dt = new Date(ts);

            final String fileName = mCmdid + "_" + format.format(dt) + ".zip";
            final File file = File.createTempFile(fileName, null, new File(appDir));
            if (file == null) {
                return;
            }

            ZipUtils.ZipFiles(paths, file);

            if (!file.exists()) {
                return;
            }

            FileUploader fileUploader = new FileUploader(url);
            fileUploader.addFilePart("file", file, fileName, "application/x-zip-compressed");

            String response = fileUploader.finish();
            if (response != null) {

            }
        } catch (Exception ex) {

        }
    }

    private void buildParams(OutputStream output, List<Pair<String, String>> params) {
        BufferedWriter bufferedWriter = null;
        OutputStreamWriter outputStreamWriter = null;
        try {
            JSONObject jsonObject = new JSONObject();

            for (Pair<String, String> pair : params) {
                jsonObject.put(pair.first, pair.second);
            }

            outputStreamWriter = new OutputStreamWriter(output, "UTF-8");
            bufferedWriter = new BufferedWriter(outputStreamWriter);
            bufferedWriter.write(jsonObject.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (outputStreamWriter != null) {
                    outputStreamWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void postParams(OutputStream output, List<Pair<String, String>> paramsList) {

        BufferedWriter bufferedWriter = null;
        try {
            StringBuilder stringBuilder = new StringBuilder();
            for (Pair<String, String> pair : paramsList) {
                if (!TextUtils.isEmpty(stringBuilder)) {
                    stringBuilder.append("&");
                }
                stringBuilder.append(URLEncoder.encode(pair.first, "UTF-8"));
                stringBuilder.append("=");
                stringBuilder.append(URLEncoder.encode(pair.second, "UTF-8"));
                bufferedWriter = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));
                bufferedWriter.write(stringBuilder.toString());
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private String convertStreamToString(InputStream inputStream) {
        BufferedReader bufferedReader = null;
        StringBuffer stringBuffer = new StringBuffer();
        String line;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return stringBuffer.toString();
    }



}
