<%@page import="org.apache.catalina.connector.Response"%>
<%@page import="org.apache.jasper.tagplugins.jstl.core.Set"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.HashMap"%>
<%@ page import="java.util.LinkedHashMap" %>
<%@page import="org.json.JSONObject"%>
<%@page import="javax.crypto.Cipher"%>
<%@page import="javax.crypto.spec.IvParameterSpec"%>
<%@page import="javax.crypto.spec.SecretKeySpec"%>
<%@page import="java.util.Base64"%>
<%@page import="java.io.PrintWriter"%>
<%@page import="java.util.Enumeration"%>
<%@page import="java.security.NoSuchAlgorithmException"%>
<%@page import="java.util.zip.CRC32"%>
<%@page import="java.util.zip.Checksum"%>
<%@page import="java.text.DateFormat"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.*"%>
<%@page import="java.security.MessageDigest"%>
<%@page import="java.security.SecureRandom"%>
<%@page import="java.nio.charset.StandardCharsets"%>
<%@ page import="java.io.OutputStreamWriter" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.net.HttpURLConnection" %>
<%@ page import="java.net.URL" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.stream.Collectors" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="java.nio.charset.StandardCharsets" %>
<%@ page import="com.fasterxml.jackson.databind.ObjectMapper" %>
<%@ page import="com.fasterxml.jackson.core.JsonProcessingException" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>airpay</title>
<%
    String Username = application.getInitParameter("UserName");
    String Password = application.getInitParameter("Password");
    String Secret = application.getInitParameter("Secret");
    String sMerId = application.getInitParameter("MercId");
    String sHiddenMode = application.getInitParameter("HiddenMode");
    String url = application.getInitParameter("Url");
    String tokenurl = application.getInitParameter("tokenUrl");
    String client_id = application.getInitParameter("clientid");
    String client_secret = application.getInitParameter("clientsecret");
    

    String sEmail = request.getParameter("buyerEmail").trim();
    String sPhone = request.getParameter("buyerPhone").trim();
    String sFName = request.getParameter("buyerFirstName").trim();
    String sLName = request.getParameter("buyerLastName").trim();
    String sAddress = request.getParameter("buyerAddress").trim();
    String sAmount = request.getParameter("amount").trim();
    String sCity = request.getParameter("buyerCity").trim();
    String sState = request.getParameter("buyerState").trim();
    String sPincode = request.getParameter("buyerPinCode").trim();
    String sCountry = request.getParameter("buyerCountry").trim();
    String customvar = request.getParameter("customvar").trim();
    String txnsubtype = request.getParameter("txnsubtype").trim();
    String orderid = request.getParameter("orderid").trim();
    String code = "INR";
    String currency = "356"; 

    Map<String, String> dataMap = new HashMap<>();
    dataMap.put("buyer_email", sEmail);
    dataMap.put("buyer_phone", sPhone);
    dataMap.put("buyer_firstname", sFName);
    dataMap.put("buyer_lastname", sLName);
    dataMap.put("buyer_address", sAddress);
    dataMap.put("amount", sAmount);
    dataMap.put("buyer_city", sCity);
    dataMap.put("buyer_state", sState);
    dataMap.put("buyer_pincode", sPincode);
    dataMap.put("buyer_country", sCountry);
    dataMap.put("orderid", orderid);
    dataMap.put("currency_code", currency);
    dataMap.put("iso_currency", code);
    dataMap.put("merchant_id", sMerId);
    String sOrderId = request.getParameter("orderid").trim();

    

    
%>
<%! 

    public static String aes256encrypt(String data, String username, String password) throws Exception {
    // Generate key using MD5 hash of username and password
    MessageDigest md = MessageDigest.getInstance("MD5");
    String keyMaterial = username + "~:~" + password;
    byte[] key = md.digest(keyMaterial.getBytes(StandardCharsets.UTF_8));
    
    // Ensure key size is 128 bits as MD5 generates 16 bytes
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

    // Generate a 16-byte IV (128-bit)
    byte[] iv = new byte[16];
    new SecureRandom().nextBytes(iv);
    IvParameterSpec ivSpec = new IvParameterSpec(iv);

    // Set up cipher for encryption
    Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    aesCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);

    // Encrypt data
    byte[] encrypted = aesCipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

    // Encode the encrypted data to Base64
    String encryptedData = Base64.getEncoder().encodeToString(encrypted);

    // Return the IV concatenated with the encrypted data, encoded in Base64
    return bytestohex(iv) + encryptedData;
}
private static String bytestohex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02x", b));
    }
    return sb.toString();
}

    public String encrypt(String strToEncrypt, String secretKey) throws Exception {

        // Generate a random 8-byte IV
        byte[] iv = new byte[8];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(iv);

        // Convert the 8-byte IV to a hex string (16 characters long)
        String ivHex = bytesToHex(iv);

        // Convert the hex string back to bytes (8 bytes again)
        byte[] ivBytes = ivHex.getBytes(StandardCharsets.UTF_8);
        IvParameterSpec ivspec = new IvParameterSpec(ivBytes);

        // Prepare the secret key
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");

        // Initialize the cipher for AES-256-CBC encryption
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivspec);

        // Encrypt the data
        byte[] cipherText = cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8));

        // Combine IV (as hex string) and Base64-encoded encrypted data
        String encryptedData = Base64.getEncoder().encodeToString(cipherText);

        return ivHex + encryptedData;
    }


    // Helper function to convert byte array to hex string
    public String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    
    

    public String encrypt_sha(String data, String salt) throws NoSuchAlgorithmException {
        String toHash = salt + "@" + data;
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hash = md.digest(toHash.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(hash);
    }

    public byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

  
    public String decrypt(String requestData, String secretKey) throws Exception {
        // Extract the initialization vector (IV) and encrypted data
        byte[] iv = requestData.substring(0, 16).getBytes(StandardCharsets.UTF_8);
        String encryptedData = requestData.substring(16);

        // Prepare the IV and the secret key
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");

        // Initialize the cipher for AES-256-CBC decryption
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);

        // Decode the Base64-encoded string and decrypt it
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));

        // Convert decrypted bytes to a string
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
    
    

    public String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte b : messageDigest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    public String checksumcal(Map<String, String> postData) throws NoSuchAlgorithmException {
        // Sort the data by key
        TreeMap<String, String> sortedMap = new TreeMap<>(postData);
        StringBuilder data = new StringBuilder();

        // Concatenate all values
        for (String value : sortedMap.values()) {
            data.append(value);
        }

        // Append current date in 'Y-m-d' format
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        data.append(sdf.format(new Date()));

        // Calculate and return the checksum
        return calculateChecksumHelper(data.toString());
    }

    // Helper method to calculate checksum
    private String calculateChecksumHelper(String data) throws NoSuchAlgorithmException {
        return makeEnc(data);
    }

    // Method to hash the data using SHA-256
    private String makeEnc(String data) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(data.getBytes(StandardCharsets.UTF_8));
        
        // Convert byte array to hexadecimal string
        StringBuilder hexString = new StringBuilder();
        for (byte b : digest) {
            hexString.append(String.format("%02x", b));
        }
        
        return hexString.toString();
    }

    public String sendPostData(String tokenUrl, Map<String, String> postData) {
        HttpURLConnection connection = null;
        try {
            // Prepare the URL and connection
            URL url = new URL(tokenUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("Accept-Charset", "UTF-8");
    
            String postParams = postData.entrySet().stream()
            .map((Map.Entry<String, String> entry) -> {
                try {
                    return URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8");
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            })
            .collect(Collectors.joining("&"));
    
            // Send POST data
            OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
            writer.write(postParams);
            writer.flush();
            writer.close();
    
            // Get the response
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
    
            return response.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "Error: " + e.getMessage();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    public void createsendBack(String err, String action, HttpServletResponse response) {
        try {
            PrintWriter out = response.getWriter();
            out.print("<!DOCTYPE HTML>");
            out.print("<html lang=\"en\"");
            out.print("<head>");
            out.print("<meta charset=\"utf-8\" />");
            out.print("</head>");
            out.print("<script type=\"text/javascript\">");
            out.print("function submitForm()");
            out.print("{");
            out.print("var form = document.forms[0];");
            out.print("form.submit();");
            out.print("}");
            out.print("</script>");
            out.print("<body onLoad=javascript:submitForm()>");
            out.print("<form name='errorform' id='errorform' method='post' action='error.jsp'>");
            out.print("<input type='hidden' id='status' name='status' value='"+err+"'>");
            out.print("</form>");
            out.print("</body>");
            out.print("</html>");
            out.flush();
            out.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
%>
<%
   

    Map<String, String> requestMap = new LinkedHashMap<>();
    requestMap.put("client_id", client_id);
    requestMap.put("client_secret", client_secret);
    requestMap.put("grant_type", "client_credentials");
    requestMap.put("merchant_id", sMerId);

    String combinedString = Username + "~:~" + Password;

    // Compute MD5 hash
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(combinedString.getBytes());
    byte[] digest = md.digest();

    // Convert the byte array to a hexadecimal string
    StringBuilder sb = new StringBuilder();
    for (byte b : digest) {
        sb.append(String.format("%02x", b & 0xff));
    }
    String secretKey = sb.toString();


    StringBuilder jsonBuilder = new StringBuilder();
    jsonBuilder.append("{");
    jsonBuilder.append("\"client_id\":").append("\"").append(client_id).append("\"").append(",");
    jsonBuilder.append("\"client_secret\":").append("\"").append(client_secret).append("\"").append(",");
    jsonBuilder.append("\"grant_type\":").append("\"").append("client_credentials").append("\"").append(",");
    jsonBuilder.append("\"merchant_id\":").append("\"").append(sMerId).append("\"");
    jsonBuilder.append("}");

    String requestJson = jsonBuilder.toString();
    String encre = encrypt(requestJson,secretKey);
   
    Map<String, String> req = new LinkedHashMap<>();
    req.put("merchant_id", requestMap.get("merchant_id"));
    req.put("encdata", encre);
    String checksum = checksumcal(requestMap);
    req.put("checksum", checksum);
  
    String access_token = sendPostData(tokenurl,req);
    
   
    JSONObject decodedJson = new JSONObject(access_token);
    String decryptData = decrypt(decodedJson.getString("response"), secretKey);

    // Step 3: Decode the decrypted JSON string into a JSONObject
    JSONObject tokenResponse = new JSONObject(decryptData);
    Map<String, Object> tokenResponseMap = new HashMap<>();
    for (String key : tokenResponse.keySet()) {
        tokenResponseMap.put(key, tokenResponse.get(key));
    } 
  
    JSONObject dataObject = tokenResponse.getJSONObject("data");
    String accessToken = dataObject.getString("access_token");
   
   
    url = url + "?token=" + accessToken;
    String combined = Username + ":|:" + Password;
    String privatekey = encrypt_sha(combined,Secret);
    String checksumReq = checksumcal(dataMap);
    Map<String, String> details = new LinkedHashMap<>();
    details.put("buyer_email", sEmail);
    details.put("buyer_phone", sPhone);
    details.put("buyer_firstname", sFName);
    details.put("buyer_lastname", sLName);
    details.put("buyer_address", sAddress);
    details.put("amount", sAmount);
    details.put("buyer_city", sCity);
    details.put("buyer_state", sState);
    details.put("buyer_pincode", sPincode);
    details.put("buyer_country", sCountry);
    details.put("orderid", orderid);
    details.put("currency_code", currency);
    details.put("iso_currency", code);
    details.put("merchant_id", sMerId);
    ObjectMapper objectMapper = new ObjectMapper();
    String jsonString = objectMapper.writeValueAsString(details);
    String request_data = encrypt(jsonString,secretKey);
    String chmod ="";
  
%>
<script type="text/javascript">
function submitForm() {
    var form = document.forms[0];
    form.submit();
}
</script>
</head>
<body onload="javascript:submitForm()">
<center>
<table width="500px;">
    <tr>
        <td align="center" valign="middle">Do Not Refresh or Press Back <br/> Redirecting to airpay</td>
    </tr>
    <tr>
        <td align="center" valign="middle">
            <form action="<%= url %>" method="post">
                <input type="hidden" name="privatekey" value="<%=privatekey%>">
                <input type="hidden" name="merchant_id" value="<%=sMerId%>">
				<input type="hidden" name="encdata" value="<%=request_data%>">
				<input type="hidden" name="checksum" value="<%=checksumReq%>">
				<input type="hidden" name="chmod" value="<%=chmod%>">
            </form>
        </td>
    </tr>
</table>
</center>
</body>
</html>
