package eu.dnetlib.functionality.recommendation.app;

import eu.dnetlib.domain.ActionType;
import eu.dnetlib.domain.EPR;
import eu.dnetlib.domain.enabling.Notification;
import eu.dnetlib.domain.functionality.Community;
import eu.dnetlib.domain.functionality.UserProfile;
import eu.dnetlib.domain.functionality.UserProfileSearchCriteria;
import gr.uoa.di.driver.enabling.ISLookUp;
import gr.uoa.di.driver.enabling.issn.NotificationListener;
import gr.uoa.di.driver.enabling.resultset.ResultSet;
import gr.uoa.di.driver.enabling.resultset.ResultSetFactory;
import gr.uoa.di.driver.xml.CommunityXmlConverter;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.xml.bind.JAXBException;

import org.apache.log4j.Logger;

public class CommunityNotificationManager implements NotificationListener {

    private String communityUpdatedMessage = "Community has changed";
    private String communityDeletedMessage = "Community has deleted";
    private String communityMailSubject = "Driver info about communities";
    private int recommendationDaysToExpire = 10;
    private Logger logger = Logger.getLogger( this.getClass() );
    private CommunityXmlConverter xmlConverter = null;
    private RecommendationServiceImpl recommendationService;
    private Community com = null;
    private ISLookUp<UserProfile> userProfilesLookup;
    private ResultSetFactory rsFactory = null;
    
    public CommunityNotificationManager() {
        try {
            xmlConverter = new CommunityXmlConverter();
        } catch ( javax.xml.bind.JAXBException e ) {
            logger.error( e );
            xmlConverter = null;
        }
    }

    @Override
    public void processNotification( Notification notification ) {
        logger.debug( "notification has arrived and being processed. Notification topic: " + notification.getTopic() + "\n" );

        if ( xmlConverter == null ) {
            logger.error( "Can not process notification, xml converter is not working" );
            return;
        }

        String message = notification.getMessage();

        try {
            com = xmlConverter.XmlToObject( message );
            if( notification.getActionType().equals( ActionType.UPDATE)) {
                communityUpdated( com );
            } else if ( notification.getActionType().equals( ActionType.DELETE )) {
                communityDeleted( com );
            }
        } catch ( JAXBException e ) {
            logger.error( "Unable to convert message to object" );
            logger.error( e );
            return;
        }
    }

    @SuppressWarnings("deprecation")
	public void communityUpdated( Community com ) {
        logger.debug( "New community has been updated \n" );
        try {
            Set<String> userIds = new HashSet<String>();
            Set<String> communityIds = new HashSet<String>();
            communityIds.add( com.getResourceId() );
            UserProfileSearchCriteria uSearchCriteria = new UserProfileSearchCriteria();
            uSearchCriteria.setBelongsToCommunity( com.getResourceId() );

            EPR epr = getUserProfilesLookup().search( uSearchCriteria );
            ResultSet<UserProfile> rs = rsFactory.createResultSet( epr, UserProfile.class );

            Date expireDate = new Date();
            expireDate.setDate( expireDate.getDate() + getRecommendationDaysToExpire() );

            for ( int i = 1; i <= rs.size(); i += 10 ) {
                List<UserProfile> profiles = rs.get( i, i + 10 );
                for ( UserProfile profile : profiles ) {
                    userIds.add( profile.getResourceId() );
                    logger.debug( "User email = " + profile.getEmail() + "===" );
                    if ( profile.getRecommendationSendEmail() ) {
                        logger.debug( "Sending email " );
                        recommendationService.sendMail( "alexm@di.uoa.gr", com.getName() + " " + getCommunityUpdatedMessage() + " from " + this.recommendationService.getWebServiceUrl(), getCommunityMailSubject() );
                        recommendationService.sendMail( profile.getEmail(), com.getName() + " " + getCommunityUpdatedMessage(), getCommunityMailSubject() );
                    } else {
                        logger.debug( "User " + profile.getEmail() + " does not wants emails!!!!" );
                    }
                    recommendationService.generateUserRecommendation( 0, true,
                            profile.getResourceId(),
                            "",
                            com.getName() + " " + getCommunityUpdatedMessage().replaceAll( "---", com.getName() ),
                            new Date(),
                            expireDate );
                }
            }

        } catch ( Exception e ) {
            logger.error( "Could not process notification " + e );
            e.printStackTrace();
        }
    }

    @SuppressWarnings("deprecation")
	public void communityDeleted( Community com ) {
        logger.debug( "New community has been deleted \n" );

        try {
            Set<String> userIds = new HashSet<String>();
            Set<String> communityIds = new HashSet<String>();
            communityIds.add( com.getResourceId() );
            UserProfileSearchCriteria uSearchCriteria = new UserProfileSearchCriteria();
            uSearchCriteria.setBelongsToCommunity( com.getResourceId() );
            EPR epr = getUserProfilesLookup().search( uSearchCriteria );
            ResultSet<UserProfile> rs = rsFactory.createResultSet( epr, UserProfile.class );

            for ( int i = 1; i <= rs.size(); i += 10 ) {
                List<UserProfile> profiles = rs.get( i , i + 10 );
                for ( UserProfile profile : profiles ) {
                    userIds.add( profile.getResourceId() );
                    logger.debug( "User email = " + profile.getEmail() + "" );
                    if ( profile.getRecommendationSendEmail() ) {
                        logger.debug( "Sending email " );
                        recommendationService.sendMail( "alexm@di.uoa.gr", com.getName() + " " + getCommunityDeletedMessage().replaceAll( "---", com.getName() ), getCommunityMailSubject() );
                        recommendationService.sendMail( profile.getEmail(), com.getName() + " " + getCommunityDeletedMessage().replaceAll( "---", com.getName() ), getCommunityMailSubject() );
                    } else {
                        logger.debug( "User " + profile.getEmail() + " does not wants emails!!!!" );
                    }
                }
            }

            Date expireDate = new Date();
            expireDate.setDate( expireDate.getDate() + getRecommendationDaysToExpire() );

            logger.debug( "SO i am gonna generate a recommendation now" );
            recommendationService.generateCommunityRecommendationForUsers( 0, true, "",
                    getCommunityDeletedMessage().replaceAll( "---", com.getName() ), new Date(), expireDate, communityIds, userIds );
            logger.debug( "Recommendation abou community deletion has been generated" );

        } catch ( Exception e ) {
            logger.error( "Could not process notification " + e );
            e.printStackTrace();
        }
    }

    /**
     * @return the communityUpdatedMessage
     */
    public String getCommunityUpdatedMessage() {
        return communityUpdatedMessage;
    }

    /**
     * @param communityUpdatedMessage the communityUpdatedMessage to set
     */
    public void setCommunityUpdatedMessage( String communityUpdatedMessage ) {
        this.communityUpdatedMessage = communityUpdatedMessage;
    }

    /**
     * @return the communityDeletedMessage
     */
    public String getCommunityDeletedMessage() {
        return communityDeletedMessage;
    }

    /**
     * @param communityDeletedMessage the communityDeletedMessage to set
     */
    public void setCommunityDeletedMessage( String communityDeletedMessage ) {
        this.communityDeletedMessage = communityDeletedMessage;
    }

    public String getCommunityMailSubject() {
        return communityMailSubject;
    }

    public void setCommunityMailSubject( String aCommunitySubject ) {
        communityMailSubject = aCommunitySubject;
    }

    /**
     * @return the userProfilesLookup
     */
    public ISLookUp<UserProfile> getUserProfilesLookup() {
        return userProfilesLookup;
    }

    /**
     * @param userProfilesLookup the userProfilesLookup to set
     */
    public void setUserProfilesLookup( ISLookUp<UserProfile> userProfilesLookup ) {
        this.userProfilesLookup = userProfilesLookup;
    }

    /**
     * @return the recommendationDaysToExpire
     */
    public int getRecommendationDaysToExpire() {
        return recommendationDaysToExpire;
    }

    /**
     * @param recommendationDaysToExpire the recommendationDaysToExpire to set
     */
    public void setRecommendationDaysToExpire( int recommendationDaysToExpire ) {
        this.recommendationDaysToExpire = recommendationDaysToExpire;
    }

	public ResultSetFactory getRsFactory() {
		return rsFactory;
	}

	public void setRsFactory(ResultSetFactory rsFactory) {
		this.rsFactory = rsFactory;
	}
}
