/*
 * 
 */
package com.bankaudit.service;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bankaudit.constants.BankAuditConstant;
import com.bankaudit.dao.MaintHolidayDao;
import com.bankaudit.dto.DataTableResponse;
import com.bankaudit.model.MaintHoliday;
import com.bankaudit.model.MaintHolidayHst;
import com.bankaudit.model.MaintHolidayWrk;
import com.bankaudit.util.ServiceStatus;


/**
 * The Class {@link MaintHolidayServiceImpl} Implements the business logic
 * method.
 *
 * @author amit.patel
 * @version 1.0
 */
@Service("maintHolidayService")
@Transactional("transactionManager")
public class MaintHolidayServiceImpl implements MaintHolidayService {

	/**
	 * The maint holiday dao is autowired and make methods available from dao
	 * layer .
	 */
	@Autowired
	MaintHolidayDao maintHolidayDao;
	
	/**
	 * The business date service is autowired and make methods available from
	 * dao layer .
	 */
	@Autowired
	BusinessDateService businessDateService;
	
	/* (non-Javadoc)
	 * @see com.bankaudit.service.MaintHolidayService#createMaintHoliday(com.bankaudit.model.MaintHoliday)
	 */
	@Override
	public void createMaintHoliday(MaintHoliday maintHoliday)throws Exception{
		
		if(maintHoliday.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_UNAUTH)){
			MaintHolidayWrk maintHolidayWrk=new MaintHolidayWrk(); 
			BeanUtils.copyProperties(maintHoliday, maintHolidayWrk);
			maintHolidayDao.save(maintHolidayWrk);
			
		}else if (maintHoliday.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_AUTH)) {
			maintHolidayDao.save(maintHoliday);
		}else{
			throw new Exception("invalid status");
		}
	
	}

	/* (non-Javadoc)
	 * @see com.bankaudit.service.MaintHolidayService#updateMaintHoliday(com.bankaudit.model.MaintHoliday)
	 */
	@Override
	public void updateMaintHoliday(MaintHoliday maintHoliday) {

		if(!maintHoliday.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_AUTH)){
			if(maintHoliday.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_UNAUTH)
					|| maintHoliday.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_MOD)){
				maintHoliday.setMakerTimestamp(businessDateService.getBusinessDateTimestampByLegalEntityCode(maintHoliday.getLegalEntityCode()));
			}
			// get Db object and save into the history
			MaintHoliday maintHolidayDb=
					getMaintHoliday(maintHoliday.getLegalEntityCode(), BankAuditConstant.STATUS_UNAUTH);
			if(maintHolidayDb!=null){
				maintHolidayDao.flushSession();
				MaintHolidayHst maintHolidayHst=new MaintHolidayHst();
				BeanUtils.copyProperties(maintHolidayDb, maintHolidayHst);
				maintHolidayDao.save(maintHolidayHst);
			}
			//delete the existing object rfrom work  
			// delete the existing work maintEntityAuditSubgroupMapping 
			MaintHolidayWrk maintHolidayWrk=new MaintHolidayWrk();
			BeanUtils.copyProperties(maintHoliday, maintHolidayWrk);
			maintHolidayDao.flushSession();
			
			
			maintHolidayDao.saveOrUpdate(maintHolidayWrk);
			
		}else{
			// get Db object and save into the history
			MaintHoliday maintHolidayDb=
					getMaintHoliday(maintHoliday.getLegalEntityCode(), BankAuditConstant.STATUS_AUTH);
			if(maintHolidayDb!=null){
				MaintHolidayHst maintHolidayHst=new MaintHolidayHst();
				BeanUtils.copyProperties(maintHolidayDb, maintHolidayHst);
				maintHolidayDao.save(maintHolidayHst);
			}
			//delete the existing object from both the tables  
			maintHolidayDao.deleteMaintHoliday(maintHoliday.getId(), BankAuditConstant.STATUS_UNAUTH);
			maintHolidayDao.flushSession();
			maintHoliday.setCheckerTimestamp(maintHoliday.getBusinessdateTimestamp());
			// save again 
			maintHolidayDao.saveOrUpdate(maintHoliday);
			 
		}
		
	}

	/* (non-Javadoc)
	 * @see com.bankaudit.service.MaintHolidayService#getMaintHolidays(java.lang.Integer, java.lang.String, java.lang.Integer, java.lang.String, java.lang.Integer, java.lang.Integer)
	 */
	@Override
	public DataTableResponse getMaintHolidays(Integer legalEntityCodeStr,String search, Integer orderColumn, String orderDirection, Integer page,
			Integer size) {
		
		return maintHolidayDao.getMaintHolidays( legalEntityCodeStr, search,  orderColumn,  orderDirection,  page,
				 size);
	}

	/* (non-Javadoc)
	 * @see com.bankaudit.service.MaintHolidayService#getMaintHoliday(java.lang.Integer, java.lang.String)
	 */
	@Override
	public MaintHoliday getMaintHoliday(Integer id,String status) {
		Map<String,Object> properties=new HashMap<String, Object >();
		properties.put("id",id);
		
		if(!BankAuditConstant.STATUS_AUTH.equalsIgnoreCase(status)){
		
			MaintHoliday maintHoliday=null;
			
			MaintHolidayWrk maintHolidayWrk=(MaintHolidayWrk)maintHolidayDao.getUniqueEntityByMatchingProperties(MaintHolidayWrk.class, properties);	
			
			if(maintHolidayWrk!=null){
				maintHoliday=new MaintHoliday();
				BeanUtils.copyProperties(maintHolidayWrk, maintHoliday);
			}
		
			return maintHoliday;
			
		}else {
			return (MaintHoliday)maintHolidayDao.getUniqueEntityByMatchingProperties(MaintHoliday.class, properties);		
		}
		
	}
	
	/* (non-Javadoc)
	 * @see com.bankaudit.service.MaintHolidayService#validateHoliday(com.bankaudit.model.MaintHoliday)
	 */
	@Override
	public ServiceStatus validateHoliday(MaintHoliday maintHoliday) {
						
		return (ServiceStatus)maintHolidayDao.validateHoliday(maintHoliday);
	}
	
	@Override
	public void deleteHolidayByID(Integer legalEntityCode, Integer id, String userId) {
		maintHolidayDao.deleteMaintHoliday(id, BankAuditConstant.STATUS_REJ);
	}
		
	/**************  Start -- Get holidays -> add the number of holidays between two date  **************/
	@Override
	public Integer getNumberOfBusinessDaysBetweenDates(Integer legalEntityCode,String unitCode,Date StDate,Date EnDate){
		
		Map<String,List<String>>  weeklyAndFortnightlyHoliday  = maintHolidayDao.getWeeklyAndFortnightlyHoliday(legalEntityCode, unitCode);		 
		 
		Calendar startDateCal = new GregorianCalendar();
		startDateCal.setTime(StDate);
		
		Calendar endDateCal =new GregorianCalendar();
		endDateCal.setTime(EnDate); 
		//endDateCal.add(Calendar.DATE, -1);
		
		int daysCount = 0;
		return getTotalHolidaysCount(legalEntityCode, unitCode, startDateCal, endDateCal, weeklyAndFortnightlyHoliday,  daysCount ,0 );		 
		
	}
	
	public int getTotalHolidaysCount(Integer legalEntityCode,String unitCode, Calendar startDateCal , Calendar endDateCal, 
			Map<String,List<String>>  weeklyAndFortnightlyHoliday,  int daysCount, int normalHolidayCountVal ){
						
		Calendar startDateCalInit = new GregorianCalendar() ;
		startDateCalInit.setTime(startDateCal.getTime());
		 		 
		List<String> weekly = weeklyAndFortnightlyHoliday.get("W");
		List<String> fortnightly = weeklyAndFortnightlyHoliday.get("F");
		
		while(startDateCal.before(endDateCal)  || startDateCal.equals(endDateCal) ){
			if(normalHolidayCountVal==0){
				daysCount++;
				if(weekly!=null && weekly.contains(String.valueOf(startDateCal.get(Calendar.DAY_OF_WEEK)))){
					endDateCal.add(Calendar.DATE, 1); 
				}
				else if(fortnightly !=null && (startDateCal.get(Calendar.WEEK_OF_MONTH)==2 || startDateCal.get(Calendar.WEEK_OF_MONTH)==4) 
						&& fortnightly.contains(String.valueOf(startDateCal.get(Calendar.DAY_OF_WEEK)))){
					endDateCal.add(Calendar.DATE, 1); 
				} 			
				startDateCal.add(Calendar.DATE, 1);
			}else{
				if(weekly!=null && weekly.contains(String.valueOf(startDateCal.get(Calendar.DAY_OF_WEEK)))){
					endDateCal.add(Calendar.DATE, 1); 
					daysCount++;
				}
				else if(fortnightly !=null && (startDateCal.get(Calendar.WEEK_OF_MONTH)==2 || startDateCal.get(Calendar.WEEK_OF_MONTH)==4) 
						&& fortnightly.contains(String.valueOf(startDateCal.get(Calendar.DAY_OF_WEEK)))){
					endDateCal.add(Calendar.DATE, 1); 
					daysCount++;
				} 			
				startDateCal.add(Calendar.DATE, 1);
			}
		} 	
		//daysCount = daysCount - normalHolidayCountVal;
		 
		List<Date> holidayList = maintHolidayDao.getNormalHolidaysCount(legalEntityCode, unitCode, startDateCalInit.getTime() , endDateCal.getTime());		
		int normalHolidayCount = holidayList.size();
		if( normalHolidayCount>0){
			//Check if Normal holidays falls under weekly or fortnightly holidays
			for (Date date : holidayList) {
				Calendar normalHolidayCal =  new GregorianCalendar();
				normalHolidayCal.setTime(date);
				if(weekly!=null && weekly.contains(String.valueOf(normalHolidayCal.get(Calendar.DAY_OF_WEEK)))){
					normalHolidayCount--;
				}
				else if(fortnightly !=null && (normalHolidayCal.get(Calendar.WEEK_OF_MONTH)==2 || normalHolidayCal.get(Calendar.WEEK_OF_MONTH)==4) 
						&& fortnightly.contains(String.valueOf(normalHolidayCal.get(Calendar.DAY_OF_WEEK)))){
					normalHolidayCount--;
				}
			}
			daysCount = daysCount + normalHolidayCount;
			 
			//Derived new start and end date
			endDateCal.add(Calendar.DATE, normalHolidayCount);			 
			//startDateCal.add(Calendar.DATE, 1); 
			return  getTotalHolidaysCount(legalEntityCode, unitCode, startDateCal ,  endDateCal, weeklyAndFortnightlyHoliday, daysCount, normalHolidayCount);			
		}
		
		return daysCount;
	}
	/**************   End -- Get holidays -> add the number of holidays between two date  **************/
}
