package router.client;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

@SuppressWarnings( { "ConstantConditions", "WeakerAccess", "SameParameterValue" } )
public final class RouteManager
{
  private final RoutingBackend _backend;
  @Nonnull
  private final List<RouteDefinition> _routes = new ArrayList<>();
  @Nonnull
  private final Object _target;
  @Nullable
  private String _defaultLocation;
  @Nullable
  private Route _lastRoute;
  private Object _callback;

  public RouteManager( @Nonnull final RoutingBackend backend, @Nonnull final Object target )
  {
    _backend = Objects.requireNonNull( backend );
    _target = Objects.requireNonNull( target );
  }

  public void addRoute( @Nonnull final RouteDefinition route )
  {
    _routes.add( Objects.requireNonNull( route ) );
  }

  @Nullable
  public String getDefaultLocation()
  {
    return _defaultLocation;
  }

  public void setDefaultLocation( @Nullable final String defaultLocation )
  {
    _defaultLocation = defaultLocation;
  }

  public void install()
  {
    uninstall();
    _callback = _backend.addListener( h -> onHashChange() );
  }

  public void uninstall()
  {
    if ( null != _callback )
    {
      _backend.removeListener( _callback );
      _callback = null;
    }
  }

  private boolean onHashChange()
  {
    route();
    return true;
  }

  @Nullable
  public Route route()
  {
    final String location = _backend.getHash();

    final Route route = attemptRouteMatch( location );
    if ( null != route )
    {
      return route;
    }
    else if ( null != _defaultLocation )
    {
      _backend.setHash( _defaultLocation );
      return attemptRouteMatch( location );
    }
    else
    {
      return null;
    }
  }

  private Route attemptRouteMatch( final String location )
  {
    for ( final RouteDefinition definition : _routes )
    {
      final Map<String, Object> routeData = definition.match( location );
      final Route route = new Route( location, definition, routeData );
      if ( null != routeData && processRoute( route ) )
      {
        _lastRoute = route;
        return route;
      }
    }
    return null;
  }

  private boolean processRoute( @Nonnull final Route route )
  {
    assert null != route;
    final RouteDefinition definition = route.getDefinition();
    final PreRouteGuardCallback preRouteGuard = definition.getPreRouteGuard();
    if ( preRouteGuard == null || preRouteGuard.preRouteGuard( route ) )
    {
      if ( null != _lastRoute && _lastRoute.getDefinition() == definition )
      {
        final UpdateRouteCallback updateRoute = definition.getUpdateRoute();
        if ( null != updateRoute )
        {
          updateRoute.updateRoute( route );
          return true;
        }
      }
      final BeforeRouteCallback beforeRoute = definition.getBeforeRoute();
      if ( null != beforeRoute )
      {
        beforeRoute.beforeRoute( route, () -> completeRouting( route ) );
      }
      else
      {
        completeRouting( route );
      }
      return true;
    }
    else
    {
      return false;
    }
  }

  private void completeRouting( @Nonnull final Route route )
  {
    final RouteDefinition definition = route.getDefinition();
    definition.getRoute().route( route, _target );
    final PostRouteCallback postRoute = definition.getPostRoute();
    if ( null != postRoute )
    {
      postRoute.postRoute( route );
    }
  }
}

@@ -210,64 +210,20 @@
  %7B %22
-ConstantConditions%22, %22WeakerAccess%22, %22SameParameterValue
+WeakerAccess
 %22 %7D 
@@ -1978,24 +1978,65 @@
 location );%0A
+      if ( null != routeData )%0A      %7B%0A  
       final 
@@ -2105,33 +2105,14 @@
     
+  
 if (
- null != routeData &&
  pro
@@ -2130,34 +2130,38 @@
 route ) )%0A      
+ 
+ 
 %7B%0A
+  
         _lastRou
@@ -2168,24 +2168,26 @@
 te = route;%0A
+  
         retu
@@ -2192,24 +2192,34 @@
 turn route;%0A
+        %7D%0A
       %7D%0A    
@@ -2315,28 +2315,39 @@
     
-assert null !=
+Objects.requireNonNull(
  route
+ )
 ;%0A  
@@ -2660,143 +2660,35 @@
     
-final UpdateRouteCallback updateRoute = definition.getUpdateRoute();%0A        if ( null != updateRoute )%0A        %7B%0A          updateRoute
+definition.getUpdateRoute()
 .upd
@@ -2710,26 +2710,24 @@
  );%0A        
-  
 return true;
@@ -2727,26 +2727,16 @@
 n true;%0A
-        %7D%0A
       %7D%0A

Simplify code