/*
 *  Kontalk Java client
 *  Copyright (C) 2016 Kontalk Devteam <[email protected]>
 *
 *  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/>.
 */

package org.kontalk.view;

import javax.swing.Icon;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;

import com.alee.extended.panel.GroupPanel;
import com.alee.global.StyleConstants;
import com.alee.laf.label.WebLabel;
import com.alee.laf.panel.WebPanel;
import com.alee.laf.rootpane.WebDialog;
import com.alee.laf.rootpane.WebFrame;
import com.alee.laf.separator.WebSeparator;
import com.alee.laf.text.WebTextArea;
import com.alee.managers.notification.NotificationIcon;
import com.alee.managers.notification.NotificationListener;
import com.alee.managers.notification.NotificationManager;
import com.alee.managers.notification.NotificationOption;
import com.alee.managers.notification.WebNotificationPopup;
import com.alee.managers.popup.PopupStyle;
import org.kontalk.crypto.Coder;
import org.kontalk.crypto.PGPUtils;
import org.kontalk.misc.KonException;
import org.kontalk.misc.ViewEvent;
import org.kontalk.model.Contact;
import org.kontalk.model.message.InMessage;
import org.kontalk.model.message.KonMessage;
import org.kontalk.system.RosterHandler;
import org.kontalk.util.MediaUtils;
import org.kontalk.util.Tr;

/**
 * Inform user about events.
 * @author Alexander Bikadorov {@literal <[email protected]>}
 */
final class Notifier {

    //private static final Icon NOTIFICATION_ICON = Utils.getIcon("ic_msg_pending.png");

    private final View mView;
    private final WebFrame mWindow;

    Notifier(View view, WebFrame window) {
        mView = view;
        mWindow = window;
    }

    void onNewMessage(InMessage newMessage) {
        if (mView.chatIsVisible(newMessage.getChat()))
            return;

        MediaUtils.playSound(MediaUtils.Sound.NOTIFICATION);
    }

    void showException(KonException ex) {
        if (ex.getError() == KonException.Error.LOAD_KEY_DECRYPT) {
            mView.showPasswordDialog(true);
            return;
        }
        Icon icon = NotificationIcon.error.getIcon();
        NotificationManager.showNotification(mWindow, textArea(Utils.getErrorText(ex)), icon);
    }

    // TODO more information for message exs
    void showSecurityErrors(KonMessage message) {
        //TODO too intrusive for user, but use the explanation for message view
        if (true) return;
        String errorText = "<html>";

        boolean isOut = !message.isInMessage();
        errorText += isOut ? Tr.tr("Encryption error") : Tr.tr("Decryption error");
        errorText += ":";

        for (Coder.Error error : message.getCoderStatus().getErrors()) {
            errorText += "<br>";
            switch (error) {
                case UNKNOWN_ERROR:
                    errorText += Tr.tr("Unknown error");
                    break;
                case KEY_UNAVAILABLE:
                    errorText += Tr.tr("Public key for receiver not found.");
                    break;
                case INVALID_PRIVATE_KEY:
                    errorText += Tr.tr("This message was encrypted with an old or invalid public key");
                    break;
                default:
                    errorText += Tr.tr("Unusual coder error")+": " + error.toString();
            }
        }

        errorText += "</html>";
        NotificationManager.showNotification(mWindow, errorText);
    }

    void showPresenceError(Contact contact, RosterHandler.Error error) {
        WebPanel panel = panel(Tr.tr("Contact error"), contact);

        panel.add(new WebLabel(Tr.tr("Error:")).setBoldFont());
        String errorText = Tr.tr(error.toString());
        switch (error) {
            case SERVER_NOT_FOUND:
                errorText = Tr.tr("Server not found");
                break;
        }

        panel.add(textArea(errorText));

        NotificationManager.showNotification(mWindow, panel, NotificationOption.cancel);
    }

    void confirmNewKey(final Contact contact, final PGPUtils.PGPCoderKey key) {
         final boolean overwriting = contact.hasKey();

        WebPanel panel = panel(overwriting ?
                Tr.tr("Received a new public key for contact") :
                Tr.tr("Public key for contact was found"), contact);

        panel.add(new WebLabel(Tr.tr("Key fingerprint:")));
        WebTextArea fpArea = Utils.createFingerprintArea();
        fpArea.setText(Utils.fingerprint(key.fingerprint));
        panel.add(fpArea);

        String expl = overwriting ?
                Tr.tr("When declining the key, communication with this contact will be blocked.") :
                Tr.tr("When accepting the key, communication with this contact will be encrypted.");
        panel.add(textArea(expl));

        WebNotificationPopup popup = NotificationManager.showNotification(mWindow, panel,
                NotificationOption.accept, NotificationOption.decline,
                NotificationOption.cancel);
        popup.setClickToClose(false);
        popup.addNotificationListener(new NotificationListener() {
            @Override
            public void optionSelected(NotificationOption option) {
                switch (option) {
                    case accept :
                        mView.getControl().acceptKey(contact, key);
                        break;
                    case decline :
                        if (overwriting)
                             mView.getControl().declineKey(contact);
                }
            }
            @Override
            public void accepted() {}
            @Override
            public void closed() {}
        });
    }

    void confirmContactDeletion(final Contact contact) {
        WebPanel panel = panel(Tr.tr("Contact was deleted on server"), contact);

        String expl = Tr.tr("Remove this contact from your contact list?") + "\n" +
                mView.tr_remove_contact;
        panel.add(textArea(expl));

        panel.add(textArea(Tr.tr("The reset option will recreate the server entry.")));

        WebNotificationPopup popup = NotificationManager.showNotification(mWindow, panel,
                NotificationOption.yes, NotificationOption.reset,
                NotificationOption.cancel);
        popup.setClickToClose(false);
        popup.addNotificationListener(new NotificationListener() {
            @Override
            public void optionSelected(NotificationOption option) {
                switch (option) {
                    case yes :
                        mView.getControl().deleteContact(contact);
                        break;
                    case reset:
                        mView.getControl().createRosterEntry(contact);
                        break;
                }
            }
            @Override
            public void accepted() {}
            @Override
            public void closed() {}
        });
    }

    void confirmSubscription(ViewEvent.SubscriptionRequest event){
        final Contact contact = event.contact;

        WebPanel panel = panel(Tr.tr("Authorization request"), contact);

        String expl = Tr.tr("When accepting, this contact will be able to see your online status.");
        panel.add(textArea(expl));

        WebNotificationPopup popup = NotificationManager.showNotification(mWindow, panel,
                NotificationOption.accept, NotificationOption.decline,
                NotificationOption.cancel);
        popup.setClickToClose(false);
        popup.addNotificationListener(new NotificationListener() {
            @Override
            public void optionSelected(NotificationOption option) {
                switch (option) {
                    case accept :
                        mView.getControl().sendSubscriptionResponse(contact, true);
                        break;
                    case decline :
                        mView.getControl().sendSubscriptionResponse(contact, false);
                }
            }
            @Override
            public void accepted() {}
            @Override
            public void closed() {}
        });
    }

    // TODO not used
    private void showNotification() {
        final WebDialog dialog = new WebDialog();
        dialog.setUndecorated(true);
        dialog.setBackground(Color.BLACK);
        dialog.setBackground(StyleConstants.transparent);

        WebNotificationPopup popup = new WebNotificationPopup(PopupStyle.dark);
        popup.setIcon(Utils.getIcon("kontalk_small.png"));
        popup.setMargin(View.MARGIN_DEFAULT);
        popup.setDisplayTime(6000);
        popup.addNotificationListener(new NotificationListener() {
            @Override
            public void optionSelected(NotificationOption option) {
            }
            @Override
            public void accepted() {
            }
            @Override
            public void closed() {
                dialog.dispose();
            }
        });

        // content
        WebPanel panel = new WebPanel();
        panel.setMargin(View.MARGIN_DEFAULT);
        panel.setOpaque(false);
        WebLabel title = new WebLabel("A new Message!");
        title.setFontSize(View.FONT_SIZE_BIG);
        title.setForeground(Color.WHITE);
        panel.add(title, BorderLayout.NORTH);
        String text = "this is some message, and some longer text was added";
        WebLabel message = new WebLabel(text);
        message.setForeground(Color.WHITE);
        panel.add(message, BorderLayout.CENTER);
        popup.setContent(panel);

        //popup.packPopup();
        dialog.setSize(popup.getPreferredSize());

        // set position on screen
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gd.getDefaultConfiguration();
        Rectangle screenBounds = gc.getBounds();
        // get height of the task bar
        // doesn't work on all environments
        //Insets toolHeight = toolkit.getScreenInsets(popup.getGraphicsConfiguration());
        int toolHeight  = 40;
        dialog.setLocation(screenBounds.width - dialog.getWidth() - 10,
                screenBounds.height - toolHeight - dialog.getHeight());

        dialog.setVisible(true);
        NotificationManager.showNotification(dialog, popup);
    }

    void hideNotifications() {
        NotificationManager.hideAllNotifications();
    }

    private static WebPanel panel(String title, Contact contact) {
        WebPanel panel = new GroupPanel(View.GAP_DEFAULT, false);
        panel.setOpaque(false);

        panel.add(new WebLabel(title).setBoldFont());
        panel.add(new WebSeparator(true, true));

        panel.add(new WebLabel(Tr.tr("Contact:")).setBoldFont());
        panel.add(new WebLabel(contactText(contact)));

        return panel;
    }

    private static String contactText(Contact contact){
        return Utils.name(contact, View.MAX_NAME_IN_NOTIFIER_LENGTH)
                + " < " + Utils.jid(contact.getJID(), View.MAX_JID_IN_NOTIFIER_LENGTH) + " >";
    }

    private static WebTextArea textArea(String text) {
        WebTextArea textArea = new WebTextArea(0, 30);
        textArea.setEditable(false);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setText(text);
        return textArea;
    }
}