felix@2743: package de.intevation.flys.artifacts.model;
felix@2743: 
felix@2743: import java.util.List;
felix@2743: import java.awt.geom.Point2D;
felix@2743: 
felix@2743: import org.apache.log4j.Logger;
felix@2743: 
felix@2743: import de.intevation.artifacts.Artifact;
felix@2743: import de.intevation.artifacts.CallContext;
felix@2743: import de.intevation.artifacts.DataProvider;
felix@2743: 
felix@2743: import de.intevation.flys.artifacts.StaticWKmsArtifact;
felix@5797: import de.intevation.flys.artifacts.StaticWQKmsArtifact;
felix@2747: import de.intevation.flys.artifacts.math.Linear;
felix@2743: 
felix@2743: /**
felix@2747:  * Facet to access a point.
felix@2743:  */
felix@2743: public class RelativePointFacet
felix@2743: extends      BlackboardDataFacet
felix@2743: implements   FacetTypes {
felix@2743: 
felix@2999:     /** Own logger. */
felix@2743:     private static Logger logger = Logger.getLogger(RelativePointFacet.class);
felix@2743: 
felix@2743:     /** Trivial Constructor. */
felix@2743:     public RelativePointFacet(String description) {
felix@2743:         this(RELATIVE_POINT, description);
felix@2743:     }
felix@2743: 
felix@2747: 
felix@2743:     public RelativePointFacet(String name, String description) {
felix@2743:         this.name        = name;
felix@2743:         this.description = description;
felix@2743:         this.index       = 0;
felix@2743:     }
felix@2743: 
felix@2743: 
felix@2758:     protected Point2D calculateDurationCurvePoint(CallContext context,
felix@5797:         WKms wKms)
felix@2758:     {
felix@2760:         // TODO here and in reference curve calc: Do warn if more than 1
felix@2760:         // provider found or (way better) handle it.
felix@2747:         Object wqdays = null;
felix@3442:         double km     = 0d;
felix@2743:         List<DataProvider> providers = context.
felix@2758:             getDataProvider(DurationCurveFacet.BB_DURATIONCURVE);
felix@2743:         if (providers.size() < 1) {
felix@2747:             logger.warn("Could not find durationcurve data provider.");
felix@2743:         }
felix@2743:         else {
felix@2747:             wqdays = providers.get(0).provideData(
felix@2747:                 DurationCurveFacet.BB_DURATIONCURVE,
felix@2747:                 null,
felix@2747:                 context);
felix@2743:         }
felix@2747:         List<DataProvider> kmproviders = context.
felix@2747:             getDataProvider(DurationCurveFacet.BB_DURATIONCURVE_KM);
felix@2747:         if (kmproviders.size() < 1) {
felix@2747:             logger.warn("Could not find durationcurve.km data provider.");
felix@2747:         }
felix@2747:         else {
felix@2747:             logger.debug("Found durationcurve.km data provider.");
felix@2747:             String dckm = providers.get(0).provideData(
felix@2747:                 DurationCurveFacet.BB_DURATIONCURVE_KM,
felix@2747:                 null,
felix@2747:                 context).toString();
felix@2747:             km = Double.valueOf(dckm);
felix@2747:         }
felix@2747: 
felix@2747:         if (wqdays != null) {
felix@2747:             // Which W at this km?
felix@5797:             double w = StaticWKmsArtifact.getWAtKmLin(wKms, km);
felix@2747:             if (w == -1) {
felix@2747:                 logger.warn("w is -1, already bad sign!");
felix@2747:             }
felix@2747:             // Where is this W passed by in the wq-curve?
felix@2747:             WQDay wqday = (WQDay) wqdays;
felix@2747:             // Doing a linear Day Of KM.
felix@2747:             int idx = 0;
felix@2747:             boolean wIncreases = wqday.getW(0) < wqday.getW(wqday.size()-1);
felix@2747:             if (wIncreases) {
felix@2747:                 while (idx < wqday.size() && wqday.getW(idx) < w) {
felix@2747:                     idx++;
felix@2747:                 }
felix@2747:             }
felix@2747:             else {
felix@2747:                 idx = wqday.size() -1;
felix@2747:                 while (idx > 0 && wqday.getW(idx) > w) {
felix@2747:                     idx--;
felix@2747:                 }
felix@2747:             }
felix@2747: 
felix@2747:             double day = 0d;
felix@2747:             int mod = (wIncreases) ? -1 : +1;
felix@2747:             if (idx != 0 && idx <= wqday.size()-1) {
felix@3442:                 day = Linear.linear(w, wqday.getW(idx+mod), wqday.getW(idx),
felix@2747:                     wqday.getDay(idx+mod), wqday.getDay(idx));
felix@2747:             }
felix@2747: 
felix@2747:             return new Point2D.Double((double) day, w);
felix@2747:         }
felix@2747:         logger.warn("not wqkms / w / day found");
felix@2758:         // TODO better signal failure.
felix@2758:         return new Point2D.Double(0d, 0d);
felix@2758:     }
felix@2758: 
felix@2758: 
felix@2758:     /**
felix@2758:      * Calculate a reference curve point, that is, a point made of
felix@2758:      * the Ws from start and end km param of the reference curve.
felix@2758:      */
felix@2758:     public Point2D calculateReferenceCurvePoint(CallContext context,
felix@5797:         WKms wKms) {
felix@5797: 
felix@2758:         List<DataProvider> providers = context.
felix@2758:             getDataProvider(ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM);
felix@2758:         if (providers.size() < 1) {
felix@2758:             logger.warn("Could not find reference curve startkm data provider.");
felix@2758:         }
felix@2758: 
felix@2758:         Double start = (Double) providers.get(0).
felix@2758:             provideData(ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM, null, context);
felix@2758: 
felix@2758:         providers = context.
felix@2758:             getDataProvider(ReferenceCurveFacet.BB_REFERENCECURVE_ENDKMS);
felix@2758:         if (providers.size() < 1) {
felix@2758:             logger.warn("Could not find reference curve endkms data provider.");
felix@2758:         }
felix@2758:         double[] ends = (double[]) providers.get(0).
felix@2758:             provideData(ReferenceCurveFacet.BB_REFERENCECURVE_ENDKMS, null, context);
felix@2758: 
felix@2758:         logger.debug("Got s " + start + " e " + ends);
felix@5797: 
felix@5797:         double startW = StaticWKmsArtifact.getWAtKmLin(wKms, start.doubleValue());
felix@2758:         // TODO handle multiple ends.
felix@5797:         double endW = StaticWKmsArtifact.getWAtKmLin(wKms, ends[0]);
felix@2758:         logger.debug("Gotw s " + startW + " e " + endW);
felix@2758:         return new Point2D.Double(startW, endW);
felix@2758:     }
felix@2758: 
felix@2758: 
felix@2758:     /**
felix@2758:      * Returns the data this facet requires.
felix@2758:      *
felix@2758:      * @param artifact the owner artifact.
felix@2758:      * @param context  the CallContext (ignored).
felix@2758:      *
felix@2758:      * @return the data.
felix@2758:      */
felix@2758:     @Override
felix@2758:     public Object getData(Artifact artifact, CallContext context) {
felix@5797:         WKms wKms = null;
felix@5797:         if (artifact instanceof StaticWKmsArtifact) {
felix@5797:             wKms = ((StaticWKmsArtifact) artifact).getWKms(0);
felix@5797:         }
felix@5797:         else if (artifact instanceof StaticWQKmsArtifact) {
felix@5797:             wKms = ((StaticWQKmsArtifact) artifact).getWQKms();
felix@5797:         }
felix@5797:         else {
felix@5797:             logger.error("Cannot handle Artifact to create relative point.");
felix@5797:             return null;
felix@5797:         }
felix@5797: 
felix@2758:         // Find out whether we live in a duration curve context, there we would
felix@2758:         // provide only a single point.
felix@2758: 
felix@2758:         if (context.getDataProvider(
felix@2758:             DurationCurveFacet.BB_DURATIONCURVE_KM).size() > 0) {
felix@5797:             return calculateDurationCurvePoint(context, wKms);
felix@2758:         }
felix@2758:         else if (context.getDataProvider(
felix@2758:             ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM).size() > 0) {
felix@5797:             return calculateReferenceCurvePoint(context, wKms);
felix@2758:         }
felix@2758: 
felix@2747:         // TODO better signal failure.
felix@2747:         return new Point2D.Double(0d, 0d);
felix@2743:     }
felix@2743: 
felix@2743: 
felix@2743:     /**
felix@2743:      * Create a deep copy of this Facet.
felix@2743:      * @return a deep copy.
felix@2743:      */
felix@2743:     @Override
felix@2743:     public RelativePointFacet deepCopy() {
felix@2743:         RelativePointFacet copy = new RelativePointFacet(description);
felix@2743:         copy.set(this);
felix@2743:         return copy;
felix@2743:     }
felix@2743: }
felix@2743: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :