package com.imofan.android.basic;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.imofan.android.basic.MFNetSpeedMonitor.NetspeedData;

import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.telephony.TelephonyManager;
import android.util.Log;
//import cn.com.pcgroup.android.framework.http.client.AsyncHttpClient;
//import cn.com.pcgroup.android.framework.http.client.AsyncHttpResponseHandler;

//TODO: 未按规则成对的添加resume和pause事件时的处理方式
/**
 * 魔方用户行为分析SDK工具类
 */
public class Mofang {
    //PUBLISH CHECK
    public static boolean DEBUG = false;
//    public static boolean DEBUG = true;
    private static boolean developDebug = false;
    final static String SDK_VERSION = "1.2.0";
    public final static String LOG_TAG = "Mofang_Debug";

    private static boolean init = false;

    //PUBLISH CHECK
    private final static String COLLECTOR = "http://c.imofan.com/";
//    private final static String COLLECTOR = "http://192.168.74.37/";
    private final static String REGISTER = "http://m.imofan.com/register/";
    private final static String COLLECTOR_OPEN = "http://v.imofan.com/open/";

    //数据发送策略
    private final static int SEND_WAY_OPEN = 1;         //每次启动时发送
    private final static int SEND_WAY_DAY = 2;          //每日发送一次
    private final static int SEND_WAY_REAL_TIME = 3;   //实时发送
    private final static int SEND_WAY_WIFI = 4;         //WIFI环境下实时发送

    private static int sendWay = SEND_WAY_OPEN;
    private static int maxLeaveTime = 30000;         //应用最大离开（退出应用、回到桌面、切换到其它应用或屏幕关闭）时间，单位：毫秒
    private static int minUseTime = 3000;            //应用最小使用时间，单位：毫秒
    private static int maxUseTime = 6*60*60*1000;    //应用最长使用时间，超过就当做错误数据忽略，单位：毫秒

    private static String appKey = null;
    static MFDatabaseManager dbManager = null;

    private static boolean newStart = true;                 //是否新打开应用的标记
    private static Class currentActivity = null;           //当前激活的Activity类
    private static String currentActivityAlias = null;     //当前激活的Activity对象的别名
    private static long resumeTime = -1;                    //界面激活时间
    private static int activityId = 0;                      //Activity顺序号
    
    private final static Object workLock = new Object();
    
    public static void setDebugEnable(boolean isDebug){
    	DEBUG = isDebug;
    }

    //初始化魔方SDK
    public synchronized static void init(Context context) {
        //初始化应用
        if(!init) {
            if(getAppKey(context) != null) {
                //初始化数据库
                if(dbManager == null) {
                    dbManager = MFDatabaseManager.getInstance(context);
                }
                //更新设备信息
                MFStatInfo.init(context);
                long now = System.currentTimeMillis();
                int[] intTime = getDateAndHour(now);
                MFStatInfo.updateAppAndDeviceInfo(dbManager, context, intTime[0], intTime[1]);
                init = true;
            }
        } else {
            newStart = false;
        }
    }

    /**
     * 获取魔方为当前应用分配的appkey
     * @param context 当前应用的context对象
     * @return 应用的appkey
     */
    public static String getAppKey(Context context) {
        //初始化appkey
        if(appKey == null) {
            try {
                Object appKeyObj = context.getPackageManager().getApplicationInfo(context.getPackageName(),
                        PackageManager.GET_META_DATA).metaData.get("MOFANG_APPKEY");
                if(appKeyObj instanceof Integer) {
                    appKey = Integer.toString(((Integer)appKeyObj).intValue());
                } else if(appKeyObj instanceof  Long) {
                    appKey = Long.toString(((Long)appKeyObj).intValue());
                } else {
                    appKey = (String)appKeyObj;
                }
                Log.i(LOG_TAG, "imofan appkey: " + appKey);
            } catch (Exception e) {
                Log.e(LOG_TAG, "[getAppKey]Can't find metadata \"MOFANG_APPKEY\" in AndroidManifest.xml");
                e.printStackTrace();
            }
        }
        return appKey;
    }

    public static String getDevId(Context context) {
        String devId = null;
        try {
            devId = MFStatInfo.getString(MFStatInfo.KEY_DEV_ID, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return devId;
    }

    /**
     * 开启魔方API调试模式，建议开发过程中开启，以便打印详细的异常信息。应用正式打包发布时请去掉该方法的调用。
     */
    public static void debug() {
        developDebug = true;
    }

    /**
     * 判断当前是否开启了调试模式
     * @return 是否开启了调试模式
     */
    public static boolean isDebug() {
        return developDebug;
    }

    public static void enableCrashCollector(Activity context) {
        init(context);
        //初始化异常捕获器
        MFCrashHandler.init(dbManager);
    }

    /**
     * 当Activity被激活时（被置于屏幕前端时）的触发事件，需要在Activity的onResume方法中调用此方法。
     * @param context 被激活的Activity对象
     * @param name 被激活的Activity的别名，为空时自动取类名
     */
    public static void onResume(final Activity context, final String name) {
    	if(isScreenLocked(context)){
    		return;
    	}
    	
        init(context);
        
        //获取Activity激活时间
        resumeTime = System.currentTimeMillis();
        int[] intTime = getDateAndHour(resumeTime);

        //获取Activity名称
        currentActivity = context.getClass();
        if(name != null && name.trim().length() > 0) {
            currentActivityAlias = name;
        } else {
            currentActivityAlias = currentActivity.getName();
        }

        //获取Activity ID
        if(activityId > 0) {
            activityId++;
        } else {
            activityId = (int)(resumeTime - resumeTime/1000000000*1000000000);
        }

        if(DEBUG) {
            Log.d(LOG_TAG, "[onResume]" + currentActivityAlias + "@" + resumeTime);
            
            LogUtils.writeLog("[onResume]"+ currentActivityAlias + "@" + resumeTime);
        }

        //判断是否是一次新的启动，包括长时间的离开（返回桌面、切换到其它应用、屏幕关闭）后返回
        long activityPauseTime = MFStatInfo.getLong(MFStatInfo.KEY_USER_PAUSE_TIME, -1);
        if(newStart || resumeTime - activityPauseTime > maxLeaveTime) {     //如果是新启动
//        	Log.v(LOG_TAG, "############ onResume ############");
            //添加退出应用访问节点
            MFStatAccessPath.addAccessNode(0, null);

            //记录上次使用的结束事件
            long appUseDuration = MFStatInfo.getLong(MFStatInfo.KEY_USER_DURATION, 0);
            if(appUseDuration > minUseTime && appUseDuration <= maxUseTime) {
                recordCloseEvent(appUseDuration);
            }
            
            
            //记录应用启动事件
            recordOpenEvent(resumeTime);

            //初始化应用使用时长
            MFStatInfo.putLong(MFStatInfo.KEY_USER_DURATION, 0);

            //PUBLISH CHECK 添加网速监测代码
            MFNetSpeedMonitor.initCurrentArea(context);
            //记录每次启动时间
            MFNetSpeedMonitor.recordStartTime(context);

            //如果退出时间和最后一次发送成功的时间间隔大于半个小时就主动发送一次魔方数据
//        	long latestSendTime = MFStatInfo.getLong(MFStatInfo.KEY_LATEST_SENDT_TIME, -1);
//        	if(activityPauseTime-latestSendTime > 1800000){
        		//发送事件数据到服务器
        		startEventSender(context, resumeTime, false);
//        	}
        }

        //添加访问路径点
        MFStatAccessPath.addAccessNode(activityId, currentActivityAlias);
    }

    /**
     * 当Activity被激活时（被置于屏幕前端时）的触发事件，需要在Activity的onResume方法中调用此方法。
     * @param context 被激活的Activity对象
     */
    public static void onResume(Activity context) {
    	onResume(context, null);
    }

    //判断是否锁屏
    private static boolean isScreenLocked(Context context) {
        KeyguardManager mKeyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
        return mKeyguardManager.inKeyguardRestrictedInputMode();
    }
    
    /**
     * 通过推送service按照时间间隔发送事件数据到服务器
     * @param context
     */
    public static void sendDataByService(Context context){
    	long currentTime = System.currentTimeMillis();
    	init(context);
    	long activityPauseTime = MFStatInfo.getLong(MFStatInfo.KEY_USER_PAUSE_TIME, -1);
    	LogUtils.writeLog("准备发送魔方数据到服务端");
    	if(resumeTime > activityPauseTime){
    		LogUtils.writeLog("不发送魔方事件");
    		return ;
    	}
    	if(currentTime - activityPauseTime > maxLeaveTime) {     //如果是新启动
    		//Log.v("ly", "sendDataByService : 发送事件数据到服务器");
    		LogUtils.writeLog("开始发送魔方数据到服务端");
    		//发送事件数据到服务器
            startEventSender(context, currentTime, true);
    	}
    }
    
    /**
     * 当Activity从屏幕上消失时的触发事件，需要在Activity的onPause方法中调用此方法。
     * @param context 被激活的Activity对象
     * @param duration Activity使用时长
     */
    private static void onPause(Activity context, long duration) {
    	MFStatInfo.init(context);
    	
        //记录界面退出时间
        long pauseTime = System.currentTimeMillis();
        if(DEBUG) {
            Log.d(LOG_TAG, "[onPause]" + currentActivityAlias + "@" + pauseTime);
        }
        MFStatInfo.putLong(MFStatInfo.KEY_USER_PAUSE_TIME, pauseTime);

        if(resumeTime > 0) {
            //记录应用使用时长
            long appUseDuration = MFStatInfo.getLong(MFStatInfo.KEY_USER_DURATION, 0);
            long activityUseDuration = pauseTime - resumeTime;
            appUseDuration += activityUseDuration;
            MFStatInfo.putLong(MFStatInfo.KEY_USER_DURATION, appUseDuration);

            //记录界面使用路径
            if(duration >= 0) {
                if(duration <= maxUseTime) {
                    MFStatAccessPath.updateAccessDuration(activityId, duration);
                }
            } else {
                if(activityUseDuration <= maxUseTime) {
                    MFStatAccessPath.updateAccessDuration(activityId, activityUseDuration);
                }
            }
        }
    }

    /**
     * 当Activity从屏幕上消失时的触发事件，需要在Activity的onPause方法中调用此方法。
     * @param context 被激活的Activity对象
     */
    public static void onPause(Activity context) {
        onPause(context, -1);
    }

    /**
     * 用于触发自定义事件
     * @param eventKey 事件KEY
     * @param lable 事件标签
     * @param count 触发次数
     */
    public static void onEvent(Context context, String eventKey, String lable, int count) {
        init(context);

        long time = System.currentTimeMillis();
        int[] intTime = getDateAndHour(time);
        String eventValue = eventKey + ":" + (lable == null ? "-" : lable);

        //判断该事件是否今日第一次触发
        boolean isFirst = false;
        List<MFStatEvent> eventList = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_DEVELOPER,
                eventValue, intTime[0], false);
        List<MFStatEvent> sentEventList = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_DEVELOPER,
                eventValue, intTime[0], true);
        if((eventList == null || eventList.size() == 0)
                && (sentEventList == null || sentEventList.size() == 0)) {
            isFirst = true;
        }

        //存储事件数据
        MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_DEVELOPER, intTime[0], intTime[1],
                eventValue, count, 0, isFirst, 0);
    }

    /**
     * 用于触发自定义事件
     * @param eventKey 事件KEY
     * @param lable 事件标签
     */
    public static void onEvent(Context context, String eventKey, String lable) {
        onEvent(context, eventKey, lable, 1);
    }

    /**
     * 用于触发自定义事件
     * @param eventKey 事件KEY
     * @param count 触发次数
     */
    public static void onEvent(Activity context, String eventKey, int count) {
        onEvent(context, eventKey, null, count);
    }

    /**
     * 用于触发自定义事件
     * @param eventKey 事件KEY
     */
    public static void onEvent(Context context, String eventKey) {
        onEvent(context, eventKey, null, 1);
    }
    
    public static void onNotificationReceive(Context context, String notificationId) {
        if(DEBUG) {
            Log.d(LOG_TAG, "[onNotificationReceive] notificationId = " + notificationId);
        }
        long time = System.currentTimeMillis();
        int[] dataAndHour = getDateAndHour(time);
        if(notificationId != null && notificationId.trim().length() > 0) {
            if(dbManager == null) {
                dbManager = MFDatabaseManager.getInstance(context);
            }
            MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_NOTIFICATION_RECEIVE,
                    dataAndHour[0], dataAndHour[1], notificationId);
        }
    }

    public static void onNotificationClick(Context context, String notificationId) {
        if(DEBUG) {
            Log.d(LOG_TAG, "[onNotificationClick] notificationId = " + notificationId);
        }
        long time = System.currentTimeMillis();
        int[] dataAndHour = getDateAndHour(time);
        if(notificationId != null && notificationId.trim().length() > 0) {
            if(dbManager == null) {
                dbManager = MFDatabaseManager.getInstance(context);
            }
            MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_NOTIFICATION_OPEN,
                    dataAndHour[0], dataAndHour[1], notificationId);
        }
    }

    /**
     * 用于触发程序异常事件
     * @param context 当前Activity
     * @param exception 异常
     */
    public static void onError(Activity context, Throwable exception) {
        init(context);

        JSONObject exceptionJson = new JSONObject();
        try {
            exceptionJson.put("name", exception.toString());
            exceptionJson.put("stack", Log.getStackTraceString(exception));
            Date now = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            SimpleDateFormat hourFormat = new SimpleDateFormat("H");
            MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_CRASH, Integer.parseInt(dateFormat.format(now)),
                    Integer.parseInt(hourFormat.format(now)), exceptionJson.toString());
        } catch (JSONException e) {

        }
    }

    /*
     * 用于在访问路径中添加自定的访问节点
     * @param nodeName  节点名称
     * @param duration  访问时长
     */
//    public static void addAccessNode(String nodeName, long duration) {
//        MFStatAccessPath.addAccessNode(0, nodeName, duration);
//    }

    //记录应用启动事件
    private static void recordOpenEvent(long time) {
        int[] intTime = getDateAndHour(time);

        //记录Open事件
        MFOpenEvent.addEvent(dbManager, MFStatInfo.getString(MFStatInfo.KEY_APP_VERSION, ""), time);

        //查找是否是今日第一次启动
        boolean first = false;
        List<MFStatEvent> todayOpenEventsSent = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_OPEN,
                null, intTime[0], true);
        List<MFStatEvent> todayOpenEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_OPEN, null, intTime[0], false);
        if((todayOpenEvents == null || todayOpenEvents.size() == 0)
                && (todayOpenEventsSent == null || todayOpenEventsSent.size() == 0)) {
            first = false;
        }

        //生成启动事件
        MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_OPEN, intTime[0], intTime[1], null, 1, 0, first, 0);
    }

    //记录应用结束事件
    private static void recordCloseEvent(long duration) {
        long appCloseTime = MFStatInfo.getLong(MFStatInfo.KEY_USER_PAUSE_TIME, System.currentTimeMillis());
        int[] intTime = getDateAndHour(appCloseTime);

        //生成应用退出事件
        MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_COLSE, intTime[0], intTime[1],
                null, 1, duration, false, appCloseTime);
    }
    
    
    //根据发送策略发送数据到服务器端
    private static void startEventSender(final Context context, final long time, final boolean includePath) {
        switch (sendWay) {
            case SEND_WAY_DAY:
                break;
            case SEND_WAY_WIFI:
                break;
            case SEND_WAY_REAL_TIME:
                break;
            default:    //SEND_WAY_OPEN
                new Thread(new Runnable() {
                    public void run() {
                    	synchronized(workLock){
	                        sendOpenEventsToServer(context, resumeTime);
	                        NetspeedData netspeedData=null;
	                        if(includePath){
	                            netspeedData = MFNetSpeedMonitor.generateSendData(context, dbManager);
	                        }
	                    	SendData data = generateSendData(context, netspeedData,time, includePath);
	                        sendEventsToServer(data, time);
                    	}
                    }
                }).start();
        }
    }

    //发送Open数据
    private static void sendOpenEventsToServer(Context context, final long time) {
        List<Integer> eventIds = new ArrayList<Integer>();
        String[] appVersions = MFOpenEvent.getAppVersions(dbManager, false);
        if(appVersions != null && appVersions.length > 0) {
            for(String appVersion : appVersions) {
                List<MFOpenEvent> openEvents = null;
                if(appVersion != null) {
                    openEvents = MFOpenEvent.getEvents(dbManager, appVersion, false);
                }
                if(openEvents != null && openEvents.size() > 0) {
                    if(!appVersion.equals("")) {
                        JSONObject json = new JSONObject();

                        //消息发送时间
                        try {
                            json.put("send_time", Math.round(time/1000.0));

                            //设备uuid，由device-id、mac地址、serialNo等计算所得，需要ACCESS_WIFI_STATE权限
                            json.put(MFStatInfo.KEY_DEV_ID, MFStatInfo.getString(MFStatInfo.KEY_DEV_ID, null));

                            //无法取得计算设备uuid需要的硬件信息时，发送该标志，仅在安装App后第一次使用时发送
                            int isDevIdUndefined = MFStatInfo.getInt(MFStatInfo.KEY_DEV_ID_UNDEFINED, 0);
                            if(isDevIdUndefined == 1) {
                                json.put(MFStatInfo.KEY_DEV_ID_UNDEFINED, isDevIdUndefined);
                            }

                            //应用版本
                            json.put(MFStatInfo.KEY_APP_VERSION, appVersion);

                            //启动数据
                            JSONArray openArray = new JSONArray();
                            for(MFOpenEvent openEvent : openEvents) {
                                openArray.put(Math.round(openEvent.getTime()/1000.0));
                                eventIds.add(openEvent.getId());
                            }
                            
                            json.put("open", openArray);

                            if(Mofang.DEBUG) {
                                Log.d(LOG_TAG, "[sendOpenEventsToServer]json: " + json.toString());
                            }

                            //发送数据
                            HttpURLConnection connection = null;
                            DataOutputStream output = null;

                            byte[] data = json.toString().getBytes("utf-8");
                            String appKey = Mofang.getAppKey(context);
                            URL url = new URL(COLLECTOR_OPEN + appKey);

                            connection = (HttpURLConnection) url.openConnection();
                            connection.setDoOutput(true);
                            connection.setDoInput(true);
                            connection.setReadTimeout(20000);
                            connection.setConnectTimeout(20000);
                            connection.setRequestMethod("POST");
                            connection.setUseCaches(false);
                            connection.setRequestProperty("Connection", "Keep-Alive");
                            connection.setRequestProperty("Content-Type", "application/octet-stream");
                            connection.setRequestProperty("Content-Length", Integer.toString(data.length));
                            connection.connect();
                            output = new DataOutputStream(connection.getOutputStream());
                            output.write(data);
                            output.flush();
                            int httpCode = connection.getResponseCode();

                            if(httpCode == HttpStatus.SC_OK) {
                                LogUtils.writeLog("更新Open数据已发送，准备清空历史数据");
                                //更新已发送数据
                                MFOpenEvent.signSentEvent(dbManager, eventIds);
                                //清除历史数据
                                MFOpenEvent.clearHistoryEvents(dbManager, getDateAndHour(time)[0]);
                                LogUtils.writeLog("更新Open数据已发送，清空历史数据");
                                if(DEBUG) {
                                    Log.d(LOG_TAG, "[sendOpenEventsToServer]Send open events success: " + url);
                                }
                            } else {
                                if(DEBUG) {
                                    Log.d(LOG_TAG, "[sendOpenEventsToServer]Send open events fail: " + url);
                                }
                            }
                        } catch (JSONException e) {
                            Log.e(LOG_TAG, "[sendOpenEventsToServer]JSONException");
                            if(isDebug()) {
                                e.printStackTrace();
                            }
                        } catch (UnsupportedEncodingException e) {
                            Log.e(LOG_TAG, "[sendOpenEventsToServer]UnsupportedEncodingException");
                            if(isDebug()) {
                                e.printStackTrace();
                            }
                        } catch (IOException e) {
                            Log.e(LOG_TAG, "[sendOpenEventsToServer]IOException");
                            if(isDebug()) {
                                e.printStackTrace();
                            }
                        } catch (Exception e) {
                            Log.e(LOG_TAG, "[sendOpenEventsToServer]Exception");
                            if(isDebug()) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        for(MFOpenEvent openEvent : openEvents) {
                            eventIds.add(openEvent.getId());
                        }
                    }
                }
            }
        }
    }

    //发送数据到魔方服务器
    private static void sendEventsToServer(SendData data,long time) {
    	if(data==null) return;
        HttpURLConnection connection = null;
        Deflater deflater = null;
        DataOutputStream output = null;
        try {
            //压缩数据
            byte[] input = data.getJson().toString().getBytes("utf-8");
            deflater = new Deflater();
            deflater.setInput(input);
            deflater.finish();
            int size = 0;
            byte[] byteData = new byte[0];
            byte[] buf = new byte[128];
            while (!deflater.finished()) {
                int byteCount = deflater.deflate(buf);
                byte[] temp = new byte[byteData.length + byteCount];
                for(int i=0; i<byteData.length; i++) {
                    temp[i] = byteData[i];
                }
                for(int i=0; i<byteCount; i++) {
                    temp[byteData.length + i] = buf[i];
                }
                byteData = temp;
                size += byteCount;
            }

            //发送数据
            URL url = new URL(COLLECTOR + appKey);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setReadTimeout(20000);
            connection.setConnectTimeout(20000);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", "application/octet-stream");
            connection.connect();
            output = new DataOutputStream(connection.getOutputStream());
            output.write(byteData);
            output.flush();
            int httpCode = connection.getResponseCode();

            if(httpCode == HttpStatus.SC_OK) {
                if(DEBUG) {
                    Log.i(LOG_TAG, "[sendEventsToServer]Send to " + COLLECTOR + appKey + "[" + size + "]: "
                            + data.getJson().toString());
                    LogUtils.writeLog("[sendEventsToServer]Send to " + COLLECTOR + appKey + "[" + size + "]: "
                            + data.getJson().toString());
                }
                StringBuffer sb = new StringBuffer();
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line).append("\n");
                    }
                } catch (IOException e) {
                	LogUtils.writeLog("[sendEventsToServer]IOException: get response");
                    Log.e(LOG_TAG, "[sendEventsToServer]IOException: get response");
                    e.printStackTrace();
                } finally {
                    if(reader != null) {
                        try {
                            reader.close();
                        } catch (IOException e) {
                        	LogUtils.writeLog("[sendEventsToServer]IOException: reader.close()");
                            Log.e(LOG_TAG, "[sendEventsToServer]IOException: reader.close()");
                            e.printStackTrace();
                        }
                    }
                }
                String response = sb.toString();
                if(Mofang.DEBUG) {
                    Log.d(LOG_TAG, "[sendEventsToServer]Server response: " + response);
                    LogUtils.writeLog("[sendEventsToServer]Server response: " + response);
                }
                if(response.indexOf("HTTPSQS_PUT_OK") > -1) {
                	LogUtils.writeLog("更新数据已发送，准备清空历史数据");
                    //更新已发送数据
                    MFStatEvent.signSentEvent(dbManager, data.getIdList());
                    //清除历史数据
                    MFStatEvent.clearAccessPath(dbManager);
                    MFStatEvent.clearHistoryEvents(dbManager, getDateAndHour(time)[0]);
                    if(data.getNetspeedData()!=null){
                        //标记已经发送的网速数据
                        MFAPPBasicInfo.signSendData(dbManager, data.getNetspeedData().getIdList());
                        //清空网速数据
                        MFNetSpeedMonitor.clearData(dbManager,data.getNetspeedData().getIdList());
                    }
                    
                    LogUtils.writeLog("更新数据已发送，清空历史数据");
                    //存储最近发送过数据之后的时间
                    MFStatInfo.putLong(MFStatInfo.KEY_LATEST_SENDT_TIME, System.currentTimeMillis());
                }
                
                LogUtils.writeLog("数据发送成功");
            }
        } catch (UnsupportedEncodingException e) {
            Log.e(LOG_TAG, "[sendEventsToServer]UnsupportedEncodingException");
            LogUtils.writeLog("[sendEventsToServer]UnsupportedEncodingException");
            e.printStackTrace();
        } catch (MalformedURLException e) {
        	LogUtils.writeLog("[sendEventsToServer]MalformedURLException");
            Log.e(LOG_TAG, "[sendEventsToServer]MalformedURLException");
            e.printStackTrace();
        } catch (ProtocolException e) {
        	LogUtils.writeLog("[sendEventsToServer]ProtocolException");
            Log.e(LOG_TAG, "[sendEventsToServer]ProtocolException");
            e.printStackTrace();
        } catch (IOException e) {
        	LogUtils.writeLog("[sendEventsToServer]IOException");
            Log.e(LOG_TAG, "[sendEventsToServer]IOException");
            e.printStackTrace();
        } catch (Exception e) {
        	LogUtils.writeLog("[sendEventsToServer]Exception");
            Log.e(LOG_TAG, "[sendEventsToServer]Exception");
            e.printStackTrace();
        } finally {
            if(output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                	LogUtils.writeLog("[sendEventsToServer]IOException: output.close()");
                    Log.e(LOG_TAG, "[sendEventsToServer]IOException: output.close()");
                    e.printStackTrace();
                }
            }
            if(deflater != null) {
                deflater.end();
            }
            if(connection != null) {
                connection.disconnect();
            }
        }
    }

    //生成发送的json数据，同时更新Info值
    private static SendData generateSendData(Context context,NetspeedData netspeedData, long time, boolean includePath) {
    	boolean isSendData = false;
    	
        int[] intTime = getDateAndHour(time);
        List<Integer> eventIds = new ArrayList<Integer>();
        JSONObject json = new JSONObject();

        try {
            //消息发送时间
            json.put("send_time", Math.round(time/1000.0));

            //应用安装日期
            json.put(MFStatInfo.KEY_INSTALL_DATE, MFStatInfo.getInt(MFStatInfo.KEY_INSTALL_DATE, intTime[0]));

            //设备uuid，由device-id、mac地址、serialNo等计算所得，需要ACCESS_WIFI_STATE权限
            json.put(MFStatInfo.KEY_DEV_ID, MFStatInfo.getString(MFStatInfo.KEY_DEV_ID, null));

            //无法取得计算设备uuid需要的硬件信息时，发送该标志，仅在安装App后第一次使用时发送
            int isDevIdUndefined = MFStatInfo.getInt(MFStatInfo.KEY_DEV_ID_UNDEFINED, 0);
            if(isDevIdUndefined == 1) {
                json.put(MFStatInfo.KEY_DEV_ID_UNDEFINED, isDevIdUndefined);
            }

            //魔方SDK版本信息
            json.put(MFStatInfo.KEY_SDK_VERSION, MFStatInfo.getString(MFStatInfo.KEY_SDK_VERSION, null));

            //应用版本
            json.put(MFStatInfo.KEY_APP_VERSION, MFStatInfo.getString(MFStatInfo.KEY_APP_VERSION, null));

            //发布渠道版本
            json.put(MFStatInfo.KEY_CHANNEL, MFStatInfo.getString(MFStatInfo.KEY_CHANNEL, null));

            //操作系统
            json.put(MFStatInfo.KEY_OS, "Android");

            //操作系统版本);
            json.put(MFStatInfo.KEY_OS_VERSION, MFStatInfo.getString(MFStatInfo.KEY_OS_VERSION, null));

            //运营商
            json.put(MFStatInfo.KEY_CARRIER, MFStatInfo.getString(MFStatInfo.KEY_CARRIER, null));

            //网络访问方式
            String network = "NONE";
            NetworkInfo networkInfo;
            NetworkInfo.State state = null;
            if(null!=context){
            	//WIFI网络判断
            	ConnectivityManager connectivityManager =
            			(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
            	if(null!=connectivityManager){
            		networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            		if(null!=networkInfo){
            			state = networkInfo.getState();
            		}
            	}
            	if(state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING){
            		network = "WiFi";
            	} else {
            		//3G网络判断
            		if(null!=connectivityManager){
            			networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
            			if(null!=networkInfo){
            				state = networkInfo.getState();
            				if(state == NetworkInfo.State.CONNECTED||state == NetworkInfo.State.CONNECTING){
            					network = "2G/3G";
            					TelephonyManager telephonyManager =
            							(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
            					int networkType = telephonyManager.getNetworkType();
            					switch (networkType) {
            					case 1:
            					case 2:
            					case 4:
            					case 7:
            						network = "2G";
            						break;
            					case 3:
            					case 5:
            					case 6:
            					case 8:
            					case 9:
            					case 10:
            						network = "3G";
            					}
            				}
            			}
            		}
            	}
            	
            }
            json.put("access", network);

            //分辨率
            json.put(MFStatInfo.KEY_RESOLUTION, MFStatInfo.getString(MFStatInfo.KEY_RESOLUTION, null));

            //设备型号
            json.put(MFStatInfo.KEY_MODEL, MFStatInfo.getString(MFStatInfo.KEY_MODEL, null));

            //时区
            json.put(MFStatInfo.KEY_TIMEZONE, MFStatInfo.getInt(MFStatInfo.KEY_TIMEZONE, 8));

            //语言
            json.put(MFStatInfo.KEY_LANGUAGE, MFStatInfo.getString(MFStatInfo.KEY_LANGUAGE, null));

            //国家
            json.put(MFStatInfo.KEY_COUNTRY, MFStatInfo.getString(MFStatInfo.KEY_COUNTRY, null));

            //设备id
            json.put(MFStatInfo.KEY_DEVICE_ID, MFStatInfo.getString(MFStatInfo.KEY_DEVICE_ID, null));

            //Mac地址
            json.put(MFStatInfo.KEY_MAC_ADDRESS, MFStatInfo.getString(MFStatInfo.KEY_MAC_ADDRESS, null));

            //事件数据
            boolean appVersionUpdate = false;
            int[] dates = MFStatEvent.getEventDates(dbManager);
            if(dates != null && dates.length > 0) {
            	isSendData = true;
            	if(DEBUG) {
            		Log.d(LOG_TAG, "event date num = " + dates.length);
            	}
                JSONObject data = new JSONObject();
                //每日数据
                for(int date : dates) {
                    if(DEBUG) {
                        Log.d(LOG_TAG, "event date = " + date);
                    }
                    JSONObject dateEvent = new JSONObject();

                    //检查是否重复安装
                    String oldVersion = null;
                    List<MFStatEvent> install = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_INSTALL, null, date, false);
                    List<MFStatEvent> upgrade = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_UPGRADE, null, date, false);
                    if((install != null && install.size() > 0) || (upgrade != null && upgrade.size() > 0)) {
                        HttpParams param = new BasicHttpParams();
                        HttpConnectionParams.setConnectionTimeout(param, 20000);
                        HttpConnectionParams.setSoTimeout(param, 20000);

                        HttpClient httpClient = new DefaultHttpClient(param);

                        String appKey = Mofang.getAppKey(context);
                        String appId = Long.valueOf(appKey.substring(appKey.length() - 8), 16).toString();
                        String devId = MFStatInfo.getString(MFStatInfo.KEY_DEV_ID, "");
                        int installDate = intTime[0];
                        if(install != null && install.size() > 0) {
                            installDate = install.get(0).getDate();
                        }
                        String channel = MFStatInfo.getString(MFStatInfo.KEY_CHANNEL, "");
                        String appVer = MFStatInfo.getString(MFStatInfo.KEY_APP_VERSION, "");
//                        app_id:dev_id:install_date:channel:app_ver
                        if(DEBUG) {
                            Log.d(LOG_TAG, "appId: " + appId);
                        }
                        String sum = devId + ":" + appId + ":" + channel + ":" + appVer + ":" + installDate;
                        if(DEBUG) {
                            //2a433afdd77438e4a93a53e9c7ef4445:5:pconline:3.2.0:20120927
                            Log.d(LOG_TAG, "check device register md5 plaint: " + sum);
                        }
//                        String md5 = UUID.nameUUIDFromBytes(sum.getBytes()).toString().replaceAll("-", "");
                        MessageDigest md5Digest = MessageDigest.getInstance("MD5");
                        byte[]digest = md5Digest.digest(sum.getBytes());
                        StringBuilder buf = new StringBuilder();
                        for (int i = 0; i < digest.length; i ++) {
                            String b = Integer.toHexString(0xFF & digest[i]);
                            if (b.length() == 1) {
                                buf.append('0');
                            }
                            buf.append(b);
                        }
                        String md5 = buf.toString();
//                        http://m.imofan.com/register//${md5}/${app_key}/${dev_id}/${install_date}/${channel}/${app_ver}
                        String url = REGISTER + md5 + "/" + appKey + "/" + devId
                                + "/" + installDate + "/" + channel + "/" + URLEncoder.encode(appVer, "UTF-8");
                        if(DEBUG) {
                            Log.d(LOG_TAG, "check device register url: " + url);
                        }

                        HttpPost post = new HttpPost(url);
                        post.setHeader("Accept-Encoding", "gzip, deflate");

                        String responseStr = null;
                        try {
                            HttpResponse response = httpClient.execute(post);
                            if(response.getStatusLine().getStatusCode() == 200){
                                InputStream is = response.getEntity().getContent();
                                if(is != null){
                                    Header contentEncoding = response.getFirstHeader("Content-Encoding");
                                    if(contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
                                        is = new GZIPInputStream(is);
                                    }
                                    BufferedReader reader = null;
                                    String line="";
                                    StringBuffer content = new StringBuffer();
                                    try {
                                        reader = new BufferedReader(new InputStreamReader(is));
                                        while((line = reader.readLine()) != null) {
                                            content.append(line).append("\r\n");
                                        }
                                        responseStr = content.toString();
                                    } finally {
                                        if(reader != null) {
                                            reader.close();
                                        }
                                        if(is != null) {
                                            is.close();
                                        }
                                    }
                                }
                            } else {
                                if(DEBUG) {
                                    Log.d(LOG_TAG, "check device register http status: " + response.getStatusLine().getStatusCode());
                                }
                            }
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                            return null;
                        } catch (ClientProtocolException e) {
                            e.printStackTrace();
                            return null;
                        } catch (IOException e) {
                            e.printStackTrace();
                            return null;
                        } catch (Exception e) {
                            e.printStackTrace();
                            return null;
                        }

                        if(DEBUG) {
                            Log.d(LOG_TAG, "check device register response: " + responseStr);
                        }
                        if(responseStr != null && responseStr.trim().length() > 0) {
                            //{"status":1,"install_date":20120901,"channel":"app_store","app_ver":"1.0.2"}
                            JSONObject responseJson = new JSONObject(responseStr);
                            int status = responseJson.optInt("status", 1);
                            if(status == 1) {
                                oldVersion = responseJson.optString("app_ver", null);
                            }
                        }
                    }

                    //安装和更新事件
                    if(oldVersion != null) {
                        String appVersion = null;
                        try {
                            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
                                    context.getPackageName(), PackageManager.GET_CONFIGURATIONS);
                            appVersion = packageInfo.versionName;
                        } catch (PackageManager.NameNotFoundException e) {
                            Log.e(LOG_TAG, "[generateSendData]Get app version error");
                            e.printStackTrace();
                        }
                        if(appVersion != null && !appVersion.equals(oldVersion)) {
                            //更新事件
                            dateEvent.put("upgrade", oldVersion);
                            appVersionUpdate = true;
                        }
                    } else {
                        if(install != null && install.size() > 0) {
                            dateEvent.put("install", install.get(install.size()-1).getHour());
                        }
                    }

                    if(install != null && install.size() > 0) {
                        for(MFStatEvent installEvent : install) {
                            eventIds.add(installEvent.getId());
                        }
                    }
                    if(upgrade != null && upgrade.size() > 0) {
                        for(MFStatEvent upgradeEvent : upgrade) {
                            eventIds.add(upgradeEvent.getId());
                        }
                    }

                    //回头用户事件
                    List<MFStatEvent> returnUser = MFStatEvent.getEvents(dbManager,
                            MFStatEvent.EVENT_RETURN_USER, null, date, false);
                    if(returnUser != null && returnUser.size() > 0) {
                        dateEvent.put("returned", 1);
                        for(MFStatEvent returnEvent : returnUser) {
                            eventIds.add(returnEvent.getId());
                        }
                    }

                    //启动事件
                    List<MFStatEvent> openEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_OPEN, null, date, false);
                    if(openEvents != null && openEvents.size() > 0) {
                        JSONObject openJson = new JSONObject();
                        Map<Integer, Integer> hourData = new HashMap<Integer, Integer>();
                        for(MFStatEvent openEvent : openEvents) {
                            int hourCount = 0;
                            if(hourData.containsKey(openEvent.getHour())) {
                                hourCount = hourData.get(openEvent.getHour());
                            }
                            hourData.put(openEvent.getHour(), hourCount + 1);
                            eventIds.add(openEvent.getId());
                        }
                        Iterator<Integer> iter = hourData.keySet().iterator();
                        while(iter.hasNext()) {
                            Integer key = iter.next();
                            openJson.put(Integer.toString(key), hourData.get(key));
                        }
                        dateEvent.put("open", openJson);
                        //本日首次发送
                        List<MFStatEvent> sentOpenEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_OPEN, null, date, true);
                        if(sentOpenEvents == null || sentOpenEvents.size() == 0) {
                            dateEvent.put("daily_first", 1);
                            //PUBLISH CHECK
                            /*AsyncHttpClient.getHttpClientInstance().post("http://count.pcauto.com.cn/count.php?channel=7267",
                            		new AsyncHttpResponseHandler(){
                        		@Override
                        		public void onSuccess(int statusCode, String content) {
                        			 Log.v("CountUtils", "Send count request success: " + 7267);
                        		}
                        		
                        		@Override
                        		public void onFailure(Throwable error, String content) {
                        			 Log.v("CountUtils", "error: " + error.getMessage());
                        			 Log.v("CountUtils", "content: " + content);
                        			 Log.v("CountUtils", "Send count request fail: " + 7267);
                        		}
                        	});*/
                        }

                    }

                    //关闭应用事件
                    List<MFStatEvent> closeEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_COLSE, null, date, false);
                    if(closeEvents != null && closeEvents.size() > 0) {
                        JSONArray close = new JSONArray();
                        for(MFStatEvent closeEvent : closeEvents) {
                            close.put(Math.round(closeEvent.getDuration()/1000.0));
                            eventIds.add(closeEvent.getId());
                        }
                        dateEvent.put("close", close);
                    }

                    //自定义事件
                    List<MFStatEvent> devEvents = MFStatEvent.getEvents(dbManager,
                            MFStatEvent.EVENT_DEVELOPER, null, date, false);
                    if(devEvents != null && devEvents.size() > 0) {
                        JSONObject devJson = new JSONObject();
                        Map<String, MFStatEvent> devDataMap = new HashMap<String, MFStatEvent>();
                        for(MFStatEvent devEvent : devEvents) {
                            MFStatEvent mapData = devDataMap.get(devEvent.getValue());
                            if(mapData == null) {
                                mapData = new MFStatEvent();
                                mapData.setValue(devEvent.getValue());
                            }
                            mapData.setCount(mapData.getCount() + devEvent.getCount());
                            if(devEvent.isFirst()) {
                                mapData.setFirst(true);
                            }
                            devDataMap.put(devEvent.getValue(), mapData);
                            eventIds.add(devEvent.getId());
                        }
                        Iterator<String> iter = devDataMap.keySet().iterator();
                        while(iter.hasNext()) {
                            String key = iter.next();
                            JSONArray devJsonValue = new JSONArray();
                            MFStatEvent mapData = devDataMap.get(key);
                            devJsonValue.put(mapData.getCount()).put(mapData.isFirst() ? 1 : 0);
                            devJson.put(key, devJsonValue);
                        }
                        dateEvent.put("event", devJson);
                    }

                    data.put(Integer.toString(date), dateEvent);
                }
                json.put("data", data);
            }

            //设备更新信息
            List<MFStatEvent> updateEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_UPDATE, null, 0, false);
            if((updateEvents != null && updateEvents.size() > 0)) {
            	isSendData = true;
                JSONArray update = new JSONArray();
                boolean existAppVersionUpdate = false;
                for(MFStatEvent updateEvent : updateEvents) {
                    if(MFStatInfo.KEY_APP_VERSION.equals(updateEvent.getValue())) {
                        existAppVersionUpdate = true;
                    }
                    update.put(updateEvent.getValue());
                    eventIds.add(updateEvent.getId());
                }
                if(appVersionUpdate && !existAppVersionUpdate) {
                    update.put(MFStatInfo.KEY_APP_VERSION);
                }
                json.put("update", update);
            }

            if(includePath) {
                //访问节点和路径信息
                List<MFStatAccessPath.Node> accessNodes = MFStatAccessPath.getAccessNodes();
                //路径和节点数据
                List<MFStatEvent> pathEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_ACCESS_PATH, null, 0, false);
                List<MFStatEvent> nodeEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_ACCESS_NODE, null, 0, false);
                if((accessNodes != null && accessNodes.size() > 0) ||(pathEvents != null && pathEvents.size() > 0)
                        ||(nodeEvents != null && nodeEvents.size() > 0)) {
                    //生成访问节点和路径的信息map
                    Map<String, Integer> pathMap = new HashMap<String, Integer>();
                    Map<String, MFStatAccessPath.Node> nodeMap = new HashMap<String, MFStatAccessPath.Node>();
                    if(accessNodes!=null && accessNodes.size()>0){
                        for(int i=0; i<accessNodes.size(); i++) {
                            MFStatAccessPath.Node accessNode = accessNodes.get(i);
                            if(accessNode.getActivity() != null) {
                                MFStatAccessPath.Node mapNode = nodeMap.get(accessNode.getActivity());
                                if(mapNode != null) {
                                    mapNode.incCount();
                                    mapNode.setDuration(mapNode.getDuration() + accessNode.getDuration());
                                } else {
                                    mapNode = new MFStatAccessPath.Node();
                                    mapNode.setActivity(accessNode.getActivity());
                                    mapNode.setCount(1);
                                    mapNode.setDuration(accessNode.getDuration());
                                }

                                String accessPath = null;
                                if((i > 0 && accessNodes.get(i-1).getActivity() == null) || i == 0) {
                                    accessPath = ">" + mapNode.getActivity();
                                } else {
                                    accessPath = accessNodes.get(i-1).getActivity() + ">" + mapNode.getActivity();
                                }
                                int pathCount = 1;
                                if(pathMap.containsKey(accessPath)) {
                                    pathCount += pathMap.get(accessPath);
                                }
                                pathMap.put(accessPath, pathCount);
                                if((i < accessNodes.size() - 1 && accessNodes.get(i+1).getActivity() == null)
                                        || i == accessNodes.size() - 1) {
                                    mapNode.incExit();
                                    accessPath = mapNode.getActivity() + ">";
                                    pathCount = 1;
                                    if(pathMap.containsKey(accessPath)) {
                                        pathCount += pathMap.get(accessPath);
                                    }
                                    pathMap.put(accessPath, pathCount);
                                }

                                nodeMap.put(mapNode.getActivity(), mapNode);
                            }
                        }
                    }

                    //合并访问路径事件数据
                    if(pathEvents != null && pathEvents.size() > 0) {
                        for(MFStatEvent pathEvent : pathEvents) {
                            if(pathMap.containsKey(pathEvent.getValue())) {
                                pathMap.put(pathEvent.getValue(),
                                        pathMap.get(pathEvent.getValue()) + pathEvent.getCount());
                            } else {
                                pathMap.put(pathEvent.getValue(), pathEvent.getCount());
                            }
                        }
                    }

                    //合并访问节点事件数据
                    if(nodeEvents != null && nodeEvents.size() > 0) {
                        for(MFStatEvent nodeEvent : nodeEvents) {
                            MFStatAccessPath.Node mapNode = nodeMap.get(nodeEvent.getValue());
                            if(mapNode != null) {
                                mapNode.setCount(mapNode.getCount() + nodeEvent.getCount());
                                mapNode.setExit(mapNode.getExit() + nodeEvent.getExit());
                                mapNode.setDuration(mapNode.getDuration() + nodeEvent.getDuration());
                                nodeMap.put(nodeEvent.getValue(), mapNode);
                            } else {
                                mapNode = new MFStatAccessPath.Node();
                                mapNode.setActivity(nodeEvent.getValue());
                                mapNode.setCount(nodeEvent.getCount());
                                mapNode.setExit(nodeEvent.getExit());
                                mapNode.setDuration(nodeEvent.getDuration());
                                nodeMap.put(nodeEvent.getValue(), mapNode);
                            }
                        }
                    }

                    //清理访问路径事件数据
                    MFStatInfo.putString(MFStatInfo.KEY_USER_ACCESS_PATH, "");
                    MFStatEvent.clearAccessPath(dbManager);

                    //生成路径json数据，并重新添加访问路径事件数据
                    if(pathMap.size() > 0) {
                        isSendData = true;
                        JSONObject paths = new JSONObject();
                        Iterator<String> pathKeys = pathMap.keySet().iterator();
                        while(pathKeys.hasNext()) {
                            String pathKey = pathKeys.next();
                            paths.put(pathKey.substring(pathKey.lastIndexOf(".")+1), pathMap.get(pathKey));
                            MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_ACCESS_PATH, intTime[0], intTime[1],
                                    pathKey, pathMap.get(pathKey), 0, false, resumeTime);
                        }
                        json.put("path", paths);
                    }

                    //生成访问节点信息，并重新添加访问节点事件数据
                    if(nodeMap.size() > 0) {
                        isSendData = true;
                        JSONObject pages = new JSONObject();
                        Iterator<String> pageKeys = nodeMap.keySet().iterator();
                        while(pageKeys.hasNext()) {
                            String pageKey = pageKeys.next();
                            MFStatAccessPath.Node node = nodeMap.get(pageKey);
                            JSONArray pageInfo = new JSONArray();
                            pageInfo.put(node.getCount());
                            pageInfo.put(node.getExit());
                            pageInfo.put(Math.round(node.getDuration()/1000.0));
                            pages.put(pageKey.substring(pageKey.lastIndexOf(".")+1), pageInfo);
                            MFStatEvent.addEvent(dbManager, MFStatEvent.EVENT_ACCESS_NODE, intTime[0], intTime[1],
                                    pageKey, node.getCount(), node.getExit(), node.getDuration(), false, resumeTime);
                        }
                        json.put("page", pages);
                    }
                    
                    if(netspeedData!=null){
                        json.put("network", netspeedData.getJsonArray());
                    }
                }
            }

            //统计Crash异常数据
            List<MFStatEvent> crashEvents = MFStatEvent.getEvents(dbManager, MFStatEvent.EVENT_CRASH, null, 0, false);
            Map<String, CrashData> crashMap = new HashMap<String, CrashData>();
            if(crashEvents != null && crashEvents.size() > 0) {
                for(MFStatEvent event : crashEvents) {
                    if(Mofang.DEBUG) {
                        Log.d(LOG_TAG, "[generateSendData]crash: " + event.getValue());
                    }
                    JSONObject exceptionJson = new JSONObject(event.getValue());
                    String exceptionName = exceptionJson.optString("name");
                    String exceptionStack = exceptionJson.optString("stack");
//                        String[] crashInfo = event.getValue().split("\\\\|\\\\");
                    //计算异常stack md5
                    MessageDigest md5Encoder= MessageDigest.getInstance("MD5");
                    byte[] md5Bytes = md5Encoder.digest(exceptionStack.getBytes("utf-8"));
                    StringBuilder md5Hex = new StringBuilder();
                    for(byte b : md5Bytes) {
                        md5Hex.append(Integer.toHexString(0xFF & b));
                    }
                    String md5 = md5Hex.toString().toLowerCase();
                    //合并统计Crash异常
                    CrashData crashData = crashMap.get(md5);
                    if(crashData == null) {
                        crashData = new CrashData();
                        crashData.setName(exceptionName);
                        crashData.setStack(exceptionStack);
                    }
                    crashData.addTime(event.getTime());
                    crashMap.put(md5, crashData);
                    eventIds.add(event.getId());
                }
            }
            //生成Crash信息Json
            if(crashMap.size() > 0) {
            	isSendData = true;
                JSONObject crash = new JSONObject();
                Iterator<String> crashMd5s = crashMap.keySet().iterator();
                while(crashMd5s.hasNext()) {
                    String md5 = crashMd5s.next();
                    CrashData crashData = crashMap.get(md5);
                    JSONObject crashObject = new JSONObject();
                    crashObject.put("name", crashData.getName());
                    crashObject.put("stack", crashData.getStack());
                    JSONArray timeArray = new JSONArray();
                    for(long crashTime : crashData.getTimeList()) {
                        timeArray.put(crashTime);
                    }
                    crashObject.put("time", timeArray);
                    crash.put(md5, crashObject);
                }
                json.put("crash", crash);
            }

            //收到推送信息事件
            List<MFStatEvent> notificationReciveEvents = MFStatEvent.getEvents(
                    dbManager, MFStatEvent.EVENT_NOTIFICATION_RECEIVE, null, 0, false);
            if(notificationReciveEvents != null && notificationReciveEvents.size() > 0) {
            	isSendData = true;
                JSONArray pushReceive = new JSONArray();
                Map<String, String> pushReceiveMap = new HashMap<String, String>();
                for(MFStatEvent notificationEvent : notificationReciveEvents) {
                    if(!pushReceiveMap.containsKey(notificationEvent.getValue()))  {
                        pushReceive.put(notificationEvent.getValue());
                        pushReceiveMap.put(notificationEvent.getValue(), notificationEvent.getValue());
                        eventIds.add(notificationEvent.getId());
                    }
                }
                json.put("push_recv", pushReceive);
            }

            //打开推送信息事件
            List<MFStatEvent> notificationOpenEvents = MFStatEvent.getEvents(
                    dbManager, MFStatEvent.EVENT_NOTIFICATION_OPEN, null, 0, false);
            if(notificationOpenEvents != null && notificationOpenEvents.size() > 0) {
            	isSendData = true;
                JSONArray pushOpen = new JSONArray();
                Map<String, String> pushOpenMap = new HashMap<String, String>();
                for(MFStatEvent notificationEvent : notificationOpenEvents) {
                    if(!pushOpenMap.containsKey(notificationEvent.getValue())){
                        pushOpen.put(notificationEvent.getValue());
                        pushOpenMap.put(notificationEvent.getValue(), notificationEvent.getValue());
                        eventIds.add(notificationEvent.getId());
                    }
                }
                json.put("push_open", pushOpen);
            }

            if(Mofang.DEBUG) {
                Log.d(LOG_TAG, "[generateSendData]json: " + json.toString());
            }

            LogUtils.writeLog("检测是否发送数据: "+isSendData);
            if(isSendData){
                SendData sendData = new SendData();
                sendData.setJson(json);
                sendData.setIdList(eventIds);
                sendData.setNetspeedData(netspeedData);
                LogUtils.writeLog("需要发送数据: "+sendData);
                if(DEBUG) {
                    Log.i(LOG_TAG, "[generateSendData]data = " + sendData.toString());
                    LogUtils.writeLog("[generateSendData]data =  " + sendData.toString());
                }
                return sendData;
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "[generateSendData]JSONException");
            if(isDebug()) {
                e.printStackTrace();
            }
        } catch (NoSuchAlgorithmException e) {
            Log.e(LOG_TAG, "[generateSendData]NoSuchAlgorithmException");
            if(isDebug()) {
                e.printStackTrace();
            }
        } catch (UnsupportedEncodingException e) {
            Log.e(LOG_TAG, "[generateSendData]UnsupportedEncodingException");
            if(isDebug()) {
                e.printStackTrace();
            }
        }

        return null;
    }

    //根据时间计算日期和小时数据
    private static int[] getDateAndHour(long time) {
        Date today = new Date(time);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat hourFormat = new SimpleDateFormat("H");
        return new int[]{Integer.parseInt(dateFormat.format(today)), Integer.parseInt(hourFormat.format(today))};
    }

    private static class SendData {
        private JSONObject json;
        private List<Integer> idList;
        private NetspeedData netspeedData;

        public JSONObject getJson() {
            return json;
        }

        public void setJson(JSONObject json) {
            this.json = json;
        }

        public List<Integer> getIdList() {
            return idList;
        }

        public void setIdList(List<Integer> idList) {
            this.idList = idList;
        }

        public NetspeedData getNetspeedData() {
            return netspeedData;
        }

        public void setNetspeedData(NetspeedData netspeedData) {
            this.netspeedData = netspeedData;
        }
        
    }

    private static class CrashData {
        private String name;
        private String stack;
        private List<Long> timeList;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getStack() {
            return stack;
        }

        public void setStack(String stack) {
            this.stack = stack;
        }

        public List<Long> getTimeList() {
            return timeList;
        }

        public synchronized void addTime(long time) {
            if(timeList == null) {
                timeList = new ArrayList<Long>();
            }
            timeList.add(Math.round(time/1000.0));
        }
    }

    public static void main(String[] args) {
        String accessPath = "";
        System.out.println("[updateAccessDuration] id = " + 719155321  + ", accessPath = " + accessPath);
        String str2 = ";" + 719155321 + ",";
        System.out.println("str2 = " + str2);
        String[] str1And3456 = accessPath.split(str2);
        System.out.println("str1And3456.length = " + str1And3456.length);
        System.out.println("str1And3456[0] = " + str1And3456[0]);
        if(str1And3456.length == 1) {
            str2 = 719155321 + ",";
            str1And3456 = new String[2];
            str1And3456[0] = "";
            str1And3456[1] = accessPath.substring(accessPath.indexOf(",") + 1);
        }
        System.out.println("str1And3456[1] = " + str1And3456[1]);
        String str1 = str1And3456[0];
        System.out.println("str1 = " + str1);
        System.out.println("str2 = " + str2);
        String str3 = str1And3456[1].substring(0, str1And3456[1].indexOf(","));
        System.out.println("str3 = " + str3);
        String str4 = ",";
        System.out.println("str4 = " + str4);
        String str56 = str1And3456[1].substring(str1And3456[1].indexOf(",") + 1);
        String str5 = Long.toString(555);
        System.out.println("str5 = " + str5);
        String str6 = "";
        if(str56.indexOf(";") > 0) {
            str6 = str56.substring(str56.indexOf(";"));
        }
        System.out.println("str6 = " + str6);
        accessPath = str1 + str2 + str3 + str4 + str5 + str6;
        System.out.println("accessPath = " + accessPath);
    }
}
