package de.uka.ipd.consensus.impl;

import java.util.Collection;
import java.util.Collections;

import de.uka.ipd.consensus.foundation.ontology.OntologyManagerException;
import de.uka.ipd.consensus.foundation.rights.DynamicRightsManagerException;
import de.uka.ipd.consensus.foundation.schema.Rateable;
import de.uka.ipd.consensus.foundation.schema.Rating;
import de.uka.ipd.consensus.foundation.schema.User;
import de.uka.ipd.consensus.foundation.schema.Version;
import de.uka.ipd.consensus.foundation.schema.Versionable;
import de.uka.ipd.consensus.foundation.user.UserManagerException;

/**
 * 
 * TODO
 * @author Thomas Much
 * @version 2006-06-14
 */
public class SQLRatingImpl implements Rating {

	private int      id;
	private double   value;
	private String   comment;
	private boolean  historical;
	private long     date;
	private long     rateddate;
	private User     creator;
	private Rateable rateable,wrappedRateable;
	private String   username;
	
	private SQLRatingManagerImpl rmi;


	protected SQLRatingImpl(SQLRatingManagerImpl rmi, int id, User creator, String username, double value, long date) {
		this( rmi, id, creator, username, null, value, null, date, 0L);
	}


	protected SQLRatingImpl(SQLRatingManagerImpl rmi, int id, String username, Rateable rateable, double value, String comment, long date, long rateddate) {
		this( rmi, id, null, username, rateable, value, comment, date, rateddate );
	}
	
	
	protected SQLRatingImpl(SQLRatingManagerImpl rmi, int id, User creator, String username, Rateable rateable, double value, String comment, long date, long rateddate) {
		this( rmi, id, creator, username, rateable, value, comment, date, rateddate, false );
	}


	protected SQLRatingImpl(SQLRatingManagerImpl rmi, int id, User creator, String username, Rateable rateable, double value, String comment, long date, long rateddate, boolean historical) {
		this.rmi        = rmi;
		this.id         = id;
		this.creator    = creator;
		this.username   = username;
		this.rateable   = rateable;
		this.value      = value;
		this.comment    = comment;
		this.date       = date;
		this.rateddate  = rateddate;
		this.historical = historical;
	}
	
	
	protected int getId() {
		return this.id;
	}
	
	
	protected String getUsername() {
		return this.username;
	}


	protected void setRateable(Rateable rateable) {
		this.rateable = rateable;
	}


	protected void setHistorical(boolean historical) {
		this.historical = historical;
	}


	public boolean isHistorical() {
		return this.historical;
	}


	public Rateable getRateable() {
		if (this.rateable == null) {
			this.wrappedRateable = null;
		}
		else if (this.wrappedRateable == null) {
			this.wrappedRateable = this.rmi.getOntologyManager().checkInternalRateable( this.rateable );
		}
		return this.wrappedRateable;
	}


	protected Rateable getInternalRateable() {
		return this.rateable;
	}


	public User getCreator() {
		if ((this.creator == null) && (this.username != null)) {
			try {
				this.creator = rmi.getUserManager().getUserByUsername( this.username );
			}
			catch (UserManagerException e) {
				rmi.getLoggingManager().error("Error reading rating creator: " + e);
			}
		}
		return this.creator;
	}
	

	public double getValue() {
		return this.value;
	}


	public void setValue(double value) {
		if (this.isHistorical()) return;
		if (!rmi.changesAllowed()) return;

		if (this.value != value) {
			Rateable rateable = this.getInternalRateable();
			
			Version ver = this.getVersion();
			long olddate = ver.getDate().getTime();
			((VersionImpl)ver).inc();
			long newdate = ver.getDate().getTime();

			long newrateddate = 0L;
			if ((rateable != null) && (rateable instanceof Versionable)) {
				// Users aren't Versionable
				Version ratedver = ((Versionable)rateable).getVersion();
				if (ratedver != null) {
					newrateddate = ratedver.getDate().getTime();
				}
			}

			rmi.changeRatingValue( this, value, this.value, newdate, olddate, newrateddate, this.rateddate, this.comment );

			this.value     = value;
			this.date      = newdate;
			this.rateddate = newrateddate;
			if (rateable != null) {
				// if this rating is assigned to a rateable, the SQLRatingManagerImpl has put the current
				// rating values into the history and has reset the comment
				this.comment = null;
			}
		}
	}


	public String getComment() {
		if (this.comment == null) {
			return "";
		}
		else {
			return this.comment;
		}
	}


	public void setComment(User setter, String comment) throws OntologyManagerException,DynamicRightsManagerException {
		if (this.isHistorical()) return;

		if ((setter == null) || (!setter.equals( this.getCreator() ))) {
			throw new DynamicRightsManagerException("Only the user himself may change his ratings' comments");
		}

		this.comment = comment;
		rmi.changeRatingComment( this, comment );
	}


	public Version getVersion() {
		return new VersionImpl( this, this.date );
	}


	public Version getRatedVersion() {
		Rateable rateable = this.getInternalRateable();
		if ((rateable != null) && (rateable instanceof Versionable) && (this.rateddate > 0L)) {
			return new VersionImpl( (Versionable)rateable, this.rateddate );
		}
		else {
			// Users aren't Versionable
			return null;
		}
	}


	public Collection getHistory() {
		if (this.isHistorical()) {
			return Collections.EMPTY_SET;
		}
		else {
			return rmi.getHistory( this );
		}
	}

	
	public boolean equals(Object obj) {

		if (obj == null) return false;
		
		if (this.getClass() != obj.getClass()) return false;

		SQLRatingImpl other = (SQLRatingImpl)obj;

		return (this.id == other.id);
	}


	public int hashCode() {
		return this.id;
	}


	public int compareTo(Object obj) {
		long otherDate = ((SQLRatingImpl)obj).date;
		
		if (this.date < otherDate) {
			return -1;
		}
		else if (this.date > otherDate) {
			return 1;
		}
		else {
			return 0;
		}
	}


	public String toString() {
		return "Rating for " + this.getRateable() + " by " + this.getCreator() + " (value " + this.getValue() + ") " + this.getVersion();
	}

}
