// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.tenant;

import com.yahoo.path.Path;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory;
import com.yahoo.vespa.config.server.GlobalComponentRegistry;
import com.yahoo.vespa.config.server.host.HostValidator;
import com.yahoo.vespa.config.server.RequestHandler;
import com.yahoo.vespa.config.server.application.TenantApplications;
import com.yahoo.vespa.config.server.deploy.TenantFileSystemDirs;
import com.yahoo.vespa.config.server.monitoring.Metrics;
import com.yahoo.vespa.config.server.session.*;

import java.util.Collections;

/**
 * Builder for helping out with tenant creation. Each of a tenants dependencies may be overridden for testing.
 *
 * @author Ulf Lilleengen
 */
public class TenantBuilder {

    private final Path tenantPath;
    private final GlobalComponentRegistry componentRegistry;
    private final TenantName tenant;
    private RemoteSessionRepo remoteSessionRepo;
    private LocalSessionRepo localSessionRepo;
    private SessionFactory sessionFactory;
    private LocalSessionLoader localSessionLoader;
    private TenantApplications applicationRepo;
    private TenantRequestHandler reloadHandler;
    private RequestHandler requestHandler;
    private RemoteSessionFactory remoteSessionFactory;
    private HostValidator<ApplicationId> hostValidator;

    private TenantBuilder(GlobalComponentRegistry componentRegistry, TenantName tenant) {
        this.componentRegistry = componentRegistry;
        this.tenantPath = TenantRepository.getTenantPath(tenant);
        this.tenant = tenant;
    }

    public static TenantBuilder create(GlobalComponentRegistry componentRegistry, TenantName tenant) {
        return new TenantBuilder(componentRegistry, tenant);
    }

    public TenantBuilder withSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
        return this;
    }

    public TenantBuilder withLocalSessionRepo(LocalSessionRepo localSessionRepo) {
        this.localSessionRepo = localSessionRepo;
        return this;
    }

    public TenantBuilder withRemoteSessionRepo(RemoteSessionRepo remoteSessionRepo) {
        this.remoteSessionRepo = remoteSessionRepo;
        return this;
    }

    public TenantBuilder withApplicationRepo(TenantApplications applicationRepo) {
        this.applicationRepo = applicationRepo;
        return this;
    }

    public TenantBuilder withRequestHandler(RequestHandler requestHandler) {
        this.requestHandler = requestHandler;
        return this;
    }

    /**
     * Create a real tenant from the properties given by this builder.
     *
     * @return a new {@link Tenant} instance.
     */
    public Tenant build() {
        createTenantRequestHandler();
        createApplicationRepo();
        createRemoteSessionFactory();
        createRemoteSessionRepo();
        createSessionFactory();
        createLocalSessionRepo();
        return new Tenant(tenant,
                          tenantPath,
                          sessionFactory,
                          localSessionRepo,
                          remoteSessionRepo,
                          requestHandler,
                          reloadHandler,
                          applicationRepo,
                          componentRegistry.getCurator());
    }

	private void createLocalSessionRepo() {
        if (localSessionRepo == null) {
            localSessionRepo = new LocalSessionRepo(tenant, componentRegistry, localSessionLoader);
        }
    }

    private void createSessionFactory() {
        if (sessionFactory == null || localSessionLoader == null) {
            SessionFactoryImpl impl = new SessionFactoryImpl(componentRegistry, applicationRepo, hostValidator, tenant);
            if (sessionFactory == null) {
                sessionFactory = impl;
            }
            if (localSessionLoader == null) {
                localSessionLoader = impl;
            }
        }
    }

    private void createApplicationRepo() {
        if (applicationRepo == null) {
            applicationRepo = reloadHandler.applications();
        }
    }

    private void createTenantRequestHandler() {
        if (requestHandler == null || reloadHandler == null) {
            TenantRequestHandler impl = new TenantRequestHandler(componentRegistry.getMetrics(),
                                                                 tenant,
                                                                 Collections.singletonList(componentRegistry.getReloadListener()),
                                                                 ConfigResponseFactory.create(componentRegistry.getConfigserverConfig()),
                                                                 componentRegistry);
            if (hostValidator == null) {
                this.hostValidator = impl;
            }
            if (requestHandler == null) {
                requestHandler = impl;
            }
            reloadHandler = impl;
        }
    }

    private void createRemoteSessionFactory() {
        if (remoteSessionFactory == null) {
            remoteSessionFactory = new RemoteSessionFactory(componentRegistry, tenant);
        }
    }

    private void createRemoteSessionRepo() {
        if (remoteSessionRepo == null) {
            remoteSessionRepo = new RemoteSessionRepo(componentRegistry,
                                                      remoteSessionFactory,
                                                      reloadHandler,
                                                      tenant,
                                                      applicationRepo);

        }
    }

    public TenantName getTenantName() { return tenant; }
}

@@ -163,36 +163,8 @@
 t;%0A%0A
-import com.yahoo.path.Path;%0A
 impo
@@ -208,16 +208,16 @@
 tionId;%0A
+
 import c
@@ -563,131 +563,8 @@
 ns;%0A
-import com.yahoo.vespa.config.server.deploy.TenantFileSystemDirs;%0Aimport com.yahoo.vespa.config.server.monitoring.Metrics;%0A
 impo
@@ -821,43 +821,8 @@
  %7B%0A%0A
-    private final Path tenantPath;%0A
     
@@ -1502,74 +1502,8 @@
 ry;%0A
-        this.tenantPath = TenantRepository.getTenantPath(tenant);%0A
     
@@ -2022,174 +2022,8 @@
  %7D%0A%0A
-    public TenantBuilder withRemoteSessionRepo(RemoteSessionRepo remoteSessionRepo) %7B%0A        this.remoteSessionRepo = remoteSessionRepo;%0A        return this;%0A    %7D%0A%0A
     
@@ -2762,25 +2762,45 @@
             
-t
+TenantRepository.getT
 enantPath,%0A 
@@ -2796,16 +2796,24 @@
 nantPath
+(tenant)
 ,%0A      
@@ -4571,53 +4571,8 @@
 y);%0A
-            if (hostValidator == null) %7B%0A    
     
@@ -4602,38 +4602,24 @@
 tor = impl;%0A
-            %7D%0A
             
@@ -4998,53 +4998,8 @@
 ) %7B%0A
-        if (remoteSessionRepo == null) %7B%0A    
     
@@ -5059,28 +5059,24 @@
 ntRegistry,%0A
-    
             
@@ -5177,36 +5177,32 @@
                 
-    
 reloadHandler,%0A 
@@ -5246,36 +5246,32 @@
             
- 
-   
 tenant,%0A
             
@@ -5250,36 +5250,32 @@
         tenant,%0A
-    
                 
@@ -5327,26 +5327,16 @@
 Repo);%0A%0A
-        %7D%0A
     %7D%0A%0A 

Remove unused method