/*
 * Engine.java
 * Created on 2005.05.29.
 * Author:  Laszlo Felfoldi, Etixpert GmbH 
 * mail:    laszlo.felfoldi@etixpert.com
 */
package com.etixpert.evolution.app.order;

import java.io.BufferedReader;
import java.io.FileReader;
import java.net.MalformedURLException;
import java.sql.Connection;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jdom2.Document;
import org.jdom2.Element;

import com.etixpert.evolution.app.utils.XMLUtils;
import com.etixpert.evolution.gui.servlets.SortingMap;
import com.etixpert.evolution.value.DistributorValue;
import com.etixpert.evolution.value.order.BankAccountValue;
import com.etixpert.evolution.value.order.CreditCardValue;
import com.etixpert.evolution.value.order.OrderHeaderValue;

public class Payment {
	private static DateFormat dateformat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN);
	private static  String xslt;
	
	private static String string(Object src) {
		return src != null ? "" + src : "";
	}	
	
	private static void generateOrderListXML(Map environment, List orders, Set processedOrderIds, Element to) {
		Map distributorEntries = new Hashtable();
		Map creditcardEntries  = new Hashtable();
		Map bankEntries        = new Hashtable();
		
		for (Iterator it = orders.iterator(); it.hasNext(); ) {
			OrderHeaderValue oh = (OrderHeaderValue) it.next();
			if (processedOrderIds.contains(oh.getOrderId())) {
				// distributor entry
				DistributorValue dv = oh.getOrderer();
				Element de = (Element) distributorEntries.get(dv);
				if (de == null) {
					// add distributor entry
					de = new Element("distributor");
					de.setAttribute("Id", string(dv.getId()));
					de.setAttribute("Name", string(dv.getName()));
					de.setAttribute("Info", string(dv.getAddress()));
					to.addContent(de);
					distributorEntries.put(dv, de);
					creditcardEntries. put(dv, new Hashtable());
					bankEntries.       put(dv, new Hashtable());
				}

				// creaditcard entry
				Map creditCardEntry = (Map) creditcardEntries.get(dv);
				CreditCardValue ccv = oh.getCreditCard();
				Element cce = null; 
				if (ccv != null) {
					cce = (Element) creditCardEntry.get(ccv); 
					if (cce == null) {
						// add creditcard entry
						cce = new Element("creditcard");
						cce.setAttribute("CreditcartNumber", ccv.getCCNumber());
						cce.setAttribute("Organization", ccv.getCCOrg());
						Calendar cal = Calendar.getInstance();
						cal.setTime(ccv.getValidUntil());
						String validUntil = ("" + (cal.get(Calendar.MONTH) + 101)).substring(1) + "/" + 
											("" + cal.get(Calendar.YEAR)).substring(2);
						cce.setAttribute("ValidUntil", validUntil);
						de.addContent(cce);
						creditCardEntry.put(ccv, cce);
					}
				}
				
				// bank entry
				Map bankEntry = (Map) bankEntries.get(dv);
				BankAccountValue bav = oh.getBankAccount();
				Element bae = null;
				if (bav != null) {
					bae = (Element) bankEntry.get(bav);
					if (bae == null) {
						// add creditcard entry
						bae = new Element("bank");
						bae.setAttribute("AccountNumber", bav.getAccountNumber());
						bae.setAttribute("BankName", bav.getBankName());
						bae.setAttribute("BankCode", bav.getBankCode());
						de.addContent(bae);
						bankEntry.put(bav, bae);
					}
				}
				
				// order entry
				Element oe = new Element ("order");
				oe.setAttribute("Id", string(oh.getOrderId()==null ? "-" : oh.getOrderId()));
				oe.setAttribute("Date", dateformat.format(oh.getOrderDate()));
				oe.setAttribute("Val", "" + oh.getBrutto());
				
				if (oh.getPaymentMethodId().equals(OrderHeaderValue.PAYMENT_METHOD_BANK)) {
					bae.addContent(oe);
				} 
				else if (oh.getPaymentMethodId().equals(OrderHeaderValue.PAYMENT_METHOD_CC)) {
					cce.addContent(oe);
				}
			}
		}
	}
		
	public static byte[] generateOrderList(Map environment, List orders, Set processedOrderIds, String header, String sDate, String path) {
	    Logger logger = Logger.getLogger("mainControl.Payment");
	    logger.info("size of proccessedids: "+processedOrderIds.size());
	    if (processedOrderIds.size() > 0) {
			try {
				// read the xslt if it has not been done yet
				if (xslt == null) {
				    logger.info("setting up xslt");
		    		StringBuffer sb = new StringBuffer();
					BufferedReader reader = new BufferedReader(new FileReader(path+"/xsl/pdf/orderlist.xsl"));
					for (String line = null; (line = reader.readLine()) != null; sb.append(line));
					xslt = sb.toString();
					logger.info("xslt set up");
		    	}
		
				// get its xml representation 
				Document doc = new Document();
				Element root = new Element("orders");
				doc.setRootElement(root);
				logger.info("generating xml list");
				generateOrderListXML(environment, orders, processedOrderIds, doc.getRootElement());
				logger.info("xml list generated");
				Element eHeader = new Element("header");
				eHeader.setAttribute("title", header);
				eHeader.setAttribute("subtitle", sDate);
				root.addContent(eHeader);
				
				return XMLUtils.transformPDF(doc, xslt);
		
			} catch (Exception e) {
				e.printStackTrace(System.err);
				logger.error("Error in orderlist generation",e);
			}
    	}
    	return null;
	}
	
	public static Object[] generate(Connection con, Date date, Set orderIds, Set firstSepaTransactions, String path) {
		Logger logger = Logger.getLogger("mainControl.Payment");
		
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd.HHmmss");
	    SimpleDateFormat sdf2 = new SimpleDateFormat("dd.MM.yy HH:mm:ss");
	    String sDate = sdf.format(date);
	    
	    Object[] ret = new Object[15];
		
		List orders = new LinkedList();
		Set processedOrderIds = new HashSet();
		logger.info("getting all distributors");
		Map  environment = DistributorValue.getAll(con, DistributorValue.FLAG_NEED_NOTHING);
		Map  dlist = new Hashtable();
		
		//logger.info("making the order structure from ids");
		// make the orders structure from the ids
		for (Iterator it = orderIds.iterator(); it.hasNext(); ) {
			try {
				OrderHeaderValue oh = OrderHeaderValue.getById(con, it.next(), environment, OrderHeaderValue.FLAG_NEED_DETAILS);
				logger.info("adding order: " + oh.getOrderId());
				orders.add(oh);
				
				dlist.put(oh.getOrderer().getId(), oh.getOrderer());
			} catch (Exception e) {logger.error("Error making structure", e);}
		}

		//logger.info("create dlist of old and new distributor");
		// create dlist of old and new distributors
		Map oldDistributors = new Hashtable();
		Map newDistributors = new Hashtable();
		for (Iterator it = dlist.keySet().iterator(); it.hasNext(); ) {
			Object id = it.next();
			Integer intId = null;
			if (id instanceof String)  intId = new Integer((String) id);
			if (id instanceof Integer) intId = (Integer) id;
			if (intId != null) {
				// old distributors have values less than 2000 in the last four digits
				if (intId.intValue() % 10000 < 2000) {
					oldDistributors.put(id, environment.get(id));
				} else {
					newDistributors.put(id, environment.get(id));
				}
			}
		}
		SortingMap sortingMap = new SortingMap();
		
		for (Iterator it = dlist.values().iterator(); it.hasNext(); ) {
			DistributorValue val = (DistributorValue)it.next();
			sortingMap.put(val.getName(), val);
		}
		
		
		List sortedDistList = sortingMap.getSortedValues();
		
		//logger.info("dlist created. Creating edifacts");
		// generate edifact files
		
		// call BA SEPA first transaction
		SEPA sepa = new SEPA("BKAUATWW", "AT071200050575610800", "AT07ZZZ00000036185", "urn:iso:std:iso:20022:tech:xsd:pain.008.001.02");
		logger.info("generating SEPA for BA first transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[0] = sepa.generate(date, true, "43", orders, sortedDistList, processedOrderIds, firstSepaTransactions, false);
		logger.info("generated SEPA for BA first transaction. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[1] = generateOrderList(environment, orders, processedOrderIds, 
				"SEPA Bankeinzeug heute (first)", "SEPA_F_BA_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for BA SEPA first transactions");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();
		
		// call BA SEPA recurring transaction
		logger.info("generating SEPA for BA recurring transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[2] = sepa.generate(date, false, "43", orders, sortedDistList, processedOrderIds, null, false);
		logger.info("generated SEPA for BA recurring transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[3] = generateOrderList(environment, orders, processedOrderIds, 
				"SEPA Bankeinzeug heute (recurring)", "SEPA_R_BA_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for BA SEPA recurring transactions");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();

		// call sepa first transaction
		/*sepa = new SEPA("HYVEDEMMXXX", "DE07700202700665876594", "AT07ZZZ00000036185", "urn:iso:std:iso:20022:tech:xsd:pain.008.003.02");
		logger.info("generating SEPA for german first transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[8] = sepa.generate(date, true, "49", orders, sortedDistList, processedOrderIds, firstSepaTransactions, true);
		logger.info("generated SEPA for germans. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[9] = generateOrderList(environment, orders, processedOrderIds, 
				"SEPA Bankeinzeug heute", "SEPA_F_HVB_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for germans with SEPA first transactions");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();
		*/
		
		sepa = new SEPA("BKAUATWW", "AT071200050575610800", "AT07ZZZ00000036185", "urn:iso:std:iso:20022:tech:xsd:pain.008.001.02");
		logger.info("generating SEPA for german first transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[8] = sepa.generate(date, true, "49", orders, sortedDistList, processedOrderIds, firstSepaTransactions, false);
		logger.info("generated SEPA for germans. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[9] = generateOrderList(environment, orders, processedOrderIds, 
				"SEPA Bankeinzeug heute", "SEPA_F_BA_DE_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for germans with SEPA first transactions");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();
		
		// call sepa recurring transaction
		/*logger.info("generating SEPA for german recurring transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[10] = sepa.generate(date, false, "49", orders, sortedDistList, processedOrderIds, null, true);
		logger.info("generated SEPA for germans. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[11] = generateOrderList(environment, orders, processedOrderIds, 
				"SEPA Bankeinzeug heute", "SEPA_R_HVB_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for HVB SEPA recurring transactions");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();
*/
		
		logger.info("generating SEPA for german recurring transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[10] = sepa.generate(date, false, "49", orders, sortedDistList, processedOrderIds, null, false);
		logger.info("generated SEPA for germans recurring transactions. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[11] = generateOrderList(environment, orders, processedOrderIds, 
				"SEPA Bankeinzeug heute", "SEPA_R_BA_DE_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for BA SEPA recurring transactions");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();
		
		/*
		// call hvb
		HVB hvb = new HVB("70020270", "665876594");
		logger.info("generating hvb for germans. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[12] = hvb.generate(date, orders, dlist, processedOrderIds);
		logger.info("generating hvb for germans. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		ret[13] = generateOrderList(environment, orders, processedOrderIds, 
		        "HVB Bankeinzeug heute", "HVB_" + sDate + "_EVOLUTION.dat", path);
		logger.info("generated pdf list for HVB");
		
		orderIds.removeAll(processedOrderIds);
		logger.info("processedids sub from orderids. Size of orderIDs "+orderIds.size()+ " orders: "+orders.size());
		
		processedOrderIds.clear();
		*/
		
		logger.info("call creditcards. Size of orderIDs "+orderIds.size()+ "orders: "+orders.size());
		// call creditcarte
		try {
			CreditCard creditcard = new CreditCard("https://www.mPAY24.com/bin/at/etpv4");
			boolean test = true;
			try {
				test = !ResourceBundle.getBundle("evolution" ).getString("creditcard_processing").equals("production");
			} catch (MissingResourceException e) {}
			
			creditcard.generate(date, orders, sortedDistList, processedOrderIds, test);
			ret[14] = generateOrderList(environment, orders, processedOrderIds, 
			        "Kreditkarten-Transaktion am", "CC_" + sdf2.format(date) + "_EVOLUTION", path);
			orderIds.removeAll(processedOrderIds);
			processedOrderIds.clear();

		} catch (MalformedURLException e) {
			e.printStackTrace(System.err);
		}
		
		logger.info("creditcards called. Size of orderIDs "+orderIds.size()+ "orders: "+orders.size());
		return ret;
	}
}
