<commit_before>/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolóxico de Galicia
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.libreplan.web.common;

import static org.libreplan.web.I18nHelper._;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.validator.InvalidValue;
import org.libreplan.business.common.exceptions.ValidationException;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.EventInterceptor;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Div;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;

/**
 * It shows messages to the user. <br />
 * @author <NAME> <<EMAIL>>
 */
public class MessagesForUser extends GenericForwardComposer implements
        IMessagesForUser {

    // 2 seconds
    private static final long DEFAULT_MINIMUM_VISUALIZATION_TIME_MILLIS = 1000 * 2;

    private static final Log LOG = LogFactory.getLog(MessagesForUser.class);

    private static final class PreviousMessagesDiscarder implements
            EventInterceptor {

        private final WeakReference<MessagesForUser> messagesForUserRef;

        public PreviousMessagesDiscarder(MessagesForUser messagesForUser) {
            this.messagesForUserRef = new WeakReference<MessagesForUser>(
                    messagesForUser);
        }

        @Override
        public void afterProcessEvent(Event event) {
        }

        @Override
        public Event beforePostEvent(Event event) {
            return event;
        }

        @Override
        public Event beforeProcessEvent(Event event) {
            MessagesForUser messagesForUser = messagesForUserRef.get();
            if (messagesForUser == null) {
                return event;
            }

            if (event.getName().equals(DETACH_EVENT_NAME)
                    || messagesForUser.pendingToDetach.isEmpty()) {
                return event;
            }
            long currentTime = System.currentTimeMillis();
            ComponentHolderTimestamped currrent = null;
            while ((currrent = messagesForUser.pendingToDetach.peek()) != null
                    && currrent
                            .minimumVisualizationTimeSurpased(currentTime)) {
                currrent.component.detach();
                messagesForUser.pendingToDetach.poll();
            }
            return event;
        }

        @Override
        public Event beforeSendEvent(Event event) {
            return event;
        }
    }

    private class ComponentHolderTimestamped {
        private final Component component;
        private final long timestamp;

        ComponentHolderTimestamped(Component component) {
            this.component = component;
            this.timestamp = System.currentTimeMillis();
        }

        public boolean minimumVisualizationTimeSurpased(long currentTime) {
            return currentTime - timestamp > minimumVisualizationTimeMilliseconds;
        }
    }

    private Component container;
<commit_msg>Fix issue with messages for users<commit_after>/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolóxico de Galicia
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.libreplan.web.common;

import static org.libreplan.web.I18nHelper._;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.validator.InvalidValue;
import org.libreplan.business.common.exceptions.ValidationException;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.CheckEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.event.MouseEvent;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.EventInterceptor;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Div;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;

/**
 * <p>
 * It shows messages from the application to the user with different
 * {@link Level levels} of severity. Once the user does some action in the page,
 * like clicking a button or changing some input the messages automatically
 * disappear.
 *
 * @author <NAME> <<EMAIL>>
 */
public class MessagesForUser extends GenericForwardComposer implements
        IMessagesForUser {

    // 2 seconds
    private static final long DEFAULT_MINIMUM_VISUALIZATION_TIME_MILLIS = 1000 * 2;

    private static final Log LOG = LogFactory.getLog(MessagesForUser.class);

    private static final class PreviousMessagesDiscarder implements
            EventInterceptor {

        private final WeakReference<MessagesForUser> messagesForUserRef;

        public PreviousMessagesDiscarder(MessagesForUser messagesForUser) {
            this.messagesForUserRef = new WeakReference<MessagesForUser>(
                    messagesForUser);
        }

        @Override
        public void afterProcessEvent(Event event) {
        }

        @Override
        public Event beforePostEvent(Event event) {
            return event;
        }

        @Override
        public Event beforeProcessEvent(Event event) {
            MessagesForUser messagesForUser = messagesForUserRef.get();

            if (messagesForUser == null
                    || messagesForUser.pendingToDetach.isEmpty()
                    || !eventIndicatesUserActivity(event)) {
                return event;
            }

            long currentTime = System.currentTimeMillis();
            ComponentHolderTimestamped currrent = null;
            while ((currrent = messagesForUser.pendingToDetach.peek()) != null
                    && currrent.minimumVisualizationTimeSurpased(currentTime)) {
                currrent.component.detach();
                messagesForUser.pendingToDetach.poll();
            }
            return event;
        }

        private boolean eventIndicatesUserActivity(Event event) {
            if (event instanceof MouseEvent) {
                MouseEvent e = (MouseEvent) event;
                return e.getName().equals("onClick");
            }
            return event instanceof InputEvent || event instanceof CheckEvent
                    || event instanceof SelectEvent;
        }

        @Override
        public Event beforeSendEvent(Event event) {
            return event;
        }
    }

    private class ComponentHolderTimestamped {
        private final Component component;
        private final long timestamp;

        ComponentHolderTimestamped(Component component) {
            this.component = component;
            this.timestamp = System.currentTimeMillis();
        }

        public boolean minimumVisualizationTimeSurpased(long currentTime) {
            return currentTime - timestamp > minimumVisualizationTimeMilliseconds;
        }
    }

    private Component container;

{'fraction_non_alphanumeric': 0.07568832906030543, 'fraction_numerical': 0.0055735146583435514, 'mean_word_length': 2.7383333333333333, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6818834', 'n_tokens_mistral': 2388, 'n_tokens_neox': 2278, 'n_words': 670}