org.everit.jira.timetracker.plugin.JiraTimetrackerPluginImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.everit.jira.timetracker.plugin.JiraTimetrackerPluginImpl.java

Source

/*
 * Copyright (C) 2011 Everit Kft. (http://www.everit.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.everit.jira.timetracker.plugin;

import java.io.Serializable;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.everit.jira.timetracker.plugin.dto.ActionResult;
import org.everit.jira.timetracker.plugin.dto.ActionResultStatus;
import org.everit.jira.timetracker.plugin.dto.CalendarSettingsValues;
import org.everit.jira.timetracker.plugin.dto.EveritWorklog;
import org.everit.jira.timetracker.plugin.dto.EveritWorklogComparator;
import org.everit.jira.timetracker.plugin.dto.PluginSettingsValues;
import org.ofbiz.core.entity.EntityCondition;
import org.ofbiz.core.entity.EntityExpr;
import org.ofbiz.core.entity.EntityOperator;
import org.ofbiz.core.entity.GenericEntityException;
import org.ofbiz.core.entity.GenericValue;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import com.atlassian.jira.bc.JiraServiceContext;
import com.atlassian.jira.bc.JiraServiceContextImpl;
import com.atlassian.jira.bc.issue.worklog.WorklogInputParameters;
import com.atlassian.jira.bc.issue.worklog.WorklogInputParametersImpl;
import com.atlassian.jira.bc.issue.worklog.WorklogNewEstimateInputParameters;
import com.atlassian.jira.bc.issue.worklog.WorklogResult;
import com.atlassian.jira.bc.issue.worklog.WorklogService;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.issue.worklog.Worklog;
import com.atlassian.jira.issue.worklog.WorklogManager;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.security.PermissionManager;
import com.atlassian.jira.security.Permissions;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;

/**
 * The implementation of the {@link JiraTimetrackerPlugin}.
 */
public class JiraTimetrackerPluginImpl
        implements JiraTimetrackerPlugin, InitializingBean, DisposableBean, Serializable {

    private static final String DATE_PARSE = "plugin.date_parse";

    private static final String NOPERMISSION_ISSUE = "plugin.nopermission_issue";

    private static final String INVALID_ISSUE = "plugin.invalid_issue";

    private static final String WORKLOG_CREATE_FAIL = "plugin.worklog.create.fail";

    private static final int DATE_LENGTH = 7;

    private static final int TEN_MINUTES = 10;

    private static final int FIFTEEN_MINUTES = 15;

    private static final int TWENTY_MINUTES = 20;

    private static final int THIRTY_MINUTES = 30;

    private static final int DEFAULT_CHECK_TIME_IN_MINUTES = 1200;

    private static final int MINUTES_IN_HOUR = 60;

    private static final int FIVE_MINUTES = 5;
    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 1L;
    /**
     * Logger.
     */
    private static final Logger LOGGER = Logger.getLogger(JiraTimetrackerPluginImpl.class);

    /**
     * The plugin settings key prefix.
     */
    private static final String JTTP_PLUGIN_SETTINGS_KEY_PREFIX = "jttp";
    /**
     * The plugin setting Summary Filters key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_SUMMARY_FILTERS = "SummaryFilters";
    /**
     * The plugin setting Summary Filters key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_NON_ESTIMATED_ISSUES = "NonEstimated";
    /**
     * The plugin setting Exclude dates key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_EXCLUDE_DATES = "ExcludeDates";
    /**
     * The plugin setting Include dates key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_INCLUDE_DATES = "IncludeDates";
    /**
     * The plugin setting is calendar popup key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_IS_CALENDAR_POPUP = "isCalendarPopup";
    /**
     * The plugin setting is calendar popup key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_START_TIME_CHANGE = "startTimeChange";
    /**
     * The plugin setting is calendar popup key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_END_TIME_CHANGE = "endTimechange";
    /**
     * The plugin setting is actual date key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_IS_ACTUAL_DATE = "isActualDate";
    /**
     * The plugin setting is actual date key.
     */
    private static final String JTTP_PLUGIN_SETTINGS_IS_COLORIG = "isColoring";
    /**
     * A day in minutes.
     */
    private static final int ONE_DAY_IN_MINUTES = 1440;

    /**
     * The PluginSettingsFactory.
     */
    private PluginSettingsFactory settingsFactory;
    /**
     * The plugin setting form the settingsFactory.
     */
    private PluginSettings pluginSettings;
    /**
     * The plugin global setting form the settingsFactory.
     */
    private PluginSettings globalSettings;
    /**
     * The plugin setting values.
     */
    private PluginSettingsValues pluginSettingsValues;
    /**
     * The issue check time in minutes.
     */
    private long issueCheckTimeInMinutes;
    /**
     * The exclude dates from the properties file.
     */
    private String excludeDatesString;
    /**
     * The include dates from the properties file.
     */
    private String includeDatesString;
    /**
     * The parsed exclude dates.
     */
    private Set<String> excludeDatesSet = new HashSet<String>();
    /**
     * The parsed include dates.
     */
    private Set<String> includeDatesSet = new HashSet<String>();
    /**
     * The summary filter issues ids.
     */
    private List<Pattern> nonWorkingIssuePatterns;
    /**
     * The collector issues ids.
     */
    private List<Pattern> collectorIssuePatterns;
    /**
     * The summary filter issues ids.
     */
    private List<Pattern> defaultNonWorkingIssueIds = new ArrayList<Pattern>();
    /**
     * The collector issues ids.
     */
    private List<Pattern> defaultNonEstimedIssuePatterns = new ArrayList<Pattern>();
    /**
     * The plugin Scheduled Executor Service.
     */
    private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    /**
     * The issues Estimated Time Checker Future.
     */
    private ScheduledFuture<?> issueEstimatedTimeCheckerFuture;

    /**
     * Default constructor.
     */
    public JiraTimetrackerPluginImpl(final PluginSettingsFactory settingFactory) {
        settingsFactory = settingFactory;
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        setDefaultVariablesValue();

        final Runnable issueEstimatedTimeChecker = new IssueEstimatedTimeChecker(this);

        // //TEST SETTINGS
        // Calendar now = Calendar.getInstance();
        // Long nowPlusTWOMin = (long) ((now.get(Calendar.HOUR_OF_DAY) * 60) +
        // now.get(Calendar.MINUTE) + 1);
        // issueEstimatedTimeCheckerFuture =
        // scheduledExecutorService.scheduleAtFixedRate(issueEstimatedTimeChecker,
        // calculateInitialDelay(nowPlusTWOMin), // FIXME fix the time
        // // calculateInitialDelay(issueCheckTimeInMinutes),
        // 5, TimeUnit.MINUTES);

        issueEstimatedTimeCheckerFuture = scheduledExecutorService.scheduleAtFixedRate(issueEstimatedTimeChecker,
                calculateInitialDelay(issueCheckTimeInMinutes), ONE_DAY_IN_MINUTES, TimeUnit.MINUTES);
    }

    private long calculateInitialDelay(final long time) {
        Calendar now = Calendar.getInstance();
        long hours = now.get(Calendar.HOUR_OF_DAY);
        long minutes = now.get(Calendar.MINUTE);
        long initialDelay = time - ((hours * MINUTES_IN_HOUR) + minutes);
        if (initialDelay < 0) {
            initialDelay = initialDelay + ONE_DAY_IN_MINUTES;
        }
        return initialDelay;
    }

    private List<Long> createProjects(final ApplicationUser loggedInUser) {
        Collection<Project> projects = ComponentAccessor.getPermissionManager().getProjects(Permissions.BROWSE,
                loggedInUser);

        List<Long> projectList = new ArrayList<Long>();
        for (Project project : projects) {
            projectList.add(project.getId());
        }
        return projectList;
    }

    @Override
    public ActionResult createWorklog(final String issueId, final String comment, final String dateFormated,
            final String startTime, final String timeSpent) {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();
        LOGGER.warn("JTTP createWorklog: user: " + user.getDisplayName() + " " + user.getName() + " "
                + user.getEmailAddress());
        JiraServiceContext serviceContext = new JiraServiceContextImpl(user);
        LOGGER.warn("JTTP createWorklog: serviceContext User: " + user.getName() + " " + user.getEmailAddress());
        IssueManager issueManager = ComponentAccessor.getIssueManager();
        MutableIssue issue = issueManager.getIssueObject(issueId);
        if (issue == null) {
            return new ActionResult(ActionResultStatus.FAIL, INVALID_ISSUE, issueId);
        }
        PermissionManager permissionManager = ComponentAccessor.getPermissionManager();
        if (!permissionManager.hasPermission(Permissions.WORK_ISSUE, issue, user)) {
            return new ActionResult(ActionResultStatus.FAIL, NOPERMISSION_ISSUE, issueId);
        }
        String dateAndTime = dateFormated + " " + startTime;
        Date date;
        try {
            date = DateTimeConverterUtil.stringToDateAndTime(dateAndTime);
        } catch (ParseException e) {
            return new ActionResult(ActionResultStatus.FAIL, DATE_PARSE, dateAndTime);
        }

        WorklogNewEstimateInputParameters params = WorklogInputParametersImpl.issue(issue).startDate(date)
                .timeSpent(timeSpent).comment(comment).buildNewEstimate();
        WorklogService worklogService = ComponentAccessor.getComponent(WorklogService.class);
        WorklogResult worklogResult = worklogService.validateCreate(serviceContext, params);
        if (worklogResult == null) {
            return new ActionResult(ActionResultStatus.FAIL, WORKLOG_CREATE_FAIL);
        }
        Worklog createdWorklog = worklogService.createAndAutoAdjustRemainingEstimate(serviceContext, worklogResult,
                true);
        if (createdWorklog == null) {
            return new ActionResult(ActionResultStatus.FAIL, WORKLOG_CREATE_FAIL);
        }

        return new ActionResult(ActionResultStatus.SUCCESS, "plugin.worklog.create.success");
    }

    private List<EntityCondition> createWorklogQueryExprList(final ApplicationUser user, final Calendar startDate,
            final Calendar endDate) {

        String userKey = user.getKey();

        EntityExpr startExpr = new EntityExpr("startdate", EntityOperator.GREATER_THAN_EQUAL_TO,
                new Timestamp(startDate.getTimeInMillis()));
        EntityExpr endExpr = new EntityExpr("startdate", EntityOperator.LESS_THAN,
                new Timestamp(endDate.getTimeInMillis()));
        EntityExpr userExpr = new EntityExpr("author", EntityOperator.EQUALS, userKey);
        LOGGER.info(
                "JTTP LOG: getWorklogs start date: " + startDate.toString() + " end date:" + endDate.toString());

        List<EntityCondition> exprList = new ArrayList<EntityCondition>();
        exprList.add(userExpr);
        exprList.add(startExpr);
        exprList.add(endExpr);
        return exprList;
    }

    private List<EntityCondition> createWorklogQueryExprListWithPermissionCheck(final String selectedUser,
            final ApplicationUser loggedInUser, final Calendar startDate, final Calendar endDate)
            throws GenericEntityException {

        String userKey = ((selectedUser == null) || "".equals(selectedUser)) ? loggedInUser.getKey() : selectedUser;

        List<Long> projects = createProjects(loggedInUser);

        EntityExpr startExpr = new EntityExpr("startdate", EntityOperator.GREATER_THAN_EQUAL_TO,
                new Timestamp(startDate.getTimeInMillis()));
        EntityExpr endExpr = new EntityExpr("startdate", EntityOperator.LESS_THAN,
                new Timestamp(endDate.getTimeInMillis()));
        EntityExpr userExpr = new EntityExpr("author", EntityOperator.EQUALS, userKey);
        EntityExpr projectExpr = new EntityExpr("project", EntityOperator.IN, projects);
        LOGGER.info(
                "JTTP LOG: getWorklogs start date: " + startDate.toString() + " end date:" + endDate.toString());

        List<EntityCondition> exprList = new ArrayList<EntityCondition>();
        exprList.add(userExpr);
        exprList.add(startExpr);
        exprList.add(endExpr);
        exprList.add(projectExpr);
        return exprList;
    }

    @Override
    public ActionResult deleteWorklog(final Long id) {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();
        JiraServiceContext serviceContext = new JiraServiceContextImpl(user);
        WorklogService worklogService = ComponentAccessor.getComponent(WorklogService.class);
        WorklogResult deleteWorklogResult = worklogService.validateDelete(serviceContext, id);
        if (deleteWorklogResult == null) {
            return new ActionResult(ActionResultStatus.FAIL, "plugin.worklog.delete.fail", id.toString());
        }
        worklogService.deleteAndAutoAdjustRemainingEstimate(serviceContext, deleteWorklogResult, true);
        return new ActionResult(ActionResultStatus.SUCCESS, "plugin.worklog.delete.success", id.toString());
    }

    @Override
    public void destroy() throws Exception {
        scheduledExecutorService.shutdown();
        issueEstimatedTimeCheckerFuture.cancel(true);
        LOGGER.info("JiraTimetrackerPluginImpl destroyed");
    }

    @Override
    public ActionResult editWorklog(final Long id, final String issueId, final String comment,
            final String dateFormated, final String time, final String timeSpent) {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();
        JiraServiceContext serviceContext = new JiraServiceContextImpl(user);

        WorklogManager worklogManager = ComponentAccessor.getWorklogManager();
        Worklog worklog = worklogManager.getById(id);
        IssueManager issueManager = ComponentAccessor.getIssueManager();
        MutableIssue issue = issueManager.getIssueObject(issueId);
        if (issue == null) {
            return new ActionResult(ActionResultStatus.FAIL, "plugin.invalide_issue", issueId);
        }
        if (!worklog.getIssue().getKey().equals(issueId)) {
            PermissionManager permissionManager = ComponentAccessor.getPermissionManager();
            if (!permissionManager.hasPermission(Permissions.WORK_ISSUE, issue, user)) {
                return new ActionResult(ActionResultStatus.FAIL, NOPERMISSION_ISSUE, issueId);
            }
            // ProjectPermissions.WORK_ON_ISSUES;
            ActionResult deleteResult = deleteWorklog(id);
            if (deleteResult.getStatus() == ActionResultStatus.FAIL) {
                return deleteResult;
            }
            // String dateCreate =
            // DateTimeConverterUtil.dateToString(worklog.getStartDate());
            // String dateCreate = date;
            ActionResult createResult = createWorklog(issueId, comment, dateFormated, time, timeSpent);
            if (createResult.getStatus() == ActionResultStatus.FAIL) {
                return createResult;
            }
        } else {
            // String dateFormated =
            // DateTimeConverterUtil.dateToString(worklog.getStartDate());
            // String dateFormated = date;
            String dateAndTime = dateFormated + " " + time;
            Date dateCreate;
            try {
                dateCreate = DateTimeConverterUtil.stringToDateAndTime(dateAndTime);
            } catch (ParseException e) {
                return new ActionResult(ActionResultStatus.FAIL, DATE_PARSE + dateAndTime);
            }
            WorklogInputParameters params = WorklogInputParametersImpl.issue(issue).startDate(dateCreate)
                    .timeSpent(timeSpent).comment(comment).worklogId(id).issue(issue).build();
            WorklogService worklogService = ComponentAccessor.getComponent(WorklogService.class);
            WorklogResult worklogResult = worklogService.validateUpdate(serviceContext, params);
            if (worklogResult == null) {
                return new ActionResult(ActionResultStatus.FAIL, "plugin.worklog.update.fail");
            }

            worklogService.updateAndAutoAdjustRemainingEstimate(serviceContext, worklogResult, true);

        }
        return new ActionResult(ActionResultStatus.SUCCESS, "plugin.worklog.update.success");

    }

    @Override
    public Date firstMissingWorklogsDate(final String selectedUser) throws GenericEntityException {
        Calendar scannedDate = Calendar.getInstance();
        // one week
        scannedDate.set(Calendar.DAY_OF_YEAR,
                scannedDate.get(Calendar.DAY_OF_YEAR) - DateTimeConverterUtil.DAYS_PER_WEEK);
        for (int i = 0; i < DateTimeConverterUtil.DAYS_PER_WEEK; i++) {
            // convert date to String
            Date scanedDateDate = scannedDate.getTime();
            String scanedDateString = DateTimeConverterUtil.dateToString(scanedDateDate);
            // check excludse - pass
            if (excludeDatesSet.contains(scanedDateString)) {
                scannedDate.set(Calendar.DAY_OF_YEAR, scannedDate.get(Calendar.DAY_OF_YEAR) + 1);
                continue;
            }
            // check includes - not check weekend
            // check weekend - pass
            if (!includeDatesSet.contains(scanedDateString)
                    && ((scannedDate.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
                            || (scannedDate.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY))) {
                scannedDate.set(Calendar.DAY_OF_YEAR, scannedDate.get(Calendar.DAY_OF_YEAR) + 1);
                continue;
            }
            // check worklog. if no worklog set result else ++ scanedDate
            boolean isDateContainsWorklog = isContainsWorklog(scanedDateDate);
            if (!isDateContainsWorklog) {
                return scanedDateDate;
            } else {
                scannedDate.set(Calendar.DAY_OF_YEAR, scannedDate.get(Calendar.DAY_OF_YEAR) + 1);
            }
        }
        // if we find everything all right then return with the current date
        return scannedDate.getTime();
    }

    @Override
    public List<Pattern> getCollectorIssuePatterns() {
        if (collectorIssuePatterns == null) {
            collectorIssuePatterns = defaultNonEstimedIssuePatterns;
        }
        return collectorIssuePatterns;
    }

    @Override
    public List<Date> getDates(final String selectedUser, final Date from, final Date to, final boolean workingHour,
            final boolean checkNonWorking) throws GenericEntityException {
        List<Date> datesWhereNoWorklog = new ArrayList<Date>();
        Calendar fromDate = Calendar.getInstance();
        fromDate.setTime(from);
        Calendar toDate = Calendar.getInstance();
        toDate.setTime(to);
        while (!fromDate.after(toDate)) {
            String currentDateString = DateTimeConverterUtil.dateToString(fromDate.getTime());
            if (excludeDatesSet.contains(currentDateString)) {
                fromDate.add(Calendar.DATE, 1);
                continue;
            }
            // check includes - not check weekend
            // check weekend - pass
            if (!includeDatesSet.contains(currentDateString)
                    && ((fromDate.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
                            || (fromDate.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY))) {
                fromDate.add(Calendar.DATE, 1);
                continue;
            }
            // check worklog. if no worklog set result else ++ scanedDate
            boolean isDateContainsWorklog;
            if (workingHour) {
                isDateContainsWorklog = isContainsEnoughWorklog(fromDate.getTime(), checkNonWorking);
            } else {
                isDateContainsWorklog = isContainsWorklog(fromDate.getTime());
            }
            if (!isDateContainsWorklog) {
                datesWhereNoWorklog.add((Date) fromDate.getTime().clone());
            }
            fromDate.add(Calendar.DATE, 1);

        }
        Collections.reverse(datesWhereNoWorklog);
        return datesWhereNoWorklog;
    }

    private int getEndTimeChange() {
        int endTimeChange = FIVE_MINUTES;

        if (pluginSettings.get(JTTP_PLUGIN_SETTINGS_END_TIME_CHANGE) != null) {
            try {
                endTimeChange = Integer
                        .parseInt(pluginSettings.get(JTTP_PLUGIN_SETTINGS_END_TIME_CHANGE).toString());
                if (!validateTimeChange(Integer.toString(endTimeChange))) {
                    endTimeChange = FIVE_MINUTES;
                }
            } catch (NumberFormatException e) {
                LOGGER.error("Wrong formated endTime change value. Set the default value (1).", e);
            }
        }
        return endTimeChange;
    }

    @Override
    public List<String> getExcludeDaysOfTheMonth(final String date) {
        List<String> resultexcludeDays = new ArrayList<String>();
        for (String exludeDate : excludeDatesSet) {
            // TODO this if not handle the 2013-4-04 date..... this is wrong or
            // not? .... think about it.
            if (exludeDate.startsWith(date.substring(0, DATE_LENGTH))) {
                resultexcludeDays.add(exludeDate.substring(exludeDate.length() - 2));
            }
        }

        return resultexcludeDays;
    }

    @Override
    public List<Issue> getIssues() throws GenericEntityException {
        // List<GenericValue> issuesGV = null;
        // issuesGV = ComponentAccessor.getOfBizDelegator().findAll("Issue");
        List<Issue> issues = new ArrayList<Issue>();
        // for (GenericValue issueGV : issuesGV) {
        // issues.add(IssueImpl.getIssueObject(issueGV));
        // }
        return issues;
    }

    @Override
    public List<String> getLoggedDaysOfTheMonth(final String selectedUser, final Date date)
            throws GenericEntityException {
        List<String> resultDays = new ArrayList<String>();
        int dayOfMonth = 1;
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(date);
        startCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        Date start = startCalendar.getTime();

        while (dayOfMonth <= DateTimeConverterUtil.LAST_DAY_OF_MONTH) {
            if (isContainsWorklog(start)) {
                resultDays.add(Integer.toString(dayOfMonth));
            }
            startCalendar.set(Calendar.DAY_OF_MONTH, ++dayOfMonth);
            start = startCalendar.getTime();
        }

        return resultDays;
    }

    @Override
    public List<String> getProjectsId() throws GenericEntityException {
        List<String> projectsId = new ArrayList<String>();
        List<GenericValue> projectsGV = ComponentAccessor.getOfBizDelegator().findAll("Project");
        for (GenericValue project : projectsGV) {
            projectsId.add(project.getString("id"));
        }
        return projectsId;
    }

    private int getStartTimeChange() {
        int startTimeChange = FIVE_MINUTES;

        if (pluginSettings.get(JTTP_PLUGIN_SETTINGS_START_TIME_CHANGE) != null) {
            try {
                startTimeChange = Integer
                        .parseInt(pluginSettings.get(JTTP_PLUGIN_SETTINGS_START_TIME_CHANGE).toString());
                if (!validateTimeChange(Integer.toString(startTimeChange))) {
                    startTimeChange = FIVE_MINUTES;
                }
            } catch (NumberFormatException e) {
                LOGGER.error("Wrong formated startTime change value. Set the default value (1).", e);
            }
        }
        return startTimeChange;
    }

    @Override
    public EveritWorklog getWorklog(final Long worklogId) throws ParseException {
        WorklogManager worklogManager = ComponentAccessor.getWorklogManager();
        Worklog worklog = worklogManager.getById(worklogId);
        return new EveritWorklog(worklog);
    }

    @Override
    public List<EveritWorklog> getWorklogs(final String selectedUser, final Date date, final Date finalDate)
            throws ParseException, GenericEntityException {
        Calendar startDate = DateTimeConverterUtil.setDateToDayStart(date);
        Calendar endDate = (Calendar) startDate.clone();
        if (finalDate == null) {
            endDate.add(Calendar.DAY_OF_MONTH, 1);
        } else {
            endDate = DateTimeConverterUtil.setDateToDayStart(finalDate);
            endDate.add(Calendar.DAY_OF_MONTH, 1);
        }

        List<EveritWorklog> worklogs = new ArrayList<EveritWorklog>();

        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser loggedInUser = authenticationContext.getUser();

        String userKey;
        if ((selectedUser == null) || "".equals(selectedUser)) {
            userKey = loggedInUser.getKey();
        } else {
            userKey = selectedUser;
        }

        List<EntityCondition> exprList = createWorklogQueryExprListWithPermissionCheck(userKey, loggedInUser,
                startDate, endDate);

        List<GenericValue> worklogGVList = ComponentAccessor.getOfBizDelegator().findByAnd("IssueWorklogView",
                exprList);
        LOGGER.warn("JTTP LOG: getWorklogs worklog GV list size: " + worklogGVList.size());

        for (GenericValue worklogGv : worklogGVList) {
            EveritWorklog worklog = new EveritWorklog(worklogGv, collectorIssuePatterns);
            worklogs.add(worklog);
        }

        Collections.sort(worklogs, new EveritWorklogComparator());
        LOGGER.warn("JTTP LOG: getWorklogs worklog GV list size: " + worklogs.size());
        return worklogs;
    }

    /**
     * Check the given date is contains enough worklog. The worklog spent time have to be equal or
     * greater then 8 hours.
     *
     * @param date
     *          The date what have to check.
     * @param checkNonWorking
     *          Exclude or not the non-working issues.
     * @return True if the day contains enough worklog or weeked or exclude date.
     * @throws GenericEntityException
     *           If GenericEntity Exception.
     */
    private boolean isContainsEnoughWorklog(final Date date, final boolean checkNonWorking)
            throws GenericEntityException {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();

        Calendar startDate = DateTimeConverterUtil.setDateToDayStart(date);
        Calendar endDate = (Calendar) startDate.clone();
        endDate.add(Calendar.DAY_OF_MONTH, 1);

        List<EntityCondition> exprList = createWorklogQueryExprList(user, startDate, endDate);
        List<GenericValue> worklogGVList = ComponentAccessor.getOfBizDelegator().findByAnd("Worklog", exprList);
        if ((worklogGVList == null) || worklogGVList.isEmpty()) {
            return false;
        }
        if (checkNonWorking) {
            removeNonWorkingIssues(worklogGVList);
        }
        long timeSpent = 0;
        for (GenericValue worklog : worklogGVList) {
            timeSpent += worklog.getLong("timeworked").longValue();
        }
        if (timeSpent < DateTimeConverterUtil.EIGHT_HOUR_IN_SECONDS) {
            return false;
        }

        return true;
    }

    /**
     * Check the given date, the user have worklogs or not.
     *
     * @param date
     *          The date what have to check.
     * @return If The user have worklogs the given date then true, esle false.
     * @throws GenericEntityException
     *           GenericEntity Exception.
     */
    private boolean isContainsWorklog(final Date date) throws GenericEntityException {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();

        Calendar startDate = DateTimeConverterUtil.setDateToDayStart(date);
        Calendar endDate = (Calendar) startDate.clone();
        endDate.add(Calendar.DAY_OF_MONTH, 1);

        List<EntityCondition> exprList = createWorklogQueryExprList(user, startDate, endDate);

        List<GenericValue> worklogGVList = ComponentAccessor.getOfBizDelegator().findByAnd("Worklog", exprList);

        return !((worklogGVList == null) || worklogGVList.isEmpty());
    }

    @Override
    public String lastEndTime(final List<EveritWorklog> worklogs) throws ParseException {
        if ((worklogs == null) || (worklogs.size() == 0)) {
            return "08:00";
        }
        String endTime = worklogs.get(0).getEndTime();
        for (int i = 1; i < worklogs.size(); i++) {
            Date first = DateTimeConverterUtil.stringTimeToDateTime(worklogs.get(i - 1).getEndTime());
            Date second = DateTimeConverterUtil.stringTimeToDateTime(worklogs.get(i).getEndTime());
            if (first.compareTo(second) == 1) {
                endTime = worklogs.get(i - 1).getEndTime();
            } else {
                endTime = worklogs.get(i).getEndTime();
            }
        }
        return endTime;
    }

    @Override
    public PluginSettingsValues loadPluginSettings() {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();

        globalSettings = settingsFactory.createGlobalSettings();
        setNonWorkingIssuePatterns();
        setCollectorIssuePatterns();
        setExcludeDates();
        setIncludeDates();

        pluginSettings = settingsFactory.createSettingsForKey(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + user.getName());

        Integer isPopup = JiraTimetrackerUtil.POPUP_CALENDAR_CODE;
        if (pluginSettings.get(JTTP_PLUGIN_SETTINGS_IS_CALENDAR_POPUP) != null) {
            try {
                isPopup = Integer.valueOf(pluginSettings.get(JTTP_PLUGIN_SETTINGS_IS_CALENDAR_POPUP).toString());
            } catch (NumberFormatException e) {
                // the default is the popup calendar
                LOGGER.error("Wrong formated calender type. Set the default value (popup).", e);
                isPopup = JiraTimetrackerUtil.POPUP_CALENDAR_CODE;
            }
        }

        // the default is the Actual Date
        Boolean isActualDate = true;
        if ("false".equals(pluginSettings.get(JTTP_PLUGIN_SETTINGS_IS_ACTUAL_DATE))) {
            isActualDate = false;
        }

        // the default coloring is TRUE
        Boolean isColoring = true;
        if ("false".equals(pluginSettings.get(JTTP_PLUGIN_SETTINGS_IS_COLORIG))) {
            isColoring = false;
        }

        // SET startTime Change the default value is 5
        int startTimeChange = getStartTimeChange();
        // SET endtTime Change the default value is 5
        int endTimeChange = getEndTimeChange();
        // Here set the other values
        pluginSettingsValues = new PluginSettingsValues(
                new CalendarSettingsValues(isPopup, isActualDate, excludeDatesString, includeDatesString,
                        isColoring),
                nonWorkingIssuePatterns, collectorIssuePatterns, startTimeChange, endTimeChange);
        return pluginSettingsValues;
    }

    private void readObject(final java.io.ObjectInputStream stream)
            throws java.io.IOException, ClassNotFoundException {
        stream.close();
        throw new java.io.NotSerializableException(getClass().getName());
    }

    private void removeNonWorkingIssues(final List<GenericValue> worklogGVList) {
        List<GenericValue> worklogsCopy = new ArrayList<GenericValue>(worklogGVList);
        // if we have non-estimated issues

        // TODO FIXME summaryFilteredIssuePatterns rename nonworking
        // pattern
        if ((nonWorkingIssuePatterns != null) && !nonWorkingIssuePatterns.isEmpty()) {
            IssueManager issueManager = ComponentAccessor.getIssueManager();
            for (GenericValue worklog : worklogsCopy) {
                Long issueId = worklog.getLong("issue");
                MutableIssue issue = issueManager.getIssueObject(issueId);
                for (Pattern issuePattern : nonWorkingIssuePatterns) {
                    boolean issueMatches = issuePattern.matcher(issue.getKey()).matches();
                    // if match not count in summary
                    if (issueMatches) {
                        worklogGVList.remove(worklog);
                        break;
                    }
                }
            }
        }
    }

    @Override
    public void savePluginSettings(final PluginSettingsValues pluginSettingsParameters) {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();
        pluginSettings = settingsFactory.createSettingsForKey(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + user.getName());
        pluginSettings.put(JTTP_PLUGIN_SETTINGS_IS_CALENDAR_POPUP,
                Integer.toString(pluginSettingsParameters.isCalendarPopup()));
        pluginSettings.put(JTTP_PLUGIN_SETTINGS_IS_ACTUAL_DATE, pluginSettingsParameters.isActualDate().toString());
        pluginSettings.put(JTTP_PLUGIN_SETTINGS_IS_COLORIG, pluginSettingsParameters.isColoring().toString());
        pluginSettings.put(JTTP_PLUGIN_SETTINGS_START_TIME_CHANGE,
                Integer.toString(pluginSettingsParameters.getStartTimeChange()));
        pluginSettings.put(JTTP_PLUGIN_SETTINGS_END_TIME_CHANGE,
                Integer.toString(pluginSettingsParameters.getEndTimeChange()));

        globalSettings = settingsFactory.createGlobalSettings();
        globalSettings.put(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_SUMMARY_FILTERS,
                pluginSettingsParameters.getFilteredSummaryIssues());
        globalSettings.put(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_NON_ESTIMATED_ISSUES,
                pluginSettingsParameters.getCollectorIssues());
        globalSettings.put(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_EXCLUDE_DATES,
                pluginSettingsParameters.getExcludeDates());
        globalSettings.put(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_INCLUDE_DATES,
                pluginSettingsParameters.getIncludeDates());
    }

    private void setCollectorIssuePatterns() {
        List<String> tempIssuePatternList = (List<String>) globalSettings
                .get(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_NON_ESTIMATED_ISSUES);
        if (tempIssuePatternList != null) {
            // add collector issues
            collectorIssuePatterns = new ArrayList<Pattern>();
            for (String tempIssuePattern : tempIssuePatternList) {
                collectorIssuePatterns.add(Pattern.compile(tempIssuePattern));
            }
        } else {
            collectorIssuePatterns = defaultNonEstimedIssuePatterns;
        }
    }

    /**
     * Set the default values of the important variables.
     */
    private void setDefaultVariablesValue() {
        // DEFAULT 20:00
        issueCheckTimeInMinutes = DEFAULT_CHECK_TIME_IN_MINUTES;
        // Default exclude and include dates set are empty. No DATA!!
        // Default: no non working issue. we simple use the empty list
        // defaultNonWorkingIssueIds = new ArrayList<Long>();
        // The default non estimted issues regex. All issue non estimeted.
        defaultNonEstimedIssuePatterns = new ArrayList<Pattern>();
        defaultNonEstimedIssuePatterns.add(Pattern.compile(".*"));
    }

    private void setExcludeDates() {
        String tempSpecialDates = (String) globalSettings
                .get(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_EXCLUDE_DATES);
        excludeDatesSet = new HashSet<String>();
        excludeDatesString = "";
        if (tempSpecialDates != null) {
            excludeDatesString = tempSpecialDates;
            for (String excludeDate : excludeDatesString.split(",")) {
                excludeDatesSet.add(excludeDate);
            }
        }
    }

    private void setIncludeDates() {
        String tempSpecialDates = (String) globalSettings
                .get(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_INCLUDE_DATES);
        if (tempSpecialDates != null) {
            includeDatesString = tempSpecialDates;
            includeDatesSet = new HashSet<String>();
            for (String includeDate : includeDatesString.split(",")) {
                includeDatesSet.add(includeDate);
            }
        } else {
            // Default Empty
            includeDatesSet = new HashSet<String>();
            includeDatesString = "";
        }
    }

    private void setNonWorkingIssuePatterns() {
        List<String> tempIssuePatternList = (List<String>) globalSettings
                .get(JTTP_PLUGIN_SETTINGS_KEY_PREFIX + JTTP_PLUGIN_SETTINGS_SUMMARY_FILTERS);
        if (tempIssuePatternList != null) {
            // add non working issues
            nonWorkingIssuePatterns = new ArrayList<Pattern>();
            for (String tempIssuePattern : tempIssuePatternList) {
                nonWorkingIssuePatterns.add(Pattern.compile(tempIssuePattern));
            }
        } else {
            // default! from properties load default issues!!
            nonWorkingIssuePatterns = defaultNonWorkingIssueIds;
        }
    }

    @Override
    public String summary(final String selectedUser, final Date startSummary, final Date finishSummary,
            final List<Pattern> issuePatterns) throws GenericEntityException {
        JiraAuthenticationContext authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
        ApplicationUser user = authenticationContext.getUser();

        Calendar start = Calendar.getInstance();
        start.setTime(startSummary);
        Calendar finish = Calendar.getInstance();
        finish.setTime(finishSummary);

        // List<EntityExpr> exprList = createWorklogQueryExprList(selectedUser, user,
        // startSummary, finishSummary);
        List<EntityCondition> exprList = createWorklogQueryExprList(user, start, finish);

        List<GenericValue> worklogs;
        // worklog query
        worklogs = ComponentAccessor.getOfBizDelegator().findByAnd("Worklog", exprList);
        List<GenericValue> worklogsCopy = new ArrayList<GenericValue>();
        worklogsCopy.addAll(worklogs);
        // if we have non-estimated issues
        if ((issuePatterns != null) && !issuePatterns.isEmpty()) {
            for (GenericValue worklog : worklogsCopy) {
                IssueManager issueManager = ComponentAccessor.getIssueManager();
                Long issueId = worklog.getLong("issue");
                MutableIssue issue = issueManager.getIssueObject(issueId);
                for (Pattern issuePattern : issuePatterns) {
                    boolean issueMatches = issuePattern.matcher(issue.getKey()).matches();
                    // if match not count in summary
                    if (issueMatches) {
                        worklogs.remove(worklog);
                        break;
                    }
                }
            }
        }
        long timeSpent = 0;
        // Iterator<GenericValue> worklogsIterator = worklogs.iterator();
        // while (worklogsIterator.hasNext()) {
        // GenericValue worklog = worklogsIterator.next();
        // timeSpent = timeSpent + worklog.getLong("timeworked").longValue();
        // }
        for (GenericValue worklog : worklogs) {
            timeSpent += worklog.getLong("timeworked").longValue();
        }
        return DateTimeConverterUtil.secondConvertToString(timeSpent);
    }

    @Override
    public boolean validateTimeChange(final String changeValue) throws NumberFormatException {
        int changeValueInt = Integer.parseInt(changeValue);

        switch (changeValueInt) {
        case FIVE_MINUTES:
            return true;
        case TEN_MINUTES:
            return true;
        case FIFTEEN_MINUTES:
            return true;
        case TWENTY_MINUTES:
            return true;
        case THIRTY_MINUTES:
            return true;
        default:
            return false;
        }

    }

    private void writeObject(final java.io.ObjectOutputStream stream) throws java.io.IOException {
        stream.close();
        throw new java.io.NotSerializableException(getClass().getName());
    }
}