/**
 * Copyright (C) 2004-2011 Jive Software. All rights reserved.
 *
 * 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.jivesoftware.sparkimpl.profile;

import org.jivesoftware.resource.Default;
import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.StanzaBuilder;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.component.TitlePanel;
import org.jivesoftware.spark.ui.VCardViewer;
import org.jivesoftware.spark.ui.status.StatusBar;
import org.jivesoftware.spark.util.GraphicUtils;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.manager.Enterprise;
import org.jivesoftware.sparkimpl.settings.Sizes;
import org.jxmpp.jid.BareJid;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * Handles the UI for viewing and editing of VCard information.
 */
public class VCardEditor {
    private BusinessPanel businessPanel;
    private PersonalPanel personalPanel;
    private HomePanel homePanel;
    private AvatarPanel avatarPanel;
    private JLabel avatarLabel;

    /**
     * Displays the VCard for an individual.
     *
     * @param vCard  the users vcard.
     * @param parent the parent component, used for location.
     */
    public void editProfile(final VCard vCard, JComponent parent) {
        JTabbedPane tabbedPane = new JTabbedPane();
        // Initialize Panels
        personalPanel = new PersonalPanel();
        tabbedPane.addTab(Res.getString("tab.personal"), personalPanel);
        businessPanel = new BusinessPanel();
        tabbedPane.addTab(Res.getString("tab.business"), businessPanel);
        homePanel = new HomePanel();
        tabbedPane.addTab(Res.getString("tab.home"), homePanel);
        // See if we should remove the Avatar tab in profile dialog
        if (!Default.getBoolean(Default.DISABLE_AVATAR_TAB) && Enterprise.containsFeature(Enterprise.AVATAR_TAB_FEATURE)) {
            avatarPanel = new AvatarPanel();
            tabbedPane.addTab(Res.getString("tab.avatar"), avatarPanel);
        }

        // Build the UI
        buildUI(vCard);

        ImageIcon icon = VCardManager.getAvatarIcon(vCard);

        // Create the title panel for this dialog
        TitlePanel titlePanel = new TitlePanel(Res.getString("title.edit.profile"),
            Res.getString("message.save.profile"), icon, true);
        // Construct main panel w/ layout.
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());
        mainPanel.add(titlePanel, BorderLayout.NORTH);
        // The user should only be able to close this dialog.
        Object[] options = {
            Res.getString("save"),
            Res.getString("cancel")
        };
        JOptionPane pane = new JOptionPane(tabbedPane, JOptionPane.PLAIN_MESSAGE,
            JOptionPane.OK_CANCEL_OPTION, null, options, options[0]);

        mainPanel.add(pane, BorderLayout.CENTER);

        JOptionPane p = new JOptionPane();
        JDialog dlg = p.createDialog(parent, Res.getString("title.profile.information"));
        dlg.setModal(false);

        dlg.setMinimumSize(new Dimension(600, 500));
        dlg.setContentPane(mainPanel);
        dlg.pack();
        dlg.setResizable(true);

        PropertyChangeListener changeListener = new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent e) {
                String value = (String) pane.getValue();
                if (Res.getString("cancel").equals(value)) {
                    pane.removePropertyChangeListener(this);
                    dlg.dispose();
                } else if (Res.getString("save").equals(value)) {
                    pane.removePropertyChangeListener(this);
                    dlg.dispose();
                    saveVCard();
                }
            }
        };

        pane.addPropertyChangeListener(changeListener);

        // See if we should remove the Avatar tab in the profile dialog
        if (!Default.getBoolean(Default.DISABLE_AVATAR_TAB) && Enterprise.containsFeature(Enterprise.AVATAR_TAB_FEATURE)) {
            avatarPanel.setParentDialog(dlg);
        }

        dlg.setVisible(true);
        dlg.toFront();
        dlg.requestFocus();

        personalPanel.focus();
    }

    /**
     * Displays a users profile.
     *
     * @param jid    the jid of the user.
     * @param vcard  the users vcard.
     * @param parent the parent component, used for location handling.
     */
    public void displayProfile(final BareJid jid, VCard vcard, JComponent parent) {
        VCardViewer viewer = new VCardViewer(jid, vcard);
        JFrame dlg = new JFrame(Res.getString("title.view.profile.for", jid));

        avatarLabel = new JLabel();
        avatarLabel.setHorizontalAlignment(JButton.RIGHT);
        avatarLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray, 1, true));

        // The user should only be able to close this dialog.
        Object[] options = {
            Res.getString("close")
        };
        JOptionPane pane = new JOptionPane(viewer,
            JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null,
            options, options[0]);

        dlg.setIconImage(SparkRes.getImageIcon(SparkRes.Icon.PROFILE_IMAGE_16x16).getImage());

        dlg.setContentPane(pane);
        dlg.pack();
        dlg.setResizable(true);
        dlg.setLocationRelativeTo(parent);

        PropertyChangeListener changeListener = new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent e) {
                if (pane.getValue() instanceof Integer) {
                    pane.removePropertyChangeListener(this);
                    dlg.dispose();
                    return;
                }
                String value = (String) pane.getValue();
                if (Res.getString("close").equals(value)) {
                    pane.removePropertyChangeListener(this);
                    dlg.dispose();
                }
            }
        };

        pane.addPropertyChangeListener(changeListener);

        dlg.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent keyEvent) {
                if (keyEvent.getKeyChar() == KeyEvent.VK_ESCAPE) {
                    dlg.dispose();
                }
            }
        });

        dlg.setVisible(true);
        dlg.toFront();
        dlg.requestFocus();
    }

    /**
     * Builds the UI based on a VCard.
     */
    private void buildUI(VCard vcard) {
        fillUI(vcard);
        // Set Avatar
        byte[] bytes = vcard.getAvatar();
        if (bytes != null && bytes.length > 0) {
            ImageIcon icon = new ImageIcon(bytes);
            // See if we should remove the Avatar tab in the profile dialog
            if (!Default.getBoolean(Default.DISABLE_AVATAR_TAB) && Enterprise.containsFeature(Enterprise.AVATAR_TAB_FEATURE)) {
                avatarPanel.setAvatar(icon);
                avatarPanel.setAvatarBytes(bytes);
            }

            if (avatarLabel != null) {
                icon = GraphicUtils.scaleImageIcon(icon, Sizes.Avatar.VCARD, Sizes.Avatar.VCARD);
                avatarLabel.setIcon(icon);
            }
        }
    }

    private void fillUI(VCard vcard) {
        personalPanel.setFirstName(vcard.getFirstName());
        personalPanel.setMiddleName(vcard.getMiddleName());
        personalPanel.setLastName(vcard.getLastName());
        personalPanel.setEmailAddress(vcard.getEmailHome());
        personalPanel.setNickname(vcard.getNickName());
        personalPanel.setGender(vcard.getField("GENDER"));
        personalPanel.setBirthday(vcard.getField("BDAY"));
        personalPanel.setDescription(vcard.getField("DESC"));
        // Load business info
        businessPanel.setCompany(vcard.getOrganization());
        businessPanel.setDepartment(vcard.getOrganizationUnit());
        businessPanel.setStreetAddress(vcard.getAddressFieldWork("STREET"));
        businessPanel.setCity(vcard.getAddressFieldWork("LOCALITY"));
        businessPanel.setState(vcard.getAddressFieldWork("REGION"));
        businessPanel.setZipCode(vcard.getAddressFieldWork("PCODE"));
        businessPanel.setCountry(vcard.getAddressFieldWork("CTRY"));
        businessPanel.setJobTitle(vcard.getField("TITLE"));
        businessPanel.setPhone(vcard.getPhoneWork("VOICE"));
        businessPanel.setFax(vcard.getPhoneWork("FAX"));
        businessPanel.setPager(vcard.getPhoneWork("PAGER"));
        businessPanel.setMobile(vcard.getPhoneWork("CELL"));
        businessPanel.setWebPage(vcard.getField("URL"));
        // Load Home Info
        homePanel.setStreetAddress(vcard.getAddressFieldHome("STREET"));
        homePanel.setCity(vcard.getAddressFieldHome("LOCALITY"));
        homePanel.setState(vcard.getAddressFieldHome("REGION"));
        homePanel.setZipCode(vcard.getAddressFieldHome("PCODE"));
        homePanel.setCountry(vcard.getAddressFieldHome("CTRY"));
        homePanel.setPhone(vcard.getPhoneHome("VOICE"));
        homePanel.setFax(vcard.getPhoneHome("FAX"));
        homePanel.setPager(vcard.getPhoneHome("PAGER"));
        homePanel.setMobile(vcard.getPhoneHome("CELL"));
    }

    private void saveVCard() {
        VCard vcard = new VCard();
        // Save personal info
        vcard.setFirstName(personalPanel.getFirstName());
        vcard.setLastName(personalPanel.getLastName());
        vcard.setMiddleName(personalPanel.getMiddleName());
        vcard.setEmailHome(personalPanel.getEmailAddress());
        vcard.setNickName(personalPanel.getNickname());
        vcard.setField("GENDER", personalPanel.getGender());
        vcard.setField("BDAY", personalPanel.getBirthday());
        vcard.setField("DESC", personalPanel.getDescription());
        // Save business info
        vcard.setOrganization(businessPanel.getCompany());
        vcard.setAddressFieldWork("STREET", businessPanel.getStreetAddress());
        vcard.setAddressFieldWork("LOCALITY", businessPanel.getCity());
        vcard.setAddressFieldWork("REGION", businessPanel.getState());
        vcard.setAddressFieldWork("PCODE", businessPanel.getZipCode());
        vcard.setAddressFieldWork("CTRY", businessPanel.getCountry());
        vcard.setField("TITLE", businessPanel.getJobTitle());
        vcard.setOrganizationUnit(businessPanel.getDepartment());
        vcard.setPhoneWork("VOICE", businessPanel.getPhone());
        vcard.setPhoneWork("FAX", businessPanel.getFax());
        vcard.setPhoneWork("PAGER", businessPanel.getPager());
        vcard.setPhoneWork("CELL", businessPanel.getMobile());
        vcard.setField("URL", businessPanel.getWebPage());
        // Save Home Info
        vcard.setAddressFieldHome("STREET", homePanel.getStreetAddress());
        vcard.setAddressFieldHome("LOCALITY", homePanel.getCity());
        vcard.setAddressFieldHome("REGION", homePanel.getState());
        vcard.setAddressFieldHome("PCODE", homePanel.getZipCode());
        vcard.setAddressFieldHome("CTRY", homePanel.getCountry());
        vcard.setPhoneHome("VOICE", homePanel.getPhone());
        vcard.setPhoneHome("FAX", homePanel.getFax());
        vcard.setPhoneHome("PAGER", homePanel.getPager());
        vcard.setPhoneHome("CELL", homePanel.getMobile());

        // Save Avatar
        byte[] avatarBytes = null;
        if (avatarPanel != null) {
            avatarBytes = avatarPanel.getAvatarBytes();
            // If avatar was set, persist it in the vcard.
            if (avatarBytes != null) {
                vcard.setAvatar(avatarBytes);
            }
        }

        try {
            // Save vcard on server
            org.jivesoftware.smackx.vcardtemp.VCardManager smackVCardManager = org.jivesoftware.smackx.vcardtemp.VCardManager.getInstanceFor(SparkManager.getConnection());
            smackVCardManager.saveVCard(vcard);
            // Save vcard on a client
            VCardManager vcardManager = SparkManager.getVCardManager();
            vcardManager.setPersonalVCard(vcard);
            // Notify users on avatar change
            if (avatarBytes != null) {
                Presence presence = SparkManager.getWorkspace().getStatusBar().getPresence();
                Presence newPresence = StanzaBuilder.buildPresence()
                    .ofType(presence.getType())
                    .setStatus(presence.getStatus())
                    .setPriority(presence.getPriority())
                    .setMode(presence.getMode())
                    .build();

                // Change my own presence
                SparkManager.getSessionManager().changePresence(newPresence);
                // Change avatar in the status bar.
                StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
                statusBar.setAvatar(new ImageIcon(vcard.getAvatar()));
            } else {
                String fullName = vcard.getField("FN");
                StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
                if (ModelUtil.hasLength(fullName)) {
                    statusBar.setNickname(fullName);
                }
                statusBar.setAvatar(null);
            }
            // Notify listeners
            SparkManager.getVCardManager().notifyVCardListeners();
        } catch (XMPPException | SmackException | InterruptedException e) {
            Log.error(e);
            JOptionPane.showMessageDialog(SparkManager.getMainWindow(),
                Res.getString("message.vcard.not.supported"),
                Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
        }
    }

}
