package tim.prune.data;
import java.util.Set;
import tim.prune.UpdateMessageBroker;
/**
* Class to hold all track information, including data
* and the selection information
*/
public class TrackInfo
{
private Track _track = null;
private Selection _selection = null;
private FileInfo _fileInfo = null;
private PhotoList _photoList = null;
private AudioList _audioList = null;
/**
* Constructor
* @param inTrack Track object
*/
public TrackInfo(Track inTrack)
{
_track = inTrack;
_selection = new Selection(_track);
_fileInfo = new FileInfo();
_photoList = new PhotoList();
_audioList = new AudioList();
}
/**
* @return the Track object
*/
public Track getTrack() {
return _track;
}
/**
* @return the Selection object
*/
public Selection getSelection() {
return _selection;
}
/**
* @return the FileInfo object
*/
public FileInfo getFileInfo() {
return _fileInfo;
}
/**
* Replace the file info with a previously made clone
* @param inInfo cloned file info
*/
public void setFileInfo(FileInfo inInfo) {
_fileInfo = inInfo;
}
/**
* @return the PhotoList object
*/
public PhotoList getPhotoList() {
return _photoList;
}
/**
* @return the AudioList object
*/
public AudioList getAudioList() {
return _audioList;
}
/**
* Get the currently selected point, if any
* @return DataPoint if single point selected, otherwise null
*/
public DataPoint getCurrentPoint() {
return _track.getPoint(_selection.getCurrentPointIndex());
}
/**
* Get the currently selected photo, if any
* @return Photo if selected, otherwise null
*/
public Photo getCurrentPhoto() {
return _photoList.getPhoto(_selection.getCurrentPhotoIndex());
}
/**
* Get the currently selected audio clip, if any
* @return AudioClip if selected, otherwise null
*/
public AudioClip getCurrentAudio() {
return _audioList.getAudio(_selection.getCurrentAudioIndex());
}
/**
* Add a Set of Photos
* @param inSet Set containing Photo objects
* @return array containing number of photos and number of points added
*/
public int[] addPhotos(Set<Photo> inSet)
{
// Firstly count number of points and photos to add
int numPhotosToAdd = 0;
int numPointsToAdd = 0;
if (inSet != null && !inSet.isEmpty())
{
for (Photo photo : inSet)
{
if (photo != null && !_photoList.contains(photo))
{
numPhotosToAdd++;
if (photo.getDataPoint() != null) {
numPointsToAdd++;
}
}
}
}
// If there are any photos to add, add them
if (numPhotosToAdd > 0)
{
DataPoint[] dataPoints = new DataPoint[numPointsToAdd];
int pointNum = 0;
boolean hasAltitude = false;
// Add each Photo in turn
for (Photo photo : inSet)
{
if (photo != null && !_photoList.contains(photo))
{
// Add photo
_photoList.addPhoto(photo);
// Add point if there is one
if (photo.getDataPoint() != null)
{
dataPoints[pointNum] = photo.getDataPoint();
// Check if any points have altitudes
hasAltitude |= (photo.getDataPoint().getAltitude() != null);
pointNum++;
}
}
}
if (numPointsToAdd > 0)
{
// add points to track
_track.appendPoints(dataPoints);
// modify track field list
_track.getFieldList().extendList(Field.LATITUDE);
_track.getFieldList().extendList(Field.LONGITUDE);
if (hasAltitude) {_track.getFieldList().extendList(Field.ALTITUDE);}
}
}
int[] result = {numPhotosToAdd, numPointsToAdd};
return result;
}
/**
* Add a Set of Audio objects
* @param inSet Set containing Audio objects
* @return number of audio objects added
*/
public int addAudios(Set<AudioClip> inSet)
{
int numAudiosAdded = 0;
if (inSet != null && !inSet.isEmpty())
{
for (AudioClip audio : inSet)
{
if (audio != null && !_audioList.contains(audio))
{
// Add audio object
_audioList.addAudio(audio);
numAudiosAdded++;
// audio objects never have points when they're loaded
}
}
}
return numAudiosAdded;
}
/**
* Delete the currently selected point
* @return true if point deleted
*/
public boolean deletePoint()
{
if (_track.deletePoint(_selection.getCurrentPointIndex()))
{
_selection.modifyPointDeleted();
return true;
}
return false;
}
/**
* Delete the currently selected photo and optionally its point too
* @param inPointToo true to also delete associated point
* @return true if delete successful
*/
public boolean deleteCurrentPhoto(boolean inPointToo)
{
int photoIndex = _selection.getCurrentPhotoIndex();
if (photoIndex >= 0)
{
Photo photo = _photoList.getPhoto(photoIndex);
_photoList.deletePhoto(photoIndex);
// has it got a point?
if (photo.getDataPoint() != null)
{
if (inPointToo)
{
// delete point
int pointIndex = _track.getPointIndex(photo.getDataPoint());
_track.deletePoint(pointIndex);
}
else
{
// disconnect point from photo
photo.getDataPoint().setPhoto(null);
photo.setDataPoint(null);
}
}
// update subscribers
_selection.modifyPointDeleted();
UpdateMessageBroker.informSubscribers();
}
return true;
}
/**
* Delete the currently selected audio item and optionally its point too
* @param inPointToo true to also delete associated point
* @return true if delete successful
*/
public boolean deleteCurrentAudio(boolean inPointToo)
{
int audioIndex = _selection.getCurrentAudioIndex();
if (audioIndex >= 0)
{
AudioClip audio = _audioList.getAudio(audioIndex);
_audioList.deleteAudio(audioIndex);
// has it got a point?
if (audio.getDataPoint() != null)
{
if (inPointToo)
{
// delete point
int pointIndex = _track.getPointIndex(audio.getDataPoint());
_track.deletePoint(pointIndex);
}
else
{
// disconnect point from audio
audio.getDataPoint().setAudio(null);
audio.setDataPoint(null);
}
}
// update subscribers
_selection.modifyPointDeleted();
UpdateMessageBroker.informSubscribers();
}
return true;
}
/**
* Delete all the points which have been marked for deletion
* @param inSplitSegments true to split segments at deleted points
* @return number of points deleted
*/
public int deleteMarkedPoints(boolean inSplitSegments)
{
int numDeleted = _track.deleteMarkedPoints(inSplitSegments);
if (numDeleted > 0)
{
_selection.clearAll();
UpdateMessageBroker.informSubscribers();
}
return numDeleted;
}
/**
* Clone the selected range of data points
* @return shallow copy of DataPoint objects
*/
public DataPoint[] cloneSelectedRange()
{
return _track.cloneRange(_selection.getStart(), _selection.getEnd());
}
/**
* Merge the track segments within the given range
* @param inStart start index
* @param inEnd end index
* @return true if successful
*/
public boolean mergeTrackSegments(int inStart, int inEnd)
{
boolean firstTrackPoint = true;
// Loop between start and end
for (int i=inStart; i<=inEnd; i++) {
DataPoint point = _track.getPoint(i);
// Set all segments to false apart from first track point
if (point != null && !point.isWaypoint()) {
point.setSegmentStart(firstTrackPoint);
firstTrackPoint = false;
}
}
// Find following track point, if any
DataPoint nextPoint = _track.getNextTrackPoint(inEnd+1);
if (nextPoint != null) {nextPoint.setSegmentStart(true);}
_selection.markInvalid();
UpdateMessageBroker.informSubscribers();
return true;
}
/**
* Average selected points to create a new one
* @return true if successful
*/
public boolean average()
{
boolean success = _track.average(_selection.getStart(), _selection.getEnd());
if (success) {
selectPoint(_selection.getEnd()+1);
}
return success;
}
/**
* Select the given DataPoint
* @param inPoint DataPoint object to select
*/
public void selectPoint(DataPoint inPoint)
{
selectPoint(_track.getPointIndex(inPoint));
}
/**
* Increment the selected point index by the given increment
* @param inPointIncrement +1 for next point, -1 for previous etc
*/
public void incrementPointIndex(int inPointIncrement)
{
int index = _selection.getCurrentPointIndex() + inPointIncrement;
if (index < 0) index = 0;
else if (index >= _track.getNumPoints()) index = _track.getNumPoints()-1;
selectPoint(index);
}
/**
* Select the data point with the given index
* @param inPointIndex index of DataPoint to select, or -1 for none
*/
public void selectPoint(int inPointIndex)
{
if (_selection.getCurrentPointIndex() == inPointIndex || inPointIndex >= _track.getNumPoints()) {return;}
DataPoint selectedPoint = _track.getPoint(inPointIndex);
// get the index of the current photo
int photoIndex = _selection.getCurrentPhotoIndex();
// Check if point has photo or not
boolean pointHasPhoto = inPointIndex >= 0 && selectedPoint.getPhoto() != null;
if (pointHasPhoto) {
photoIndex = _photoList.getPhotoIndex(selectedPoint.getPhoto());
}
else if (photoIndex < 0 || _photoList.getPhoto(photoIndex).isConnected()) {
// selected point hasn't got a photo - deselect photo if necessary
photoIndex = -1;
}
// Check if point has an audio item or not
int audioIndex = _selection.getCurrentAudioIndex();
boolean pointHasAudio = inPointIndex >= 0 && selectedPoint.getAudio() != null;
if (pointHasAudio) {
audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
}
else if (audioIndex < 0 || _audioList.getAudio(audioIndex).isConnected()) {
// deselect current audio clip
audioIndex = -1;
}
// give to selection
_selection.selectPointPhotoAudio(inPointIndex, photoIndex, audioIndex);
}
/**
* Select the given Photo and its point if any
* @param inPhotoIndex index of photo to select
*/
public void selectPhoto(int inPhotoIndex)
{
if (_selection.getCurrentPhotoIndex() == inPhotoIndex) {return;}
// Photo is primary selection here, not as a result of a point selection
// Therefore the photo selection takes priority, deselecting point if necessary
// Find Photo object
Photo photo = _photoList.getPhoto(inPhotoIndex);
int pointIndex = _selection.getCurrentPointIndex();
DataPoint currPoint = getCurrentPoint();
if (photo != null)
{
// Has the photo got a point?
if (photo.isConnected()) {
pointIndex = _track.getPointIndex(photo.getDataPoint());
}
else {
// Check whether to deselect current point or not if photo not correlated
if (pointIndex >= 0 && _track.getPoint(pointIndex).getPhoto() != null) {
pointIndex = -1;
}
}
}
else {
// no photo, but maybe need to deselect point
if (currPoint != null && currPoint.getPhoto() != null) {
pointIndex = -1;
}
}
// Has the new point got an audio clip?
DataPoint selectedPoint = _track.getPoint(pointIndex);
int audioIndex = _selection.getCurrentAudioIndex();
if (selectedPoint != null && selectedPoint.getAudio() != null) {
// New point has an audio, so select it
audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
}
else if (currPoint != null && selectedPoint != currPoint && currPoint.getAudio() != null) {
// Old point had an audio, so deselect it
audioIndex = -1;
}
// give to selection object
_selection.selectPointPhotoAudio(pointIndex, inPhotoIndex, audioIndex);
}
/**
* Select the given audio object and its point if any
* @param inAudioIndex index of audio item to select
*/
public void selectAudio(int inAudioIndex)
{
if (_selection.getCurrentAudioIndex() == inAudioIndex) {return;}
// Audio selection takes priority, deselecting point if necessary
AudioClip audio = _audioList.getAudio(inAudioIndex);
int pointIndex = _selection.getCurrentPointIndex();
DataPoint currPoint = getCurrentPoint();
if (audio != null)
{
// Find point object and its index
if (audio.isConnected()) {
pointIndex = _track.getPointIndex(audio.getDataPoint());
}
else {
// Check whether to deselect current point or not if audio not correlated
if (pointIndex >= 0 && _track.getPoint(pointIndex).getAudio() != null) {
pointIndex = -1;
}
}
}
else {
// check if current point has audio or not
if (currPoint != null && currPoint.getAudio() != null) {
pointIndex = -1;
}
}
// Has the new point got a photo?
DataPoint selectedPoint = _track.getPoint(pointIndex);
int photoIndex = _selection.getCurrentPhotoIndex();
if (selectedPoint != null && selectedPoint.getPhoto() != null) {
// New point has a photo, so select it
photoIndex = _photoList.getPhotoIndex(selectedPoint.getPhoto());
}
else if (currPoint != null && selectedPoint != currPoint && currPoint.getPhoto() != null) {
// Old point had a photo, so deselect it
photoIndex = -1;
}
// give to selection object
_selection.selectPointPhotoAudio(pointIndex, photoIndex, inAudioIndex);
}
/**
* Extend the current selection to end at the given point, eg by shift-clicking
* @param inPointNum index of end point
*/
public void extendSelection(int inPointNum)
{
// See whether to start selection from current range start or current point
int rangeStart = _selection.getStart();
if (rangeStart < 0 || _selection.getCurrentPointIndex() != _selection.getEnd()) {
rangeStart = _selection.getCurrentPointIndex();
}
selectPoint(inPointNum);
if (rangeStart < inPointNum) {
_selection.selectRange(rangeStart, inPointNum);
}
}
}