package com.etixpert.evolution.ws;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.sql.Connection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPMessage;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.apache.pdfbox.util.PDFMergerUtility;
import org.hibernate.Session;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.etixpert.evolution.HibernateUtil;
import com.etixpert.evolution.ObjectSearch;
import com.etixpert.evolution.PersistableObject;
import com.etixpert.evolution.value.order.OrderHeaderValue;

public class WsHelper {

	public static Logger logger;
	public static Map<String, String> countryCodes = null;
	
	//default domestic shipping
	public static String DEFAULT_AT_TO_AT = "30";
	//sometimes? we will need an option for it on the mask
	public static String DEFAULT_AT_TO_AT_EMS = "01";
	
	//Switzerland
	public static String DEFAULT_AT_TO_CH = "70";
	
	//Germany
	public static String DEFAULT_AT_TO_DE = "70";
	
	//default international shipping
	public static String DEFAULT_AT_TO_INT = "45";
	
	//sometimes? we will need an option for it on the mask
	public static String DEFAULT_AT_TO_INT_EMS = "46";
	
	public static String URL;
	public static String ORGUNITGUID;
	public static String ORGUNITID;
	
	static {
		ResourceBundle bundle = ResourceBundle.getBundle("evolution");
		URL = bundle.getString("labelcenter_url");
		ORGUNITGUID = bundle.getString("labelcenter_orgunitguid");
		ORGUNITID = bundle.getString("labelcenter_orgunitid");
	}
	
	
	static String xmlHeader = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:post=\"http://post.ondot.at\" xmlns:arr=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" xmlns:core=\"http://Core.Model\" xmlns:ser=\"http://schemas.microsoft.com/2003/10/Serialization/\">"
			+ "<soapenv:Header/><soapenv:Body>"
			+ "<post:ImportShipment>";
	static String xmlFooter = "</post:ImportShipment></soapenv:Body></soapenv:Envelope>";
	
	
	protected static Map<String, String> extractOrderData(Object orderId, Connection conn) throws Exception {
		Map<String, String> ret = new HashMap<String, String>();
		OrderHeaderValue ov = OrderHeaderValue.getById(conn, orderId, OrderHeaderValue.FLAG_NEED_ADDRESS |
				OrderHeaderValue.FLAG_NEED_DETAILS | OrderHeaderValue.FLAG_NEED_ORDERER_EMAIL);
		
		if (ov == null) {
			logger.info("There was an error getting order with id: " + orderId);
			return null;
		}
		if (!("Post".equals(ov.getShipping()) || "Paketdienst".equals(ov.getShipping()))) return null;
		
		String deliveryTitle = ov.getDeliveryTitle().trim();
		String deliveryName = ov.getDeliveryName().trim();
		
		if (deliveryTitle != null && !"".equals(deliveryTitle)) {
			if (deliveryName != null && !"".equals(deliveryName))
				deliveryName = deliveryTitle + " " + deliveryName;
		}
			
		
		String zipCode = ov.getDeliveryPostcode().trim();
		String street = ov.getDeliveryStreet();
		String countryCode = ov.getDeliveryCountryId();
		String city = ov.getDeliveryCity();
		String email = ov.getOrderer().getEmail();
		String company = ov.getOrderer().getCompany();
		String tel1 = "";
		String tel2 = "";
		//String company = ov.getOrderer().getCompany();
		
		String[] phones = ov.getOrderer().getPhone();
		
		if (phones != null) {
			if (phones.length > 0 )
				if (phones[0] != null)
					tel1 = phones[0];
			if (phones.length > 2)
				if (phones[2] != null)
					tel2 = phones[2];
		}
		
		String distrId = ov.getOrderer().getId() + "";
		String billId = ov.getBillId() + "";
		
		if (deliveryName != null)
			deliveryName = deliveryName.replaceAll("\n", "").replaceAll("\r", "");

		if (deliveryName != null) {
			deliveryName = deliveryName.replaceAll("&", "&amp;");
			//deliveryName = deliveryName.replaceAll("\\+", "&#43;");
		}
		
		if (company != null) {
			company = company.replaceAll("\n", "").replaceAll("\r", "");
		}

		if (company != null) {
			company = company.replaceAll("&", "&amp;");
		}
		
//		if (email != null)
//			email = email.replace("@", "&#64;");
		
		ret.put("deliveryName", deliveryName);
		ret.put("street", street);
		ret.put("city", city);
		ret.put("countryCode", countryCodes.get(countryCode));
		ret.put("zipCode", zipCode);
		ret.put("email", email);
		ret.put("tel1", tel1);
		ret.put("tel2", tel2);
		
		ret.put("distrId", distrId);
		ret.put("billId", billId);
		
		ret.put("company", company);
		
		Object payMetodId = ov.getPaymentMethodId();
		Integer payMethodIdInt = new Integer(-1);
		
		try {
			payMethodIdInt = new Integer(payMetodId + "");
		} catch (NumberFormatException nfe) {
		}
		
		ret.put("paymentMethodId", payMethodIdInt.toString());
		
		double brutto = ov.getBrutto();
		
		ret.put("brutto", "" + brutto);
		
		return ret;
	}
	
	protected static void fillCountryCodes(Connection conn) throws Exception {
		if (countryCodes == null) {
			countryCodes = new HashMap<String, String>();
			
			
			ObjectSearch os = new ObjectSearch("country", new String[] {"country_code"});
		
			List l = os.search(conn);
			
			for (int i=0; i<l.size(); i++) {
				PersistableObject po = (PersistableObject)l.get(i);
				String cc = po.getString("country_code", "");
				String cpc = po.getString("country_post_code", "");
				
				if (cc.length() > 2)
					cc = cc.substring(0, 2);
				
				if ("F".equals(cc)) cc = "FR";
				if ("H".equals(cc)) cc = "HU";
				if ("S".equals(cc)) cc = "SE";
				
				countryCodes.put(cpc,  cc);
				
			}
		}
		
		
		
	}
	
	protected static String generateXmlContent(Object orderId) throws Exception {
        Session session = HibernateUtil.currentSession();
        //Transaction tx = session.beginTransaction();
        Connection conn = session.connection();
        fillCountryCodes(conn);
        
		StringBuilder sb = new StringBuilder("");
		Map<String, String> data = extractOrderData(orderId, conn);
		if (data == null) return null;
		sb.append(constructRow(data.get("deliveryName"), data.get("company"), data.get("zipCode"), data.get("street"), data.get("city"), 
				data.get("countryCode"), data.get("tel1"), data.get("tel2"), data.get("email"), data.get("paymentMethodId"), data.get("brutto"), data.get("distrId"), orderId + "", data.get("billId")));
		
		return sb.toString();
	}
	
	
	public static void callPostWS(Object[] orderIds, Logger alogger, HttpServletResponse res) throws Exception {
		SOAPConnection connection = null;
		
		logger = alogger;
		
		List<ByteArrayInputStream> pdfArrays = new LinkedList<ByteArrayInputStream>();
		
		try {
			SOAPConnectionFactory sfc = SOAPConnectionFactory.newInstance();
			connection = sfc.createConnection();

			
			
			for (int i = 0; i < orderIds.length; i++) {

				StringBuilder sb = new StringBuilder();
				sb.append(xmlHeader);
				String content = generateXmlContent(orderIds[i]);
				if (content == null) continue;
				sb.append(content);
				sb.append(xmlFooter);
				logger.info("Sending SOAP request:");
				logger.info(sb.toString());
				InputStream is = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
				SOAPMessage request = MessageFactory.newInstance().createMessage(null, is);

//				System.out.println("\n Soap Request:\n");
//				request.writeTo(System.out);
//				System.out.println();

				MimeHeaders headers = request.getMimeHeaders();
				headers.addHeader("SOAPAction",  "http://post.ondot.at/IShippingService/ImportShipment");
				request.saveChanges();
				
				URL endpoint = new URL(URL);
				//URL endpoint = new URL("http://plctest.post.at/DataService/Post.Webservice/ShippingService.svc");

				SOAPMessage response = connection.call(request, endpoint);
				
				logger.info("SOAP response: ");
				ByteArrayOutputStream os = new ByteArrayOutputStream();
				response.writeTo(os);
				logger.info(os.toString());				

				logger.info("1");
				
				NodeList nodelist = response.getSOAPBody().getChildNodes();
				
				logger.info("2");
				
				String base64 = null;
				for (int k = 0; k < nodelist.getLength(); k++) {
					logger.info("3");
					Node node = nodelist.item(k);
					logger.info("3a");
					//System.out.println(node.getNodeName());
					if ("ImportShipmentResponse".equals(node.getNodeName())) {
						logger.info("4");
						NodeList childNodeList = node.getChildNodes();
						for (int j = 0; j < childNodeList.getLength(); j++) {
							logger.info("5");
							Node childNode = childNodeList.item(j);
							if ("pdfData".equals(childNode.getNodeName())) {
								base64 = childNode.getFirstChild().getNodeValue();
							}
						}
					}
				}
				
				if (base64!=null) {
					logger.info("6");
					pdfArrays.add(new ByteArrayInputStream(Base64.decodeBase64(base64.getBytes())));
					logger.info("7");
				}
				
				os.close();
				is.close();
				
			}

			connection.close();

			
		} catch (Exception ex) {
			logger.info("Error occured during sending SOAP request: ");
			logger.info(ex.getMessage());
			ex.printStackTrace();
		} finally {
			try {
				connection.close();
			} catch (Exception ignored) {}
		}

		PDFMergerUtility ut = new PDFMergerUtility();
		
		for (int i = 0; i < pdfArrays.size(); i++) {
			ByteArrayInputStream stream = pdfArrays.get(i);
			ut.addSource(stream);
		}

		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ut.setDestinationStream(bos);
		ut.mergeDocuments();
		
		
		res.setContentType("application/octet-stream");
		res.setHeader("Content-Disposition","attachment; filename=adressen.pdf"); 
		OutputStream os = res.getOutputStream();
		os.write(bos.toByteArray());
	}
	
	protected static String constructRow(String deliveryName, String company, String zipCode, String street, String city, String countryCode, String tel1, String tel2, String email, 
			String paymentMethodId, String brutto, String distrId, String orderId, String billId) throws Exception {
		StringBuilder sb = new StringBuilder();
		String productId = DEFAULT_AT_TO_AT;

		if ("CH".equals(countryCode))
			productId = DEFAULT_AT_TO_CH;
		else if ("AT".equals(countryCode))
			productId = DEFAULT_AT_TO_AT;
		else if ("DE".equals(countryCode))
			productId = DEFAULT_AT_TO_DE;
		else productId = DEFAULT_AT_TO_INT;
		
		sb.append("<post:row>");
		sb.append("<post:ClientID>21000983</post:ClientID>");
		sb.append("<post:CustomDataBit1>false</post:CustomDataBit1>");
		
		String phones = "";
		
		if (tel1 != null && !"".equals(tel1))
			phones = tel1;
		
		if (tel2 != null && !"".equals(tel2))
			phones = "".equals(phones) ? (tel2) : (phones + ", " + tel2);
		
		if (!"".equals(phones))
			sb.append("<post:DeliveryInstruction>" + phones + "</post:DeliveryInstruction>");
		
		sb.append("<post:DeliveryServiceThirdPartyID>" + productId + "</post:DeliveryServiceThirdPartyID>");
		
		if ("3".equals(paymentMethodId) || "15".equals(paymentMethodId)) {
			sb.append("<post:FeatureList>");
			sb.append("<post:AdditionalInformationRow>");
			sb.append("<post:ThirdPartyID>006</post:ThirdPartyID>");
			sb.append("<post:Value1>" + brutto + "</post:Value1>");
			sb.append("<post:Value2>EUR</post:Value2>");
			sb.append("<post:Value3>AT071200050575610800|BKAUATWW</post:Value3>");
			sb.append("<post:Value4>KN:" + distrId + ",RN:" + billId + "</post:Value4>");
			sb.append("</post:AdditionalInformationRow>");
			sb.append("</post:FeatureList>");
		}
		
		sb.append("<post:OURecipientAddress>");
		sb.append("<post:AddressLine1>" + street + "</post:AddressLine1>");
		sb.append("<post:City>" + city + "</post:City>");
		sb.append("<post:CountryID>" + countryCode + "</post:CountryID>"); //AT
		sb.append("<post:Email>" + email + "</post:Email>");
		
		if (company == null || "".equals(company)) {
			sb.append("<post:Name1>" + deliveryName + "</post:Name1>");			
		} else {
			sb.append("<post:Name1>" + company + "</post:Name1>");			
			sb.append("<post:Name2>" + deliveryName + "</post:Name2>");

		}
		sb.append("<post:PostalCode>" + zipCode + "</post:PostalCode>");
		//sb.append("<post:AddressLine2/>");
		//sb.append("<post:HouseNumber>1</post:HouseNumber>");
		sb.append("<post:Tel1>" + tel1 + "</post:Tel1>");
		sb.append("<post:Tel2>" + tel2 + "</post:Tel2>");
		sb.append("</post:OURecipientAddress>");
		sb.append("<post:OUShipperAddress>");
		sb.append("<post:AddressLine1>Hausergasse 28</post:AddressLine1>");
		sb.append("<post:City>Villach</post:City>");
		sb.append("<post:CountryID>AT</post:CountryID>");
		sb.append("<post:Name1>EVOLUTION Handels- gesellschaft m.b.H.</post:Name1>");
		sb.append("<post:PostalCode>9500</post:PostalCode>");
		sb.append("</post:OUShipperAddress>");
		sb.append("<post:OrgUnitGuid>"+ORGUNITGUID+"</post:OrgUnitGuid>");
		sb.append("<post:OrgUnitID>"+ORGUNITID+"</post:OrgUnitID>");
		sb.append("<post:PrinterObject>");
		sb.append("<post:LabelFormatID>100x200</post:LabelFormatID>");
		sb.append("<post:LanguageID>pdf</post:LanguageID>");
		sb.append("<post:PaperLayoutID>A5</post:PaperLayoutID>");
		sb.append("</post:PrinterObject>");
		sb.append("</post:row>");
		
		return sb.toString();
		
	}
	
	

}
