package edu.gemini.qpt.osgi;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.logging.Logger;

import edu.gemini.qpt.core.util.LttsServicesClient;

import edu.gemini.qpt.ui.action.PublishAction;
import edu.gemini.spModel.core.Version;
import edu.gemini.util.security.auth.keychain.KeyChain;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import edu.gemini.qpt.ui.ShellAdvisor;
import edu.gemini.qpt.ui.util.Platform;
import edu.gemini.ui.workspace.IShellAdvisor;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
 * BundleActivator for the QPT application.
 * @author rnorris
 */
public final class Activator implements BundleActivator, AWTEventListener {

    @SuppressWarnings("unused")
    private static final Logger LOGGER = Logger.getLogger(Activator.class.getName());
    private ShellAdvisor advisor;
    private BundleContext context;

    // Credentials for publishing
    private static final String PROP_INTERNAL_USER = "edu.gemini.qpt.ui.action.destination.internal.user";
    private static final String PROP_INTERNAL_PASS = "edu.gemini.qpt.ui.action.destination.internal.pass";
    private static final String PROP_PACHON_USER   = "edu.gemini.qpt.ui.action.destination.pachon.user";
    private static final String PROP_PACHON_PASS   = "edu.gemini.qpt.ui.action.destination.pachon.pass";
    private ServiceTracker<KeyChain, KeyChain> keyChainServiceTracker = null;

    @SuppressWarnings({ "deprecation", "unchecked" })
    public void start(final BundleContext context) throws Exception {

        LttsServicesClient.LTTS_SERVICES_NORTH_URL = context.getProperty("edu.gemini.qpt.ltts.services.north.url");
        if (LttsServicesClient.LTTS_SERVICES_NORTH_URL == null) {
            LOGGER.warning("Missing bundle.properties value edu.gemini.qpt.ltts.services.north.url");
        }
        LttsServicesClient.LTTS_SERVICES_SOUTH_URL = context.getProperty("edu.gemini.qpt.ltts.services.south.url");
        if (LttsServicesClient.LTTS_SERVICES_SOUTH_URL == null) {
            LOGGER.warning("Missing bundle.properties value edu.gemini.qpt.ltts.services.south.url");
        }

        this.context = context;

        // TODO: this is set to the application install dir where we can find
        // the help files
        final String root = new File(System.getProperty("user.dir")).toURI().toString();

        keyChainServiceTracker = new ServiceTracker<>(context, KeyChain.class, new ServiceTrackerCustomizer<KeyChain, KeyChain>() {
            private final Dictionary<String, String> headers = context.getBundle().getHeaders();
            private ServiceRegistration<?> shellRegistration;

            @Override
            public KeyChain addingService(ServiceReference<KeyChain> acRef) {
                final KeyChain ac = context.getService(acRef);

                final PublishAction.Destination internal, pachon;

                internal = new PublishAction.Destination(
                    "gnconfig.gemini.edu",
                    getProp(PROP_INTERNAL_USER),
                    getProp(PROP_INTERNAL_PASS),
                    "/gemsoft/var/data/qpt",
                    "http://internal.gemini.edu/science/");

                pachon = new PublishAction.Destination(
                    "gsconfig.gemini.edu",
                    getProp(PROP_PACHON_USER),
                    getProp(PROP_PACHON_PASS),
                    "/gemsoft/var/data/qpt",
                    null);

                Activator.this.advisor = new ShellAdvisor(headers.get("Bundle-Name"), Version.current.toString(), root, ac, internal, pachon);
                shellRegistration = context.registerService(IShellAdvisor.class.getName(), advisor, new Hashtable());
                return ac;
            }

            @Override
            public void modifiedService(ServiceReference<KeyChain> serviceReference, KeyChain keyChain) {
                // nop
            }

            @Override
            public void removedService(ServiceReference<KeyChain> serviceReference, KeyChain keyChain) {
                shellRegistration.unregister();
            }
        });
        keyChainServiceTracker.open();

        if (Boolean.getBoolean("ctrl.key.hack")) {
            LOGGER.info("Enabling ctrl key hack.");
            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
        }

    }

    private String getProp(String key) {
        String val = context.getProperty(key);
        if (val == null) {
            throw new RuntimeException("Configuration key " + key + " was not specified.");
        }
        return val;
    }

    public void stop(BundleContext context) throws Exception {
        Toolkit.getDefaultToolkit().removeAWTEventListener(this);
        this.keyChainServiceTracker.close();
        this.keyChainServiceTracker = null;
        this.advisor = null;
        this.context = null;
    }

    public void eventDispatched(AWTEvent event) {
        KeyEvent ke = (KeyEvent) event;
        switch (ke.getKeyCode()) {
        case KeyEvent.VK_RIGHT:
        case KeyEvent.VK_LEFT:
            if ((ke.getModifiers() & Platform.MENU_ACTION_MASK) == 0) {
                ke.consume();
                KeyEvent ke2 = new KeyEvent((Component) ke.getSource(), ke.getID(), ke.getWhen(),
                        ke.getModifiers() | Platform.MENU_ACTION_MASK, ke.getKeyCode(), ke.getKeyChar());
                Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke2);
            }
        }
    }

}

@@ -1013,26 +1013,8 @@
 ator
-, AWTEventListener
  %7B%0A%0A
@@ -1736,16 +1736,88 @@
  = null;
+%0A    private final CtrKeyListener ctrKeyListener = new CtrKeyListener();
 %0A%0A    @S
@@ -4718,20 +4718,30 @@
 istener(
-this
+ctrKeyListener
 , AWTEve
@@ -5144,20 +5144,30 @@
 istener(
-this
+ctrKeyListener
 );%0A     
@@ -5307,32 +5307,106 @@
  = null;%0A    %7D%0A%0A
+    private final class CtrKeyListener implements AWTEventListener %7B%0A%0A    
     public void 
@@ -5421,16 +5421,22 @@
 patched(
+final 
 AWTEvent
@@ -5445,32 +5445,42 @@
 vent) %7B%0A        
+    final 
 KeyEvent ke = (K
@@ -5503,16 +5503,20 @@
         
+    
 switch (
@@ -5534,32 +5534,40 @@
 de()) %7B%0A        
+       
+ 
 case KeyEvent.VK
@@ -5574,32 +5574,40 @@
 _RIGHT:%0A        
+     
+   
 case KeyEvent.VK
@@ -5621,24 +5621,32 @@
             
+  
+      
 if ((ke.getM
@@ -5709,16 +5709,24 @@
         
+        
 ke.consu
@@ -5747,16 +5747,30 @@
         
+        
+final 
 KeyEvent
@@ -5843,16 +5843,24 @@
 When(),%0A
+        
         
@@ -5953,24 +5953,32 @@
 KeyChar());%0A
+        
             
@@ -6047,16 +6047,38 @@
 t(ke2);%0A
+                    %7D%0A
         

Refactor AWTListener into an inner class