public class SmsSingleSender extends SmsBase {

    private String url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms";

    public SmsSingleSender(int appid, String appkey) {
        super(appid, appkey, new DefaultHTTPClient());
    }

    public SmsSingleSender(int appid, String appkey, HTTPClient httpclient) {
        super(appid, appkey, httpclient);
    }

    /**
     * 普通单发
     *
     * 普通单发短信接口，明确指定内容，如果有多个签名，请在内容中以【】的方式添加到信息内容中，否则系统将使用默认签名
     *
     * @param type 短信类型，0 为普通短信，1 营销短信
     * @param nationCode 国家码，如 86 为中国
     * @param phoneNumber 不带国家码的手机号
     * @param msg 信息内容，必须与申请的模板格式一致，否则将返回错误
     * @param extend 扩展码，可填空
     * @param ext 服务端原样返回的参数，可填空
     * @return {@link}SmsSingleSenderResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsSingleSenderResult send(int type, String nationCode, String phoneNumber,
        String msg, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject()
            .put("tel", (new JSONObject()).put("nationcode", nationCode).put("mobile", phoneNumber))
            .put("type", type)
            .put("msg", msg)
            .put("sig", SmsSenderUtil.calculateSignature(this.appkey, random, now, phoneNumber))
            .put("time", now)
            .put("extend", SmsSenderUtil.isNotEmpty(extend) ? extend : "")
            .put("ext", SmsSenderUtil.isNotEmpty(ext) ? ext : "");

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 1000)
            .setBody(body.toString());

        // TODO Handle timeout exception
        try {
            // May throw IOException and URISyntaxexception
            HTTPResponse res = httpclient.fetch(req);

            // May throw HTTPException
            handleError(res);

            // May throw JSONException
            return (new SmsSingleSenderResult()).parseFromHTTPResponse(res);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }

    /**
     * 指定模板单发
     *
     * @param nationCode 国家码，如 86 为中国
     * @param phoneNumber 不带国家码的手机号
     * @param templateId 信息内容
     * @param params 模板参数列表，如模板 {1}...{2}...{3}，那么需要带三个参数
     * @param sign 签名，如果填空，系统会使用默认签名
     * @param extend 扩展码，可填空
     * @param ext 服务端原样返回的参数，可填空
     * @return {@link}SmsSingleSenderResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsSingleSenderResult sendWithParam(String nationCode, String phoneNumber, int templateId,
        ArrayList<String> params, String sign, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();

        JSONObject body = new JSONObject()
            .put("tel", (new JSONObject()).put("nationcode", nationCode).put("mobile", phoneNumber))
            .put("sig", SmsSenderUtil.calculateSignature(appkey, random, now, phoneNumber))
            .put("tpl_id", templateId)
            .put("params", params)
            .put("sign", sign)
            .put("time", now)
            .put("extend", SmsSenderUtil.isNotEmpty(extend) ? extend : "")
            .put("ext", SmsSenderUtil.isNotEmpty(ext) ? ext : "");

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 1000)
            .setBody(body.toString());

        try {
            // May throw IOException and URISyntaxexception
            HTTPResponse res = httpclient.fetch(req);

            // May throw HTTPException
            handleError(res);

            // May throw JSONException
            return (new SmsSingleSenderResult()).parseFromHTTPResponse(res);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }

    public SmsSingleSenderResult sendWithParam(String nationCode, String phoneNumber, int templateId,
        String[] params, String sign, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        return sendWithParam(nationCode, phoneNumber, templateId,
            new ArrayList<String>(Arrays.asList(params)), sign, extend, ext);
    }
} public class SmsSingleSenderResult extends SmsResultBase {

    public int result;
    public String errMsg;
    public String ext;
    public String sid;
    public int fee;

    public SmsSingleSenderResult() {
        this.errMsg = "";
        this.ext = "";
        this.sid = "";
        this.fee = 0;
    }

    @Override
    public SmsSingleSenderResult parseFromHTTPResponse(HTTPResponse response)
            throws JSONException {

        JSONObject json = parseToJson(response);

        result = json.getInt("result");
        errMsg = json.getString("errmsg");
        if (json.has("sid")) {
            sid = json.getString("sid");
        }
        if (json.has("fee")) {
            fee = json.getInt("fee");
        }
        if (json.has("ext")) {
            ext = json.getString("ext");
        }

        return this;
    }
} public class SmsMultiSender extends SmsBase {

    private String url = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2";

    public SmsMultiSender(int appid, String appkey) {
        super(appid, appkey, new DefaultHTTPClient());
    }

    public SmsMultiSender(int appid, String appkey, HTTPClient httpclient) {
        super(appid, appkey, httpclient);
    }

    /**
     * 普通群发
     *
     * 明确指定内容，如果有多个签名，请在内容中以【】的方式添加到信息内容中，否则系统将使用默认签名
     *
     * @param type 短信类型，0 为普通短信，1 营销短信
     * @param nationCode 国家码，如 86 为中国
     * @param phoneNumbers 不带国家码的手机号列表
     * @param msg 信息内容，必须与申请的模板格式一致，否则将返回错误
     * @param extend 扩展码，可填空
     * @param ext 服务端原样返回的参数，可填空
     * @return {@link}SmsMultiSenderResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsMultiSenderResult send(int type, String nationCode, ArrayList<String> phoneNumbers,
        String msg, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject();
        body.put("tel", toTel(nationCode, phoneNumbers))
            .put("type", type)
            .put("msg", msg)
            .put("sig", SmsSenderUtil.calculateSignature(appkey, random, now, phoneNumbers))
            .put("time", now)
            .put("extend", SmsSenderUtil.isNotEmpty(extend) ? extend : "")
            .put("ext", SmsSenderUtil.isNotEmpty(ext) ? ext : "");

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 1000)
            .setBody(body.toString());

        try {
            // May throw IOException and URISyntaxexception
            HTTPResponse res = httpclient.fetch(req);

            // May throw HTTPException
            handleError(res);

            // May throw JSONException
            return (new SmsMultiSenderResult()).parseFromHTTPResponse(res);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }

    public SmsMultiSenderResult send(int type, String nationCode, String[] phoneNumbers,
        String msg, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        return send(type, nationCode, new ArrayList<String>(Arrays.asList(phoneNumbers)),
                    msg, extend, ext);
    }

    /**
     * 指定模板群发
     *
     * @param nationCode 国家码，如 86 为中国
     * @param phoneNumbers 不带国家码的手机号列表
     * @param templateId 模板 id
     * @param params 模板参数列表
     * @param sign 签名，如果填空，系统会使用默认签名
     * @param extend 扩展码，可以填空
     * @param ext 服务端原样返回的参数，可以填空
     * @return {@link}SmsMultiSenderResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsMultiSenderResult sendWithParam(String nationCode, ArrayList<String> phoneNumbers,
        int templateId, ArrayList<String> params, String sign, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject()
            .put("tel", toTel(nationCode, phoneNumbers))
            .put("sign", sign)
            .put("tpl_id", templateId)
            .put("params", params)
            .put("sig", SmsSenderUtil.calculateSignature(appkey, random, now, phoneNumbers))
            .put("time", now)
            .put("extend", SmsSenderUtil.isNotEmpty(extend) ? extend : "")
            .put("ext", SmsSenderUtil.isNotEmpty(ext) ? ext : "");

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 1000)
            .setBody(body.toString());

        try {
            // May throw IOException and URISyntaxexception
            HTTPResponse res = httpclient.fetch(req);

            // May throw HTTPException
            handleError(res);

            // May throw JSONException
            return (new SmsMultiSenderResult()).parseFromHTTPResponse(res);
        } catch (URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }

    public SmsMultiSenderResult sendWithParam(String nationCode, String[] phoneNumbers,
        int templateId, String[] params, String sign, String extend, String ext)
            throws HTTPException, JSONException, IOException {

        return sendWithParam(nationCode, new ArrayList<String>(Arrays.asList(phoneNumbers)),
                             templateId, new ArrayList<String>(Arrays.asList(params)),
                             sign, extend, ext);
    }

    private ArrayList<JSONObject> toTel(String nationCode, ArrayList<String> phoneNumbers) {
        ArrayList<JSONObject> phones = new ArrayList<JSONObject>();
        for (String phoneNumber: phoneNumbers) {
            JSONObject phone = new JSONObject();
            phone.put("nationcode", nationCode);
            phone.put("mobile", phoneNumber);
            phones.add(phone);
        }
        return phones;
    }
} public class SmsMultiSenderResult extends SmsResultBase {

    public class Detail {

        public int result;
        public String errmsg = "";
        public String mobile = "";
        public String nationcode = "";
        public String sid = "";
        public int fee = 0;

        public String toString() {
            String[] fields = {"result", "errmsg", "mobile", "nationcode", "sid", "fee"};
            return (new JSONObject(this, fields)).toString();
        }

        public Detail parse(JSONObject json) throws JSONException {

            result = json.getInt("result");
            errmsg = json.getString("errmsg");

            if (json.has("mobile")) {
                mobile = json.getString("mobile");
            }
            if (json.has("nationcode")) {
                nationcode = json.getString("nationcode");
            }
            if (json.has("sid")) {
                sid = json.getString("sid");
            }
            if (json.has("fee")) {
                fee = json.getInt("fee");
            }

            return this;
        }
    }

    public int result;
    public String errMsg;
    public String ext;
    public ArrayList<Detail> details;

    public SmsMultiSenderResult() {
        this.errMsg = "";
        this.ext = "";
        this.details = new ArrayList<Detail>();
    }

    @Override
    public SmsMultiSenderResult parseFromHTTPResponse(HTTPResponse response)
            throws JSONException {

        JSONObject json = parseToJson(response);

        result = json.getInt("result");
        errMsg = json.getString("errmsg");

        if (json.has("ext")) {
            ext = json.getString("ext");
        }
        if (json.has("detail") && !json.isNull("detail")) {
            JSONArray jsonDetail = json.getJSONArray("detail");
            for (int i = 0; i < jsonDetail.length(); i++) {
                details.add((new Detail()).parse(jsonDetail.getJSONObject(i)));
            }
        }


        return this;
    }
} public class SmsStatusPuller extends SmsBase {

    private String url = "https://yun.tim.qq.com/v5/tlssmssvr/pullstatus";

    public SmsStatusPuller(int appid, String appkey) {
        super(appid, appkey, new DefaultHTTPClient());
    }

    public SmsStatusPuller(int appid, String appkey, HTTPClient httpclient) {
        super(appid, appkey, httpclient);
    }

    private HTTPResponse pull(int type, int max) throws IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject()
            .put("sig", SmsSenderUtil.calculateSignature(this.appkey, random, now))
            .put("time", now)
            .put("type", type)
            .put("max", max);

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 10000)
            .setBody(body.toString());

        try {
            // May throw IOException and URISyntaxexception
            return httpclient.fetch(req);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }

    /**
     * 拉取回执结果
     *
     * @param max  最大条数, 最多100
     * @return {@link}SmsStatusPullCallbackResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsStatusPullCallbackResult pullCallback(int max)
            throws HTTPException, JSONException, IOException {

        // May throw IOException
        HTTPResponse res = pull(0, max);

        // May throw HTTPException
        handleError(res);

        // May throw JSONException
        return (new SmsStatusPullCallbackResult()).parseFromHTTPResponse(res);
    }


    /**
     * 拉取回复信息
     *
     * @param max  最大条数, 最多100
     * @return {@link}SmsStatusPullReplyResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsStatusPullReplyResult pullReply(int max)
            throws HTTPException, JSONException, IOException {

        // May throw IOException
        HTTPResponse res = pull(1, max);

        // May throw HTTPException
        handleError(res);

        // May throw JSONException
        return (new SmsStatusPullReplyResult()).parseFromHTTPResponse(res);
    }
} public class SmsMobileStatusPuller extends SmsBase {

    private String url = "https://yun.tim.qq.com/v5/tlssmssvr/pullstatus4mobile";

    public SmsMobileStatusPuller(int appid, String appkey) {
        super(appid, appkey, new DefaultHTTPClient());
    }

    public SmsMobileStatusPuller(int appid, String appkey, HTTPClient httpclient) {
        super(appid, appkey, httpclient);
    }

    private HTTPResponse pull(int type, String nationCode, String mobile, long beginTime,
            long endTime, int max) throws IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject();
        body.put("sig", SmsSenderUtil.calculateSignature(this.appkey, random, now))
            .put("type", type)
            .put("time", now)
            .put("max", max)
            .put("begin_time", beginTime)
            .put("end_time", endTime)
            .put("nationcode", nationCode)
            .put("mobile", mobile);

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 10000)
            .setBody(body.toString());

        // May throw IOException
        try {
            return httpclient.fetch(req);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }

    public SmsStatusPullCallbackResult pullCallback(String nationCode, String mobile,
        long beginTime, long endTime, int max)
            throws HTTPException, JSONException, IOException {

        // May throw IOException
        HTTPResponse res = pull(0, nationCode, mobile, beginTime, endTime, max);

        // May throw HTTPException
        handleError(res);

        // May throw JSONException
        return (new SmsStatusPullCallbackResult()).parseFromHTTPResponse(res);
    }

    public SmsStatusPullReplyResult pullReply(String nationCode, String mobile,
        long beginTime, long endTime, int max)
            throws HTTPException, JSONException, IOException {

        // May throw IOException
        HTTPResponse res = pull(1, nationCode, mobile, beginTime, endTime, max);

        // May throw HTTPException
        handleError(res);

        // May throw JSONException
        return (new SmsStatusPullReplyResult()).parseFromHTTPResponse(res);
    }
} public class SmsStatusPullCallbackResult extends SmsResultBase {

    public class Callback {
        public String user_receive_time;
        public String nationcode;
        public String mobile;
        public String report_status;
        public String errmsg;
        public String description;
        public String sid;

        @Override
        public String toString() {
            String[] fields = {
                "user_receive_time", "nationcode", "mobile",
                "report_status", "errmsg", "description",
                "sid"
            };
            return (new JSONObject(this, fields)).toString();
        }

        public Callback parse(JSONObject json) throws JSONException {

            if (json.has("user_receive_time")) {
                user_receive_time = json.getString("user_receive_time");
            }
            if (json.has("nationcode")) {
                nationcode = json.getString("nationcode");
            }
            if (json.has("mobile")) {
                mobile = json.getString("mobile");
            }
            if (json.has("report_status")) {
                report_status = json.getString("report_status");
            }
            if (json.has("errmsg")) {
                errmsg = json.getString("errmsg");
            }
            if (json.has("description")) {
                description = json.getString("description");
            }
            if (json.has("sid")) {
                sid = json.getString("sid");
            }

            return this;
        }
    }

    public int result;
    public String errMsg;
    public int count;
    public ArrayList<Callback> callbacks;

    public SmsStatusPullCallbackResult() {
        this.errMsg = "";
        this.count = 0;
        this.callbacks = new ArrayList<Callback>();
    }

    @Override
    public SmsStatusPullCallbackResult  parseFromHTTPResponse(HTTPResponse response)
            throws JSONException {

        JSONObject json = parseToJson(response);

        result = json.getInt("result");
        errMsg = json.getString("errmsg");
        if (json.has("count")) {
            count = json.getInt("count");
        }

        if (json.has("data") && !json.isNull("data")) {
            JSONArray data = json.getJSONArray("data");
            for (int i = 0; i < data.length(); i++) {
                callbacks.add((new Callback()).parse(data.getJSONObject(i)));
            }
        }

        return this;
    }
} public class SmsStatusPullReplyResult extends SmsResultBase {

    public class Reply {

        public String nationcode;
        public String mobile;
        public String text;
        public String sign;
        public long time;
        public String extend;

        @Override
        public String toString(){
            String[] fields = {"nationcode", "mobile", "text", "sign", "time", "extend"};
            return (new JSONObject(this, fields)).toString();
        }

        public Reply parse(JSONObject json) throws JSONException {

            if (json.has("nationcode")) {
                nationcode = json.getString("nationcode");
            }
            if (json.has("mobile")) {
                mobile = json.getString("mobile");
            }
            if (json.has("text")) {
                text = json.getString("text");
            }
            if (json.has("text")) {
                sign = json.getString("text");
            }
            if (json.has("time")) {
                time = json.getLong("time");
            }
            if (json.has("extend")) {
                extend = json.getString("extend");
            }

            return this;
        }
    }

    public int result;
    public String errMsg;
    public int count;
    public ArrayList<Reply> replys;

    public SmsStatusPullReplyResult() {
        this.errMsg = "";
        this.count = 0;
        this.replys = new ArrayList<Reply>();
    }

    @Override
    public SmsStatusPullReplyResult parseFromHTTPResponse(HTTPResponse response)
            throws JSONException {

        JSONObject json = parseToJson(response);

        result = json.getInt("result");
        errMsg = json.getString("errmsg");
        if (json.has("count")) {
            count = json.getInt("count");
        }

        if (json.has("data") && !json.isNull("data")) {
            JSONArray data = json.getJSONArray("data");
            for (int i = 0; i < data.length(); i++) {
                replys.add((new Reply()).parse(data.getJSONObject(i)));
            }
        }

        return this;
    }
} public class SmsVoiceVerifyCodeSender extends SmsBase {

    private String url = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendcvoice";

    public SmsVoiceVerifyCodeSender(int appid, String appkey) {
        super(appid, appkey, new DefaultHTTPClient());
    }

    public SmsVoiceVerifyCodeSender(int appid, String appkey, HTTPClient httpclient) {
        super(appid, appkey, httpclient);
    }

    /**
     * 发送语音短信
     *
     * @param nationCode 国家码，如 86 为中国
     * @param phoneNumber 不带国家码的手机号
     * @param msg 消息类型
     * @param playtimes 播放次数
     * @param ext 服务端原样返回的参数，可填空
     * @return {@link}SmsVoiceVerifyCodeSenderResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsVoiceVerifyCodeSenderResult send(String nationCode, String phoneNumber, String msg,
        int playtimes, String ext)
            throws HTTPException, JSONException, IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject();
        body.put("tel", (new JSONObject()).put("nationcode", nationCode).put("mobile", phoneNumber))
            .put("msg", msg)
            .put("playtimes", playtimes)
            .put("sig", SmsSenderUtil.calculateSignature(this.appkey, random, now, phoneNumber))
            .put("time", now)
            .put("ext", SmsSenderUtil.isNotEmpty(ext) ? ext : "");

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 1000)
            .setBody(body.toString());

        try {
            // May throw IOException
            HTTPResponse res = httpclient.fetch(req);

            // May throw HTTPException
            handleError(res);

            // May throw JSONException
            return (new SmsVoiceVerifyCodeSenderResult()).parseFromHTTPResponse(res);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }
} public class SmsVoiceVerifyCodeSenderResult extends SmsResultBase {

    public int result;
    public String errMsg;
    public String ext;
    public String callid;

    public SmsVoiceVerifyCodeSenderResult() {
        this.errMsg = "";
        this.ext = "";
        this.callid = "";
    }

    @Override
    public SmsVoiceVerifyCodeSenderResult parseFromHTTPResponse(HTTPResponse response)
            throws JSONException {

        JSONObject json = parseToJson(response);

        result = json.getInt("result");
        errMsg = json.getString("errmsg");

        if (json.has("ext")) {
            ext = json.getString("ext");
        }
        if (json.has("callid")) {
            callid = json.getString("callid");
        }

        return this;
    }
} public class SmsVoicePromptSender extends SmsBase {

    private String url = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendvoiceprompt";

    public SmsVoicePromptSender(int appid, String appkey) {
        super(appid, appkey, new DefaultHTTPClient());
    }

    public SmsVoicePromptSender(int appid, String appkey, HTTPClient httpclient) {
        super(appid, appkey, httpclient);
    }

    /**
     * 发送语音短信
     *
     * @param nationCode 国家码，如 86 为中国
     * @param phoneNumber 不带国家码的手机号
     * @param prompttype 类型，目前固定值为2
     * @param playtimes 播放次数
     * @param msg 语音通知消息内容
     * @param ext  "扩展字段，原样返回"
     * @return {@link}SmsVoicePromptSenderResult
     * @throws HTTPException  http status exception
     * @throws JSONException  json parse exception
     * @throws IOException    network problem
     */
    public SmsVoicePromptSenderResult send(String nationCode, String phoneNumber, int prompttype,
        int playtimes, String msg, String ext)
            throws HTTPException, JSONException, IOException {

        long random = SmsSenderUtil.getRandom();
        long now = SmsSenderUtil.getCurrentTime();
        JSONObject body = new JSONObject()
            .put("tel", (new JSONObject()).put("nationcode", nationCode).put("mobile", phoneNumber))
            .put("prompttype", prompttype)
            .put("promptfile", msg)
            .put("playtimes", playtimes)
            .put("sig", SmsSenderUtil.calculateSignature(this.appkey, random, now, phoneNumber))
            .put("time", now)
            .put("ext", SmsSenderUtil.isNotEmpty(ext) ? ext : "");

        HTTPRequest req = new HTTPRequest(HTTPMethod.POST, this.url)
            .addHeader("Conetent-Type", "application/json")
            .addQueryParameter("sdkappid", this.appid)
            .addQueryParameter("random", random)
            .setConnectionTimeout(60 * 1000)
            .setRequestTimeout(60 * 1000)
            .setBody(body.toString());


        try {
            // May throw IOException and URISyntaxexception
            HTTPResponse res = httpclient.fetch(req);

            // May throw HTTPException
            handleError(res);

            // May throw JSONException
            return (new SmsVoicePromptSenderResult()).parseFromHTTPResponse(res);
        } catch(URISyntaxException e) {
            throw new RuntimeException("API url has been modified, current url: " + url);
        }
    }
} public class SmsVoicePromptSenderResult extends SmsResultBase {

    public int result;
    public String errMsg;
    public String ext;
    public String callid;

    public SmsVoicePromptSenderResult() {
        this.errMsg = "";
        this.ext = "";
        this.callid = "";
    }

    @Override
    public SmsVoicePromptSenderResult parseFromHTTPResponse(HTTPResponse response)
            throws JSONException {

        JSONObject json = parseToJson(response);

        result = json.getInt("result");
        errMsg = json.getString("errmsg");

        if (json.has("ext")) {
            ext = json.getString("ext");
        }
        if (json.has("callid")) {
            callid = json.getString("callid");
        }

        return this;
    }
} public class HTTPException extends Exception {

    private final int statusCode;
    private final String reason;

    public HTTPException(final int statusCode, final String reason) {
        super("HTTP statusCode: " + statusCode + ", reasons: " + reason);
        this.reason = reason;
        this.statusCode = statusCode;
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getReason() {
        return reason;
    }
}
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.SmsMultiSender;
import com.github.qcloudsms.SmsMultiSenderResult;
import com.github.qcloudsms.SmsStatusPuller;
import com.github.qcloudsms.SmsMobileStatusPuller;
import com.github.qcloudsms.SmsStatusPullCallbackResult;
import com.github.qcloudsms.SmsStatusPullReplyResult;
import com.github.qcloudsms.SmsVoiceVerifyCodeSender;
import com.github.qcloudsms.SmsVoiceVerifyCodeSenderResult;
import com.github.qcloudsms.SmsVoicePromptSender;
import com.github.qcloudsms.SmsVoicePromptSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import org.json.JSONException;
import java.io.IOException;




public class QcloudSmsTest {

    public static void main(String[] args) {
        // 短信应用SDK AppID
        int appid = 1400009099; // 1400开头

        // 短信应用SDK AppKey
        String appkey = "9ff91d87c2cd7cd0ea762f141975d1df37481d48700d70ac37470aefc60f9bad";

        // 需要发送短信的手机号码
        String[] phoneNumbers = {"21212313123", "12345678902", "12345678903"};

        // 短信模板ID，需要在短信应用中申请
        // NOTE: 这里的模板ID`7839`只是一个示例，
        // 真实的模板ID需要在短信控制台中申请
        int templateId = 7839;

        // 签名
        // NOTE: 这里的签名"腾讯云"只是一个示例，
        // 真实的签名需要在短信控制台中申请，另外
        // 签名参数使用的是`签名内容`，而不是`签名ID`
        String smsSign = "腾讯云";

        // 单发短信
        try {
            SmsSingleSender ssender = new SmsSingleSender(appid, appkey);
            SmsSingleSenderResult result = ssender.send(0, "86", phoneNumbers[0],