// Path: src/main/java/com/lassekoskela/maven/BuildTimelineExtension.java
// @Component(role = AbstractMavenLifecycleParticipant.class, hint = "buildtimeline")
// public class BuildTimelineExtension extends MavenExtension {
// 
//     static final String ACTIVATION_PROPERTY_KEY = "maven-build-utils.activate-timeline";
//     static final String ACTIVATION_PROFILE_KEY = "maven-build-utils.activationTimelineProfiles";
//     
// 	@Requirement
// 	Logger logger;
// 
// 	@Override
// 	public void afterProjectsRead(MavenSession session)
// 			throws MavenExecutionException {
// 
//         if (shouldBeActive(session, ACTIVATION_PROPERTY_KEY, ACTIVATION_PROFILE_KEY)) {
//             registerExecutionListener(session, new BuildTimelineListener(logger));
//         }
//     }
// }
// 
// Path: src/main/java/com/lassekoskela/maven/bean/Timeline.java
// public class Timeline {
// 
// 	private final Iterable<Project> projects;
// 
// 	public Timeline(Iterable<Project> projects) {
// 		this.projects = projects;
// 	}
// 
// 	public Iterable<Project> getProjects() {
// 		return projects;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		return Objects.hashCode(projects);
// 	}
// 
// 	@Override
// 	public boolean equals(Object object) {
// 		if (object instanceof Timeline) {
// 			Timeline that = (Timeline) object;
// 			return Objects.equal(this.projects, that.projects);
// 		}
// 		return false;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		return Objects.toStringHelper(this).add("projects", projects).toString();
// 	}
// }
// 
// Path: src/main/java/com/lassekoskela/maven/timeline/GoalOrganizer.java
// public static class DisplayableGoal {
// 
// 	private final String projectId;
// 	private final String phaseId;
// 	private final String goalId;
// 	private final String dependencies;
// 	private final long leftPosition;
// 	private final long topPosition;
// 	private final long heightPosition;
// 
// 	@VisibleForTesting
// 	DisplayableGoal(String projectId, String phaseId, String goalId, String dependencies, long leftPosition,
// 			long topPosition, long heightPosition) {
// 
// 		this.projectId = projectId;
// 		this.phaseId = phaseId;
// 		this.goalId = goalId;
// 		this.dependencies = dependencies;
// 		this.leftPosition = leftPosition;
// 		this.topPosition = topPosition;
// 		this.heightPosition = heightPosition;
// 	}
// 
// 	public String getProjectId() {
// 		return projectId;
// 	}
// 
// 	public String getPhaseId() {
// 		return phaseId;
// 	}
// 
// 	public String getGoalId() {
// 		return goalId;
// 	}
// 
// 	public String getDependencies() {
// 		return dependencies;
// 	}
// 
// 	public long getLeftPosition() {
// 		return leftPosition;
// 	}
// 
// 	public long getTopPosition() {
// 		return topPosition;
// 	}
// 
// 	public long getHeightPosition() {
// 		return heightPosition;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		return Objects
// 				.hashCode(projectId, phaseId, goalId, dependencies, leftPosition, topPosition, heightPosition);
// 	}
// 
// 	@Override
// 	public boolean equals(Object object) {
// 		if (object instanceof DisplayableGoal) {
// 			DisplayableGoal that = (DisplayableGoal) object;
// 			return Objects.equal(this.projectId, that.projectId) && Objects.equal(this.phaseId, that.phaseId)
// 					&& Objects.equal(this.goalId, that.goalId)
// 					&& Objects.equal(this.dependencies, that.dependencies)
// 					&& Objects.equal(this.leftPosition, that.leftPosition)
// 					&& Objects.equal(this.topPosition, that.topPosition)
// 					&& Objects.equal(this.heightPosition, that.heightPosition);
// 		}
// 		return false;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		return Objects.toStringHelper(this).add("projectId", projectId).add("phaseId", phaseId)
// 				.add("goalId", goalId).add("dependencies", dependencies).add("leftPosition", leftPosition)
// 				.add("topPosition", topPosition).add("heightPosition", heightPosition).toString();
// 	}
// }


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import org.codehaus.plexus.logging.Logger;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.lassekoskela.maven.BuildTimelineExtension;
import com.lassekoskela.maven.bean.Timeline;
import com.lassekoskela.maven.timeline.GoalOrganizer.DisplayableGoal;
		File exportFile = getExportFile(EXPORT_FILE);
		timelineMustache.execute(new FileWriter(exportFile), buildTimelineModel(serializedBuildItems)).flush();
		return exportFile;
	}

	private String serializeBuildItems(Timeline timeline) throws IOException {
		Writer buildItemsWriter = new StringWriter();
		for (DisplayableGoal displayableGoal : goalOrganizer.organize(timeline)) {
			buildItemMustache.execute(buildItemsWriter, buildItemModel(displayableGoal));
		}
		buildItemsWriter.flush();
		return buildItemsWriter.toString();
	}

	@VisibleForTesting
	File getExportFile(String filePath) {
		File targetDir = new File("target");
		targetDir.mkdirs();
		File exportFile = new File(targetDir, filePath);
		if (exportFile.exists() && !exportFile.delete()) {
			throw new IllegalStateException("Cannot delete existing export file");
		}
		return exportFile;
	}

	private Map<String, String> buildTimelineModel(String serializedBuildItems) {
		return ImmutableMap.of("timeline", serializedBuildItems);
	}

	@VisibleForTesting
// Path: src/main/java/com/lassekoskela/maven/BuildTimelineExtension.java
// @Component(role = AbstractMavenLifecycleParticipant.class, hint = "buildtimeline")
// public class BuildTimelineExtension extends MavenExtension {
// 
//     static final String ACTIVATION_PROPERTY_KEY = "maven-build-utils.activate-timeline";
//     static final String ACTIVATION_PROFILE_KEY = "maven-build-utils.activationTimelineProfiles";
//     
// 	@Requirement
// 	Logger logger;
// 
// 	@Override
// 	public void afterProjectsRead(MavenSession session)
// 			throws MavenExecutionException {
// 
//         if (shouldBeActive(session, ACTIVATION_PROPERTY_KEY, ACTIVATION_PROFILE_KEY)) {
//             registerExecutionListener(session, new BuildTimelineListener(logger));
//         }
//     }
// }
// 
// Path: src/main/java/com/lassekoskela/maven/bean/Timeline.java
// public class Timeline {
// 
// 	private final Iterable<Project> projects;
// 
// 	public Timeline(Iterable<Project> projects) {
// 		this.projects = projects;
// 	}
// 
// 	public Iterable<Project> getProjects() {
// 		return projects;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		return Objects.hashCode(projects);
// 	}
// 
// 	@Override
// 	public boolean equals(Object object) {
// 		if (object instanceof Timeline) {
// 			Timeline that = (Timeline) object;
// 			return Objects.equal(this.projects, that.projects);
// 		}
// 		return false;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		return Objects.toStringHelper(this).add("projects", projects).toString();
// 	}
// }
// 
// Path: src/main/java/com/lassekoskela/maven/timeline/GoalOrganizer.java
// public static class DisplayableGoal {
// 
// 	private final String projectId;
// 	private final String phaseId;
// 	private final String goalId;
// 	private final String dependencies;
// 	private final long leftPosition;
// 	private final long topPosition;
// 	private final long heightPosition;
// 
// 	@VisibleForTesting
// 	DisplayableGoal(String projectId, String phaseId, String goalId, String dependencies, long leftPosition,
// 			long topPosition, long heightPosition) {
// 
// 		this.projectId = projectId;
// 		this.phaseId = phaseId;
// 		this.goalId = goalId;
// 		this.dependencies = dependencies;
// 		this.leftPosition = leftPosition;
// 		this.topPosition = topPosition;
// 		this.heightPosition = heightPosition;
// 	}
// 
// 	public String getProjectId() {
// 		return projectId;
// 	}
// 
// 	public String getPhaseId() {
// 		return phaseId;
// 	}
// 
// 	public String getGoalId() {
// 		return goalId;
// 	}
// 
// 	public String getDependencies() {
// 		return dependencies;
// 	}
// 
// 	public long getLeftPosition() {
// 		return leftPosition;
// 	}
// 
// 	public long getTopPosition() {
// 		return topPosition;
// 	}
// 
// 	public long getHeightPosition() {
// 		return heightPosition;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		return Objects
// 				.hashCode(projectId, phaseId, goalId, dependencies, leftPosition, topPosition, heightPosition);
// 	}
// 
// 	@Override
// 	public boolean equals(Object object) {
// 		if (object instanceof DisplayableGoal) {
// 			DisplayableGoal that = (DisplayableGoal) object;
// 			return Objects.equal(this.projectId, that.projectId) && Objects.equal(this.phaseId, that.phaseId)
// 					&& Objects.equal(this.goalId, that.goalId)
// 					&& Objects.equal(this.dependencies, that.dependencies)
// 					&& Objects.equal(this.leftPosition, that.leftPosition)
// 					&& Objects.equal(this.topPosition, that.topPosition)
// 					&& Objects.equal(this.heightPosition, that.heightPosition);
// 		}
// 		return false;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		return Objects.toStringHelper(this).add("projectId", projectId).add("phaseId", phaseId)
// 				.add("goalId", goalId).add("dependencies", dependencies).add("leftPosition", leftPosition)
// 				.add("topPosition", topPosition).add("heightPosition", heightPosition).toString();
// 	}
// }


// Path: src/main/java/com/lassekoskela/maven/timeline/Exporter.java
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import org.codehaus.plexus.logging.Logger;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.lassekoskela.maven.BuildTimelineExtension;
import com.lassekoskela.maven.bean.Timeline;
import com.lassekoskela.maven.timeline.GoalOrganizer.DisplayableGoal;

		File exportFile = getExportFile(EXPORT_FILE);
		timelineMustache.execute(new FileWriter(exportFile), buildTimelineModel(serializedBuildItems)).flush();
		return exportFile;
	}

	private String serializeBuildItems(Timeline timeline) throws IOException {
		Writer buildItemsWriter = new StringWriter();
		for (DisplayableGoal displayableGoal : goalOrganizer.organize(timeline)) {
			buildItemMustache.execute(buildItemsWriter, buildItemModel(displayableGoal));
		}
		buildItemsWriter.flush();
		return buildItemsWriter.toString();
	}

	@VisibleForTesting
	File getExportFile(String filePath) {
		File targetDir = new File("target");
		targetDir.mkdirs();
		File exportFile = new File(targetDir, filePath);
		if (exportFile.exists() && !exportFile.delete()) {
			throw new IllegalStateException("Cannot delete existing export file");
		}
		return exportFile;
	}

	private Map<String, String> buildTimelineModel(String serializedBuildItems) {
		return ImmutableMap.of("timeline", serializedBuildItems);
	}

	@VisibleForTesting
	Map<String, String> buildItemModel(DisplayableGoal goal) {