/*
 *
 * Created on Aug 1, 2005
 *
 * György Süveges
 * Etixpert Kft.
 * Copyright(c) 2005
 *
 */
package com.etixpert.evolution.gui.servlets.pageactions;


import javax.servlet.http.*;
import org.hibernate.*;
import java.util.*;
import java.sql.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

import com.etixpert.evolution.*;
import com.etixpert.evolution.gui.servlets.*;

import org.apache.commons.fileupload.*;
import java.io.*;
import org.apache.log4j.*;
import javax.activation.DataSource;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.jstl.fmt.*;

/**
 * @author Suveges Gyorgy
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class newsletter_send extends MultipartPageActionHandler {
     private int success=0;
     private boolean allowed;
     private Message mess;
     private List feedbacks= new ArrayList();


     public static class StringDataSource implements DataSource {
    	 private String str="";
    	 public StringDataSource(String str) {
    		 this.str = str;
    	 }

    	 public InputStream getInputStream() {
    		 return new ByteArrayInputStream(str.getBytes());
    	 }

    	 public OutputStream getOutputStream() {
    		 throw new UnsupportedOperationException("For string there is no outputStream");
    	 }

    	 public String getName() {
    		 return "report.txt";
    	 }

    	 public String getContentType() {
    		 return "text/html";
    	 }

     }


     /**
     *
     */
    private  class Sender implements Runnable {

    	private List dbEmails;
    	private String[] tos;


    	Sender(List dbEmails, String[] tos) {

    		this.dbEmails = dbEmails;
    		this.tos = tos;

    	}

    	public void run() {
    		feedbacks = new ArrayList();
        	for (int i=0; i<dbEmails.size(); i++)
        	    sendMessage(mess, dbEmails.get(i), feedbacks);

        	if (tos!=null && tos.length>0) {
        	    for (int i=0; i<tos.length; i++)
        	        sendMessage(mess,tos[i], feedbacks);

        	}

        	reply(mess, feedbacks);

    	}




    }
    public newsletter_send() {

        super();

      //  sentToResponse = true;
    }

    /* (non-Javadoc)
     * @see com.etixpert.evolution.gui.servlets.pageactions.PageActionHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */



    protected void handle(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        success=0;
        HttpSession session = request.getSession();

        Map jspMap = (Map) session.getAttribute("newsletter.jsp");


        String [] tos = new String[0];
        logger.debug("getting to addresses");
        String address =Tools.getVal(jspMap, "address", "");

        if (address!=null && address.length()>0)
            tos = getToAddresses(Tools.getVal(jspMap, "address",""));

        logger.debug("querying the email addresses");
        List l = getEmailAddresses(request);

        if (! allowed) {
            sentToResponse=true;
            response.sendRedirect("process/newsletter.jsp?saveState=nothing&link=process/newsletter.jsp");
            return;
        }

        logger.debug("Allowed to send");
        logger.info("Sending email to "+(l.size()+tos.length)+ " recipients");
        java.util.Properties props = System.getProperties();


        ResourceBundle bundle = ResourceBundle.getBundle("evolution");


        String smtp = bundle.getString("smtp");
        logger.info("Using smtp: "+smtp);
    	props.put("mail.smtp.host", smtp);
    	props.put("mail.transport.protocol", "smtp");
    	//props.put("mail.mime.charset", "UTF-8");

    	javax.mail.Session mailSession= javax.mail.Session.getDefaultInstance(props, null);
        mess =new MimeMessage(mailSession);


    	if (l.size()==0 && tos.length==0) {
    	    logger.error("No recipient given");
    	    session.setAttribute("sent", new ArrayList());
    	    session.setAttribute("sent_success", new Integer(0));

    	    return;
    	}



    	String from = Tools.getVal(jspMap, "from", "");
        try {
    	  mess.setFrom(new InternetAddress(from));
        } catch (Exception e) {
            logger.error("invalid from address");
            session.setAttribute("newsletter_error", "ungültige Eingabe beim Von: "+from);
            sentToResponse=true;
            response.sendRedirect("process/newsletter.jsp?saveState=nothing&link=process/newsletter.jsp");
            return;
        }
        session.removeAttribute("newsletter.jsp");
        String sub = NewsletterHelper.decodeEuro(Tools.getVal(jspMap, "subject","kein Betreff"));

        mess.setSubject(sub);
        MimeMultipart mp = new MimeMultipart();
        MimeBodyPart bp = new MimeBodyPart();


    	bp.setText(NewsletterHelper.decodeEuro(Tools.getVal(jspMap, "mail","")));
    	//bp.setText(Tools.getVal(jspMap, "mail",""));
    	bp.setDisposition(MimeBodyPart.INLINE);
    	mp.addBodyPart(bp);
    	//attachments

    	List files = (List) jspMap.get("files");
    	if (files!=null)
    	    for (int i=0; i<files.size(); i++) {
    	        FileItem item = (FileItem) files.get(i);
    	        MimeBodyPart bp1 = new MimeBodyPart();
    	        bp1.setDisposition(MimeBodyPart.ATTACHMENT);
    	        bp1.setDataHandler(new DataHandler(new FileItemDataSource(item)));
    	        String fn = Tools.getFileName(item.getName());
    	        //igy kell kodolni
    	       // String encoded_fn = new String(fn.getBytes(), "UTF-8");
    	        String efn = MimeUtility.encodeText(fn);
    	        bp1.setFileName(efn);

    	        mp.addBodyPart(bp1);

    	    }

    	mess.setContent(mp);

    	//request.getRequestDispatcher("../ShowMessage?msg=PleaseWait...").include(request,response);
    	//response.getOutputStream().flush();
    	//new thread

    	//logger.info("Sending emails in a separate thread");
    	Sender sender = new Sender(l, tos);
    	sender.run();


        session.setAttribute("sent", feedbacks);
        session.setAttribute("sent_success", new Integer(success));


    	//request.getRequestDispatcher("../sent_report.jsp").include(request, response);


    }
    public  void sendMessage(Message mess, Object to, List sent_reports) {
        String id="";
        String lastname="";
        String email=null;


            if (to instanceof PersistableObject) {
                PersistableObject po = (PersistableObject) to;
                id = po.getString("id","");
                lastname=po.getString("lastname","");
                email = po.getString("email","");
            } else
                email = (String) to;

            if (email==null || email.trim().equals("") || email.trim().length()<3) {
                sent_reports.add(new Object[]{id, email, lastname, new EvolutionException(LocaleSupport.getLocalizedMessage(pageContext,"INVALID_EMAIL_ADDRESS"))});
                logger.error("Invalid email address for distributor "+id+" (length<3)");
                return;
            }

         String[] tos= getToAddresses(email);
         for (int i=0; i<tos.length; i++) {
         try {
        	 tos[i]=tos[i].trim();
             logger.info("Sending mail to "+tos[i] +(!id.equals("")?" with id("+id+")":""));

             mess.setRecipient(Message.RecipientType.TO, new InternetAddress(tos[i]));
             Transport.send(mess);
             logger.info("Mail sent successfully");
             sent_reports.add(new Object[]{id, tos[i], lastname, null});
             success++;
         } catch (Exception e) {
            logger.error("Error sending mail to "+tos[i], e);
            sent_reports.add(new Object[]{id, tos[i], lastname, e});
         }
        }
      }

    private void reply(Message message, List feedbacks) {
      Message reply = null;
      try {
    	logger.info("Sending report to the sender of newsletter");
    	reply = message.reply(false);

    	logger.debug("1");
    	reply.setFrom(new InternetAddress("evolution@berggasse.dyndns.tv"));
    	logger.debug("2");
    	MimeMultipart mp = new MimeMultipart();
    	logger.debug("3");
        MimeBodyPart bp = new MimeBodyPart();

        logger.debug("4");
    	bp.setText(LocaleSupport.getLocalizedMessage(pageContext,"NEWSLETTER_SENT_SUCCESSFULLY", new Object[]{new Integer(success)}));
    	logger.debug("5");
    	bp.setDisposition(MimeBodyPart.INLINE);
    	logger.debug("6");
    	mp.addBodyPart(bp);
    	logger.debug("7");
    	//attachment
    	bp = new MimeBodyPart();
    	logger.debug("8");
	    bp.setDisposition(MimeBodyPart.ATTACHMENT);
	    logger.debug("9");
	    bp.setDataHandler(new DataHandler(new StringDataSource(generateReport(feedbacks))));
	    logger.debug("10");
	    bp.setFileName(LocaleSupport.getLocalizedMessage(pageContext,"REPLY_ATTACHMENT"));
	    logger.debug("11");
	    mp.addBodyPart(bp);
	    logger.debug("12");
    	reply.setContent(mp);
    	logger.debug("13");
    	Transport.send(reply);
    	logger.debug("14");
    	logger.info("Report sent");

      } catch (Exception e) {
    	  String to = "";
    	  try {
    		  to = reply.getRecipients(Message.RecipientType.TO)[0].toString();
    	  } catch(Exception e1) {
    		  logger.warn("There is no address to reply", e1);
    	  }
    	  e.printStackTrace();
    	  logger.error("Report message couldn't be send to "+to,e);
      }
    }

    private String generateReport(List feedBacks) {
    	StringBuffer sb = new StringBuffer();
    	sb.append("<HTML>\n");
    	sb.append("<head>\n");
    	sb.append(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-2\">");
    	sb.append("</head>\n");
    	sb.append("<BODY>\n");
    	sb.append("<table  border=\"0\">");
    	for (int i=0; i<feedBacks.size(); i++) {
            Object[] infos= (Object[]) feedBacks.get(i);
            sb.append("<tr><td>");
            sb.append(generateReportRow(infos)).append("\n");
            sb.append("</td></tr>");
    	}
    	sb.append("</table>");
    	sb.append("</BODY>\n");
    	sb.append("</HTML>");
    	return sb.toString();


    }

    private String generateReportRow(Object[] infos) {
    	 if (infos[3]==null)
    		 return "<small>"+LocaleSupport.getLocalizedMessage(pageContext, "EMAIL_SUCCESS", infos)+"</small>";
    	 else
    		 return "<small style=\"color:red;\">"+LocaleSupport.getLocalizedMessage(pageContext, "EMAIL_FAILED", infos)+"</small>";

    }

    public void addRecipient(Message mess, Object rec, List l) {
        String email=null;
        String id = "";
        String successMessage ="";
        if (rec instanceof PersistableObject) {
            PersistableObject po = (PersistableObject) rec;
            id = po.getString("id","-");
            String name = po.getString("firstname","")+" "+po.getString("lastname","");
            email = po.getString("email","");
            if (email==null || email.equals("")) {
                logger.warn("empty email address for distributor "+id);
                //l.add("FEHLER: Der Newsletter konnte an Distributor: "+id+" mit leerer Email-Adresse nicht verschickt werden ");
                l.add(new Object[]{id, email, new EvolutionException("keine Email Addresse angegeben")});
                return;
            }


        } else {
            email = (String) rec;
        }

        try {
          mess.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
          logger.info(email+" added successfully to recipients");
          l.add(new Object[]{id, email, null});
          success++;
        } catch (Exception e) {
            //l.add("FEHLER: Der Newsletter konnte an Distributor "+id+ " mit Email "+email+" verschickt werden");
            logger.error("Invalid email addresse "+email, e);
            l.add(new Object[]{id, email, e});
            return;
        }

        //l.add("der Newsletter wurde an Distributor "+id+"mit Email-Adresse" +
          //      email+" erfolgreich verschickt");

    }

    private List getEmailAddresses(HttpServletRequest request) throws Exception {
        HttpSession session = request.getSession();
        Map jspMap = (Map) session.getAttribute("newsletter.jsp");
        Transaction tx = null;
        try {


	        allowed=true;
	        String query = "select id, email, firstname, lastname from distributor where active and not deleted and newsletter";
	        //common things
	        //country
	        String[] countries = (String[]) jspMap.get("country");
	        if (countries!=null)
	            logger.info("country size: "+countries.length);
	        if (countries==null || countries.length==0) return new ArrayList();
	        
	        String countrySQL = Tools.arrayToSql("country_code", countries, true);
	        query+=" AND "+countrySQL;
	        
	        String[] partnerTypes = (String[]) jspMap.get("partner_type");
	        logger.info("partner_type size: "+(partnerTypes==null?0:partnerTypes.length));
	        if (partnerTypes==null || partnerTypes.length==0) return new ArrayList();
	        String partnerTypeSQL = Tools.arrayToSql("partner_type_id", partnerTypes, false);
	        query+=" AND "+partnerTypeSQL;
	        
	        String[] roles = (String[]) jspMap.get("role_id");
	        if (roles!=null)
	            logger.info("roles size: "+roles.length);
	        if (roles==null || roles.length==0) return new ArrayList();
	        String roleSQL = Tools.arrayToSql("level_id", roles, false);
	        query+=" AND "+roleSQL;


	        org.hibernate.Session hibernateSession = HibernateUtil.currentSession();
	        tx = hibernateSession.beginTransaction();
	        Connection conn = hibernateSession.connection();
	        //special
	        String right =NewsletterHelper.getRight(conn, session);

	        if (right.equalsIgnoreCase("x"))
	            throw new EvolutionException("Keine Berechtigung");


	        String id = Tools.getVal(jspMap, "cnr", (String) session.getAttribute("USER_LOGGED_ID"));
	        String downline = "id in (select * from st("+id+"))";
	        query+=" AND "+downline;

	        allowed = checkRight(conn, id,  (String) session.getAttribute("USER_LOGGED_ID"), right);
	        if (!allowed) {
	            logger.error("Invalid request from "+session.getAttribute("USER_LOGGED_ID")+". No right to select downline of "+id);
	            session.setAttribute("newsletter_error","Keine Berechtigung Newsletter an die Downline von Distributor " + id +" zu schicken");
	            tx.commit();
	            HibernateUtil.closeSession();
	            return new ArrayList();
	        }

	        ObjectSearch os = new ObjectSearch();
	        List l = os.search(conn, query);
	        tx.commit();
	        HibernateUtil.closeSession();
	        return l;

        } catch(Exception e) {
            if (tx!=null)
                 try {tx.rollback();} catch(Exception ex) {}
            HibernateUtil.closeSession();
            throw e;

        }

    }



    private boolean checkRight(Connection conn, String cnr, String user, String right) throws Exception {
        if (right.equalsIgnoreCase("x"))
            return false;
        else if (right.equalsIgnoreCase("a"))
            return true;
        else {
            ObjectSearch os = new ObjectSearch();

            String query = "select ("+cnr+" in (select * from "+right.toLowerCase()+"("+user+"))) as allowed";
            logger.debug("Query: "+query);
            List l = os.search(conn, query);
            PersistableObject allowed = (PersistableObject) l.get(0);
            Map m = allowed.getValues();

            if (allowed.get("allowed")==null) return false;
            return ((Boolean) allowed.get("allowed")).booleanValue();

        }
    }
    private String [] getToAddresses(String from) {
        if (from == null) return new String[0];
        String [] froms = from.split(";|,");
        return froms;

    }

}
