package brooklyn.location.access;

import static org.testng.Assert.assertEquals;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import brooklyn.config.ConfigKey;
import brooklyn.entity.basic.ConfigKeys;
import brooklyn.entity.proxying.EntitySpec;
import brooklyn.entity.rebind.RebindTestFixtureWithApp;
import brooklyn.entity.rebind.RebindTestUtils;
import brooklyn.location.Location;
import brooklyn.location.LocationSpec;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.test.entity.TestEntity;
import brooklyn.test.entity.TestEntityImpl;
import brooklyn.util.flags.SetFromFlag;
import brooklyn.util.net.Networking;

import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.net.HostAndPort;

public class PortForwardManagerRebindTest extends RebindTestFixtureWithApp {

    private static final Logger log = LoggerFactory.getLogger(PortForwardManagerRebindTest.class);

    private Map<HostAndPort, HostAndPort> portMapping;
    private String machineAddress = "1.2.3.4";
    private SshMachineLocation origSimulatedMachine;

    
    @Override
    @BeforeMethod(alwaysRun=true)
    public void setUp() throws Exception {
        super.setUp();

        origSimulatedMachine = origManagementContext.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
                .configure("address", Networking.getInetAddressWithFixedName(machineAddress))
                .configure("port", 1234)
                .configure("user", "myuser"));
    }
    
    @Test
    public void testHostAndPortTransformingEnricher() throws Exception {
        String publicIpId = "5.6.7.8";
        String publicAddress = "5.6.7.8";

        TestEntity origEntity = origApp.createAndManageChild(EntitySpec.create(TestEntity.class).impl(MyEntity.class));
        PortForwardManager origPortForwardManager = origEntity.getConfig(MyEntity.PORT_FORWARDING_MANAGER);

        // We first wait for persisted, to ensure that it is the PortForwardManager.onChanged that is causing persistence.
        RebindTestUtils.waitForPersisted(origApp);
        origPortForwardManager.recordPublicIpHostname(publicIpId, publicAddress);
        origPortForwardManager.acquirePublicPortExplicit(publicIpId, 40080);
        origPortForwardManager.associate(publicIpId, 40080, origSimulatedMachine, 80);
     
        newApp = rebind(false);
        
        TestEntity newEntity = (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));
        Location newSimulatedMachine = newApp.getManagementContext().getLocationManager().getLocation(origSimulatedMachine.getId());
        PortForwardManager newPortForwardManager = newEntity.getConfig(MyEntity.PORT_FORWARDING_MANAGER);
        
        assertEquals(newPortForwardManager.getPublicIpHostname(publicIpId), publicAddress);
        assertEquals(newPortForwardManager.lookup(newSimulatedMachine, 80), HostAndPort.fromParts(publicAddress, 40080));
    }
    
    public static class MyEntity extends TestEntityImpl {
        public static final ConfigKey<PortForwardManager> PORT_FORWARDING_MANAGER = ConfigKeys.newConfigKey(PortForwardManager.class, "myentity.portForwardingManager");

        @Override
        public void init() {
            super.init();
            
            if (getConfig(PORT_FORWARDING_MANAGER) == null) {
                setConfig(PORT_FORWARDING_MANAGER, new PortForwardManager(this));
            }
        }
        @SetFromFlag("myconfigflagname")
        public static final ConfigKey<String> MY_CONFIG_WITH_FLAGNAME = ConfigKeys.newStringConfigKey("myentity.myconfigwithflagname");
    }
    
}

@@ -458,16 +458,92 @@
 tUtils;%0A
+import brooklyn.event.AttributeSensor;%0Aimport brooklyn.event.basic.Sensors;%0A
 import b
@@ -2103,35 +2103,32 @@
 ity.PORT_FORWARD
-ING
 _MANAGER);%0A%0A    
@@ -2930,35 +2930,32 @@
 ity.PORT_FORWARD
-ING
 _MANAGER);%0A     
@@ -3179,24 +3179,102 @@
 %0A    %7D%0A    %0A
+    public interface HasPfm %7B%0A        PortForwardManager getPfm();%0A    %7D%0A    %0A
     public s
@@ -3317,16 +3317,34 @@
 ityImpl 
+implements HasPfm 
 %7B%0A      
@@ -3399,35 +3399,32 @@
 er%3E PORT_FORWARD
-ING
 _MANAGER = Confi
@@ -3493,18 +3493,188 @@
 ward
-ing
 Manager
+%22);%0A        public static final AttributeSensor%3CPortForwardManager%3E PORT_FORWARD_MANAGER_LIVE = Sensors.newSensor(PortForwardManager.class, %22myentity.portForwardManager.live
 %22);%0A
@@ -3790,35 +3790,32 @@
 fig(PORT_FORWARD
-ING
 _MANAGER) == nul
@@ -3835,16 +3835,209 @@
         
+PortForwardManagerAuthority pfm = new PortForwardManagerAuthority();%0A                pfm.injectOwningEntity(this);%0A                setAttribute(PORT_FORWARD_MANAGER_LIVE, pfm);%0A                
 setConfi
@@ -4054,11 +4054,8 @@
 WARD
-ING
 _MAN
@@ -4059,20 +4059,16 @@
 MANAGER,
- new
  PortFor
@@ -4082,40 +4082,226 @@
 ager
-(this));%0A            %7D%0A        %7D
+Client.fromMethodOnEntity(this, %22getPfm%22));%0A            %7D%0A        %7D%0A        %0A        @Override%0A        public PortForwardManager getPfm() %7B%0A            return getAttribute(PORT_FORWARD_MANAGER_LIVE);%0A        %7D%0A        
 %0A   

fix the orig uni ttest