/*
 * CreditCard.java
 * Created on May 11, 2005 
 * Author: 	L�szl� Felf�ldi, Etixpert GmbH
 * mail:	laszlo.felfoldi@etixpert.com		
 */package com.etixpert.evolution.app.order;

 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.log4j.Logger;

import com.etixpert.evolution.value.DistributorValue;
import com.etixpert.evolution.value.order.CreditCardValue;
import com.etixpert.evolution.value.order.OrderHeaderValue;

public class CreditCard {
	private URL    url;
	private Random rnd = new Random(System.currentTimeMillis());
	private long   cnt = 1000000;
	
	private static String format(String val, String def) {
		String ret = def + val;
		return ret.substring(ret.length() - def.length());
	}
	
	private static String format(long val, String def) {
		return format("" + val, def);
	}
	
	public boolean send(Date date, String name, String brand, String id, String expires, 
						double val, String user_field, boolean test) {
		// Generate unique transaction identifier	  
	  	long   z   = (long) (999999999 * rnd.nextDouble() + 1);
	    long   t   = System.currentTimeMillis();
	    String tid = "" + z + t + cnt++;

	    // Generate timestamp
		Calendar     cal = Calendar.getInstance();
		cal.setTime(date);

		int year   = cal.get(Calendar.YEAR);
		int month  = cal.get(Calendar.MONTH) + 1;
		int day    = cal.get(Calendar.DAY_OF_MONTH);
		int hour   = cal.get(Calendar.HOUR);
		int minute = cal.get(Calendar.MINUTE);
		int second = cal.get(Calendar.SECOND);
	    String timestamp = format(year, "0000") + format(month, "00") + format(day, "00") +
				format(hour, "00") + format(minute, "00") + format(second, "00");

	    try {
		    String strdata =
		    	"OPERATION=ACCEPTPAYMENT" +
				"&MERCHANTID=" + (test ? "70263" : "70067") +
				"&TIMESTAMP=" + timestamp +
				"&PRICE=" + Math.round(val * 100) +
				"&CURRENCY=EUR" +
				"&IDENTIFIER=" + (test ? "4444111122223333" : id) +
				"&EXPIRY=" + expires + 
				"&P_TYPE=CC" +
				"&TID=" + tid +
				"&ORDERNUMBER=" + // ordernumber +
				"&BRAND=" + (test ? "VISA" : brand) +
				"&CUSTOMER=" + URLEncoder.encode(name, "UTF-8") +
				"&USER_FIELD=" + URLEncoder.encode(user_field, "UTF-8");
			
		    // open https connection
		    HttpURLConnection con = (HttpURLConnection) url.openConnection();
		    con.setDoInput(true);
		    con.setDoOutput(true);
		    con.setRequestMethod("POST");
		    con.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
		    con.connect();
		   
		    // send data
		    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()));
		    bw.write(strdata, 0, strdata.length());
		    bw.flush();
		    bw.close();
		    
		    // get the response
		    StringBuffer res = new StringBuffer();
		    BufferedReader s = new BufferedReader(new InputStreamReader(con.getInputStream()));
		    for (String line = null; (line = s.readLine()) != null; res.append(line)); 
		    s.close();

		    Logger logger= Logger.getLogger("mainControl.Payment");
		    logger.info("Creditcard to " + name + "(" + id + ")");
		    logger.info("Creditcard send :" + strdata);
		    logger.info("Creditcard response :" + res);
		    
		    String[] vals = res.toString().split("&");
		    for (int i = 0; i < vals.length; i++) {
		    	if (vals[i].startsWith("STATUS")) {
		    		String[] name_val = vals[i].split("=");
		    		return name_val.length > 1 && name_val[1].equals("OK");
		    	}
		    }
	    } catch (Exception e) {
	    }
	    return false;
	}
	
	public CreditCard(String aURL) throws MalformedURLException {
		url = new URL(aURL);
	}
	
	public String generate(Date date, List orders, List environment, Set processedOrders, boolean test) {
		StringBuffer ret = new StringBuffer();
		for (Iterator it = environment.iterator(); it.hasNext(); ) {
			DistributorValue dv = (DistributorValue) it.next();
			
			Map vals = new Hashtable();

			StringBuffer details = new StringBuffer();
			List aProcessedOrders = new LinkedList();
			for (Iterator it2 = orders.iterator(); it2.hasNext(); ) {
				OrderHeaderValue ov = (OrderHeaderValue) it2.next();
				CreditCardValue cc = ov.getCreditCard();
				
				// handling validUntil storage bug
				Date validUntil = cc != null ? cc.getValidUntil() : null;
				if (validUntil != null) {
				    Calendar cal = Calendar.getInstance();
				    cal.setTime(validUntil);
				    cal.set(Calendar.DAY_OF_MONTH, 1);
				    cal.add(Calendar.MONTH, 1);
				    validUntil = cal.getTime();
				}
				
				if (ov.getOrderer().equals(dv) && cc != null) {
				    if (validUntil != null && validUntil.before(date)) {
				        Logger logger= Logger.getLogger("mainControl.Payment");
				        logger.info("Credit card for DNr " + dv.getId() + " expired");
				    } 
				    else 
				    if (!(cc.getCCNumber().length() > 0 && cc.getCCOrg().length() > 0 &&
				            ov.getPaymentMethodId().equals(OrderHeaderValue.PAYMENT_METHOD_CC))) {
				        Logger logger= Logger.getLogger("mainControl.Payment");
				        logger.info("Credit Card data for DNr " + dv.getId() + " not correct");
				    } 
				    else {
						Object[] item = (Object[]) vals.get(cc);
						Double val = item != null ? (Double) item[0] : null;
						if (val == null) {
							item = new Object[] {val = new Double (0), new LinkedList()};
							vals.put(cc, item);
						}
						item[0] =  new Double(val.doubleValue() + ov.getBrutto());
						((List) item[1]).add(ov.getOrderId());
						
						if (details.length() > 0) 
							details.append("+");
						details.append(ov.getOrderId());
				    }
				}
			}

			for (Iterator it2 = vals.keySet().iterator(); it2.hasNext(); ) {
				CreditCardValue cc = (CreditCardValue) it2.next();
				Object[] item = (Object[]) vals.get(cc);
				double val = ((Double)item[0]).doubleValue();

				Calendar cal = Calendar.getInstance();
				cal.setTime(cc.getValidUntil());
				String validUntil = format(cal.get(Calendar.YEAR) % 100, "00") + format(cal.get(Calendar.MONTH) + 1, "00");
				if (send(date, dv.getName(), cc.getCCOrg(), cc.getCCNumber().replace(" ", ""), validUntil, val, details.toString(), test))
					processedOrders.addAll((List) item[1]);
			}
		}
		return ret.toString();
	}
}