package org.helioviewer.gl3d.camera;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.helioviewer.base.logging.Log;
import org.helioviewer.base.physics.DifferentialRotation;
import org.helioviewer.gl3d.scenegraph.math.GL3DQuatd;
import org.helioviewer.gl3d.scenegraph.math.GL3DVec3d;
import org.helioviewer.gl3d.scenegraph.rt.GL3DRay;
import org.helioviewer.gl3d.scenegraph.rt.GL3DRayTracer;
import org.helioviewer.gl3d.view.GL3DSceneGraphView;
import org.helioviewer.gl3d.wcs.CoordinateVector;
import org.helioviewer.gl3d.wcs.conversion.SolarSphereToStonyhurstHeliographicConversion;
import org.helioviewer.gl3d.wcs.impl.SolarSphereCoordinateSystem;
import org.helioviewer.gl3d.wcs.impl.StonyhurstHeliographicCoordinateSystem;
import org.helioviewer.viewmodel.changeevent.ChangeEvent;
import org.helioviewer.viewmodel.changeevent.TimestampChangedReason;
import org.helioviewer.viewmodel.view.LinkedMovieManager;
import org.helioviewer.viewmodel.view.TimedMovieView;
import org.helioviewer.viewmodel.view.View;
import org.helioviewer.viewmodel.view.ViewListener;
import org.helioviewer.viewmodel.view.jp2view.datetime.ImmutableDateTime;

/**
 * This camera is used when solar rotation tracking is enabled. It extends the
 * {@link GL3DTrackballCamera} by automatically rotating the camera around the
 * Y-Axis (pointing to solar north) by an amount calculated through
 * {@link DifferentialRotation}.
 * 
 * @author Simon Spoerri (simon.spoerri@fhnw.ch)
 * 
 */
public class GL3DTrackballCamera extends GL3DSolarRotationTrackingTrackballCamera implements ViewListener {
    private Date startDate = null;

    private CoordinateVector startPosition = null;

    private Date currentDate = null;
    private double currentRotation = 0.0;

    private StonyhurstHeliographicCoordinateSystem stonyhurstCoordinateSystem = new StonyhurstHeliographicCoordinateSystem();
    private SolarSphereCoordinateSystem solarSphereCoordinateSystem = new SolarSphereCoordinateSystem();
    private SolarSphereToStonyhurstHeliographicConversion stonyhurstConversion = (SolarSphereToStonyhurstHeliographicConversion) solarSphereCoordinateSystem.getConversion(stonyhurstCoordinateSystem);

    public GL3DTrackballCamera(GL3DSceneGraphView sceneGraphView) {
        super(sceneGraphView);
        Calendar cal = new GregorianCalendar();
        cal.set(2000, 1, 1, 0, 0, 0);
        startDate = cal.getTime();
    }

    public void activate(GL3DCamera precedingCamera) {
        super.activate(precedingCamera);
        sceneGraphView.addViewListener(this);
    }

    public void deactivate() {
        sceneGraphView.removeViewListener(this);
    };

    public String getName() {
        return "Solar Rotation Tracking Camera";
    }

    public void viewChanged(View sender, ChangeEvent aEvent) {
        TimestampChangedReason timestampReason = aEvent.getLastChangedReasonByType(TimestampChangedReason.class);
        if ((timestampReason != null) && (timestampReason.getView() instanceof TimedMovieView) && LinkedMovieManager.getActiveInstance().isMaster((TimedMovieView) timestampReason.getView())) {
            currentDate = timestampReason.getNewDateTime().getTime();
            if (startPosition != null) {
                long timediff = (currentDate.getTime() - startDate.getTime()) / 1000;

                double rotation = -DifferentialRotation.calculateRotationInRadians(0., timediff);
                // Log.debug("GL3DSolarRotationTracking: Rotating: "+rotation);

                this.getRotation().rotate(GL3DQuatd.createRotation(currentRotation - rotation, new GL3DVec3d(0, 1, 0)));
                this.updateCameraTransformation();
                this.currentRotation = rotation;
            } else {
                currentRotation = 0.0;
                resetStartPosition();
            }

        }

    }

    private void resetStartPosition() {
        GL3DRayTracer positionTracer = new GL3DRayTracer(sceneGraphView.getHitReferenceShape(), this);
        GL3DRay positionRay = positionTracer.castCenter();

        GL3DVec3d position = positionRay.getHitPoint();

        if (position != null) {
            CoordinateVector solarSpherePosition = solarSphereCoordinateSystem.createCoordinateVector(position.x, position.y, position.z);
            CoordinateVector stonyhurstPosition = stonyhurstConversion.convert(solarSpherePosition);
            // Log.debug("GL3DSolarRotationTrackingCam: StonyhurstPosition="+stonyhurstPosition);
            this.startPosition = stonyhurstPosition;

            Log.debug("GL3DSolarRotationTracking.Set Start hitpoint! " + positionRay.getDirection());
        } else {
            Log.debug("GL3DSolarRotationTracking.cannot reset hitpoint! " + positionRay.getDirection());

        }

    }

    private Date getStartDate() {
        if (LinkedMovieManager.getActiveInstance() == null) {
            return null;
        }
        TimedMovieView masterView = LinkedMovieManager.getActiveInstance().getMasterMovie();
        if (masterView == null) {
            return null;
        }
        ImmutableDateTime idt = masterView.getCurrentFrameDateTime();
        if (idt == null) {
            return null;
        }
        return idt.getTime();
    }
}

@@ -159,16 +159,63 @@
 ng.Log;%0A
+import org.helioviewer.base.physics.Constants;%0A
 import o
@@ -810,32 +810,78 @@
 ordinateSystem;%0A
+import org.helioviewer.jhv.display.Displayer;%0A
 import org.helio
@@ -1709,43 +1709,8 @@
 er %7B
-%0A    private Date startDate = null;
 %0A%0A  
@@ -2374,129 +2374,8 @@
 w);%0A
-        Calendar cal = new GregorianCalendar();%0A        cal.set(2000, 1, 1, 0, 0, 0);%0A        startDate = cal.getTime();%0A
     
@@ -3239,38 +3239,42 @@
 me()
- - startDate.getTime()) / 1000
+) / 1000 - Constants.referenceDate
 ;%0A%0A 
@@ -3372,87 +3372,21 @@
 iff)
-;%0A                // Log.debug(%22GL3DSolarRotationTracking: Rotating: %22+rotation
+%25(Math.PI*2.0
 );%0A%0A
@@ -3721,33 +3721,32 @@
    %7D%0A%0A        %7D%0A
-%0A
     %7D%0A%0A    priva

use reference date