package weikfield;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.search.FlagTerm;

import org.apache.log4j.Logger;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.transform.AliasToEntityMapResultTransformer;
import org.json.simple.JSONObject;

import com.sun.mail.util.BASE64DecoderStream;
 

public class ReadMailAttachments {
	private static SessionFactory factory;
	static Logger logger = Logger.getLogger("LOG"); 

    private String saveDirectory;
 

    public void setSaveDirectory(String dir) {
        this.saveDirectory = dir;
    }
 
    /**
     * Downloads new messages and saves attachments to disk if any.
     * @param host
     * @param port
     * @param userName
     * @param password
     */
    public void downloadEmailAttachments(org.hibernate.Session hibernate_session,String host,String port,String userName, String password,String ignore_subject_key_words) {
        Properties properties = new Properties();
        // server setting
        properties.put("mail.imaps.host", host);
        properties.put("mail.imaps.port", port);
 
        // SSL setting
        properties.setProperty("mail.imaps.socketFactory.class",
                "javax.net.ssl.SSLSocketFactory");
        properties.setProperty("mail.imaps.socketFactory.fallback", "true");
        properties.setProperty("mail.imaps.socketFactory.port",
                String.valueOf(port));
 
        Session session = Session.getDefaultInstance(properties);
 
        try {
            // connects to the message store
            Store store = session.getStore("imaps");
            store.connect(userName, password);
 
            // opens the inbox folder
            Folder folderInbox = store.getFolder("INBOX");
            folderInbox.open(Folder.READ_WRITE);
            
            
            System.out.println("getUnreadMessageCount..."+folderInbox.getUnreadMessageCount());
            int unreadMsgCount=folderInbox.getUnreadMessageCount();
            
            if(unreadMsgCount==0)
            	logger.info("No Unread Message Found...Count=="+folderInbox.getUnreadMessageCount());
            
 
            // fetches new messages from server
            Message[] arrayMessages = folderInbox.search(
                    new FlagTerm(new Flags(Flags.Flag.SEEN), false));
            System.out.println("arrayMessages.length.."+arrayMessages.length);
        
            for (int i = 0; i < arrayMessages.length; i++) {
            	
                Message message = arrayMessages[i];
                folderInbox.setFlags(new Message[] {message}, new Flags(Flags.Flag.SEEN), true);
              
                
                Address[] fromAddress = message.getFrom();
               
                
                System.out.println("axz..."+InternetAddress.toString(message.getFrom()));

                String from = fromAddress[0].toString();
                String subject = message.getSubject();
                String sentDate = message.getSentDate().toString();
                String recDate= message.getReceivedDate().toString();
                
                System.out.println("aaaa...");
                int ignoreFlag=0;
                String[] keyWordArr = new String[100];
               
              
                keyWordArr=ignore_subject_key_words.split(",");
                
                
                for(int j=0;j<=keyWordArr.length-1;j++)
            	{
            		if(subject.toLowerCase().contains(keyWordArr[j].toLowerCase()))
            		{
            			ignoreFlag=1;
            		}
            	}
                
                System.out.println("bbb...");
                int messageID=message.getMessageNumber();
                logger.info("Message Reading Started..."+messageID);
               
                
                logger.info(" From: " + from+" Subject: " + subject+" Sent Date: " + sentDate+"  Recv Date: " + recDate);
               
               
                // print out details of each message
                System.out.println("\t Message ID: " + message.getMessageNumber());
                System.out.println("\t From: " + from);
                System.out.println("\t Subject: " + subject);
                System.out.println("\t Sent Date: " + sentDate);
                System.out.println("\t Recv Date: " + recDate);
                
                String formattedRecvDate=GetFormattedDate(recDate);
                String formattedSentDate=GetFormattedDate(sentDate);
                
             
               
                if(ignoreFlag==1)
                {
                	logger.info("Not a PO.Ignore Flag Set.Skipping the record..."+messageID+"==Subject===>"+subject);
                	continue;
                	
                }
               
                 
                
                String contentType = message.getContentType();
               
                String messageContent = "";
 
                // store attachment file name, separated by comma
                String attachFiles = "";
                String fileName="";
                String origfileName="";
                
                System.out.println("ddd..."+contentType);
                if (contentType.contains("multipart") || contentType.contains("multipart/MIXED;")) {
                	
                	System.out.println("asasa");
                    // content may contain attachments
                    Multipart multiPart = (Multipart) message.getContent();
                    int numberOfParts = multiPart.getCount();
                    for (int partCount = 0; partCount < numberOfParts; partCount++) {
                    	 attachFiles = "";
                           fileName="";
                           origfileName="";
                         
                        MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(partCount);
                        if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
                            // this part is attachment
                             fileName = part.getFileName();
                              origfileName=fileName;
                             
                             Pattern pt = Pattern.compile("[^a-zA-Z0-9._]");
                             Matcher match= pt.matcher(fileName);
                             while(match.find())
                             {
                                 String s= match.group();
                                 fileName=fileName.replaceAll("\\"+s, "_");
                             }
                             
                             System.out.println("fileName......"+fileName);
                             System.out.println("origfileName......"+origfileName);
                             String extension_arr[]=origfileName.trim().split("\\.");
                             String extension=extension_arr[extension_arr.length-1];
                             extension=extension.toLowerCase();
                             int randomNum = ThreadLocalRandom.current().nextInt(0, 1000 + 1);
                             
                             if(origfileName.length()>15 || origfileName.contains("UTF"))
                             {
                            	 fileName=Integer.toString(randomNum)+".pdf";
                            	 extension="pdf";
                             }
                             
                             
                             System.out.println("extension..."+extension);
                             if(!extension.equals("pdf") && !extension.equals("txt") && !extension.equals("xls") && !extension.equals("xlsx") && !extension.equals("csv"))
                             {
                            	 logger.info("Invalid Extension.Skipping the record..."+messageID+"==Subject===>"+subject);
                            	 continue;
                             }
                             
                            

                             System.out.println("randomNum...."+randomNum);
                             fileName=formattedRecvDate.split(" ")[0]+"_"+messageID+"_"+randomNum+"_"+fileName;
                             
                            
                             
                             System.out.println("fileName...."+fileName);
                             int dupCount=GetDupCount(hibernate_session,messageID,formattedRecvDate,fileName);
                             if(dupCount>0)
                             {
                             	logger.info("Duplicate Record Found.Skipping the record..."+messageID+"==Subject===>"+subject);
                             	continue;
                             }
                            attachFiles += fileName + ", ";
                            
                           // part.saveFile("C:\\tarka\\"+fileName+"");
                            
                            part.saveFile(saveDirectory + File.separator + fileName);
                            InsertMailDetailsToTable(hibernate_session,messageID,subject,formattedRecvDate,formattedSentDate,fileName,from);
                            logger.info("Insertion Successfull.Attachment Downloaded..!!"+"File Name "+fileName+" From: " + from+" Subject: " + subject+" Sent Date: " + sentDate+"  Recv Date: " + recDate);
                           
                        } else {
                            // this part may be the message content
                            messageContent = part.getContent().toString();
                            
                           
                        }
                    }
 
                   
                    
                   
                } else if (contentType.contains("text/plain")
                        || contentType.contains("text/html")) {
                    Object content = message.getContent();
                   
                    if (content != null) {
                        messageContent = content.toString();
                    }
                    
                }
                else if(contentType.contains("APPLICATION/OCTET-STREAM"))
                {
                	 System.out.println("qwwww....q`");
                	 BASE64DecoderStream bs = (BASE64DecoderStream) message.getContent();
                	
                   
                     ByteArrayOutputStream out = new ByteArrayOutputStream();
                     int c;
                     while ((c = bs.read()) != -1) {
                         out.write(c);
                     }
                     fileName= message.getFileName();
                     byte[] bytes = out.toByteArray();
                     
                     Pattern pt = Pattern.compile("[^a-zA-Z0-9._]");
                     Matcher match= pt.matcher(fileName);
                     while(match.find())
                     {
                         String s= match.group();
                         fileName=fileName.replaceAll("\\"+s, "_");
                     }
                     String extension_arr[]= message.getFileName().trim().split("\\.");
                     String extension=extension_arr[extension_arr.length-1];
                     extension=extension.toLowerCase();
                     System.out.println("extension..."+extension);
                     if(!extension.equals("pdf") && !extension.equals("txt") && !extension.equals("xls") && !extension.equals("xlsx") && !extension.equals("csv"))
                     {
                    	 logger.info("Invalid Extension.Skipping the record..."+messageID+"==Subject===>"+subject);
                    	 continue;
                     }
                     
                     int randomNum = ThreadLocalRandom.current().nextInt(0, 1000 + 1);

                     System.out.println("randomNum...."+randomNum);
                     fileName=formattedRecvDate.split(" ")[0]+"_"+messageID+"_"+randomNum+"_"+fileName;
                     System.out.println("fileName...."+fileName);
                     int dupCount=GetDupCount(hibernate_session,messageID,formattedRecvDate,fileName);
                     if(dupCount>0)
                     {
                     	logger.info("Duplicate Record Found.Skipping the record..."+messageID+"==Subject===>"+subject);
                     	continue;
                     }
                    attachFiles += fileName + ", ";
                    
                    Path path = Paths.get(saveDirectory+fileName);
                    Files.write(path, bytes);
                    InsertMailDetailsToTable(hibernate_session,messageID,subject,formattedRecvDate,formattedSentDate,fileName,from);
                    logger.info("Insertion Successfull.Attachment Downloaded..!!"+"File Name "+fileName+" From: " + from+" Subject: " + subject+" Sent Date: " + sentDate+"  Recv Date: " + recDate);
                   

                }
            }
            // disconnect
            folderInbox.close(false);
            store.close();
        } catch (NoSuchProviderException ex) {
        	logger.info("No provider for IMAP."+ex.getMessage());
            System.out.println("No provider for IMAP.");
            ex.printStackTrace();
        } catch (MessagingException ex) {
        	logger.info("Could not connect to the message store"+ex.getMessage());
            System.out.println("Could not connect to the message store");
            ex.printStackTrace();
        } catch (IOException ex) {
        	logger.info("File Not Found Exception."+ex.getMessage());
            ex.printStackTrace();
        }
        catch (Exception ex) {
        	logger.info("Exception..."+ex.getMessage());
            ex.printStackTrace();
        }
    }
 

	private void InsertMailDetailsToTable(org.hibernate.Session hibernate_session, int messageNumber,String subject, String recDate, String sentDate, String fileName,String from) {
		
		try {
			subject=subject.replaceAll("'", "");
			subject=subject.replaceAll("\"", "");
			
			String sql=" insert into po_mails(message_id,subject,received_date,sent_date,file_name,created_date,from_email) values "
					+ "('"+messageNumber+"','"+subject+"','"+recDate+"','"+sentDate+"','"+fileName+"',now(),'"+from+"') ";
		
			Transaction tx=hibernate_session.beginTransaction();
			System.out.println(sql);
			Query q = hibernate_session.createSQLQuery(sql);
			q.executeUpdate(); 
			tx.commit();
		} catch (HibernateException e) {
			logger.info("Exception in Insertion..."+e.getMessage());
			e.printStackTrace();
		} 
		
	}
	
	private String GetFormattedDate(String dateToBeformatted)
	{
		String formattedDate="";
		 try {
			String month=dateToBeformatted.trim().split(" ")[1];
			 String dd=dateToBeformatted.trim().split(" ")[2];
			 String yyyy=dateToBeformatted.trim().split(" ")[5];
			 String time=dateToBeformatted.trim().split(" ")[3];
			 
			 String DateString = month+dd+yyyy+time;
			 
			 DateFormat originalFormat  = new SimpleDateFormat("MMMddyyyyhh:mm:ss", Locale.ENGLISH);              
			 DateFormat targetFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			 Date date = originalFormat .parse(DateString);
			  formattedDate = targetFormat.format(date);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 return formattedDate;
	}

	

	private static JSONObject GetMailSetupDetails(org.hibernate.Session hibernate_session)
	{
		List<Map<String,Object>> query_data_obj= new ArrayList<Map<String,Object>>();
		JSONObject return_obj=new JSONObject();
		try
		{
			
			String Sql = " select  HOST,port_address,user_name,PASSWORD,ignore_subject_key_words "
						+ " from mail_pdf_read_set_up  order by 1 limit 1 "	;
			System.out.println("GetMailSetupDetails..."+Sql);
			SQLQuery q = hibernate_session.createSQLQuery(Sql)
					.addScalar("HOST", Hibernate.STRING)
					.addScalar("port_address", Hibernate.STRING)
					.addScalar("user_name", Hibernate.STRING)
					.addScalar("ignore_subject_key_words", Hibernate.STRING)
					.addScalar("PASSWORD", Hibernate.STRING);

			if(q.list().size()>0)
			{
				q.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
				query_data_obj=q.list();  
				for(Map map2:query_data_obj)
				{
					return_obj.put("HOST",map2.get("HOST").toString().trim());
					return_obj.put("port_address",map2.get("port_address").toString().trim());
					return_obj.put("user_name",map2.get("user_name").toString().trim());
					return_obj.put("PASSWORD",map2.get("PASSWORD").toString().trim());
					return_obj.put("ignore_subject_key_words",map2.get("ignore_subject_key_words").toString().trim());
					
				}
				
			}
		}
		
	
		catch (HibernateException ex) {
			Throwable cause = ex.getCause();
			if (cause instanceof SQLException) { }
		}

		return return_obj;
	}

	
	private static int GetDupCount(org.hibernate.Session hibernate_session,int messageID,String formattedRecvDate, String fileName)
	{
		List<Map<String,Object>> query_data_obj= new ArrayList<Map<String,Object>>();
		int dupCount=0;
		try
		{
			
			String Sql = " SELECT COUNT(1)as dupCount FROM po_mails "
					+ "WHERE message_id='"+messageID+"' AND "
					+ "DATE_FORMAT('"+formattedRecvDate+"','%Y-%m-%d')=DATE_FORMAT(received_date,'%Y-%m-%d') and file_name='"+fileName+"'" ;
			System.out.println("GetPDFStorePath..."+Sql);
			SQLQuery q = hibernate_session.createSQLQuery(Sql)
					.addScalar("dupCount", Hibernate.INTEGER);
			if(q.list().size()>0)
			{
				q.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
				query_data_obj=q.list();  
				for(Map map2:query_data_obj)
				{
					dupCount=(int)map2.get("dupCount");
					
				}
				
			}
		}
		
	
		catch (HibernateException ex) {
			Throwable cause = ex.getCause();
			if (cause instanceof SQLException) { }
		}

		return dupCount;
	}
	
	private static String GetPDFStorePath(org.hibernate.Session hibernate_session)
	{
		List<Map<String,Object>> query_data_obj= new ArrayList<Map<String,Object>>();
		String pdf_path="";
		try
		{
			
			String Sql = " select  pdf_path from company_setup "	;
			System.out.println("GetPDFStorePath..."+Sql);
			SQLQuery q = hibernate_session.createSQLQuery(Sql)
					.addScalar("pdf_path", Hibernate.STRING);
			if(q.list().size()>0)
			{
				q.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
				query_data_obj=q.list();  
				for(Map map2:query_data_obj)
				{
					 pdf_path=map2.get("pdf_path").toString().trim();
					
				}
				
			}
		}
		
	
		catch (HibernateException ex) {
			Throwable cause = ex.getCause();
			if (cause instanceof SQLException) { }
		}

		return pdf_path;
	}
    public static void main(String[] args) {
    	

        try {
			String config_file_s=System.getProperty("user.dir")+"/hibernate.weikfield.cfg.xml";
			File file = new File(config_file_s);
			Configuration configuration = new Configuration().configure(file);
			
		   factory = configuration.buildSessionFactory();
		   org.hibernate.Session hibernate_session = factory.openSession();
		   JSONObject mailSetupDetails =GetMailSetupDetails(hibernate_session);
		   
		  String host = mailSetupDetails.get("HOST").toString();
		  String port = mailSetupDetails.get("port_address").toString();
		  String userName =mailSetupDetails.get("user_name").toString();
		  String password =mailSetupDetails.get("PASSWORD").toString();
		  String ignore_subject_key_words =mailSetupDetails.get("ignore_subject_key_words").toString();
		  
		  String saveDirectory=GetPDFStorePath(hibernate_session);
		  //String saveDirectory = "C:/tarka/Attachment";
 
			ReadMailAttachments receiver = new ReadMailAttachments();
			receiver.setSaveDirectory(saveDirectory);
			receiver.downloadEmailAttachments(hibernate_session,host, port, userName, password,ignore_subject_key_words);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
 
    }
}