package com.momega.spacesimulator.service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.momega.spacesimulator.model.BaryCentre;
import com.momega.spacesimulator.model.CelestialBody;
import com.momega.spacesimulator.model.HistoryPoint;
import com.momega.spacesimulator.model.KeplerianTrajectory;
import com.momega.spacesimulator.model.ManeuverPoint;
import com.momega.spacesimulator.model.Model;
import com.momega.spacesimulator.model.MovingObject;
import com.momega.spacesimulator.model.OrbitIntersection;
import com.momega.spacesimulator.model.Planet;
import com.momega.spacesimulator.model.PositionProvider;
import com.momega.spacesimulator.model.Spacecraft;
import com.momega.spacesimulator.model.SurfacePoint;
import com.momega.spacesimulator.model.Timestamp;
import com.momega.spacesimulator.model.UserOrbitalPoint;
/**
* The class contains set of the useful methods to manipulate with the model.
* Created by martin on 12/29/14.
*/
@Component
public class ModelService {
private static final Logger logger = LoggerFactory.getLogger(ModelService.class);
@Autowired
private TargetService targetService;
@Autowired
private ManeuverService maneuverService;
/**
* Returns all moving object withing the model
* @param model model
* @return the list of the moving object
*/
public List<MovingObject> findAllMovingObjects(Model model) {
List<MovingObject> result = new ArrayList<>();
if (model == null) {
return result;
}
for(MovingObject dp : model.getMovingObjects()) {
result.add(dp);
}
return result;
}
/**
* Finds the moving object by its name
* @param model the model
* @param name the given name
* @return the moving object
*/
public MovingObject findMovingObjectByName(Model model, String name) {
Assert.notNull(name);
for(MovingObject dp : model.getMovingObjects()) {
if (name.equals(dp.getName())) {
return dp;
}
}
return null;
}
/**
* Returns the current valid position provider. The method returns very similar results as @{#findAllMovingObjects}
* except this method filters future maneuver points
* @param model the model
* @param timestamp the current timestamp
* @return the collection of the position providers
*/
public List<PositionProvider> findAllPositionProviders(Model model, Timestamp timestamp) {
List<PositionProvider> result = new ArrayList<>();
for(MovingObject dp : findAllMovingObjects(model)) {
result.add(dp);
KeplerianTrajectory keplerianTrajectory = dp.getTrajectory();
if (dp instanceof CelestialBody || dp instanceof BaryCentre || dp instanceof Spacecraft) {
result.add(keplerianTrajectory.getApoapsis());
result.add(keplerianTrajectory.getPeriapsis());
for(UserOrbitalPoint userOrbitalPoint : dp.getUserOrbitalPoints()) {
result.add(userOrbitalPoint);
}
}
if (dp instanceof CelestialBody) {
CelestialBody body = (CelestialBody) dp;
for(SurfacePoint surfacePoint : body.getSurfacePoints()) {
result.add(surfacePoint);
}
}
if (dp instanceof Spacecraft) {
Spacecraft spacecraft = (Spacecraft) dp;
for(HistoryPoint hp : spacecraft.getNamedHistoryPoints()) {
result.add(hp);
}
for(OrbitIntersection intersection : targetService.getOrbitIntersections(spacecraft)) {
result.add(intersection);
}
for(ManeuverPoint maneuverPoint : maneuverService.findActiveOrNextPoints(spacecraft, timestamp)) {
result.add(maneuverPoint);
}
if (spacecraft.getExitSoiOrbitalPoint()!=null) {
result.add(spacecraft.getExitSoiOrbitalPoint());
if (spacecraft.getExitSoiOrbitalPoint().getClosestPoint()!=null){
result.add(spacecraft.getExitSoiOrbitalPoint().getClosestPoint());
}
}
}
}
return result;
}
/**
* Returns the object by its index
* @param model TODO
* @param index index of the object
* @return the moving object inctance
*/
public MovingObject findMovingObjectByIndex(Model model, int index) {
Assert.isTrue(index > 0);
for(MovingObject body : findAllMovingObjects(model)) {
if (body.getIndex()==index) {
return body;
}
}
return null;
}
/**
* Gets all celestial bodies within the model
* @param model TODO
* @return the list of the celestial bodies
*/
public List<CelestialBody> findAllCelestialBodies(Model model) {
List<CelestialBody> result = new ArrayList<>();
for(MovingObject dp : findAllMovingObjects(model)) {
if (dp instanceof CelestialBody) {
result.add((CelestialBody) dp);
}
}
return result;
}
/**
* Returns the celestial objects
* @param model TODO
* @param onlyMoving if true only moving objects are returned
* @return the list of celestial bodies
*/
public List<CelestialBody> findCelestialBodies(Model model, boolean onlyMoving) {
List<CelestialBody> list = new ArrayList<>();
for (MovingObject mo : findAllMovingObjects(model)) {
if (mo instanceof CelestialBody) {
CelestialBody cb = (CelestialBody) mo;
if (!onlyMoving || !cb.isStatic()) {
list.add(cb);
}
}
}
list = sortNamedObjects(list);
return list;
}
public <T extends PositionProvider> List<T> sortNamedObjects(List<T> list) {
Collections.sort(list, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return o1.getName().compareTo(o2.getName());
}
});
return list;
}
/**
* Returns all the planets within the model
* @param model the model
* @return all planet instances
*/
public List<Planet> findAllPlanets(Model model) {
List<Planet> result = new ArrayList<>();
for(MovingObject dp : findAllMovingObjects(model)) {
if (dp instanceof Planet) {
result.add((Planet) dp);
}
}
return result;
}
public List<Spacecraft> findAllSpacecrafs(Model model) {
List<Spacecraft> result = new ArrayList<>();
for(MovingObject dp : findAllMovingObjects(model)) {
if (dp instanceof Spacecraft) {
result.add((Spacecraft) dp);
}
}
return result;
}
/**
* Removes the moving object from the model
* @param model the model
* @param movingObject the moving object
*/
public void removeMovingObject(Model model, MovingObject movingObject) {
Assert.notNull(movingObject);
logger.info("removing object '{}' from model", movingObject.getName());
model.getMovingObjects().remove(movingObject);
}
}