package denominator;

import static com.google.common.collect.Ordering.usingToString;
import static java.lang.String.format;
import static java.util.logging.Logger.getAnonymousLogger;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;

import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicLong;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

import denominator.model.ResourceRecordSet;

/**
 * extend this and initialize manager {@link BeforeClass}
 */
public abstract class BaseReadOnlyLiveTest extends BaseProviderLiveTest {

    @Test
    private void testListRRSs() {
        skipIfNoCredentials();
        for (Iterator<String> zone = zoneApi().list(); zone.hasNext();) {
            String zoneName = zone.next();
            for (Iterator<ResourceRecordSet<?>> rrsIterator = roApi(zoneName).list(); rrsIterator.hasNext();) {
                ResourceRecordSet<?> rrs = rrsIterator.next();
                recordTypeCounts.getUnchecked(rrs.getType()).addAndGet(rrs.size());
                checkRRS(rrs);
                Iterator<ResourceRecordSet<?>> byNameAndType = roApi(zoneName).listByNameAndType(rrs.getName(), rrs.getType());
                assertTrue(byNameAndType.hasNext(), "could not lookup by name and type: " + rrs);
                assertTrue(ImmutableList.copyOf(byNameAndType).contains(rrs));
            }
        }
        logRecordSummary();
    }

    @Test
    private void testListByName() {
        skipIfNoCredentials();
        for (Iterator<String> zone = zoneApi().list(); zone.hasNext();) {
            String zoneName = zone.next();
            Iterator<ResourceRecordSet<?>> rrsIterator = roApi(zoneName).list();
            if (!rrsIterator.hasNext())
                continue;
            ResourceRecordSet<?> rrset = rrsIterator.next();
            String name = rrset.getName();
            List<ResourceRecordSet<?>> withName = Lists.newArrayList();
            withName.add(rrset);
            while (rrsIterator.hasNext()) {
                rrset = rrsIterator.next();
                if (!name.equalsIgnoreCase(rrset.getName()))
                        break;
                withName.add(rrset);
            }
            List<ResourceRecordSet<?>> fromApi = Lists.newArrayList(roApi(zoneName).listByName(name));
            assertEquals(usingToString().immutableSortedCopy(fromApi), usingToString().immutableSortedCopy(withName));
            break;
        }
    }

    @Test
    private void testListByNameWhenNotFound() {
        skipIfNoCredentials();
        for (Iterator<String> zone = zoneApi().list(); zone.hasNext();) {
            String zoneName = zone.next();
            assertFalse(roApi(zoneName).listByName("ARGHH." + zoneName).hasNext());
            break;
        }
    }

    @Test
    private void testListByNameAndTypeWhenEmpty() {
        skipIfNoCredentials();
        for (Iterator<String> zone = zoneApi().list(); zone.hasNext();) {
            String zoneName = zone.next();
            assertFalse(roApi(zoneName).listByNameAndType("ARGHH." + zoneName, "TXT").hasNext());
            break;
        }
    }

    private void logRecordSummary() {
        for (Entry<String, AtomicLong> entry : recordTypeCounts.asMap().entrySet())
            getAnonymousLogger().info(
                    format("%s ::: %s records: count: %s", manager, entry.getKey(), entry.getValue()));
    }

    private LoadingCache<String, AtomicLong> recordTypeCounts = CacheBuilder.newBuilder().build(
            new CacheLoader<String, AtomicLong>() {
                public AtomicLong load(String key) throws Exception {
                    return new AtomicLong();
                }
            });

    private AllProfileResourceRecordSetApi roApi(String zoneName) {
        return manager.getApi().getAllProfileResourceRecordSetApiForZone(zoneName);
    }
}

@@ -1430,70 +1430,317 @@
     
-Iterator%3CResourceRecordSet%3C?%3E%3E byNameAndType = roApi(zoneName)
+checkListByNameAndTypeConsistent(zoneName, rrs);%0A            %7D%0A        %7D%0A        logRecordSummary();%0A    %7D%0A%0A    protected void checkListByNameAndTypeConsistent(String zoneName, ResourceRecordSet%3C?%3E rrs) %7B%0A        List%3CResourceRecordSet%3C?%3E%3E byNameAndType = ImmutableList.copyOf(roApi(zoneName)%0A                
 .lis
@@ -1779,34 +1779,27 @@
 s.getType())
+)
 ;%0A
-        
         asse
@@ -1800,19 +1800,20 @@
   assert
-Tru
+Fals
 e(byName
@@ -1820,23 +1820,23 @@
 AndType.
-hasNext
+isEmpty
 (), %22cou
@@ -1873,32 +1873,24 @@
 : %22 + rrs);%0A
-        
         asse
@@ -1896,37 +1896,16 @@
 ertTrue(
-ImmutableList.copyOf(
 byNameAn
@@ -1909,17 +1909,16 @@
 eAndType
-)
 .contain
@@ -1927,60 +1927,71 @@
 rrs)
-);%0A            %7D%0A        %7D%0A        logRecordSummary(
+, rrs + %22 not found in list by name and type: %22 + byNameAndType
 );%0A 

make it possible to filter out list by name verification