/*
 * Copyright (C) 2013  Christian Autermann, Jan Alexander Wirwahn,
 *                     Arne De Wall, Dustin Demuth, Saqib Rasheed
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package io.car.server.mongo.entity;

import java.util.Set;

import org.bson.types.ObjectId;
import org.joda.time.DateTime;

import com.github.jmkgreen.morphia.Key;
import com.github.jmkgreen.morphia.annotations.Embedded;
import com.github.jmkgreen.morphia.annotations.Entity;
import com.github.jmkgreen.morphia.annotations.Id;
import com.github.jmkgreen.morphia.annotations.Indexed;
import com.github.jmkgreen.morphia.annotations.Property;
import com.github.jmkgreen.morphia.annotations.Transient;
import com.github.jmkgreen.morphia.mapping.Mapper;
import com.google.common.collect.Sets;
import com.vividsolutions.jts.geom.Geometry;

import io.car.server.core.entities.Measurement;
import io.car.server.core.entities.MeasurementValue;
import io.car.server.core.entities.MeasurementValues;
import io.car.server.core.entities.Sensor;
import io.car.server.core.entities.Track;
import io.car.server.core.entities.User;

/**
 * @author Christian Autermann <autermann@uni-muenster.de>
 * @author Arne de Wall
 */
@Entity("measurements")
public class MongoMeasurement extends MongoEntityBase implements Measurement {
    public static final String IDENTIFIER = Mapper.ID_KEY;
    public static final String PHENOMENONS = "phenomenons";
    public static final String USER = "user";
    public static final String SENSOR = "sensor";
    public static final String TRACK = "track";
    public static final String GEOMETRY = "geometry";
    public static final String TIME = "time";
    @Id
    private ObjectId id = new ObjectId();
    @Property(GEOMETRY)
    private Geometry geometry;
    @Indexed
    @Property(TIME)
    private DateTime time;
    @Indexed
    @Property(USER)
    private Key<MongoUser> user;
    @Property(SENSOR)
    private Key<MongoSensor> sensor;
    @Indexed
    @Property(TRACK)
    private Key<MongoTrack> track;
    @Embedded(PHENOMENONS)
    private Set<MongoMeasurementValue> values = Sets.newHashSet();
    @Transient
    private MongoTrack _track;
    @Transient
    private MongoUser _user;
    @Transient
    private MongoSensor _sensor;

    @Override
    public Geometry getGeometry() {
        return this.geometry;
    }

    @Override
    public void setGeometry(Geometry location) {
        this.geometry = location;
    }

    @Override
    public String getIdentifier() {
        return this.id == null ? null : this.id.toString();
    }

    @Override
    public void setIdentifier(String identifier) {
        this.id = id == null ? null : new ObjectId(identifier);
    }

    @Override
    public DateTime getTime() {
        return this.time;
    }

    @Override
    public void setTime(DateTime time) {
        this.time = time;
    }

    @Override
    public boolean hasGeometry() {
        return getGeometry() != null;
    }

    @Override
    public boolean hasIdentifier() {
        return getIdentifier() != null;
    }

    @Override
    public boolean hasTime() {
        return getTime() != null;
    }

    @Override
    public MeasurementValues getValues() {
        return MeasurementValues.from(this.values).build();
    }

    @Override
    public int compareTo(Measurement o) {
        return this.getTime().compareTo(o.getTime());
    }

    @Override
    public MongoUser getUser() {
        if (this._user == null) {
            this._user = getMongoDB().dereference(MongoUser.class, this.user);
        }
        return this._user;
    }

    @Override
    public void setUser(User user) {
        this._user = (MongoUser) user;
        this.user = getMongoDB().reference(this._user);
    }

    @Override
    public void addValue(MeasurementValue value) {
        this.values.add((MongoMeasurementValue) value);
    }

    @Override
    public void removeValue(MeasurementValue value) {
        this.values.remove((MongoMeasurementValue) value);
    }

    @Override
    public MongoSensor getSensor() {
        if (this._sensor == null) {
            this._sensor = getMongoDB()
                    .dereference(MongoSensor.class, this.sensor);
        }
        return this._sensor;
    }

    @Override
    public void setSensor(Sensor sensor) {
        this._sensor = (MongoSensor) sensor;
        this.sensor = getMongoDB().reference(this._sensor);
    }

    @Override
    public void setTrack(Track track) {
        this._track = (MongoTrack) track;
        this.track = getMongoDB().reference(this._track);
    }

    @Override
    public MongoTrack getTrack() {
        if (this._track == null) {
            this._track = getMongoDB().dereference(MongoTrack.class, this.track);
        }
        return this._track;
    }

    @Override
    public boolean hasUser() {
        return getUser() != null;
    }

    @Override
    public boolean hasSensor() {
        return getSensor() != null;
    }

    @Override
    public boolean hasTrack() {
        return getTrack() != null;
    }
}

@@ -2512,24 +2512,24 @@
 r;%0A    @
-Property
+Embedded
 (SENSOR)
@@ -2537,28 +2537,24 @@
     private 
-Key%3C
 MongoSensor%3E
@@ -2552,17 +2552,16 @@
 goSensor
-%3E
  sensor;
@@ -2817,56 +2817,8 @@
 ser;
-%0A    @Transient%0A    private MongoSensor _sensor;
 %0A%0A  
@@ -4619,160 +4619,8 @@
 ) %7B%0A
-        if (this._sensor == null) %7B%0A            this._sensor = getMongoDB()%0A                    .dereference(MongoSensor.class, this.sensor);%0A        %7D%0A
     
@@ -4631,25 +4631,24 @@
 return this.
-_
 sensor;%0A    
@@ -4716,25 +4716,24 @@
        this.
-_
 sensor = (Mo
@@ -4755,68 +4755,8 @@
 or;%0A
-        this.sensor = getMongoDB().reference(this._sensor);%0A
     

embed sensor in MongoMeasurement