var navCamera = new NavCamera();

var navLng = new Array(
   0,                   // Custom
  -123.139427052731,    // Home (North)
  -123.1346685345038,   // Perspective (dougs) -web cam #1
  -123.14109684587588,  // Into English Bay - web cam #3
  -123.14332653025622,  // Museum - web cam #2
  -123.13947559372119,  // Marina
  -123.139512,          // Bird's Eye
  -123.15006617223321,  // Aerial perspective close
  -123.14463574945621,  // On a boat
  -123.14401940966879,  // Inukshuk
  -123.13536469447385,  // Granville Island
  -123.11113355484397,  // From BC place
  -123.12352742423766,  // From the Sheraton
  -123.1048630981596,   // Aerial perspective far
  -123.19207838403985); // Cypress Mountain very far

var navLat = new Array(
  0,                    // Custom
  49.273436612464856,   // Home
  49.277239076094745,   // Perspective (dougs) -web cam #1
  49.28277176571056,    // Into English Bay - web cam #3
  49.27527064809804,    // Museum - web cam #2
  49.27502713115128,    // Marina
  49.277884,            // Bird's Eye
  49.276918781180484,   // Aerial perspective close
  49.28026669931191,    // On a boat
  49.284667389014935,   // Inukshuk
  49.27316728244839,    // Granville Island
  49.27709667334821,    // From BC place
  49.28587443068528,    // From the Sheraton
  49.286923221898626,   // Aerial perspective far
  49.397323805955146);  // Cypress Mountain
  
var navAlt = new Array(
  0,                    // Custom
  109.73938968465751,   // Home
  94.76225546826079,    // Perspective (dougs) -web cam #1
  24.394554738312124,   // Into English Bay - web cam #3
  6.9575449662874025,   // Museum - web cam #2
  3.450198828389595,    // Marina
  500,                  // Bird's Eye
  527.3081034693367,    // Aerial perspective close
  0.23733860731221074,  // On a boat
  11.586145625883915,   // Inukshuk
  0.8922590427761877,   // Granville Island
  100.73938984818132,   // From BC place
  216.75655295309465,   // From the Sheraton
  539.3081030174164,    // Aerial perspective far
  1146.8088171680631);  // Cypress Mountain
  
var navHeading = new Array(  
  0,                    // Custom
  1.5013043749798307,   // Home
  -72.61611522477811,   // Perspective (dougs) -web cam #1
  164.5054078013242,    // Into English Bay - web cam #3
  38.152360406140524,   // Museum - web cam #2
  -4.756754302787974,   // Marina
  0,                    // Bird's Eye
  67.60022101045169,    // Aerial perspective close
  120.31383678618788,   // On a boat
  148.16048494764,      // Inukshuk
  -24.20690497843532,   // Granville Island
  -86.58722791436843,   // From BC place
  -131.46276163456065,  // From the Sheraton
  -104.72054703373159,  // Aerial perspective far
  164.11631601448477);  // Cypress Mountain
  
var navTilt = new Array(
  0,                    // Custom
  89.79989776876803,    // Home
  92.35524888279369,    // Perspective (dougs) -web cam #1
  104.78809564119511,   // Into English Bay - web cam #3 
  113.03339099215499,   // Museum - web cam #2;
  122.87870904856292,   // Marina
  0,                    // Bird's Eye
  63.82439839012316,    // Aerial perspective close
  104.98478900106726,   // On a boat
  98.50668848313391,    // Inukshuk
  97.40085247617824,    // Granville Island
  87.12637422737939,    // From BC place
  80.26025864311315,    // From the Sheraton
  66.64693204530592,    // Aerial perspective far
  77.23505116221818);   // Cypress Mountain
 
var navRoll = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);   

//var ArcStartX = 221.3780203703791;
//var ArcStartY = 219.98605464340653;

//var ArcEndX = -436.92897746898234;
//var ArcEndY = -312.0933280806639;

var ArcStartX = 313; 
var ArcStartY = 311;

var ArcEndX = 84;
var ArcEndY = 81;

var ArcZ = 5;

var ArcHeading = 135;
var ArcTilt = 90;

var ArcForwardsTime = 15000;
var ArcReturnTime = 15000;

var FallA = 0.001;
var MaxFallV = 25;

var OrbitSpeed = 0.01;
var OrbitTilt = 20;
var OrbitRange = 750;

var RotateSpeed = 0.0067;
var MinFallZ = 5;


function NavCamera() {
  var cameraMode = {stopped: 0, rotate: 1, orbitRise: 2, orbit: 3, 
                    arcStart: 4, arcReturn: 5, arcForwards: 6, settingView: 7,
                    stoppingBeforeSettingView: 8};

  this.startTime = 0;
  
  this.fallZ = 0; // the altitude we fall to
  this.tiltV = 0;
  this.startTilt = 0;
  
  this.fallAlt = 0;
  
  this.startTime = 0;
  this.mode = cameraMode.stopped;
  
  this.arcStartPt = new Point3D();
  this.arcCtrPt = new Point3D();
  this.arcEndPt = new Point3D();
  
  this.arcEndGeoPt = new GeoPoint();
  
  this.arcR = 0;
  
  this.watchDogID = 0;
  this.watchDogSet = false;
  
  this.selectedView = 0;
  
  this.init =
    function(ge) {
      google.earth.addEventListener(navGE, 'frameend', tickAnimation);
      google.earth.addEventListener(navGE.getView(), 'viewchangeend', viewChangeEnd);
      this.selectView(1);
    }
    
  this.selectView = 
    function(i) {
      this.mode = cameraMode.settingView;
      var camera = navGE.getView().copyAsCamera(navGE.ALTITUDE_RELATIVE_TO_GROUND);
      
      camera.setLongitude(navLng[i]);
      camera.setLatitude(navLat[i]);
      camera.setAltitude(navAlt[i]);
  
      camera.setHeading(navHeading[i]);
      camera.setTilt(navTilt[i]);
      camera.setRoll(navRoll[i]);
  
      navGE.getView().setAbstractView(camera); 
    }     

  this.fall = 
    function() {
      this.stop();
      
      var camera = navGE.getView().copyAsCamera(navGE.ALTITUDE_RELATIVE_TO_GROUND);

// get our current height
      var startZ = camera.getAltitude();

// calculate the height we'll fall to
      var lat = camera.getLatitude();
      var lng = camera.getLongitude();
      var endZ = navGE.getGlobe().getGroundAltitude(lat,lng);
      if (endZ < MinFallZ) endZ = MinFallZ;
      
// don't fall up      
      if (startZ <= endZ) return;

      camera.setAltitude(endZ);
      camera.setTilt(90);
      navGE.getView().setAbstractView(camera);
    } 
    
  this.stop = 
    function() {
      if ((this.mode == cameraMode.rotate) || (this.mode == cameraMode.orbit) ||
          (this.mode == cameraMode.arcReturn) || (this.mode == cameraMode.arcForwards))
      {    
  ////      google.earth.removeEventListener(navGE, 'frameend', tickAnimation);
      }  
      this.mode = cameraMode.stopped;
      navGE.getOptions().setFlyToSpeed(1);
    }
    
  this.setWatchDog =
    function() {
      this.watchDogID = setTimeout('watchDogCallBack', 100);
      this.watchDogSet = true;
    }
    
  this.clearWatchDog = 
    function() {  
      clearTimeout(this.watchDogID);
      this.watchDogSet = false;
    }
  
  this.rotate = 
    function() {
      this.stop(); 
      navGE.getOptions().setFlyToSpeed(navGE.SPEED_TELEPORT);
      var now = new Date();
      this.startTime = now.getTime();
      this.mode = cameraMode.rotate;
      this.setWatchDog(); // the watch dog makes sure cameraDoneMoving is called
    }
    
  this.updateRotate =
    function() {
      var camera = navGE.getView().copyAsCamera(navGE.ALTITUDE_RELATIVE_TO_GROUND);
      var heading = camera.getHeading();
      
      var now = new Date();
      var ms = now.getTime();
      var elapsedTime = ms - this.startTime;
      this.startTime = ms;
      
      heading += RotateSpeed * elapsedTime;
      camera.setHeading(heading);
      navGE.getView().setAbstractView(camera);
    }  
    
  this.orbit = 
    function() {
      this.stop(); 

// move the camera into position
      var lookAt = navGE.getView().copyAsLookAt(navGE.ALTITUDE_RELATIVE_TO_GROUND);
      lookAt.setLatitude(originLatitude);
      lookAt.setLongitude(originLongitude);
      lookAt.setAltitude(0);
      lookAt.setRange(OrbitRange);
      lookAt.setTilt(OrbitTilt);
      
 // first go to the end point
      this.mode = cameraMode.orbitRise;
      
      navGE.getView().setAbstractView(lookAt);
//    this.setWatchDog();
    }      
    
  this.updateOrbit = 
    function() {
      var lookAt = navGE.getView().copyAsLookAt(navGE.ALTITUDE_RELATIVE_TO_GROUND);
      var heading = lookAt.getHeading();
      
      var now = new Date();
      var ms = now.getTime();
      var elapsedTime = ms - this.startTime;
      this.startTime = ms;
      
      if (elapsedTime == 0) elapsedTime = 1;
      heading += OrbitSpeed * elapsedTime;
      lookAt.setHeading(heading);
      navGE.getView().setAbstractView(lookAt);
    }  
    
  this.setArcStartPt = 
    function() {
      ArcStartX = marker.target.x;
      ArcStartY = marker.target.y;
    }    
    
  this.setArcEndPt = 
    function() {
      ArcEndX = marker.target.x;
      ArcEndY = marker.target.y;
    }    
    
  this.arc = 
    function() {
      this.stop();
      
// set the start point      
      this.arcStartPt.x = ArcStartX;
      this.arcStartPt.y = ArcStartY;
      this.arcStartPt.z = ArcZ;
      
// set the end point      

      this.arcEndPt.x = ArcEndX;
      this.arcEndPt.y = ArcEndY;
      this.arcEndPt.z = ArcZ;
      
// convert to lat,lng      
      this.arcEndGeoPt.setFromXY(ArcEndX, ArcEndY);
      
// find the radius      
      this.arcR = this.arcStartPt.distanceTo(this.arcEndPt) / 2;

      this.moveToArcEnd();
      
// first go to the end point
      this.mode = cameraMode.arcStart;
    }     
    
  this.moveToArcEnd = 
    function() {
      
      var camera = navGE.getView().copyAsCamera(navGE.ALTITUDE_RELATIVE_TO_GROUND);

      camera.setLatitude(this.arcEndGeoPt.lat);
      camera.setLongitude(this.arcEndGeoPt.lng);
      camera.setAltitude(ArcZ);
  
      camera.setHeading(ArcHeading);
      camera.setTilt(ArcTilt);
      camera.setRoll(0);
  
      navGE.getView().setAbstractView(camera); 
    }     
    
    
  this.updateArcReturn = 
    function() {
      var now = new Date();
      var ms = now.getTime();
      var elapsedTime = ms - this.startTime;
      
      var frac = elapsedTime / ArcReturnTime;
      if (frac >= 1) { 
        frac = 1;
        this.mode = cameraMode.arcForwards;
        this.startTime = ms;
      }

// find XY      
      var pt = new Point3D();
      pt.interpolate(this.arcEndPt, this.arcStartPt, frac);
      
// convert to lat/lng      
      var geoPt = new GeoPoint();
      geoPt.setFromXY(pt.x, pt.y);

// find Z
      var angle = frac * Math.PI;
      var z = ArcZ + this.arcR * Math.sin(angle);
      
      var camera = navGE.getView().copyAsCamera(navGE.ALTITUDE_RELATIVE_TO_GROUND);

      camera.setLatitude(geoPt.lat);
      camera.setLongitude(geoPt.lng);
      camera.setAltitude(z);
  
      navGE.getView().setAbstractView(camera); 
    }   
    
  this.updateArcForwards = 
    function() {
      var now = new Date();
      var ms = now.getTime();
      var elapsedTime = ms - this.startTime;
      
      var frac = elapsedTime / ArcForwardsTime;
      if (frac >= 1) { 
        frac = 1;
        this.mode = cameraMode.arcReturn;
        this.startTime = ms;
      }
      
 // find XY      
      var pt = new Point3D();
      pt.interpolate(this.arcStartPt, this.arcEndPt, frac);
      
// convert to lat/lng      
      var geoPt = new GeoPoint();
      geoPt.setFromXY(pt.x, pt.y);
     
      var camera = navGE.getView().copyAsCamera(navGE.ALTITUDE_RELATIVE_TO_GROUND);

      camera.setLatitude(geoPt.lat);
      camera.setLongitude(geoPt.lng);
     
      navGE.getView().setAbstractView(camera); 
    }   
    
  this.updateAnimation = 
    function() {
      switch (this.mode) {
      
        case cameraMode.rotate : 
          this.updateRotate(); 
          break;
          
        case cameraMode.orbit :
          this.updateOrbit();
          break;
          
        case cameraMode.arcReturn : 
          this.updateArcReturn();
          break;
          
        case cameraMode.arcForwards :
          this.updateArcForwards();
          break;
      }
    } 
    
  this.setModeToSettingView = 
    function() {
      this.mode = cameraMode.settingView;
    }  

  this.selectViewFromCombo = 
    function(i) {    
      navGE.getOptions().setFlyToSpeed(1);
      if (this.mode == cameraMode.stopped) {
        this.selectView(i);
      }
      else {
        this.selectView(i);
        this.mode = cameraMode.stoppingBeforeSettingView;
      }
      this.selectedView = i;
      setTimeout(assertSelectedView, 500);
    }  
  
  this.assertSelectedView = 
    function() {
      navCombo = document.getElementById('navCombo');
      navCombo.selectedIndex = this.selectedView;    
      if (this.mode == cameraMode.stoppingBeforeSettingView) {
        this.mode = cameraMode.settingView;
      }
    }
    
  this.cameraDoneMoving = 
    function() {
    
      if (this.watchDogSet) {
        this.clearWatchDog();
      }
      
      switch (this.mode) {
      
        case cameraMode.arcStart :
          this.mode = cameraMode.arcReturn;
          break;
          
        case cameraMode.orbitRise : 
        
// make sure we're in position first         
          var lookAt = navGE.getView().copyAsLookAt(navGE.ALTITUDE_RELATIVE_TO_GROUND);
          if (Math.abs(lookAt.getRange()-OrbitRange) < 1) {
            this.mode = cameraMode.orbit;
          }  
          log(lookAt.getRange());
          
          break;
          
        case cameraMode.stopped : 
          selectCustomVantagePoint();
          return;  
            
        case cameraMode.stoppingBeforeSettingView :
          this.mode = cameraMode.settingView;
          return;
          
        case cameraMode.settingView : 
          this.mode = cameraMode.stopped;
          return;  
                 
        default : 
          return;
      }
       
// arc start and orbit rise are done       
      navGE.getOptions().setFlyToSpeed(navGE.SPEED_TELEPORT);
   
      var now = new Date();
      this.startTime = now.getTime();
      
// we'll update arc and orbit with the frameend event listener      
   //   google.earth.addEventListener(navGE, 'frameend', tickAnimation);
      this.updateAnimation();
    }
}

function tickAnimation() {
  navCamera.updateAnimation();
}

function viewChangeEnd() {
  navCamera.cameraDoneMoving();
}

function watchDogCallBack() {
  navCamera.cameraDoneMoving();
}

function assertSelectedView() {
  navCamera.assertSelectedView();
}
