/*
 * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.micode.notes.gtask.remote;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import net.micode.notes.gtask.data.Node;
import net.micode.notes.gtask.data.Task;
import net.micode.notes.gtask.data.TaskList;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.gtask.exception.NetworkFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.ui.NotesPreferenceActivity;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

//标明了这个类的名字
public class GTaskClient {
    private static final String TAG = GTaskClient.class.getSimpleName(); //私有化一个用于日志输出的标签常量

    private static final String GTASK_URL = "https://mail.google.com/tasks/"; //私有化Google Tasks 的基本 URL 地址

    private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";//私有化获取任务的 URL 地址

    private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";//私有化提交任务的 URL 地址

    private static GTaskClient mInstance = null; //mInstance 是 GTaskClient 类的单例实例

    private DefaultHttpClient mHttpClient;//mHttpClient 是一个 DefaultHttpClient 对象，用于发送 HTTP 请求

    private String mGetUrl; //mGetUrl 和 mPostUrl 是用于存储获取任务和提交任务的 URL 地址

    private String mPostUrl;//mGetUrl 和 mPostUrl 是用于存储获取任务和提交任务的 URL 地址

    private long mClientVersion;//私有化客户端版本的长整型变量

    private boolean mLoggedin;//表示是否已登录的布尔型变量

    private long mLastLoginTime;//上次登录时间的长整型变量

    private int mActionId;//表示当前操作的整型变量

    private Account mAccount;//一个 Account 对象，用于存储用户账号信息

    private JSONArray mUpdateArray;//一个 JSONArray 对象，用于存储任务更新信息


    //GTaskClient 类的一个私有构造方法，使用 private 关键字修饰，表示只能在类内部调用
    private GTaskClient() {
        mHttpClient = null;     //初始化为null
        mGetUrl = GTASK_GET_URL;
        mPostUrl = GTASK_POST_URL;
        mClientVersion = -1;
        mLoggedin = false;
        mLastLoginTime = 0;
        mActionId = 1;
        mAccount = null;
        mUpdateArray = null;
    }

    //用来获取的实例化对象
    public static synchronized GTaskClient getInstance() {  //使用 public 关键字修饰，表示可以从任何地方访问
        if (mInstance == null) { //首先判断 mInstance 是否为 null，即判断是否已经存在单例实例
            mInstance = new GTaskClient();//如果 mInstance 为 null，则创建一个新的 GTaskClient 实例，并赋值给 mInstance
        }
        return mInstance;   //返回mInstance这个实例化对象
    }

    //用来实现登录操作的函数，传入的参数是一个Activity
    public boolean login(Activity activity) {
        // we suppose that the cookie would expire after 5 minutes
        // then we need to re-login
        // 设置登录操作限制时间,如果超时则需要重新登录
        final long interval = 1000 * 60 * 5;  // 判断距离最后一次登录操作是否超过5分钟
        if (mLastLoginTime + interval < System.currentTimeMillis()) {  // 判断上次登录时间加上限制时间是否小于当前系统时间
            mLoggedin = false;  // 如果超时了，设置登录状态为未登录
        }

        // need to re-login after account switch
        //重新登录操作
        if (mLoggedin && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity.getSyncAccountName(activity))) {  // 如果已经登录且同步账户名称发生变化
            mLoggedin = false;  // 设置登录状态为未登录
        }

        //如果没超过时间，则不需要重新登录
        if (mLoggedin) {  // 如果已经登录
            Log.d(TAG, "already logged in");  // 打印日志，表示已经登录
            return true;  // 返回已经登录的状态
        }

        mLastLoginTime = System.currentTimeMillis();  // 更新最后登录时间为当前系统时间
        String authToken = loginGoogleAccount(activity, false);  // 尝试使用谷歌账户登录，获取授权令牌
        if (authToken == null) {  // 如果获取的授权令牌为空
            Log.e(TAG, "login google account failed");  // 打印错误日志，表示谷歌账户登录失败
            return false;  // 返回登录失败的状态
        }

        // login with custom domain if necessary
        //尝试使用用户自己的域名登录
        if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase().endsWith("googlemail.com"))) {  // 如果用户账户不是以gmail.com或googlemail.com结尾
            StringBuilder url = new StringBuilder(GTASK_URL).append("a/");  // 构建自定义域名的URL
            int index = mAccount.name.indexOf('@') + 1;  // 获取@符号后的索引位置
            String suffix = mAccount.name.substring(index);  // 获取@符号后的字符串作为域名后缀
            url.append(suffix + "/");  // 拼接域名后缀到URL
            mGetUrl = url.toString() + "ig";  // 设置用户对应的getUrl
            mPostUrl = url.toString() + "r/ig";  // 设置用户对应的postUrl

            if (tryToLoginGtask(activity, authToken)) {  // 尝试使用自定义域名登录
                mLoggedin = true;  // 设置登录状态为已登录
            }
        }

        // try to login with google official URL
        //如果用户账户无法登录，则使用谷歌官方的URI进行登录
        if (!mLoggedin) {  // 如果之前的登录尝试未成功
            mGetUrl = GTASK_GET_URL;  // 设置使用谷歌官方URL进行get请求
            mPostUrl = GTASK_POST_URL;  // 设置使用谷歌官方URL进行post请求
            if (!tryToLoginGtask(activity, authToken)) {  // 尝试使用谷歌官方的URL进行登录
                return false;  // 如果登录失败，返回登录失败状态
            }
        }

        mLoggedin = true;  // 设置登录状态为已登录
        return true;  // 返回登录成功的状态
    }


    //具体实现登录谷歌账户的方法
    private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
        String authToken;  // 定义一个用于存储认证令牌的变量

        AccountManager accountManager = AccountManager.get(activity);  // 获取账户管理器实例，用于管理用户账户信息

        Account[] accounts = accountManager.getAccountsByType("com.google");  // 获取所有类型为"com.google"的账户列表

        if (accounts.length == 0) {  // 如果没有找到Google账户
            Log.e(TAG, "there is no available google account");  // 记录错误日志，表示没有可用的Google账户
            return null;  // 返回空值
        }

        String accountName = NotesPreferenceActivity.getSyncAccountName(activity);  // 获取同步账户的名称

        Account account = null;
        for (Account a : accounts) {  // 遍历查找已记录的账户信息
            if (a.name.equals(accountName)) {  // 如果找到了同名的账户
                account = a;  // 将找到的账户赋给account变量
                break;  // 跳出循环
            }
        }
        if (account != null) {  // 如果找到了匹配的账户
            mAccount = account;  // 将匹配的账户信息存储在mAccount中
        } else {
            Log.e(TAG, "unable to get an account with the same name in the settings");  // 记录错误日志，表示无法获取相同名称的账户
            return null;  // 返回空值
        }

        // get the token now
        // 获取认证令牌
        AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null);  // 异步获取指定账户的认证令牌
        try {
            Bundle authTokenBundle = accountManagerFuture.getResult();  // 获取异步操作的结果
            authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);  // 从结果中获取认证令牌

            // 如果需要废除认证令牌
            if (invalidateToken) {
                accountManager.invalidateAuthToken("com.google", authToken);  // 废除认证令牌
                loginGoogleAccount(activity, false);  // 重新调用登录方法
            }
        } catch (Exception e) {
            Log.e(TAG, "get auth token failed");  // 记录获取认证令牌失败的错误日志
            authToken = null;  // 将认证令牌置为空
        }

        return authToken;  // 返回获取到的认证令牌
    }


    //尝试登陆Gtask，这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法
    private boolean tryToLoginGtask(Activity activity, String authToken) {
        if (!loginGtask(authToken)) {
            // maybe the auth token is out of date, now let's invalidate the
            // token and try again
            //删除过一个无效的authToken，申请一个新的后再次尝试登陆
            authToken = loginGoogleAccount(activity, true);
            if (authToken == null) {
                Log.e(TAG, "login google account failed");
                return false;
            }

            if (!loginGtask(authToken)) {
                Log.e(TAG, "login gtask failed");
                return false;
            }
        }
        return true;
    }

    //实现登录GTask的具体操作
    private boolean loginGtask(String authToken) {
        int timeoutConnection = 10000;
        int timeoutSocket = 15000;  //socket是一种通信连接实现数据的交换的端口
        HttpParams httpParameters = new BasicHttpParams();  //实例化一个新的HTTP参数类
        HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);   //设置连接超时时间
        HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);   //设置设置端口超时时间
        mHttpClient = new DefaultHttpClient(httpParameters);
        BasicCookieStore localBasicCookieStore = new BasicCookieStore();    //设置本地cookie
        mHttpClient.setCookieStore(localBasicCookieStore);
        HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);

        // login gtask
        try {
            String loginUrl = mGetUrl + "?auth=" + authToken;   //设置登录的url
            HttpGet httpGet = new HttpGet(loginUrl);    //通过登录的uri实例化网页上资源的查找
            HttpResponse response = null;
            response = mHttpClient.execute(httpGet);

            //获取CookieStore里存放的cookie
            // get the cookie now
            List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();
            boolean hasAuthCookie = false;
            for (Cookie cookie : cookies) { //看如果存有“GTL”，则说明有验证成功的有效的cookie
                if (cookie.getName().contains("GTL")) {
                    hasAuthCookie = true;
                }
            }
            if (!hasAuthCookie) {
                Log.w(TAG, "it seems that there is no auth cookie");
            }

            // get the client version
            //获取client的内容
            String resString = getResponseContent(response.getEntity());
            String jsBegin = "_setup(";
            String jsEnd = ")}</script>";
            int begin = resString.indexOf(jsBegin);
            int end = resString.lastIndexOf(jsEnd);
            String jsString = null;
            if (begin != -1 && end != -1 && begin < end) {  //if循环用来在返回的Content中截取从_setup(开始到)}</script>中间的字符串内容，也就是gtask_url的内容
                jsString = resString.substring(begin + jsBegin.length(), end);
            }
            JSONObject js = new JSONObject(jsString);
            mClientVersion = js.getLong("v");
        } catch (JSONException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            return false;
        } catch (Exception e) {
            // simply catch all exceptions
            Log.e(TAG, "httpget gtask_url failed");
            return false;
        }

        return true;
    }

    private int getActionId() {
        return mActionId++;
    }

    //实例化创建一个用于向网络传输数据的对象
    private HttpPost createHttpPost() {
        HttpPost httpPost = new HttpPost(mPostUrl);
        httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        httpPost.setHeader("AT", "1");
        return httpPost;    //返回一个空的httpPost实例化对象
    }

    //通过URL获取响应后返回的数据
    private String getResponseContent(HttpEntity entity) throws IOException {
        String contentEncoding = null;
        if (entity.getContentEncoding() != null) { //使用getContentEncoding()获取网络上的资源和数据
            contentEncoding = entity.getContentEncoding().getValue();
            Log.d(TAG, "encoding: " + contentEncoding);
        }

        InputStream input = entity.getContent();
        if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {  //GZIP是使用DEFLATE进行压缩数据的另一个压缩库
            input = new GZIPInputStream(entity.getContent());
        } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {    //DEFLATE是一个无专利的压缩算法，它可以实现无损数据压缩
            Inflater inflater = new Inflater(true);
            input = new InflaterInputStream(entity.getContent(), inflater);
        }

        try {
            InputStreamReader isr = new InputStreamReader(input);
            BufferedReader br = new BufferedReader(isr);    //是一个包装类，它可以包装字符流，将字符流放入缓存里，先把字符读到缓存里，到缓存满了时候，再读入内存，是为了提供读的效率而设计的
            StringBuilder sb = new StringBuilder();

            while (true) {
                String buff = br.readLine();
                if (buff == null) {
                    return sb.toString();
                }
                sb = sb.append(buff);
            }
        } finally {
            input.close();
        }
    }

    //通过JSON发送请求
    //请求的具体内容在json的实例化对象js中然后传入
    private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
        if (!mLoggedin) {
            Log.e(TAG, "please login first");
            throw new ActionFailureException("not logged in");
        }

        //实例化一个httpPost的对象用来向服务器传输数据，在这里就是发送请求，而请求的内容在js里
        HttpPost httpPost = createHttpPost();
        try {
            LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();
            list.add(new BasicNameValuePair("r", js.toString()));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
            httpPost.setEntity(entity);

            // execute the post
            //执行这个请求
            HttpResponse response = mHttpClient.execute(httpPost);
            String jsString = getResponseContent(response.getEntity());
            return new JSONObject(jsString);

        } catch (ClientProtocolException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new NetworkFailureException("postRequest failed");
        } catch (IOException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new NetworkFailureException("postRequest failed");
        } catch (JSONException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new ActionFailureException("unable to convert response content to jsonobject");
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new ActionFailureException("error occurs when posting request");
        }
    }

    //创建单个任务
    //传入参数是一个.gtask.data.Task包里Task类的对象
    public void createTask(Task task) throws NetworkFailureException {
        commitUpdate();
        try {

            JSONObject jsPost = new JSONObject();//利用json获取Task里的内容,并且创建相应的jsPost
            JSONArray actionList = new JSONArray();

            // action_list
            actionList.put(task.getCreateAction(getActionId()));
            jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);

            // client_version
            jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);

            // post
            JSONObject jsResponse = postRequest(jsPost);
            JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
                    GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
            task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); //使用task.setGid设置task的new_ID

        } catch (JSONException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new ActionFailureException("create task: handing jsonobject failed");
        }
    }

    //创建一个任务列表
    public void createTaskList(TaskList tasklist) throws NetworkFailureException {
        commitUpdate();
        try {
            JSONObject jsPost = new JSONObject();
            JSONArray actionList = new JSONArray();

            // action_list
            actionList.put(tasklist.getCreateAction(getActionId()));
            jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);

            // client version
            jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);

            // post
            JSONObject jsResponse = postRequest(jsPost);
            JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
                    GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
            tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));

        } catch (JSONException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new ActionFailureException("create tasklist: handing jsonobject failed");
        }
    }

    //同步更新操作
    public void commitUpdate() throws NetworkFailureException {
        if (mUpdateArray != null) {
            try {
                JSONObject jsPost = new JSONObject();   //使用JSONObject进行数据存储

                // action_list
                jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);  //使用jsPost.put，Put的信息包括UpdateArray和ClientVersion

                // client_version
                jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);

                postRequest(jsPost);    //使用postRequest发送这个jspost,进行处理
                mUpdateArray = null;
            } catch (JSONException e) {
                Log.e(TAG, e.toString());
                e.printStackTrace();
                throw new ActionFailureException("commit update: handing jsonobject failed");
            }
        }
    }

    //添加更新的事项
    public void addUpdateNode(Node node) throws NetworkFailureException {
        if (node != null) {
            // too many update items may result in an error
            // set max to 10 items
            if (mUpdateArray != null && mUpdateArray.length() > 10) {
                commitUpdate();     //调用commitUpdate()来提交更新
            }

            if (mUpdateArray == null)
                mUpdateArray = new JSONArray();
            mUpdateArray.put(node.getUpdateAction(getActionId()));
        }
    }

    //用来移动任务，它通过构建 JSON 对象和发送 POST 请求来实现任务的移动操作
    public void moveTask(Task task, TaskList preParent, TaskList curParent)
            throws NetworkFailureException {
        commitUpdate();
        try {
            JSONObject jsPost = new JSONObject();
            JSONArray actionList = new JSONArray();
            JSONObject action = new JSONObject();

            // action_list
            //type——移动类型，ID——操作的 ID，GTASK_JSON_ID——要移动的任务的 ID
            //SOURCE_LIST——要移动任务的原始父任务列表的 ID，DEST_PARENT——要移动任务的新父任务列表的 ID
            action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
                    GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
            action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
            action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
            if (preParent == curParent && task.getPriorSibling() != null) {
                // put prioring_sibing_id only if moving within the tasklist and
                // it is not the first one
                //设置优先级ID，只有当移动是发生在文件中
                action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
            }
            action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());//设置移动前所属列表
            action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());//设置当前所属列表
            if (preParent != curParent) {
                // put the dest_list only if moving between tasklists
                action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
            }
            actionList.put(action);
            //最后将ACTION_LIST加入到jsPost中
            jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);

            // client_version
            jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);

            postRequest(jsPost);

        } catch (JSONException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new ActionFailureException("move task: handing jsonobject failed");
        }
    }

    //用来删除节点，它通过构建 JSON 对象和发送 POST 请求来实现节点的删除操作
    public void deleteNode(Node node) throws NetworkFailureException {
        commitUpdate();  // 提交更新操作

        try {
            JSONObject jsPost = new JSONObject();  // 创建一个新的JSON对象，用于存储POST请求的参数
            JSONArray actionList = new JSONArray();  // 创建一个新的JSON数组，用于存储操作列表

            // action_list
            node.setDeleted(true);  // 标志该节点已被删除
            actionList.put(node.getUpdateAction(getActionId()));  // 将删除操作的ID加入到操作列表中
            jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);  // 将操作列表加入到POST请求参数中

            // client_version
            jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);  // 将客户端版本号加入到POST请求参数中

            postRequest(jsPost);  // 发送POST请求
            mUpdateArray = null;  // 将更新数组置为空
        } catch (JSONException e) {  // 捕获JSON异常
            Log.e(TAG, e.toString());  // 记录错误日志
            e.printStackTrace();
            throw new ActionFailureException("delete node: handing jsonobject failed");  // 抛出操作失败异常
        }
    }


    //获取任务列表
    public JSONArray getTaskLists() throws NetworkFailureException {
        if (!mLoggedin) {  // 如果未登录
            Log.e(TAG, "please login first");  // 记录错误日志
            throw new ActionFailureException("not logged in");  // 抛出操作失败异常
        }

        try {
            HttpGet httpGet = new HttpGet(mGetUrl);  // 创建一个HTTP GET请求对象
            HttpResponse response = null;  // 定义一个HTTP响应对象

            response = mHttpClient.execute(httpGet);  // 执行HTTP GET请求，并将响应存储在response对象中

            // get the task list
            String resString = getResponseContent(response.getEntity());  // 从响应实体中获取响应内容
            String jsBegin = "_setup(";  // 定义JS脚本开始标记
            String jsEnd = ")}</script>";  // 定义JS脚本结束标记
            int begin = resString.indexOf(jsBegin);  // 查找JS脚本开始标记的位置
            int end = resString.lastIndexOf(jsEnd);  // 查找JS脚本结束标记的位置
            String jsString = null;

            // 如果找到了JS脚本开始和结束标记
            if (begin != -1 && end != -1 && begin < end) {
                jsString = resString.substring(begin + jsBegin.length(), end);  // 截取JS脚本字符串
            }

            JSONObject js = new JSONObject(jsString);  // 创建一个新的JSON对象，用于解析JS脚本字符串
            return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);  // 返回解析结果中的任务列表信息
        } catch (ClientProtocolException e) {  // 捕获客户端协议异常
            Log.e(TAG, e.toString());  // 记录错误日志
            e.printStackTrace();
            throw new NetworkFailureException("gettasklists: httpget failed");  // 抛出网络操作失败异常
        } catch (IOException e) {  // 捕获IO异常
            Log.e(TAG, e.toString());  // 记录错误日志
            e.printStackTrace();
            throw new NetworkFailureException("gettasklists: httpget failed");  // 抛出网络操作失败异常
        } catch (JSONException e) {  // 捕获JSON异常
            Log.e(TAG, e.toString());  // 记录错误日志
            e.printStackTrace();
            throw new ActionFailureException("get task lists: handing jasonobject failed");  // 抛出操作失败异常
        }
    }


    //通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务
    public JSONArray getTaskList(String listGid) throws NetworkFailureException {
        commitUpdate();
        try {
            JSONObject jsPost = new JSONObject();//创建一个新的 JSONObject jsPost 用于存储 POST 请求的数据。
            JSONArray actionList = new JSONArray();//创建一个新的 JSONArray actionList 用于存列表。
            JSONObject action = new JSONObject();//创建一个新的 JSONObject action 用于表示单个操作。

            // action_list
            action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
                    GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
            action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());//这里设置为传入的listGid
            action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
            action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
            actionList.put(action);
            jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);

            // client_version
            jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);

            JSONObject jsResponse = postRequest(jsPost);
            return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
        } catch (JSONException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
            throw new ActionFailureException("get task list: handing jsonobject failed");
        }
    }

    //用于获取同步账户信息
    public Account getSyncAccount() {
        return mAccount;
    }

    //重置更新内容
    public void resetUpdateArray() {
        mUpdateArray = null;
    }
}
