package org.netbeans.gradle.project.model;
import java.io.File;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.model.GenericProjectProperties;
import org.netbeans.gradle.model.GradleProjectTree;
import org.netbeans.gradle.model.GradleTaskID;
import org.netbeans.gradle.model.util.CollectionUtils;
import org.netbeans.gradle.project.script.ScriptFileProvider;
import org.netbeans.gradle.project.util.NbFileUtils;
public final class NbGradleProjectTree implements Serializable {
private static final long serialVersionUID = 1L;
private final GenericProjectProperties genericProperties;
private final Collection<GradleTaskID> tasks;
private final Collection<NbGradleProjectTree> children;
private final AtomicReference<NbGradleProjectTree> parentRef;
private final AtomicReference<Map<String, NbGradleProjectTree>> childrenMap;
private final AtomicInteger numberOfSubprojectsRef;
public NbGradleProjectTree(
GenericProjectProperties genericProperties,
Collection<GradleTaskID> tasks,
Collection<NbGradleProjectTree> children) {
ExceptionHelper.checkNotNullArgument(genericProperties, "genericProperties");
this.genericProperties = genericProperties;
this.tasks = CollectionUtils.copyNullSafeList(tasks);
this.children = CollectionUtils.copyNullSafeList(children);
this.childrenMap = new AtomicReference<>(null);
this.parentRef = new AtomicReference<>(null);
this.numberOfSubprojectsRef = new AtomicInteger(-1);
}
public NbGradleProjectTree(GradleProjectTree tree) {
ExceptionHelper.checkNotNullArgument(tree, "tree");
this.genericProperties = tree.getGenericProperties();
this.tasks = tree.getTasks();
this.children = fromModels(tree.getChildren());
this.childrenMap = new AtomicReference<>(null);
this.parentRef = new AtomicReference<>(null);
this.numberOfSubprojectsRef = new AtomicInteger(-1);
}
public int getNumberOfSubprojects() {
int result = numberOfSubprojectsRef.get();
if (result < 0) {
result = calculateNumberOfSubprojects();
numberOfSubprojectsRef.set(result);
}
return result;
}
private int calculateNumberOfSubprojects() {
int result = 0;
for (NbGradleProjectTree child: children) {
result++;
result += child.getNumberOfSubprojects();
}
return result;
}
public NbGradleProjectTree getParent(NbGradleProjectTree root) {
if (root == this) {
return null;
}
NbGradleProjectTree result = parentRef.get();
if (result == null) {
root.updateParentRefOfChildren();
result = parentRef.get();
}
return result;
}
private void updateParentRefOfChildren() {
for (NbGradleProjectTree child: children) {
child.parentRef.set(this);
child.updateParentRefOfChildren();
}
}
private static NbGradleProjectTree findParent(NbGradleProjectTree root, NbGradleProjectTree project) {
// TODO: We could optimize this by first guessing by the project path.
for (NbGradleProjectTree child: root.getChildren()) {
if (child == project) {
return root;
}
NbGradleProjectTree candidate = findParent(child, project);
if (candidate != null) {
return candidate;
}
}
return null;
}
private static Collection<NbGradleProjectTree> fromModels(Collection<GradleProjectTree> models) {
List<NbGradleProjectTree> result = new ArrayList<>(models.size());
for (GradleProjectTree model: models) {
result.add(new NbGradleProjectTree(model));
}
return Collections.unmodifiableList(result);
}
public static NbGradleProjectTree createEmpty(Path projectDir, ScriptFileProvider scriptProvider) {
String baseName = NbFileUtils.getFileNameStr(projectDir);
return new NbGradleProjectTree(
NbGenericModelInfo.createProjectProperties(baseName, ":" + baseName, projectDir, scriptProvider),
Collections.<GradleTaskID>emptyList(),
Collections.<NbGradleProjectTree>emptyList());
}
public GenericProjectProperties getGenericProperties() {
return genericProperties;
}
public Collection<GradleTaskID> getTasks() {
return tasks;
}
public String getProjectName() {
return genericProperties.getProjectName();
}
public String getProjectFullName() {
return genericProperties.getProjectFullName();
}
public File getProjectDir() {
return genericProperties.getProjectDir();
}
public Collection<NbGradleProjectTree> getChildren() {
return children;
}
private Map<String, NbGradleProjectTree> createChildrenMap() {
Map<String, NbGradleProjectTree> result = CollectionUtils.newHashMap(children.size());
for (NbGradleProjectTree child: children) {
result.put(child.getProjectName(), child);
}
return Collections.unmodifiableMap(result);
}
private Map<String, NbGradleProjectTree> getChildrenMap() {
Map<String, NbGradleProjectTree> result = childrenMap.get();
if (result == null) {
childrenMap.set(createChildrenMap());
result = childrenMap.get();
}
return result;
}
public NbGradleProjectTree findByPath(String path) {
NbGradleProjectTree result = this;
for (String name: path.split(":")) {
if (name.length() != 0) {
result = result.getChildrenMap().get(name);
if (result == null) {
return null;
}
}
}
return result;
}
private Object writeReplace() {
return new SerializedFormat(this);
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Use proxy.");
}
private static final class SerializedFormat implements Serializable {
private static final long serialVersionUID = 1L;
private final GenericProjectProperties genericProperties;
private final Collection<GradleTaskID> tasks;
private final Collection<NbGradleProjectTree> children;
public SerializedFormat(NbGradleProjectTree source) {
this.genericProperties = source.genericProperties;
this.tasks = source.tasks;
this.children = source.children;
}
private Object readResolve() throws ObjectStreamException {
return new NbGradleProjectTree(genericProperties, tasks, children);
}
}
}