/*
 * Copyright PMEase (c) 2005-2008,
 * Date: Feb 24, 2008
 * Time: 4:29:05 PM
 * All rights reserved.
 * 
 * Revision: $$Id: ArtifactPublishStep.java 1209 2008-07-28 00:16:18Z robin $$ 
 */
package com.pmease.quickbuild.plugin.artifact;

import java.io.File;
import java.util.Stack;

import org.hibernate.validator.constraints.NotEmpty;

import com.google.common.base.Preconditions;
import com.pmease.quickbuild.ArtifactFile;
import com.pmease.quickbuild.Context;
import com.pmease.quickbuild.QuickbuildException;
import com.pmease.quickbuild.annotation.Editable;
import com.pmease.quickbuild.annotation.Expressions;
import com.pmease.quickbuild.annotation.ScriptApi;
import com.pmease.quickbuild.annotation.Scriptable;
import com.pmease.quickbuild.migration.VersionedDocument;
import com.pmease.quickbuild.model.Build;
import com.pmease.quickbuild.setting.configuration.artifactstorage.ArtifactStorage;
import com.pmease.quickbuild.setting.configuration.artifactstorage.ServerArtifactStorage;
import com.pmease.quickbuild.stepsupport.Step;
import com.pmease.quickbuild.util.FileUtils;

@Editable(category="Publish", order=30, name="Artifacts", description="Publish specified files to server as build artifacts. This step " +
		"can run either from server side or from agent side.")
@ScriptApi("This step publish specified files as build artifacts.")
public class ArtifactPublishStep extends Step {
	
	private static final long serialVersionUID = 1L;
	
	private String srcPath;
	
	private String filePatterns = "**";
    
	private String destPath;
	
	@Editable(order=1000, name="Source Directory", description=
		"Specify the directory from which the files will be published. A non-absolute path " +
		"is considered to be relative to current workspace directory . If left empty, the " +
		"workspace directory itself will be used."
		)
	@ScriptApi("Get source path under which files will be published as artifacts. Null " +
			"will be returned if publish files under the workspace.")
	@Scriptable
    public String getSrcPath() {
		return srcPath;
	}

	public void setSrcPath(String srcPath) {
		this.srcPath = srcPath;
	}

	@Editable(order=1100, name="Files To Publish", description=
    	"Specify patterns of files that need to be published. Patterns will be matched " +
    	"under the <b>source directory</b> specified above. Matched files will be copied " +
    	"to the <b>destination path</b> specified below. The directory structure will " +
    	"be preserved during the copy.<br>" +
    	"<strong>NOTE:</strong> refer to " +
    	"<a href=\"$docroot/File+Pattern+Reference\" target=\"_blank\">the file patterns reference</a> " +
    	"for details of the file patterns." 
    	)
    @Expressions({
    	"all files (recursively)", "**", 
    	"all files (non-recursively)", "*"
    	})
    @NotEmpty
    @ScriptApi("Get patterns of files to be published as artifacts.")
	@Scriptable
    public String getFilePatterns() {
        return filePatterns;
    }

    public void setFilePatterns(String fileNamePatterns) {
        this.filePatterns = fileNamePatterns;
    }

    @Editable(order=1300, name="Destination Directory", description=
    	"Specify a destination directory for this publishing. Specified path is considered to be " +
    	"relative to current build's artifacts directory. If left empty, the artifacts directory " +
    	"itself will be used."
    	)
    @ScriptApi("Get destination path of published build artifacts. Null will be returned " +
    		"if publish to the <em>artifacts</em> directory itself.")
	@Scriptable
    public String getDestPath() {
   		return destPath;
    }

    public void setDestPath(String destPath) {
        this.destPath = destPath;
    }

	public void run() {
		Build build = Context.getBuild();
    	File srcDir = FileUtils.resolvePath(Context.getConfiguration().getWorkspaceDir(), getSrcPath());
    	if (!srcDir.exists())
    		throw new QuickbuildException("Can not find source directory for artifact publishing: " + srcDir.getAbsolutePath());
    	
    	String destPath;
    	if (getDestPath() != null)
    		destPath = Build.ARTIFACT_DIR + "/" + getDestPath();
    	else
    		destPath = Build.ARTIFACT_DIR;

    	ArtifactStorage artifactStorage = Context.getConfiguration().findArtifactStorage();
    	if (artifactStorage instanceof ServerArtifactStorage) {
    		artifactStorage.getBatchSupport().upload(srcDir, getFilePatterns(), build, destPath);
    	} else {
			File tempDir = FileUtils.createTempDir("artifactpublish");
			try {
				for (File file: FileUtils.listFiles(srcDir, getFilePatterns())) {
					if (file.isFile()) {
						String relativePath = FileUtils.getRelativePath(file.getAbsolutePath(), srcDir.getAbsolutePath());
						Preconditions.checkNotNull(relativePath);
						File artifactFile = new File(tempDir, relativePath);
						FileUtils.createDir(artifactFile.getParentFile());
						ArtifactFile.writeTo(artifactFile, file.length());
						if (artifactStorage.getBatchSupport() == null)
							artifactStorage.upload(artifactFile, build, destPath + relativePath);
					}
				}
				build.publish(tempDir.getAbsolutePath(), "**", destPath);
				if (artifactStorage.getBatchSupport() != null)
					artifactStorage.getBatchSupport().upload(srcDir, getFilePatterns(), build, destPath);
			} finally {
				FileUtils.deleteDir(tempDir);
			}
    	}
    }
	
	@SuppressWarnings("unused")
	private void migrate1(VersionedDocument dom, Stack<Integer> versions) {
    	if (!versions.empty()) {
    		versions.pop();
    	} else {
    		versions.push(0);
    		versions.push(0);
    	}
    }

    @SuppressWarnings("unused")
	private void migrate2(VersionedDocument dom, Stack<Integer> versions) {
    	if (dom.getRootElement().element("publishAsLinks") == null)
    		dom.getRootElement().addElement("publishAsLinks").setText("false");
    }

    @SuppressWarnings("unused")
	private void migrate3(VersionedDocument dom, Stack<Integer> versions) {
		dom.getRootElement().element("publishAsLinks").detach();
	}
	
}
