gt: 						Date startDateMsProject = taskElement.getStart();
context: /**
   * Genji Scrum Tool and Issue Tracker
   * Copyright (C) 2015 Steinbeis GmbH & Co. KG Task Management Solutions
  
   * <a href="http://www.trackplus.com">Genji Scrum Tool</a>
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program. If not, see <http://www.gnu.org/licenses/>.
   */
  
  /* $Id:$ */
  
  package com.aurel.track.exchange.msProject.importer;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  import java.util.SortedMap;
  import java.util.TreeMap;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import net.sf.mpxj.ProjectFile;
  import net.sf.mpxj.ProjectHeader;
  import net.sf.mpxj.Relation;
  import net.sf.mpxj.Resource;
  import net.sf.mpxj.ResourceAssignment;
  import net.sf.mpxj.Task;
  import net.sf.mpxj.TimeUnit;
  
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  import org.w3c.dom.Element;
  
  import com.aurel.track.accessControl.AccessBeans;
  import com.aurel.track.admin.customize.lists.systemOption.StatusBL;
  import com.aurel.track.admin.customize.role.FieldsRestrictionsToRoleBL;
  import com.aurel.track.admin.customize.treeConfig.field.FieldBL;
  import com.aurel.track.admin.project.ProjectBL;
  import com.aurel.track.admin.project.ProjectConfigBL;
  import com.aurel.track.admin.project.release.ReleaseBL;
  import com.aurel.track.beans.ILabelBean;
  import com.aurel.track.beans.TActualEstimatedBudgetBean;
  import com.aurel.track.beans.TBudgetBean;
  import com.aurel.track.beans.TBudgetBean.BUDGET_TYPE;
  import com.aurel.track.beans.TComputedValuesBean;
  import com.aurel.track.beans.TCostBean;
  import com.aurel.track.beans.TFieldBean;
  import com.aurel.track.beans.TFieldConfigBean;
  import com.aurel.track.beans.TMSProjectTaskBean;
  import com.aurel.track.beans.TPersonBean;
  import com.aurel.track.beans.TProjectBean;
  import com.aurel.track.beans.TReleaseBean;
  import com.aurel.track.beans.TStateBean;
  import com.aurel.track.beans.TWorkItemBean;
  import com.aurel.track.beans.TWorkItemLinkBean;
  import com.aurel.track.dao.DAOFactory;
  import com.aurel.track.dao.MsProjectTaskDAO;
  import com.aurel.track.errors.ErrorData;
  import com.aurel.track.errors.ErrorHandlerJSONAdapter;
  import com.aurel.track.errors.ErrorParameter;
  import com.aurel.track.exchange.ImportCounts;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeBL;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDOMHelper;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean.ASSIGNMENT_ELEMENTS;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean.COMMON_ELEMENTS;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean.LAG_FORMAT;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean.PREDECESSOR_CROSS_PROJECT;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean.PROJECT_ELEMENTS;
  import com.aurel.track.exchange.msProject.exchange.MsProjectExchangeDataStoreBean.TASK_TYPE;
  import com.aurel.track.fieldType.constants.BooleanFields;
  import com.aurel.track.fieldType.constants.SystemFields;
  import com.aurel.track.fieldType.runtime.base.FieldsManagerRT;
  import com.aurel.track.fieldType.runtime.base.LookupContainer;
  import com.aurel.track.fieldType.runtime.base.WorkItemContext;
  import com.aurel.track.fieldType.runtime.bl.FieldRuntimeBL;
  import com.aurel.track.fieldType.runtime.system.select.SystemManagerRT;
  import com.aurel.track.item.ItemBL;
  import com.aurel.track.item.budgetCost.AccountingBL;
  import com.aurel.track.item.budgetCost.AccountingBL.TIMEUNITS;
  import com.aurel.track.item.budgetCost.BudgetBL;
  import com.aurel.track.item.budgetCost.ComputedValueBL;
  import com.aurel.track.item.budgetCost.ExpenseBL;
  import com.aurel.track.item.budgetCost.RemainingPlanBL;
  import com.aurel.track.item.history.HistoryLoaderBL;
  import com.aurel.track.item.history.HistoryLoaderBL.LONG_TEXT_TYPE;
  import com.aurel.track.item.history.HistoryValues;
  import com.aurel.track.item.link.ItemLinkBL;
  import com.aurel.track.linkType.LinkTypeBL;
  import com.aurel.track.linkType.MsProjectLinkType;
  import com.aurel.track.prop.ApplicationBean;
  import com.aurel.track.report.execute.ComputedValuesLoaderBL;
  import com.aurel.track.resources.LocalizationKeyPrefixes;
  import com.aurel.track.resources.LocalizeUtil;
  import com.aurel.track.screen.SystemActions;
  import com.aurel.track.screen.item.bl.runtime.ScreenRuntimeBL;
  import com.aurel.track.util.DateTimeUtils;
  import com.aurel.track.util.EqualUtils;
  import com.aurel.track.util.GeneralUtils;
  import com.aurel.track.util.IntegerStringBean;
  import com.aurel.track.util.PropertiesHelper;
  
  public class MsProjectImporterBL {
  	private static final Logger LOGGER = LogManager.getLogger(MsProjectImporterBL.class);
  	private static MsProjectTaskDAO msProjectTaskDAO = DAOFactory.getFactory().getMsProjectTaskDAO();
  	
  	public interface EXCHANGE_DIRECTION {
  		static public int IMPORT = 1;
  		static public int EXPORT = 2;
  	}
  	
  	public interface CONFLICT_RESOLUTION {
  		static public Boolean OVERWRITE = Boolean.valueOf(true);
  		static public Boolean LEAVE = Boolean.valueOf(false);
  	}
  	
  	public interface DELETE_RESOLUTION {
  		static public Boolean LEAVE = Boolean.valueOf(false);
  		static public Boolean DELETE = Boolean.valueOf(true);
  	}
  	
  	public interface UNDELETE_RESOLUTION {
  		static public Boolean LEAVE = Boolean.valueOf(false);
  		static public Boolean UNDELETE = Boolean.valueOf(true);
  	}
  	
  	public interface CONFLICT_MAP_ENTRY {
  		public static Integer UID = Integer.valueOf(0);
  		public static Integer WORKITEM_ID = Integer.valueOf(1);
  		public static Integer SYNOPSIS = Integer.valueOf(2);
  		public static Integer MS_PROJECT_VALUE = Integer.valueOf(3);
  		public static Integer TRACKPLUS_VALUE = Integer.valueOf(4);
  		public static Integer ITEM_ID = Integer.valueOf(5);
  	}
  			
  	public interface CONFLICT_ON {
  		public static final int BUDGET = 1;
  		public static final int STARTDATE = 2;
  		public static final int ENDDATE = 3;
  		public static final int DELETED = 4;
  		public static final int UNDELETED = 5;
  	}
  	
  	/**
  	 * Prepares the resources match
  	 * @return
  	 */
  	static String prepareResourceMatch(MsProjectExchangeDataStoreBean msProjectExchangeDataStoreBean, Locale locale) {
  		//there are some resources in the msProject file
  		List<TPersonBean> personsList = MSProjectResourceMappingBL.getTrackPlusPersons();
  		List<IntegerStringBean> trackPlusPersons = new ArrayList<IntegerStringBean>();
  		//Map<String, Integer> trackLoginNameToPersonIDMap = new HashMap<String, Integer>();
  		Map<String, ILabelBean> trackPersonFullnameToPersonBeanMap = new HashMap<String, ILabelBean>();
  		for (TPersonBean trackPlusPerson : personsList) {
  			String fullName = trackPlusPerson.getName();
  			trackPersonFullnameToPersonBeanMap.put(fullName, trackPlusPerson);
  			trackPlusPersons.add(new IntegerStringBean(
  					trackPlusPerson.getLoginName() + " (" + fullName + ")", trackPlusPerson.getObjectID()));
  		}
  		trackPlusPersons.add(0, new IntegerStringBean(LocalizeUtil.getLocalizedTextFromApplicationResources(
  				"admin.actions.importMSProject.lbl.addResourceAsNewUser", locale),	MSProjectResourceMappingBL.ADD_AS_NEW));
  		Map<Integer, Integer> resourceUIDToPersonIDMap = msProjectExchangeDataStoreBean.getResourceUIDToPersonIDMap();
  		//first rendering try to match by similar names		
  		SortedMap<String, Integer> resourceNameToResourceUIDMap=MsProjectImporterBL.getResourceNameToResourceUIDMap(msProjectExchangeDataStoreBean.getWorkResources());
  		if (resourceUIDToPersonIDMap==null) {
  			//no previous import -> no previous resource to person mapping stored in the database
  			resourceUIDToPersonIDMap = new HashMap<Integer, Integer>();
  		}
  		Iterator<String> itrResourceNameToUID = resourceNameToResourceUIDMap.keySet().iterator();
  		while (itrResourceNameToUID.hasNext()) {
  			String name = itrResourceNameToUID.next();
  			Integer UID = resourceNameToResourceUIDMap.get(name);
  			if (resourceUIDToPersonIDMap.get(UID)==null) {
  				Integer personID =new SystemManagerRT().getLookupIDByLabel(SystemFields.INTEGER_PERSON, 
  						null, null, locale, name, trackPersonFullnameToPersonBeanMap, null);
  				if (personID==null) {
  					resourceUIDToPersonIDMap.put(UID, MSProjectResourceMappingBL.ADD_AS_NEW);
  				} else {
  					resourceUIDToPersonIDMap.put(UID, personID);
  				}
  			}
  		}
  		return MsProjectImportJSON.getResourceMappingJSON(trackPlusPersons, resourceNameToResourceUIDMap, resourceUIDToPersonIDMap);
  	}
  	
  	/**
  	 * Imports the tasks from the msProjectImporterBean into the trackPlus database
  	 * @param msProjectExchangeDataStoreBean
  	 * @param resourceUIDsToPersonIDs
  	 * @param errorsMap
  	 * @param workItemContextsMap
  	 * @return
  	 */
  	public static SortedMap<Integer, List<ErrorData>> validateAndPrepareTasks(
  			MsProjectExchangeDataStoreBean msProjectExchangeDataStoreBean,
  			Map<Integer, TWorkItemBean> existingTrackPlusWorkItems,
  			Map<Integer, TMSProjectTaskBean> existingTrackPlusTasks,
  			Map<Integer, WorkItemContext> workItemContextsMap) {
  		
  		SortedMap<Integer, List<ErrorData>> errorsMap = new TreeMap<Integer, List<ErrorData>>();
  		Integer issueTypeID = msProjectExchangeDataStoreBean.getIssueType();
  		Integer projectID = msProjectExchangeDataStoreBean.getProjectID();
  		TPersonBean personBean = msProjectExchangeDataStoreBean.getPersonBean();
  		Integer personID = personBean.getObjectID();
  		Locale locale = msProjectExchangeDataStoreBean.getLocale();
  		Set<Integer> presentFieldIDs = getPresentFields(projectID, issueTypeID);
  		Map<Integer, TFieldConfigBean> fieldConfigsMap = FieldRuntimeBL.getLocalizedFieldConfigs(
  				presentFieldIDs, projectID, issueTypeID, locale);
  		
  		Map<Integer, TWorkItemBean> workItemBeanMap = prepareWorkItemBeans(msProjectExchangeDataStoreBean, 
  				existingTrackPlusTasks, existingTrackPlusWorkItems, fieldConfigsMap);
  		Map<String, Object> fieldSettings = FieldRuntimeBL.getFieldSettings(fieldConfigsMap);
  		//build the workItemContext for each workItemBean and validate the workItemBeans before save
  		Iterator<Integer> itrUID = workItemBeanMap.keySet().iterator();
  		while (itrUID.hasNext()) {
  			Integer UID = itrUID.next();
  			TWorkItemBean workItemBean = workItemBeanMap.get(UID);
  			WorkItemContext workItemContext = FieldsManagerRT.createImportContext(workItemBean,
  					presentFieldIDs, personID, locale,
  					fieldConfigsMap, fieldSettings);
  			workItemContextsMap.put(UID, workItemContext);
  			List<ErrorData> validationErrorList = FieldsManagerRT.validate(workItemBean, workItemContext, false, false, null, false, false);
  			if (validationErrorList!=null && !validationErrorList.isEmpty()) {
  				errorsMap.put(UID, validationErrorList);
  			}
  		}
  		return errorsMap;
  	}
  	
  	/**
  	 * Gets the project specific IDs map
  	 * @param workItemIDs
  	 * @param entityID
  	 * @param entityType
  	 * @return
  	 */
  	static Map<Integer, String> getProjectSpecificItemIDs(int[] workItemIDs, Integer entityID, Integer entityType) {
  		Map<Integer, String> projectSpecificItemIDsMap = null;
  		if (ApplicationBean.getInstance().getSiteBean().getProjectSpecificIDsOn()) {
  			projectSpecificItemIDsMap = ItemBL.getProjectSpecificIssueIDsMap(
  					ItemBL.loadByWorkItemKeys(workItemIDs));
  		}
  		return projectSpecificItemIDsMap;
  	}
  	
  	/**
  	 * Get the conflicted budgets map: those budgets which are different in Genji
  	 * and the one found in import file since the last edit of the MS Project file
  	 * Whether the budget was changed in MS Project file or in Genji not has no importance
  	 * @param msProjectExchangeDataStoreBean
  	 * @param taskUIDToWorkItemIDMap
  	 * @param overwriteBudgetMap
  	 * @param budgetConflictValuesMap
  	 */
  	static void budgetConflictResolution(
  			MsProjectExchangeDataStoreBean msProjectExchangeDataStoreBean,
  			Double hoursPerWorkday,
  			Map<Integer, Integer> taskUIDToWorkItemIDMap,
  			Map<Integer, Boolean> overwriteBudgetMap,
  			Map<Integer, Map<Integer, String>> budgetConflictValuesMap,
  			Map<Integer, String> projectSpecificItemIDsMap) {
  		
  		List<Task> msProjectTasks = msProjectExchangeDataStoreBean.getTasks();
  		Locale locale = msProjectExchangeDataStoreBean.getLocale();
  		Date projectLastSavedDate = msProjectExchangeDataStoreBean.getLastSavedDate(); 	
  		String strHours = LocalizeUtil.getLocalizedTextFromApplicationResources(
  				LocalizationKeyPrefixes.TIME_UNIT_KEY_PREFIX + AccountingBL.TIMEUNITS.HOURS, locale);
  		String strWorkdays = LocalizeUtil.getLocalizedTextFromApplicationResources(
  				LocalizationKeyPrefixes.TIME_UNIT_KEY_PREFIX + AccountingBL.TIMEUNITS.WORKDAYS, locale);
  		
  		//budget conflict handling
  		//budgets modified after project modification date, no matter who has modified (personID=null)
  		Collection<Integer> existingWorkItems = taskUIDToWorkItemIDMap.values();
  		SortedMap<Integer, TBudgetBean> workItemIDToConflictingBudgetBeanMap = BudgetBL.loadLastBudgetForWorkItemsMap(
  				GeneralUtils.createIntArrFromIntegerList(GeneralUtils.createIntegerListFromCollection(existingWorkItems)), 
  				null, null, projectLastSavedDate, null);
  		Iterator<Task> itrTaskElement = msProjectTasks.iterator();
  		while (itrTaskElement.hasNext()) {
  			Task taskElement = itrTaskElement.next();
  			Double UIDTmp = (Double) taskElement.getFieldByAlias("trackPlusId");
  			Integer UID;
  			if(UIDTmp != null) {
  				UID = UIDTmp.intValue();
  			}else {
  				UID = taskElement.getUniqueID();
  			}
  			Integer workItemID = taskUIDToWorkItemIDMap.get(UID);
  			
  			if (workItemID!=null) {
  				//workItem exists in track+ ...
  				TBudgetBean budgetBeanTrackPlus = workItemIDToConflictingBudgetBeanMap.get(workItemID);
  				if (budgetBeanTrackPlus!=null) {
  					//...and track+ budget exists: possible conflict
  					//transform the track+ side budget to hours because the msProject duration is in hours
  					//TODO see whether msProject duration is always in hours
  					Double transformedHours = AccountingBL.transformToTimeUnits(budgetBeanTrackPlus.getEstimatedHours(), 
  							hoursPerWorkday, budgetBeanTrackPlus.getTimeUnit(), AccountingBL.TIMEUNITS.HOURS);
  					//set this values for hasChanged
  					budgetBeanTrackPlus.setTimeUnit(AccountingBL.TIMEUNITS.HOURS);
  					budgetBeanTrackPlus.setEstimatedHours(transformedHours);
  										
  					TBudgetBean budgetBeanMsProject = new TBudgetBean();
  					budgetBeanMsProject.setEstimatedHours(taskElement.getWork().getDuration());
  					budgetBeanMsProject.setTimeUnit(TIMEUNITS.HOURS);
  					//leave the original value for fields which are not present in 
  					//MS Project to not cause the hasChanged function to return erroneously true 
  					budgetBeanMsProject.setEstimatedCost(budgetBeanTrackPlus.getEstimatedCost());
  					budgetBeanMsProject.setChangeDescription(budgetBeanTrackPlus.getChangeDescription());
  					if (budgetBeanMsProject.hasChanged(budgetBeanTrackPlus)) {
  						Boolean overwriteBudget = overwriteBudgetMap.get(workItemID);
  						if (overwriteBudget==null) {
  							//conflict was not handled (it should be rendered)
  							//add as conflict							
  							Map<Integer, String> conflictValuesMapForTask = new HashMap<Integer, String>();
  							budgetConflictValuesMap.put(workItemID, conflictValuesMapForTask);
  							conflictValuesMapForTask.put(CONFLICT_MAP_ENTRY.UID, UID.toString());
  							conflictValuesMapForTask.put(CONFLICT_MAP_ENTRY.WORKITEM_ID, workItemID.toString());
  							if (projectSpecificItemIDsMap!=null) {
  								conflictValuesMapForTask.put(CONFLICT_MAP_ENTRY.ITEM_ID, projectSpecificItemIDsMap.get(workItemID));
  							}
  							conflictValuesMapForTask.put(CONFLICT_MAP_ENTRY.SYNOPSIS, taskElement.getName());
  							conflictValuesMapForTask.put(CONFLICT_MAP_ENTRY.MS_PROJECT_VALUE, 
  									AccountingBL.getFormattedDouble(budgetBeanMsProject.getEstimatedHours(), locale, true) + " " + strHours+ "");
  							String timeUnit;
  							if (budgetBeanTrackPlus.getTimeUnit()==null || budgetBeanTrackPlus.getTimeUnit().equals(TIMEUNITS.HOURS)) {
  								timeUnit = strHours;	
  							} else {
  								timeUnit = strWorkdays;
  							}
  							conflictValuesMapForTask.put(CONFLICT_MAP_ENTRY.TRACKPLUS_VALUE, 
  									AccountingBL.getFormattedDouble(budgetBeanTrackPlus.getEstimatedHours(), locale, true) + " " + timeUnit);
  							//initialize with overwrite
  							overwriteBudgetMap.put(workItemID, Boolean.valueOf(CONFLICT_RESOLUTION.OVERWRITE));
  						}
  					}
  				}
  			}
  		}
  	}
  	
  	/**
  	 * Get the conflicted start and end dates map: those dates which were changed in Genji to a value 
  	 * different from the ones found in import file since the last modification of the MS Project file
  	 * Whether the date was changed in MS Project file or not has no importance 
  	 * @param msProjectExchangeDataStoreBean
  	 * @param existingTrackPlusWorkItems
  	 * @param taskUIDToWorkItemIDMap
  	 * @param overwriteStartDateMap
  	 * @param overwriteEndDateMap
  	 * @param startDateConflictValuesMap
  	 * @param endDateConflictValuesMap
  	 * @param workItemContextsMap
  	 */
  	static void dateConflictResolution(
  			MsProjectExchangeDataStoreBean msProjectExchangeDataStoreBean,
  			Map<Integer, TWorkItemBean> existingTrackPlusWorkItems,
  			Map<Integer, Integer> taskUIDToWorkItemIDMap,
  			Map<Integer, Boolean> overwriteStartDateMap,
  			Map<Integer, Boolean> overwriteEndDateMap,
  			Map<Integer, Map<Integer, String>> startDateConflictValuesMap,
  			Map<Integer, Map<Integer, String>> endDateConflictValuesMap,
  			Map<Integer, WorkItemContext> workItemContextsMap,
  			Map<Integer, String> projectSpecificItemIDsMap) {
  		
  		List<Task> msProjectTasks = msProjectExchangeDataStoreBean.getTasks();
  		Locale locale = msProjectExchangeDataStoreBean.getLocale();
  
  		Date projectLastSavedDate = msProjectExchangeDataStoreBean.getLastSavedDate();
  		
  		Map<Integer, SortedMap<Integer, Map<Integer, HistoryValues>>> conflictingStartDates = 
  			HistoryLoaderBL.getWorkItemsHistory(
  					GeneralUtils.createIntArrFromSet(existingTrackPlusWorkItems.keySet()), 
  					new Integer[] {SystemFields.INTEGER_STARTDATE}, 
  					true, null, projectLastSavedDate, null, locale, false, LONG_TEXT_TYPE.ISFULLHTML, false, null);
  		Map<Integer, SortedMap<Integer, Map<Integer, HistoryValues>>> conflictingEndDates = 
  		HistoryLoaderBL.getWorkItemsHistory(
  					GeneralUtils.createIntArrFromSet(existingTrackPlusWorkItems.keySet()), 
  					new Integer[] {SystemFields.INTEGER_ENDDATE}, 
  					true, null, projectLastSavedDate, null, locale, false, LONG_TEXT_TYPE.ISFULLHTML, false, null);
  		Iterator<Task> itrTaskElement = msProjectTasks.iterator();
  		HashSet<Integer> taskUIDSet = new HashSet<Integer>(taskUIDToWorkItemIDMap.values());
  		while (itrTaskElement.hasNext()) {
  			Task taskElement = itrTaskElement.next();
  			Double UIDTmp = (Double) taskElement.getFieldByAlias("trackPlusId");
  			Integer UID;
  			if(UIDTmp != null) {
  				UID = UIDTmp.intValue();
  			}else {
  				UID = taskElement.getUniqueID();
  			}
  			Integer workItemID = null;
  			if(taskUIDSet.contains(UID)) {
  				workItemID = UID;
  			}
  			WorkItemContext workItemContext = workItemContextsMap.get(UID);
  			if (workItemID!=null) {
  				//date history exists in track+ ... (the HistoryValues is not 
  				//important because the dates are taken from the workItemBeanOriginal)
  				Map<Integer, Map<Integer, HistoryValues>> startDateConflict = conflictingStartDates.get(workItemID);
  				Map<Integer, Map<Integer, HistoryValues>> endDateConflict = conflictingEndDates.get(workItemID);
  				//we should take the original one because by preparing the workItemBean it was overwritten 
  				TWorkItemBean workItemBeanOriginal = workItemContext.getWorkItemBeanOriginal();
  				if (workItemBeanOriginal!=null) {
  					if (startDateConflict!=null) {
  						Date startDateTrackplus = workItemBeanOriginal.getStartDate();
  