/*
 * Copyright (c) 2006-2015 DMDirc Developers
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.dmdirc.ui.messages;

import com.dmdirc.DMDircMBassador;
import com.dmdirc.config.ConfigBinding;
import com.dmdirc.events.BaseChannelTextEvent;
import com.dmdirc.events.BaseQueryTextEvent;
import com.dmdirc.events.ChannelHighlightEvent;
import com.dmdirc.events.DisplayableEvent;
import com.dmdirc.events.QueryHighlightEvent;
import com.dmdirc.events.UnreadStatusChangedEvent;
import com.dmdirc.interfaces.WindowModel;
import com.dmdirc.util.colours.Colour;

import java.util.Optional;

import net.engio.mbassy.listener.Handler;

/**
 * Tracks unread messages and other notifications.
 */
public class UnreadStatusManager {

    private final DMDircMBassador eventBus;
    private final WindowModel container;
    private final ColourManager colourManager;

    private int unreadLines;
    private Optional<Colour> notificationColour = Optional.empty();

    private Optional<Colour> miscellaneousColour = Optional.of(Colour.GREEN);
    private Optional<Colour> messageColour = Optional.of(Colour.BLUE);
    private Optional<Colour> highlightColour = Optional.of(Colour.RED);

    public UnreadStatusManager(final WindowModel container) {
        this.container = container;
        this.eventBus = container.getEventBus();
        this.colourManager = new ColourManager(container.getConfigManager());
    }

    @Handler
    public void handleDisplayableEvent(final DisplayableEvent event) {
        if (event.getSource().equals(container)) {
            updateStatus(miscellaneousColour, unreadLines + 1);
        }
    }

    @Handler
    public void handleChannelTextEvent(final BaseChannelTextEvent event) {
        if (event.getSource().equals(container)) {
            updateStatus(messageColour);
        }
    }

    @Handler
    public void handleQueryTextEvent(final BaseQueryTextEvent event) {
        if (event.getSource().equals(container)) {
            updateStatus(messageColour);
        }
    }

    @Handler
    public void handleChannelHighlightEvent(final ChannelHighlightEvent event) {
        if (event.getChannel().equals(container)) {
            updateStatus(highlightColour);
        }
    }

    @Handler
    public void handleQueryHighlightEvent(final QueryHighlightEvent event) {
        if (event.getQuery().equals(container)) {
            updateStatus(highlightColour);
        }
    }

    public int getUnreadLines() {
        return unreadLines;
    }

    public Optional<Colour> getNotificationColour() {
        return notificationColour;
    }

    public void clearStatus() {
        updateStatus(Optional.empty(), 0);
    }

    private void updateStatus(final Optional<Colour> desiredColour) {
        updateStatus(desiredColour, unreadLines);
    }

    private void updateStatus(final Optional<Colour> desiredColour, final int newUnreadCount) {
        final Optional<Colour> newColour = getBestColour(desiredColour, notificationColour);
        final boolean updated = !newColour.equals(notificationColour)
                || newUnreadCount != unreadLines;
        notificationColour = newColour;
        unreadLines = newUnreadCount;

        if (updated) {
            publishChangedEvent();
        }
    }

    private Optional<Colour> getBestColour(
            final Optional<Colour> desiredColour,
            final Optional<Colour> existingColour) {
        if (!desiredColour.isPresent()) {
            // If we're trying to explicitly reset, go with the empty one.
            return desiredColour;
        }

        if (desiredColour.equals(highlightColour)
                || !existingColour.isPresent()
                || existingColour.equals(miscellaneousColour)) {
            return desiredColour;
        } else {
            return existingColour;
        }
    }

    @ConfigBinding(domain = "ui", key = "miscellaneousNotificationColour")
    void handleMiscellaneousColour(final String colour) {
        final Optional<Colour> newColour = Optional.ofNullable(
                colourManager.getColourFromString(colour, Colour.GREEN));
        if (notificationColour.equals(miscellaneousColour)) {
            notificationColour = newColour;
            publishChangedEvent();
        }
        miscellaneousColour = newColour;
    }

    @ConfigBinding(domain = "ui", key = "messageNotificationColour")
    void handleMessageColour(final String colour) {
        final Optional<Colour> newColour = Optional.ofNullable(
                colourManager.getColourFromString(colour, Colour.BLUE));
        if (notificationColour.equals(messageColour)) {
            notificationColour = newColour;
            publishChangedEvent();
        }
        messageColour = newColour;
    }

    @ConfigBinding(domain = "ui", key = "highlightNotificationColour")
    void handleHighlightColour(final String colour) {
        final Optional<Colour> newColour = Optional.ofNullable(
                colourManager.getColourFromString(colour, Colour.RED));
        if (notificationColour.equals(highlightColour)) {
            notificationColour = newColour;
            publishChangedEvent();
        }
        highlightColour = newColour;
    }

    private void publishChangedEvent() {
        eventBus.publishAsync(new UnreadStatusChangedEvent(container, this, notificationColour,
                unreadLines));
    }

}

@@ -1361,32 +1361,74 @@
 HighlightEvent;%0A
+import com.dmdirc.events.DisplayProperty;%0A
 import com.dmdir
@@ -2584,42 +2584,26 @@
 if (
-event.getSource().equals(container
+includeEvent(event
 )) %7B
@@ -2788,42 +2788,26 @@
 if (
-event.getSource().equals(container
+includeEvent(event
 )) %7B
@@ -2965,42 +2965,26 @@
 if (
-event.getSource().equals(container
+includeEvent(event
 )) %7B
@@ -3152,43 +3152,26 @@
 if (
-event.getChannel().equals(container
+includeEvent(event
 )) %7B
@@ -3337,41 +3337,26 @@
 if (
-event.getQuery().equals(container
+includeEvent(event
 )) %7B
@@ -3408,32 +3408,247 @@
        %7D%0A    %7D%0A%0A
+    private boolean includeEvent(final DisplayableEvent event) %7B%0A        return event.getSource().equals(container)%0A                && !event.getDisplayProperty(DisplayProperty.DO_NOT_DISPLAY).orElse(false);%0A    %7D%0A%0A
     public int g

Fix counting of events.