/**
 * Copyright (c) 2003-2004 System Integrator Corporation.
 *                 All Rights Reserved.
 */
package jp.co.sint.mdk;

import java.text.ParseException;
import java.util.Hashtable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import jp.co.sint.config.SIConfig;
import jp.co.sint.tools.SIDateTime;
import jp.co.sint.tools.SIStringUtil;
import jp.co.sint.tools.SIUtil;

import org.apache.log4j.Category;

import Jp.BuySmart.JPGWLib.Transaction;
import Jp.BuySmart.JPGWLib.TransactionFactory;


/**
 * @version $Id: SIMDKAction.java,v 1.0 2004/01/14 Exp $
 * @author  Jinwang Chen
 * <br>Description:
 * <p>History</p>
 * <p>Author&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reason</p>
 *  ============&nbsp;&nbsp;&nbsp;==========&nbsp;&nbsp;===========================<br>
 * Jinwang Chen   2004/01/14 14:10:26  Original
 */
public class SIMDKAction {
  //ログ用のインスタンスの生成
  private static Category log=Category.getInstance(SIConfig.SILOG4J_WEBSHOP_CATEGORY_NAME);
  
  //注文番号
  private String orderCode="";
  
  //再取引用注文番号
  private String reOrderCode="";
  
  //決済金額
  private String price="0";
  
  //カード番号
  private String cardNo="";
  
  //カード有効期限の年
  private String cardExpiredYear="";
  
  //カード有効期限の月
  private String cardExpiredMonth="";
  
  //カード有効期限
  private String cardExpired="";
  
  //サービスタイプ
  private String serviceType="";
  
  //取引タイプ
  private String txnType="";
  
  //カード名義人
  private String custNameOfCard="";
  
  //支払方法
  private String paymentMethod=SIMDKConfig.MDK_PAYMENT_METHOD_ONE;
  
  //支払開始月
  private String paymentStartMonth="";
  
  //分割回数
  private String paymentTimes="";
  
  //与信開始時刻
  private String startDateTime="";
  
  //与信終了時刻
  private String endDateTime="";
  
  //セキュリティコード
  private String securityCode="";
  
  //与信後の結果セット
  private Hashtable resultMap=new Hashtable();
  
  public SIMDKAction(){
  }
  
  /**
   * <b>authAction</b>
   * カード情報の与信処理
   * @param  なし
   * @return 与信処理の結果
   * @throws なし
   */
  public boolean authAction(){
    if (Integer.parseInt(getPrice())<=0) return true;
    else return execAction(SIMDKConfig.MDK_AUTH_TYPE,getMDKParams());
  }
  
  /**
   * <b>authAction</b>
   * カード情報の与信売上処理
   * @param  なし
   * @return 与信処理の結果
   * @throws なし
   */
  public boolean authCaptureAction(){
    if (Integer.parseInt(getPrice())<=0) return true;
    else return execAction(SIMDKConfig.MDK_AUTH_CAPTURE_TYPE,getMDKParams());
  }
  public boolean authCaptureAction(String mvn,String xid,String xstatus,String cavva,String cavv,String eci){
    Hashtable lParamsMap=getMDKParams();
    lParamsMap.put("3d-msg-version", mvn);
    lParamsMap.put("3d-xid", xid);
    lParamsMap.put("3d-xstatus", xstatus);
    lParamsMap.put("3d-cavv-algorithm", cavva);
    lParamsMap.put("3d-cavv", cavv);
    lParamsMap.put("3d-eci", eci);
    
    if (Integer.parseInt(getPrice())<=0) return true;
    else return execAction(SIMDKConfig.MDK_AUTH_CAPTURE_TYPE,lParamsMap);
  }
  
  
  public boolean reauthAction(){
    if (Integer.parseInt(getPrice())<=0) return true;
    else return execAction(SIMDKConfig.MDK_REAUTH_CAPTURE_TYPE,getMDKParamsReAuth());
  }
  
  /**
   * <b>cancelAction</b>
   * 与信のキャンセル処理
   * @param  なし
   * @return キャンセル処理の結果
   * @throws なし
   */
  public boolean cancelAuthAction(){
    Hashtable lParamsMap=getMDKParams();
    lParamsMap.put("service-type", SIMDKConfig.MDK_SERVICE_TYPE);
    lParamsMap.put("txn-type", SIMDKConfig.MDK_AUTH_TYPE);
    
    return execAction(SIMDKConfig.MDK_CANCEL_TYPE,lParamsMap);
  }
  
  /**
   * <b>cancelCaptureAction</b>
   * 与信のキャンセル処理
   * @param  なし
   * @return キャンセル処理の結果
   * @throws なし
   */
  public boolean cancelCaptureAction(){
    Hashtable lParamsMap=getMDKParams();
    lParamsMap.put("service-type", SIMDKConfig.MDK_SERVICE_TYPE);
    lParamsMap.put("txn-type", SIMDKConfig.MDK_AUTH_CAPTURE_TYPE);
    
    return execAction(SIMDKConfig.MDK_CANCEL_TYPE,lParamsMap);
  }

  /**
   * <b>returnAction</b>
   * 与信の返品処理
   * @param  なし
   * @return 返品処理の結果
   * @throws なし
   */
  public boolean returnAction(){
    Hashtable lParamsMap=getMDKParams();
    lParamsMap.put("service-type", SIMDKConfig.MDK_SERVICE_TYPE);
    lParamsMap.put("txn-type", SIMDKConfig.MDK_AUTH_TYPE);
    
    return execAction(SIMDKConfig.MDK_RETURN_TYPE,lParamsMap);
  }
  
  /**
   * <b>salesAction</b>
   * 売上処理
   * @param  なし
   * @return 売上処理の結果
   * @throws なし
   */
  public boolean salesAction(){
    Hashtable lParamsMap=getMDKParams();
    lParamsMap.put("service-type", SIMDKConfig.MDK_SERVICE_TYPE);
    
    return execAction(SIMDKConfig.MDK_POST_AUTH_TYPE,lParamsMap);
  }
  
  public boolean payRequestAction(){
    Hashtable lParamsMap=getMDKParams();
    lParamsMap.put("note","");
    return execAction(SIMDKConfig.MDK_PAY_REQUEST_TYPE,lParamsMap);
  }
  
  /**
   * <b>execAction</b>
   * 決済処理の共通メソッド
   * @param  lActionType 決済タイプ
   * @param  lParamsMap パラメータのセット
   * @return 処理の結果
   * @throws なし
   */
  public boolean execAction(String lActionType,Hashtable lParamsMap){
    boolean lRes=false;
    SIDateTime lDateTime=new SIDateTime();
    setStartDateTime(lDateTime.getFullDateTime());
    
    // MDK のインスタンスを作成
    TransactionFactory lFactory = null;
    try {
      lFactory = new TransactionFactory(SIMDKConfig.MDK_CONFIG_FILE);
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
    Transaction lTran = lFactory.createInstance();
    
    // 取引をなげる
    resultMap = lTran.sendMServer(lActionType,lParamsMap);
    
    String lStatus=(String)resultMap.get("MStatus");
    
    log.debug("与信開始..."+getStartDateTime());
    log.debug("lActionType = "+lActionType);
    log.debug("OrderCode = "+getOrderCode());
    if (getCardNo().length()>6)log.debug("CardNo ="+getCardNo().substring(0,5));
    else log.debug("CardNo = "+getCardNo());
    log.debug("CustNameOfCard = "+getCustNameOfCard());
    log.debug("CardExpired = "+getCardExpired());
    
    if (SIUtil.isNotNull(lStatus)&&lStatus.equalsIgnoreCase(SIMDKConfig.MDK_STATUS_SUCCESS)){//成功
      lRes=true;
    }else{
      log.error("MStatus="+resultMap.get("MStatus")+",MErrMsg="+resultMap.get("MErrMsg"));
      log.error("action-code="+resultMap.get("action-code")+",MErrLoc="+resultMap.get("MErrLoc"));
      lRes=false;
    }
    lDateTime=new SIDateTime();
    setEndDateTime(lDateTime.getFullDateTime());
    log.debug("与信終了..."+getEndDateTime());
    return lRes;
  }
  
  private Hashtable getMDKParams(){
    // パラメータの設定
    Hashtable lParams = new Hashtable();
    lParams.put("order-id",getOrderCode());
    lParams.put("amount",getPrice());
    
    lParams.put("card-number",getCardNo());
    lParams.put("card-exp", getCardExpired());
    lParams.put("jpo-info", getPaymentType());
    lParams.put("card-cav2", getSecurityCode());
    
    return lParams;
  }
  
  private Hashtable getMDKParamsReAuth(){
    // パラメータの設定
    Hashtable lParams = new Hashtable();
    lParams.put("order-id",getOrderCode());
    lParams.put("re-order-id",getReOrderCode());
    lParams.put("amount",getPrice());
    
    lParams.put("jpo-info", getPaymentType());
    
    return lParams;
  }
  
  /**
   * <b>getCardExpired</b>
   * カード有効期限の取得
   * @param  なし
   * @return カード有効期限
   * @throws なし
   */
  public String getCardExpired() {
    if (SIUtil.isNull(getCardExpiredMonth())&&SIUtil.isNull(getCardExpiredYear()))return "";
    else return getCardExpiredMonth()+"/"+getCardExpiredYear();
  }
  
  /**
   * <b>getCardExpiredMonth</b>
   * カード有効期限の月の取得
   * @param  なし
   * @return カード有効期限の月
   * @throws なし
   */
  public String getCardExpiredMonth() {
    return cardExpiredMonth;
  }
  
  /**
   * <b>getCardExpiredYear</b>
   * カード有効期限の年の取得
   * @param  なし
   * @return カード有効期限の年
   * @throws なし
   */
  public String getCardExpiredYear() {
    return cardExpiredYear;
  }
  
  /**
   * <b>getCardNo</b>
   * カード番号の取得
   * @param  なし
   * @return カード番号
   * @throws なし
   */
  public String getCardNo() {
    return this.cardNo;
  }
  
  /**
   * <b>getCustNameOfCard</b>
   * カード名義人の取得
   * @param  なし
   * @return カード名義人
   * @throws なし
   */
  public String getCustNameOfCard() {
    return custNameOfCard;
  }
  
  /**
   * <b>getOrderCode</b>
   * 受注番号の取得
   * @param  なし
   * @return 受注番号
   * @throws なし
   */
  public String getOrderCode() {
    return this.orderCode;
  }
  
  /**
   * <b>getReOrderCode</b>
   * 再受注番号の取得
   * @param  なし
   * @return 再受注番号
   * @throws なし
   */
  public String getReOrderCode() {
    return this.reOrderCode;
  }
  
  /**
   * <b>getPrice</b>
   * 決済金額の取得
   * @param  なし
   * @return 決済金額
   * @throws なし
   */
  public String getPrice() {
    return price;
  }
  
  /**
   * <b>getServiceType</b>
   * サービスタイプの取得
   * @param  なし
   * @return サービスタイプ
   * @throws なし
   */
  public String getServiceType() {
    return serviceType;
  }
  
  /**
   * <b>getTxnType</b>
   * 取引タイプの取得
   * @param  なし
   * @return 取引タイプ
   * @throws なし
   */
  public String getTxnType() {
    return txnType;
  }
  
  /**
   * <b>getPaymentMethod</b>
   * 支払方法の取得
   * @param  なし
   * @return 支払方法
   * @throws なし
   */
  public String getPaymentMethod(){
    return this.paymentMethod;
  }
  
  /**
   * <b>getPaymentStartMonth</b>
   * 支払開始月の取得
   * @param  なし
   * @return 支払開始月
   * @throws なし
   */
  public String getPaymentStartMonth(){
    return this.paymentStartMonth;
  }
  
  /**
   * <b>getPaymentTimes</b>
   * 分割回数の取得
   * @param  なし
   * @return 分割回数
   * @throws なし
   */
  public String getPaymentTimes(){
    return this.paymentTimes;
  }
  
  public String getSecurityCode(){
    return this.securityCode;
  }
  
  /**
   * <b>getPaymentType</b>
   * 支払種別の取得
   * @param  なし
   * @return 支払種別
   * @throws なし
   */
  public String getPaymentType(){
    if (getPaymentMethod().equals(SIMDKConfig.MDK_PAYMENT_METHOD_ONE)) {
      return "";
    }else if (getPaymentMethod().equals(SIMDKConfig.MDK_PAYMENT_METHOD_MULIT)){
      if (SIUtil.isNull(getPaymentStartMonth())) return "61C"+getPaymentTimes();
      else return "61A"+getPaymentStartMonth()+"C"+getPaymentTimes();
    }else if (getPaymentMethod().equals(SIMDKConfig.MDK_PAYMENT_METHOD_BONUS)){
      return "21";
    }else if (getPaymentMethod().equals(SIMDKConfig.MDK_PAYMENT_METHOD_MULIT_BONUS)){
      if (SIUtil.isNull(getPaymentStartMonth())) return "31C"+getPaymentTimes();
      else return "31A"+getPaymentStartMonth()+"C"+getPaymentTimes();
    }else return "";
  }
  
  public void setStartDateTime(String lStartDateTime){
    if (SIUtil.isNull(lStartDateTime)) lStartDateTime="";
    this.startDateTime=lStartDateTime;
  }
  
  public void setEndDateTime(String lEndDateTime){
    if (SIUtil.isNull(lEndDateTime)) lEndDateTime="";
    this.endDateTime=lEndDateTime;
  }
  
  /**
   * <b>setCardExpired</b>
   * カード有効期限の設定
   * @param  lCardExpired 有効期限
   * @return なし
   * @throws なし
   */
  public void setCardExpired(String lCardExpired) {
    if (SIUtil.isNull(lCardExpired)) lCardExpired="";
    String[] lExp=SIStringUtil.split(lCardExpired,"/");
    if (lExp.length==1){
      setCardExpiredMonth(lExp[0]);
    }else if (lExp.length==2){
      setCardExpiredMonth(lExp[0]);
      setCardExpiredYear(lExp[1]);
    }
    cardExpired = lCardExpired;
  }
  
  /**
   * <b>setCardExpiredMonth</b>
   * カード有効期限の月の設定
   * @param  lCardExpiredMonth カード有効期限の月
   * @return なし
   * @throws なし
   */
  public void setCardExpiredMonth(String lCardExpiredMonth) {
    if (SIUtil.isNull(lCardExpiredMonth)) lCardExpiredMonth="";
    else lCardExpiredMonth=SIUtil.lFillIn(lCardExpiredMonth,2);
    cardExpiredMonth = lCardExpiredMonth;
  }
  
  /**
   * <b>setCardExpiredYear</b>
   * カード有効期限の年の設定
   * @param  lCardExpiredYear カード有効期限の年
   * @return なし
   * @throws なし
   */
  public void setCardExpiredYear(String lCardExpiredYear) {
    if (SIUtil.isNull(lCardExpiredYear)) {
      lCardExpiredYear="";
    }else if (lCardExpiredYear.length()==4){
      lCardExpiredYear=lCardExpiredYear.substring(2);
    }else {
      lCardExpiredYear=SIUtil.lFillIn(lCardExpiredYear,2);
    }
    cardExpiredYear = lCardExpiredYear;
  }
  
  /**
   * <b>setCardNo</b>
   * カード番号の設定
   * @param  lCardNo カード番号
   * @return なし
   * @throws なし
   */
  public void setCardNo(String lCardNo) {
    if (SIUtil.isNull(lCardNo)) lCardNo="";
    if (lCardNo.length()>6)log.debug("card no="+lCardNo.substring(0,5));
    else log.debug("card no="+lCardNo);
    this.cardNo = lCardNo;
  }
  
  /**
   * <b>setCustNameOfCard</b>
   * カード名義人の設定
   * @param  lCustNameOfCard カード名義人
   * @return なし
   * @throws なし
   */
  public void setCustNameOfCard(String lCustNameOfCard) {
    if (SIUtil.isNull(lCustNameOfCard)) lCustNameOfCard="";
    custNameOfCard = lCustNameOfCard;
  }
  
  /**
   * <b>setOrderCode</b>
   * 注文番号の設定
   * @param  lOrderID 注文番号
   * @return なし
   * @throws なし
   */
  public void setOrderCode(String lOrderCode) {
    if (SIUtil.isNull(lOrderCode)) lOrderCode="";
    this.orderCode = lOrderCode;
  }
  
  /**
   * <b>setReOrderCode</b>
   * 再注文番号の設定
   * @param  lReOrderCode 注文番号
   * @return なし
   * @throws なし
   */
  public void setReOrderCode(String lReOrderCode) {
    if (SIUtil.isNull(lReOrderCode)) lReOrderCode="";
    this.reOrderCode = lReOrderCode;
  }
  
  /**
   * <b>setPrice</b>
   * 決済金額の設定
   * @param  lPrice 決済金額
   * @return なし
   * @throws なし
   */
  public void setPrice(String lPrice) {
    if (SIUtil.isNull(lPrice)) lPrice="0";
    price = lPrice;
  }
  
  /**
   * <b>setServiceType</b>
   * サービスタイプの設定
   * @param  lServiceType サービスタイプ
   * @return なし
   * @throws なし
   */
  public void setServiceType(String lServiceType) {
    if (SIUtil.isNull(lServiceType)) lServiceType="";
    serviceType = lServiceType;
  }
  
  /**
   * <b>setTxnType</b>
   * 取引タイプの設定
   * @param  lTxnType 取引タイプ
   * @return なし
   * @throws なし
   */
  public void setTxnType(String lTxnType) {
    if (SIUtil.isNull(lTxnType)) lTxnType="";
    txnType = lTxnType;
  }
  
  /**
   * <b>setPaymentMethod</b>
   * 支払方法の設定
   * @param  lPaymentMethod 支払方法
   * @return なし
   * @throws なし
   */
  public void setPaymentMethod(String lPaymentMethod){
    if (SIUtil.isNull(lPaymentMethod)) lPaymentMethod=SIMDKConfig.MDK_PAYMENT_METHOD_ONE;
    this.paymentMethod = lPaymentMethod;
  }
  
  /**
   * <b>setPaymentStartMonth</b>
   * 支払開始月の設定
   * @param  lPaymentStartMonth 支払開始月
   * @return なし
   * @throws なし
   */
  public void setPaymentStartMonth(String lPaymentStartMonth){
    if (SIUtil.isNull(lPaymentStartMonth)) lPaymentStartMonth="";
    else lPaymentStartMonth=SIUtil.lFillIn(lPaymentStartMonth,2);
    this.paymentStartMonth = lPaymentStartMonth;
  }
  
  /**
   * <b>setPaymentTimes</b>
   * 分割回数の設定
   * @param  lPaymentTimes 分割回数
   * @return なし
   * @throws なし
   */
  public void setPaymentTimes(String lPaymentTimes){
    if (SIUtil.isNull(lPaymentTimes)) lPaymentTimes="";
    else lPaymentTimes=SIUtil.lFillIn(lPaymentTimes,2);
    this.paymentTimes = lPaymentTimes;
  }
  
  public void setSecurityCode(String lSecurityCode){
    if (SIUtil.isNull(lSecurityCode)) lSecurityCode="";
    this.securityCode = lSecurityCode;
  }
  
  /**
   * <b>getResultMap</b>
   * 決済処理を実行した結果セットの取得
   * @param  なし
   * @return 決済処理を実行した結果セット
   * @throws なし
   */
  public Hashtable getResultMap(){
    return resultMap;
  }
  
  /**
   * <b>getResult</b>
   * ある項目に対する結果値の取得
   * @param  なし
   * @return ある項目に対する結果値
   * @throws なし
   */
  public String getResult(String lName){
    String lRes=(String)resultMap.get(lName);
    if (SIUtil.isNull(lRes)) return "";
    else return lRes;
  }
  
  public String getStartDateTime(){
    return this.startDateTime;
  }
  
  public String getEndDateTime(){
    return this.endDateTime;
  }
  
  public String getActionTime(){
    if (SIUtil.isNull(getStartDateTime()) || SIUtil.isNull(getEndDateTime())) return "-1";
    SIDateTime lStartDateTime=new SIDateTime();
    SIDateTime lEndDateTime=new SIDateTime();
    try {
      lStartDateTime=new SIDateTime(getStartDateTime(),SIConfig.SIDATE_TIME_FORMAT);
      lEndDateTime=new SIDateTime(getEndDateTime(),SIConfig.SIDATE_TIME_FORMAT);
      long lDiff=lEndDateTime.getDateTime()-lStartDateTime.getDateTime();
      log.debug("getActionTime:lStartDateTime="+getStartDateTime()+",lEndDateTime="+getEndDateTime()+",lDiff="+lDiff);
      return String.valueOf(lDiff);
    } catch (ParseException e) {
      e.printStackTrace();
      return "-1";
    }
  }
  
  public static void cancelByFailuer(HttpServletRequest request){
    HttpSession session=request.getSession(true);//セッションの取得
    SIMDKAction lMDKAction=(SIMDKAction)session.getAttribute(SIConfig.SISESSION_MDK_AUTH_NAME);
    if (lMDKAction!=null){
      log.debug("受注失敗しました。既に決済情報もキャンセルします。");
      if (!lMDKAction.cancelCaptureAction())log.error("エラーによって、決済カードのキャンセル失敗しました。");//7.2.1 ST2007 修正 与信売上の取消に変更
      session.removeAttribute(SIConfig.SISESSION_MDK_AUTH_NAME);
    }
  }
}