/* This work has been placed into the public domain. */

package kiyut.alkitab.windows;

import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
import kiyut.alkitab.bookviewer.BookViewer;
import kiyut.alkitab.navigator.BookNavigatorPane;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookCategory;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

/**
 * TopComponent which displays {@link kiyut.alkitab.navigator.BookNavigatorPane BookNavigatorPane}.
 * 
 * @author Tonny Kohar <tonny.kohar@gmail.com>
 */
@TopComponent.Description(preferredID = "BookNavigatorTopComponent",
    //iconBase="SET/PATH/TO/ICON/HERE", 
    persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED)
@TopComponent.Registration(mode = "explorer", openAtStartup = true, position=110)
@ActionID(category = "Window", id = "kiyut.alkitab.actions.BookNavigatorAction")
@ActionReferences({
    @ActionReference(path = "Menu/Window", position = 120),
    @ActionReference(path = "Shortcuts", name = "DO-3")
})
@TopComponent.OpenActionRegistration(displayName = "#CTL_BookNavigatorAction",
    preferredID = "BookNavigatorTopComponent")
public final class BookNavigatorTopComponent extends TopComponent {

    private PropertyChangeListener tcPropertyChangeListener;
    
    private Lookup.Result<BookViewer> result = null;
    private LookupListener bookViewerLookupListener = null;
    
    private Map<BookViewer,BookNavigatorPane> navigatorMap;
    
    private BookViewer bookViewer;

    /** For bible reuse this component */
    private BookNavigatorPane bibleNavPane;
    private boolean displayUpdated = false;


    private BookNavigatorTopComponent() {
        initComponents();
        setName(NbBundle.getMessage(BookNavigatorTopComponent.class, "CTL_BookNavigatorTopComponent"));
        setToolTipText(NbBundle.getMessage(BookNavigatorTopComponent.class, "HINT_BookNavigatorTopComponent"));
//        setIcon(Utilities.loadImage(ICON_PATH, true));
        
        initCustom();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setLayout(new java.awt.BorderLayout());
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
    
    @Override
    public void componentOpened() {
        TopComponent.getRegistry().addPropertyChangeListener(tcPropertyChangeListener);
    }

    @Override
    public void componentActivated() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (!displayUpdated) {
                    if (bookViewer == null) {
                        // special case only when loading from TopComponent persistence
                        // and this got the focus (activated) from previous session.
                        Mode mode = WindowManager.getDefault().findMode("editor"); //NOI18N
                        if (mode != null) {
                            TopComponent selectedTC = mode.getSelectedTopComponent();
                            if (selectedTC != null && selectedTC instanceof BookViewerTopComponent) {
                                BookViewerTopComponent tc = (BookViewerTopComponent) selectedTC;
                                bookViewer = tc.getBookViewer();
                                registerBookViewer(bookViewer);
                                return;
                            }
                        }
                    }
                    updateDisplay();
                }
            }
        });
    }

    @Override
    public void componentClosed() {
        TopComponent.getRegistry().removePropertyChangeListener(tcPropertyChangeListener);
    }

    private void initCustom() {
        navigatorMap = new HashMap<BookViewer,BookNavigatorPane>();
        
        tcPropertyChangeListener = new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                Object obj = evt.getNewValue();
                if (!(obj instanceof BookViewerTopComponent)) {
                    return;
                }

                String propName = evt.getPropertyName();
                if (propName.equals(TopComponent.Registry.PROP_TC_CLOSED)) {
                    BookViewerTopComponent tc = (BookViewerTopComponent)obj;
                    BookViewer bookViewer = tc.getBookViewer();
                    unregisterBookViewer(bookViewer);
                } 
            }
        };
        
        bookViewerLookupListener = new LookupListener() {
            @Override
            public void resultChanged(LookupEvent lookupEvent) {
                bookViewerLookupListenerResultChanged(lookupEvent);
            }
        };

        result = Utilities.actionsGlobalContext().lookupResult(BookViewer.class);
        result.addLookupListener(bookViewerLookupListener);
        result.allInstances(); // needed to tell Nb that it is processed
        //bookViewerLookupListenerResultChanged(new LookupEvent(result));
    }
    
    private void bookViewerLookupListenerResultChanged(LookupEvent lookupEvent) {
        Collection<? extends BookViewer> c = result.allInstances();
        if (!c.isEmpty()) {
            bookViewer = (BookViewer)c.iterator().next();
            BookNavigatorPane navPane = navigatorMap.get(bookViewer);
            if (navPane == null) {
                registerBookViewer(bookViewer);
            } else {
                updateDisplay();
            }
        } 
    }
    
    private synchronized void registerBookViewer(final BookViewer bookViewer) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (bookViewer == null) { return; }
                registerBookViewerImpl(bookViewer);
                updateDisplay();
            }
        });
    }
    
    private synchronized void unregisterBookViewer(BookViewer bookViewer) {
        displayUpdated = false;
        navigatorMap.remove(bookViewer);        
        //System.out.println("BookNavTC.unregisterBookViewer()");
    }

    private void registerBookViewerImpl(BookViewer bookViewer) {
        if (navigatorMap.get(bookViewer) != null) {
            return;
        }

        if (bookViewer.getBooks().isEmpty()) {
            return;
        }

        Book book = bookViewer.getBooks().get(0);
        BookCategory bookCategory = book.getBookCategory();

        BookNavigatorPane navPane;

        if (bookCategory.equals(BookCategory.BIBLE) || bookCategory.equals(BookCategory.COMMENTARY)) {
            if (bibleNavPane == null) {
                bibleNavPane = new BookNavigatorPane();
            }
            navPane = bibleNavPane;
        } else {
            navPane = new BookNavigatorPane();
        }

        if (navigatorMap.get(bookViewer) == null) {
            navigatorMap.put(bookViewer, navPane);
            navPane.setDisplayMode(book); // build nav structure
        }
    }
    
    private void updateDisplay() {
        displayUpdated = false;

        BookNavigatorPane navPane = navigatorMap.get(bookViewer);
        if (navPane == null) {
            return;
        }

        displayUpdated = true;
        navPane.setBookViewer(bookViewer);

        this.removeAll();
        this.add(BorderLayout.CENTER,navPane);
        this.revalidate();
        this.repaint();
        
        //System.out.println("BookNavTC.updateDisplay()");
    }
}
