/*******************************************************************************
 * Copyright (c) 2017, 2019 Pivotal, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Pivotal, Inc. - initial API and implementation
 *******************************************************************************/
package org.springframework.ide.vscode.project.harness;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Collection;

import org.mockito.Mockito;
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
import org.springframework.ide.vscode.commons.boot.app.cli.ContextPath;
import org.springframework.ide.vscode.commons.boot.app.cli.LocalSpringBootApp;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;

import com.google.common.collect.ImmutableList;

public class MockRunningAppProvider {

	public final RunningAppProvider provider = mock(RunningAppProvider.class);
	public final Collection<SpringBootApp> mockedApps = new ArrayList<>();

	public MockRunningAppProvider() {
		try {
			when(provider.getAllRunningSpringApps()).thenReturn(mockedApps);
		} catch (Exception e) {
			throw ExceptionUtil.unchecked(e);
		}
	}

	/**
	 * Reset the mocks. Use this if the default's programmed into the mocks don't
	 * suite your test case.
	 * <p>
	 * Note: you may also choose to call {@link Mockito}.mock directly if you do not
	 * want to reset all of the mocks.
	 */
	public void reset() throws Exception {
		mockedApps.clear();
		Mockito.reset(provider);
	}

	public MockAppBuilder builder() {
		return new MockAppBuilder(this);
	}

	public static class MockAppBuilder {
		public final SpringBootApp app = mock(SpringBootApp.class);
		private MockRunningAppProvider runningAppProvider;
		private String processId;
		private String processName;

		public MockAppBuilder(MockRunningAppProvider runningAppProvider) {
			this.runningAppProvider = runningAppProvider;
		}

		public MockAppBuilder beans(String beans) throws Exception {
			return beans(LiveBeansModel.parse(beans));
		}

		public MockAppBuilder beans(LiveBeansModel beans) {
			when(app.getBeans()).thenReturn(beans);
			return this;
		}

		public MockAppBuilder processId(String processId) {
			this.processId = processId;
			when(app.getProcessID()).thenReturn(processId);
			return this;
		}

		public MockAppBuilder processName(String name) throws Exception {
			this.processName = name;
			when(app.getProcessName()).thenReturn(name);
			return this;
		}

		public MockAppBuilder contextPath(String contextPath) throws Exception {
			when(app.getContextPath()).thenReturn(contextPath);
			return this;
		}

		public MockAppBuilder contextPathEnvJson(String bootVersion, String envJson) throws Exception {
			String contextPath = ContextPath.getContextPath(bootVersion, envJson);
			when(app.getContextPath()).thenReturn(contextPath);
			return this;
		}

		public MockAppBuilder port(String port) throws Exception {
			when(app.getPort()).thenReturn(port);
			return this;
		}

		public MockAppBuilder host(String host) throws Exception {
			when(app.getHost()).thenReturn(host);
			return this;
		}

		public MockAppBuilder isSpringBootApp(boolean isBoot) throws Exception {
			when(app.hasUsefulJmxBeans()).thenReturn(isBoot);
			return this;
		}

		public MockAppBuilder requestMappingsJson(String mappings) throws Exception {
			Collection<RequestMapping> requestMappings = LocalSpringBootApp.parseRequestMappingsJson(mappings, "1.x");
			when(app.getRequestMappings()).thenReturn(requestMappings);
			return this;
		}

		public MockAppBuilder requestMappings(Collection<RequestMapping> rms) throws Exception {
			when(app.getRequestMappings()).thenReturn(rms);
			return this;
		}

		public MockAppBuilder liveConditionalsJson(String rawJson) throws Exception{
			when(app.getLiveConditionals()).thenReturn(LocalSpringBootApp.getLiveConditionals(rawJson, processId, processName));
			return this;
		}

		public MockAppBuilder profiles(String... names) {
			when(app.getActiveProfiles()).thenReturn(ImmutableList.copyOf(names));
			return this;
		}

		public MockAppBuilder profilesUnknown() {
			//Note, technically, we don't have to program the mock for this case as it will return
			// null by default. But it makes test code more readable. Also... how we represent the
			// 'unknown' case may change in the future and having this method will help fix the tests.
			when(app.getActiveProfiles()).thenReturn(null);
			return this;
		}


		/**
		 * Builds the mock app and adds it to the app provider
		 */
		public void build() {
			runningAppProvider.mockedApps.add(app);
		}

	}
}

@@ -1128,16 +1128,116 @@
 sModel;%0A
+import org.springframework.ide.vscode.commons.boot.app.cli.liveproperties.LivePropertiesJsonParser;%0A
 import o
@@ -4545,32 +4545,226 @@
 turn this;%0A%09%09%7D%0A%0A
+%09%09public MockAppBuilder livePropertiesJson(String envJson) throws Exception%7B%0A%09%09%09when(app.getLiveProperties()).thenReturn(LivePropertiesJsonParser.parseProperties(envJson));%0A%09%09%09return this;%0A%09%09%7D%0A%0A
 %09%09public MockApp

Add mock support for live properties