package net.squanchy.proximity.preconditions;

import android.content.Intent;
import android.support.annotation.MainThread;

import net.squanchy.proximity.preconditions.LocationProviderPrecondition.ProviderPreconditionException;
import net.squanchy.support.lang.Optional;

import timber.log.Timber;

public class ModularProximityPreconditions implements ProximityPreconditions {

    private final PreconditionsRegistry registry;
    private final Callback callback;

    ModularProximityPreconditions(PreconditionsRegistry registry, Callback callback) {
        this.registry = registry;
        this.callback = callback;
    }

    @Override
    public boolean needsActionToSatisfyPreconditions() {
        return registry.anyUnsatisfied();
    }

    @Override
    @MainThread
    public void startSatisfyingPreconditions() {
        Precondition precondition = registry.firstPrecondition();

        startCheckingFrom(precondition);
    }

    @Override
    public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        Optional<Precondition> requestingPrecondition = registry.findPreconditionHandlingRequestCode(requestCode);
        Timber.i(requestingPrecondition.toString());
        if (requestingPrecondition.isPresent()) {
            startCheckingFrom(requestingPrecondition.get());
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        Optional<Precondition> requestingPrecondition = registry.findPreconditionHandlingRequestCode(requestCode);
        if (requestingPrecondition.isPresent()) {
            startCheckingFrom(requestingPrecondition.get());
            return true;
        } else {
            return false;
        }
    }

    private void startCheckingFrom(Precondition initialPrecondition) {
        Optional<Precondition> nextPrecondition = Optional.of(initialPrecondition);
        while (nextPrecondition.isPresent()) {
            Precondition precondition = nextPrecondition.get();
            if (!precondition.available()) {
                Timber.d("Skipping unavailable precondition: %s", precondition);
                return;
            }

            if (precondition.satisfied()) {
                nextPrecondition = registry.preconditionAfter(precondition);
            } else {
                precondition.satisfy()
                        .subscribe(() -> {
                            if (!precondition.satisfied()) {
                                // Waiting on some external resource (e.g., onActivityResult) that will
                                // unblock us in the onActivityResult/onPermissionRequestResult. We give
                                // up for now, those will restart us.
                                return;
                            }

                            Optional<Precondition> preconditionOptional = registry.preconditionAfter(precondition);
                            if (preconditionOptional.isPresent()) {
                                startCheckingFrom(preconditionOptional.get());
                            } else {
                                callback.allChecksPassed();
                            }
                        });
                return;
            }
        }

        callback.allChecksPassed();
    }

    private void handleCheckError(Throwable throwable) {
        if (throwable instanceof LocationProviderPrecondition.ProviderPreconditionException) {
            ProviderPreconditionException exception = (ProviderPreconditionException) throwable;
            callback.locationProviderFailed(exception.failureInfo());
        } else {
            callback.exceptionWhileSatisfying(throwable);
        }
    }
}

@@ -1883,230 +1883,24 @@
 ion 
-initialPrecondition) %7B%0A        Optional%3CPrecondition%3E nextPrecondition = Optional.of(initialPrecondition);%0A        while (nextPrecondition.isPresent()) %7B%0A            Precondition precondition = nextPrecondition.get();%0A    
+precondition) %7B%0A
     
@@ -1932,28 +1932,24 @@
 ilable()) %7B%0A
-    
             
@@ -2017,36 +2017,32 @@
 n);%0A            
-  
-  
 return;%0A        
@@ -2037,35 +2037,27 @@
 rn;%0A        
-    %7D%0A%0A    
+%7D%0A%0A
         if (
@@ -2100,57 +2100,36 @@
     
-  
-  nextPrecondition = registry.preconditionAfter
+continueAfterSucceedingCheck
 (pre
@@ -2140,36 +2140,32 @@
 ition);%0A        
-   
- 
 %7D else %7B%0A       
@@ -2149,36 +2149,32 @@
        %7D else %7B%0A
-    
             prec
@@ -2212,20 +2212,16 @@
         
-    
 .subscri
@@ -2231,20 +2231,16 @@
 () -%3E %7B%0A
-    
         
@@ -2251,33 +2251,32 @@
             if (
-!
 precondition.sat
@@ -2287,32 +2287,122 @@
 ed()) %7B%0A        
+                    continueAfterSucceedingCheck(precondition);%0A                        %7D%0A
                 
@@ -2481,24 +2481,16 @@
 at will%0A
-        
         
@@ -2598,32 +2598,24 @@
             
-        
 // up for no
@@ -2664,79 +2664,134 @@
     
-    
-        return;%0A                            %7D%0A%0A                    
+%7D, this::handleCheckError);%0A        %7D%0A    %7D%0A%0A    private void continueAfterSucceedingCheck(Precondition passedPrecondition) %7B%0A
     
@@ -2817,17 +2817,21 @@
 dition%3E 
-p
+nextP
 recondit
@@ -2833,24 +2833,16 @@
 ondition
-Optional
  = regis
@@ -2864,16 +2864,22 @@
 nAfter(p
+assedP
 recondit
@@ -2896,33 +2896,17 @@
     
-                    if (p
+if (nextP
 reco
@@ -2912,24 +2912,16 @@
 ondition
-Optional
 .isPrese
@@ -2928,36 +2928,16 @@
 nt()) %7B%0A
-                    
         
@@ -2950,33 +2950,37 @@
 artCheckingFrom(
-p
+nextP
 reconditionOptio
@@ -2974,24 +2974,16 @@
 ondition
-Optional
 .get());
@@ -2995,239 +2995,66 @@
     
-                    %7D else %7B%0A                                callback.allChecksPassed();%0A                            %7D%0A                        %7D);%0A                return;%0A            %7D%0A        %7D%0A%0A        callback.allChecksPassed();
+%7D else %7B%0A            callback.allChecksPassed();%0A        %7D
 %0A   

Use recursion and refactor checks code