package org.witness.informacam.models.media; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.NoSuchElementException; import org.witness.informacam.InformaCam; import org.witness.informacam.informa.InformaService; import org.witness.informacam.utils.Constants.IRegionDisplayListener; import org.witness.informacam.utils.Constants.Logger; import android.app.Activity; import android.util.Log; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; public class IVideoRegion extends IRegion { public List<IVideoTrail> trail = null; private long timestampInQuestion = 0; private IRegionDisplayListener mListener; public IVideoRegion() { super(); } public IVideoRegion(IRegion region) throws InstantiationException, IllegalAccessException { super(); inflate(region); } @Override public void init(Activity context, IRegionBounds bounds, IRegionDisplayListener listener) { trail = new ArrayList<IVideoTrail>(); Log.d(LOG, "start time: " + bounds.startTime); IVideoTrail v = new IVideoTrail(bounds.startTime, bounds); trail.add(v); mListener = listener; super.init(context, bounds, listener); } @Override public void update(Activity a) { getBoundsAtTimestampInQuestion().calculate(mListener.getSpecs(),a); if (InformaService.getInstance() != null) InformaService.getInstance().updateRegion(this); } public void setBoundsAtTime(long timestamp, IRegionBounds bounds) { IVideoTrail v = new IVideoTrail(timestamp, bounds); if(trail == null) { trail = new ArrayList<IVideoTrail>(); } trail.add(v); } public IRegionBounds getBoundsAtTimestampInQuestion() { Log.d(LOG, "TIMESTAMP IN QUESTION: " + timestampInQuestion); return getBoundsAtTime(timestampInQuestion); } public void setTimestampInQuestion(long timestamp) { timestampInQuestion = timestamp; } public IRegionBounds getBoundsAtTime(final long timestamp) { // TODO: TreeSet logic... Log.d(LOG, "TIMESTAMP : " + timestamp); Log.d(LOG, "startTime: " + bounds.startTime); Log.d(LOG, "endTime: " + bounds.endTime); if(trail != null) { // TODO: binary search would be better here... // if timestamp matches, then return that, otherwise Collection<IVideoTrail> trailAtTime = Collections2.filter(trail, new Predicate<IVideoTrail>() { @Override public boolean apply(IVideoTrail videoTrail) { return videoTrail.timestamp == timestamp; } }); if (trailAtTime.size()>0) { try { return trailAtTime.iterator().next().bounds; } catch(NullPointerException e) { Logger.d(LOG, "we didn't get an exact match... moving on..."); // otherwise... } catch(NoSuchElementException e) { Logger.d(LOG, "we didn't get an exact match... moving on..."); // otherwise... } } // get the subset (2) of objs whose timestamp is before ts, and after IVideoTrail higher = null; IVideoTrail lower = null; Collection<IVideoTrail> lowerEnd = Collections2.filter(trail, new Predicate<IVideoTrail>() { @Override public boolean apply(IVideoTrail videoTrail) { return videoTrail.timestamp < timestamp; } }); if (lowerEnd.size() > 0) { try { Log.d(LOG, "lower end size: " + lowerEnd.size()); lower = Iterables.getLast(lowerEnd); // Log.d(LOG, "LOWER:\n" + lower.asJson().toString()); } catch (NoSuchElementException e) { Log.d(LOG, "lower end size not found",e); lower = new IVideoTrail(); } } Collection<IVideoTrail> higherEnd = Collections2.filter(trail, new Predicate<IVideoTrail>() { @Override public boolean apply(IVideoTrail videoTrail) { return videoTrail.timestamp > timestamp; } }); try { higher = higherEnd.iterator().next(); } catch(NoSuchElementException e) { Logger.d(LOG, "nothing higher..."); return lower.bounds; } // return the closest of those 2 try { return Math.abs(higher.timestamp - timestamp) < Math.abs(lower.timestamp - timestamp) ? higher.bounds : lower.bounds; } catch(NullPointerException e) { if(higher != null) { return higher.bounds; } else if(lower != null) { return lower.bounds; } } } return null; } }