package com.deliver8r.repo.impl;

import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.version.InvalidVersionSpecificationException;
import org.eclipse.aether.version.VersionScheme;

import com.deliver8r.repo.Coordinates;
import com.deliver8r.repo.RepoUtils;

/**
 * Base of Resources for Deliver8r.
 * 
 * @version $Revision$ $Date$
 */
public class CoordinatesImpl implements Coordinates {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5606978250219029755L;

	/**
	 * 
	 */

	private VersionScheme versionScheme = new org.eclipse.aether.util.version.GenericVersionScheme();

	//--------------------------/
	//- Class/Member Variables -/
	//--------------------------/

	/**
	 * 
	 * Optionally specified identifier .
	 */
	private String id;

	/**
	 * Field modelVersion.
	 */
	private String modelVersion = "1.0.0";

	/**
	 * <code>groupId</code> of artifact.
	 */
	private String groupId;

	/**
	 * <code>artifactId</code> of artifact.
	 */
	private String artifactId;

	/**
	 * <code>version</code> of artifact.
	 */
	private String version;

	/**
	 * <code>packaging</code> of artifact.
	 */
	private String packaging;

	/**
	 * <code>classifier</code> of artifact.
	 */
	private String classifier;

	//-----------/
	//- Methods -/
	//-----------/

	/**
	 * Get <code>artifactId</code> of artifact.
	 * 
	 * @return String
	 */
	public String getArtifactId() {
		return this.artifactId;
	} //-- String getArtifactId()

	/**
	 * Get <code>classifier</code> of artifact.
	 * 
	 * @return String
	 */
	public String getClassifier() {
		return this.classifier;
	} //-- String getClassifier()

	/**
	 * Get <code>groupId</code> of artifact.
	 * 
	 * @return String
	 */
	public String getGroupId() {
		return this.groupId;
	} //-- String getGroupId()

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#getId()
	 */
	@Override
	public String getId() {
		return this.id;
	} //-- String getId()

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#getModelVersion()
	 */
	@Override
	public String getModelVersion() {
		return this.modelVersion;
	} //-- String getModelVersion()

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#getPackaging()
	 */
	@Override
	public String getPackaging() {
		return this.packaging;
	} //-- String getPackaging()

	/**
	 * Get <code>version</code> of artifact.
	 * 
	 * @return String
	 */
	public String getVersion() {
		return this.version;
	} //-- String getVersion()

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setArtifactId(java.lang.String)
	 */
	@Override
	public Coordinates setArtifactId(String artifactId) {
		this.artifactId = artifactId;
		return this;
	} //-- void setArtifactId( String )

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setClassifier(java.lang.String)
	 */
	@Override
	public Coordinates setClassifier(String classifier) {
		this.classifier = classifier;
		return this;
	} //-- void setClassifier( String )

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setGroupId(java.lang.String)
	 */
	@Override
	public Coordinates setGroupId(String groupId) {
		this.groupId = groupId;
		return this;
	} //-- void setGroupId( String )

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setId(java.lang.String)
	 */
	@Override
	public Coordinates setId(String id) {
		this.id = id;
		return this;
	} //-- void setId( String )

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setModelVersion(java.lang.String)
	 */
	@Override
	public Coordinates setModelVersion(String modelVersion) {
		this.modelVersion = modelVersion;
		return this;
	} //-- void setModelVersion( String )

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setPackaging(java.lang.String)
	 */
	@Override
	public Coordinates setPackaging(String packaging) {
		this.packaging = packaging;
		return this;
	} //-- void setPackaging( String )

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#setVersion(java.lang.String)
	 */
	@Override
	public Coordinates setVersion(String version) {
		this.version = version;
		return this;
	} //-- void setVersion( String )

	public String getType() {
		return (getPackaging() == null) ? RepoUtils.BASIC_PACKAGING : getPackaging();
	}

	public CoordinatesImpl() {
		super();
	}

	public CoordinatesImpl(CoordinatesImpl c) {
		this(c.getGroupId(), c.getArtifactId(), c.getClassifier(), c.getVersion(), c.getPackaging());
	}

	public CoordinatesImpl(String groupId, String artifactId, String classifier, String version, String packaging) {
		this();
		this.setGroupId(groupId);
		this.setArtifactId(artifactId);
		this.setVersion(version);
		this.setClassifier(classifier);
		this.setPackaging(packaging);
	}

	public CoordinatesImpl(Artifact artifact) {
		this(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), artifact.getVersion(),
				artifact.getExtension());
	}

	@Override
	public int compareTo(Coordinates o) {
		try {
			return this.versionedCompare(o);
		} catch (InvalidVersionSpecificationException e) {
			//			throw new RuntimeException(e); // TODO Currently, I can find no way that this happens
			return 0;
		}
	}

	@Override
	public String toString() {
		return "CoordinatesImpl [versionScheme=" + versionScheme + ", id=" + id + ", modelVersion=" + modelVersion
				+ ", groupId=" + groupId + ", artifactId=" + artifactId + ", version=" + version + ", packaging="
				+ packaging + ", classifier=" + classifier + "]";
	}

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#copyFromSpec(com.deliver8r.repo.impl.CoordinatesImpl)
	 */
	@Override
	public CoordinatesImpl copyFromSpec(Coordinates hs) {
		this.setArtifactId(hs.getArtifactId());
		this.setClassifier(hs.getClassifier());
		this.setGroupId(hs.getGroupId());
		this.id = hs.getId(); // TODO Really?
		this.setVersion(hs.getVersion());
		return this;
	}

	public static Coordinates fromFullSignaturePath(String x) {
		java.util.StringTokenizer st = new java.util.StringTokenizer(x, ":");
		int t = st.countTokens();
		if (t != 5)
			throw new IllegalArgumentException("Too few tokens in " + x);
		Coordinates set = new CoordinatesImpl();
		set.setGroupId(st.nextToken());
		set.setArtifactId(st.nextToken());
		set.setClassifier(st.nextToken());
		set.setVersion(st.nextToken());
		set.setPackaging(st.nextToken());
		return set;
	}

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#matches(com.deliver8r.repo.impl.CoordinatesImpl)
	 */
	@Override
	public boolean matches(Coordinates pattern) {
		return _matcher(pattern.getGroupId(), this.getGroupId())
				&& _matcher(pattern.getArtifactId(), this.getArtifactId())
				&& _matcher(pattern.getClassifier(), this.getClassifier())
				&& _matcher(pattern.getType(), this.getType()) && _versionmatcher(pattern.getVersion());
	}

	private boolean _matcher(String pattern, String value) {
		if (value == null)
			return true;
		if (pattern == null)
			return true;
		boolean b = java.util.regex.Pattern.compile(pattern).matcher(value).matches();
		return b;
	}

	private boolean _versionmatcher(String range) {
		if (this.getVersion() == null)
			return true;
		if (range == null)
			return true;
		try {
			boolean b = this.inRange(range);
			return b;
		} catch (org.eclipse.aether.version.InvalidVersionSpecificationException e) {
			return false;
		}
	}

	@Override
	public VersionScheme getVersionScheme() {
		return this.versionScheme;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((artifactId == null) ? 0 : artifactId.hashCode());
		result = prime * result + ((classifier == null) ? 0 : classifier.hashCode());
		result = prime * result + ((groupId == null) ? 0 : groupId.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((modelVersion == null) ? 0 : modelVersion.hashCode());
		result = prime * result + ((packaging == null) ? 0 : packaging.hashCode());
		result = prime * result + ((version == null) ? 0 : version.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CoordinatesImpl other = (CoordinatesImpl) obj;
		if (artifactId == null) {
			if (other.artifactId != null)
				return false;
		} else if (!artifactId.equals(other.artifactId))
			return false;
		if (classifier == null) {
			if (other.classifier != null)
				return false;
		} else if (!classifier.equals(other.classifier))
			return false;
		if (groupId == null) {
			if (other.groupId != null)
				return false;
		} else if (!groupId.equals(other.groupId))
			return false;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (modelVersion == null) {
			if (other.modelVersion != null)
				return false;
		} else if (!modelVersion.equals(other.modelVersion))
			return false;
		if (packaging == null) {
			if (other.packaging != null)
				return false;
		} else if (!packaging.equals(other.packaging))
			return false;
		if (version == null) {
			if (other.version != null)
				return false;
		} else if (!version.equals(other.version))
			return false;
		return true;
	}

	/* (non-Javadoc)
	 * @see com.deliver8r.repo.impl.Coordinates#asDependency(java.lang.String)
	 */
	@Override
	public Dependency asDependency(String scope) {
		return new Dependency(new DefaultArtifact(getFullSignaturePath()), scope);
	}

}
