package com.renren.api.connect.android.pay.impl;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import com.renren.api.connect.android.Renren;
import com.renren.api.connect.android.RequestListener;
import com.renren.api.connect.android.exception.RenrenAuthError;
import com.renren.api.connect.android.exception.RenrenError;
import com.renren.api.connect.android.pay.IPayListener;
import com.renren.api.connect.android.pay.IPayRepairListener;
import com.renren.api.connect.android.pay.IRenrenPay;
import com.renren.api.connect.android.pay.bean.AppState;
import com.renren.api.connect.android.pay.bean.PayOrder;
import com.renren.api.connect.android.pay.bean.Payment;
import com.renren.api.connect.android.pay.util.PayStoreHelper;
import com.renren.api.connect.android.pay.util.PayUtil;
import com.renren.api.connect.android.pay.view.PayDialogListener;
import com.renren.api.connect.android.view.RenrenAuthListener;
import com.renren.api.connect.android.view.RenrenDialog;
/**
* 主要职责是接受数据、检查参数、检查App。 将打开Dialog。进行消费。 消费信息的返回值处理全部交给
* {@link PayDialogListener}
*/
public class RenrenPay implements IRenrenPay {
private static RenrenPay instance;
private static PayStoreHelper payStoreHelper;
// 线程池,目前仅作异步调用网络使用,以后可能还有别的用处
private Executor mPool = Executors.newFixedThreadPool(2);
private Renren mRenren = null;
private AppState mAppState = null;
private boolean isInitalized = false;
private boolean is4Test = false;
private IPayRepairListener repairListener;
@Override
public String generateOrderNumber() {
StringBuilder sb = new StringBuilder();
sb.append('2');
sb.append(mRenren.getAppId().substring(0, 4));
Format format = new SimpleDateFormat("yyMMddHHmm");
sb.append(format.format(new Date()));
sb.append(String.format("%04d", new Random().nextInt(9999)));
return sb.toString();
}
/**
* 查询app的状态,如果通过审核则可以调用下一步。 每次创建pay对象时会调用一遍。 一般来说调用pay4Test接口不会受appState的限制
*
* @return
*/
private boolean asynCheckApp() {
isInitalized = false;
Bundle params = new Bundle();
params.putString("app_id", mRenren.getAppId());
String time = String.valueOf(new Date().getTime());
params.putString("time", time);
params.putString("app_encode", PayUtil.getAppCode(mRenren.getAppId(),
"", mRenren.getSecret(), time));
RequestListener l = new RequestListener() {
@Override
public void onFault(Throwable e) {
// DO NOTHING
}
@Override
public void onComplete(String resString) {
// 这里可以认为是线程安全的,因为主线程并不涉及写操作,只是可能单纯的在读
mAppState = PayUtil.parseAppState(resString);
isInitalized = true;
}
@Override
public void onRenrenError(RenrenError renrenError) {
// DO NOTHING
}
};
PayUtil.request(mPool, params, PayUtil.PAY_CHECK_APP_URL, l);
return true;
}
/**
* 设置Renren和IPayRepairListener,通过调用这个方法可以主动的修改renren对象跟IPayRepairListener
*/
@Override
public void init(Renren renren, IPayRepairListener repairListener) {
if (null == renren) {
throw new RuntimeException("实例化过的renren对象必须提供");
}
if (null == repairListener) {
this.enableStore(false);
// throw new RuntimeException("实例化过的IPayRepairListener对象必须提供");
}
mRenren = renren;
this.repairListener = repairListener;
}
/**
* 读取本地存储的订单,供修复订单使用
*
* @param c
* @return
*/
public List<PayOrder> getStoredPayOrders(Context c) {
return payStoreHelper.getPayOrder(Integer.parseInt(mRenren.getAppId()),
(int) mRenren.getCurrentUid());
}
@Override
public void removeAllLocalInfo(Context context) {
payStoreHelper.removeAllByUid((int) mRenren.getCurrentUid());
}
/**
* 初始化本地存储
*
* @param Context
*/
private void initLocalStore(Context c) {
payStoreHelper = PayStoreHelper.getInstance(c);
}
private RenrenPay(Context context, Renren renren,
IPayRepairListener listener) {
if (null == context || null == renren || null == listener) {
throw new RuntimeException(
"context|renren|IPayRepairListener cannot be null!!");
}
initLocalStore(context);
init(renren, listener);
asynCheckApp();
}
/**
* 是否完成初始化
*/
public boolean isInitalized() {
return isInitalized;
}
private boolean checkLogin(final Activity act, final RenrenAuthListener ll) {
if (!mRenren.isAccessTokenValid()) {
mRenren.authorize(act, ll);
return false;
}
return true;
}
@Override
public boolean beginPay4Test(final Activity act, final Payment payment) {
is4Test = true;
return pay(act, payment);
}
@Override
public boolean beginPay(final Activity act, final Payment payment) {
is4Test = false;
return pay(act, payment);
}
/**
* 支付。之前涉及登录验证并尝试让用户登录 先设置登录的listener
*
* @param act
* @param payment
* @return
*/
private boolean pay(final Activity act, final Payment payment) {
if (null == payment) {
throw new RuntimeException("实例化过的payment对象必须提供");
}
if (null == payment.getPayListener()) {
throw new RuntimeException("实例化过的Payment.IPayListener对象必须提供");
}
final IPayListener l = payment.getPayListener();
RenrenAuthListener authListener = new RenrenAuthListener() {
@Override
public void onComplete(Bundle values) {
openDialogForPay(act, payment);
}
@Override
public void onRenrenAuthError(RenrenAuthError renrenAuthError) {
l.onError(new RenrenError(RenrenError.ERROR_CODE_AUTH_FAILED,
renrenAuthError.getErrorDescription(), renrenAuthError
.getErrorUri()));
}
@Override
public void onCancelLogin() {
l.onError(new RenrenError(
RenrenError.ERROR_CODE_AUTH_CANCELLED, "user_cancel",
null));
}
@Override
public void onCancelAuth(Bundle values) {
l.onError(new RenrenError(
RenrenError.ERROR_CODE_AUTH_CANCELLED,
"user_cancel_auth", null));
}
};
if (checkLogin(act, authListener)) {
openDialogForPay(act, payment);
}
return true;
}
/**
* 打开webView,之后的所有返回值、判断都交给RRPayDialogListener来处理了 该方法只调用onStart。
* 该方法中根据是否初始化,app是否检查过.
*
* @param context
*/
private void openDialogForPay(Context context, Payment payment) {
if (!this.is4Test && this.isInitalized
&& mAppState.getStatusCode() != AppState.OK) {
// 如果初始化了,但是没有通过审核。而且还不是测试状态
// 就没必要请求服务器了
payment.getPayListener().onError(
new RenrenError("app未通过审核,请使用Test方法或提交审核"));
return;
}
/**
* 生成PayOrder 对象
*/
PayOrder payOrder = new PayOrder(mRenren.getAppId(),
mRenren.getCurrentUid(), payment);
String url = null;
if (!this.is4Test) {
url = PayUtil.PAY_SUBMIT_ORDER_URL;
payOrder.setSandBox(false);
} else {
url = PayUtil.PAY_4TEST_URL;
payOrder.setSandBox(true);
}
String data = PayUtil.generateOrderDatas(mRenren.getAppId(),
mRenren.getSecret(), mRenren.getAccessToken(),
payment.getOrderNumber(), payment.getAmount(),
payment.getDescription(), payment.getPayment());
RenrenDialog dialog = new RenrenDialog(context, url, data,
new PayDialogListener(payOrder, payment.getPayListener()));
payStoreHelper.addOrUpdatePay(payOrder);
payment.getPayListener().onStart(payment);
dialog.show();
}
/**
* 提供修复订单功能
*
* @param activity
* @param order
*/
@Override
public void repairOrder(final Context context, final PayOrder order) {
this.is4Test = false;
this.openDialogForRepair(context, order, this.repairListener);
}
/**
* 提供修复订单功能
*
* @param activity
* @param order
*/
@Override
public void repairOrder4Test(final Context context, final PayOrder order) {
this.is4Test = true;
this.openDialogForRepair(context, order, this.repairListener);
}
/**
* 打开修复订单的WebView。
*
* @param context
*/
private void openDialogForRepair(Context context, PayOrder payOrder,
IPayRepairListener listener) {
String fixOrderUrl = null;
// 如果不是test 状态,设置url
if (!this.is4Test) {
fixOrderUrl = PayUtil.PAY_FIXORDER_URL;
} else {
fixOrderUrl = PayUtil.PAY_FIXORDER_4TEST_URL;
}
String data = PayUtil.generateRepairDatas(payOrder.getBid(), payOrder
.getAppId(), payOrder.getOrderNumber(), payOrder.getAmount(),
mRenren.getSecret(), mRenren.getAccessToken(), payOrder
.getUserId(), payOrder.getOrderTime().getTime());
RenrenDialog dialog = new RenrenDialog(context, fixOrderUrl, data,
new PayDialogListener(payOrder, listener));
dialog.show();
payStoreHelper.addOrUpdatePay(payOrder);
}
/**
* 请确保初始化之后才使用该方法
*
* @return
*/
public static IRenrenPay getInstance() throws RuntimeException {
if (null == instance) {
throw new RuntimeException("IRenrenPay未实例化");
}
return instance;
}
/**
* 单例方法
*
* @param Context
* @param Renren
* @param IPayRepairListener
* 初始化时请提供RepairListener
* @return
*/
public static synchronized IRenrenPay getInstance(Context c, Renren r,
IPayRepairListener l) {
if (null == instance) {
instance = new RenrenPay(c, r, l);
} else {
instance.init(r, l);
}
return instance;
}
@Override
public void enableStore(boolean enableStore) {
if (null != payStoreHelper) {
payStoreHelper.enableLocalStore(enableStore);
}
}
@Override
public void removeOrderByOrderNumber(String orderNumber) {
// TODO Auto-generated method stub
if (null != orderNumber && null != payStoreHelper) {
payStoreHelper.removeByUidAndOrderNumber(
(int) this.mRenren.getCurrentUid(), orderNumber);
}
}
}