package org.jenkinsci.plugins.p4.scm;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.model.AutoCompletionCandidates;
import hudson.model.TaskListener;
import hudson.util.FormValidation;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSourceOwner;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.p4.PerforceScm;
import org.jenkinsci.plugins.p4.browsers.P4Browser;
import org.jenkinsci.plugins.p4.client.NavigateHelper;
import org.jenkinsci.plugins.p4.client.ViewMapHelper;
import org.jenkinsci.plugins.p4.populate.GraphHybridImpl;
import org.jenkinsci.plugins.p4.populate.Populate;
import org.jenkinsci.plugins.p4.workspace.ManualWorkspaceImpl;
import org.jenkinsci.plugins.p4.workspace.Workspace;
import org.jenkinsci.plugins.p4.workspace.WorkspaceSpec;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class GlobalLibraryScmSource extends AbstractP4ScmSource {

	private final String path;

	public String getPath() {
		return path;
	}

	@DataBoundConstructor
	public GlobalLibraryScmSource(String credential, String charset, String path) {
		super(credential);
		this.path = path;
		setCharset(charset);
	}

	@Override
	protected SCMRevision retrieve(@NonNull final String thingName, @NonNull TaskListener listener)
			throws IOException, InterruptedException {
		try {
			P4Path p4Path = new P4Path(path, thingName);
			P4SCMHead head = new P4SCMHead(thingName, p4Path);
			SCMRevision revision = getRevision(head, listener);
			return revision;
		} catch (Exception e) {
			throw new IOException(e.getMessage());
		}
	}

	// Not used for Global Library
	@Override
	public P4Browser getBrowser() {
		return null;
	}

	@Override
	public List<P4SCMHead> getHeads(@NonNull TaskListener listener) throws Exception {
		// not used
		return new ArrayList<>();
	}

	@Override
	public List<P4SCMHead> getTags(@NonNull TaskListener listener) throws Exception {
		// not used
		return new ArrayList<>();
	}

	@Override
	public synchronized PerforceScm build(@NonNull SCMHead head, SCMRevision revision) {
		if (head instanceof P4SCMHead && revision instanceof P4SCMRevision) {
			P4SCMHead perforceHead = (P4SCMHead) head;
			P4SCMRevision perforceRevision = (P4SCMRevision) revision;

			// Build workspace from 'head' paths
			P4Path path = perforceHead.getPath();
			Workspace workspace = getWorkspace(path);

			// Build populate from revision
			String pin = perforceRevision.getRef().toString();
			Populate populate = new GraphHybridImpl(true, pin, null);
			PerforceScm scm = new PerforceScm(getCredential(), workspace, null, populate, getBrowser());
			return scm;
		} else {
			throw new IllegalArgumentException("SCMHead and/or SCMRevision not a Perforce instance!");
		}
	}

	@Override
	public Workspace getWorkspace(P4Path path) {
		if (path == null) {
			throw new IllegalArgumentException("missing path");
		}

		UUID uuid = UUID.randomUUID();
		setFormat("jenkins-lib-" + uuid);

		// patch for older configuration version when '/...' was not required.
		String depotView = path.getPath();
		if(!depotView.endsWith("/...")) {
			depotView += "/...";
		}

		String client = getFormat();
		String view = ViewMapHelper.getClientView(depotView, client);
		WorkspaceSpec spec = new WorkspaceSpec(view, null);
		return new ManualWorkspaceImpl(getCharset(), false, client, spec, true);
	}

	@Extension
	@Symbol("globalLib")
	public static final class DescriptorImpl extends P4SCMSourceDescriptor {

		@Override
		public String getDisplayName() {
			return "Helix Library";
		}

		public FormValidation doCheckPath(@QueryParameter String value) {
			if (value == null || value.isEmpty() || !value.endsWith("/...")) {
				return FormValidation.error("Please provide a valid Depot path e.g. //depot/libs/...");
			}
			return FormValidation.ok();
		}

		public AutoCompletionCandidates doAutoCompletePath(@QueryParameter String value) {
			NavigateHelper nav = new NavigateHelper(10);
			return nav.getCandidates(value);
		}

		@Override
		public boolean isApplicable(Class<? extends SCMSourceOwner> owner) {
			return false;
		}
	}
}

@@ -3409,60 +3409,642 @@
 ;%0A%09%09
-WorkspaceSpec spec = new WorkspaceSpec(view, null
+%0A%09%09// Make a workspace spec that is all default except for make it writeable.%0A%09%09// Without that, we can't do Replay in pipelines.%0A%09%09boolean allwrite = true;%09// the change%0A%09%09boolean clobber = true;%0A%09%09boolean compress = false;%0A%09%09boolean locked = false;%0A%09%09boolean modtime = false;%0A%09%09boolean rmdir = false;%0A%09%09String streamName = null;%0A%09%09String line = %22LOCAL%22;%0A%09%09String changeView = null;%0A%09%09String type = null;%0A%09%09String serverID = null;%0A%09%09boolean backup = true;%0A%09%09WorkspaceSpec spec = new WorkspaceSpec(%0A%09%09%09allwrite, clobber, compress,%0A%09%09%09locked,  modtime,  rmdir,  streamName,%0A%09%09%09line,  view,  changeView,  type,%0A%09%09%09serverID,  backup 
 );%0A
+%0A
 %09%09re

Fix ability to do Replay in Pipelines