#include <cfloat>
#include <cmath>
#include <iomanip>
#include <iostream>

#include "Constants.h"
#include "IException.h"
#include "Planar.h"
#include "Preference.h"
#include "Projection.h"
#include "ProjectionFactory.h"
#include "Pvl.h"
#include "PvlGroup.h"
#include "PvlKeyword.h"
#include "RingPlaneProjection.h"
#include "SpecialPixel.h"
#include "WorldMapper.h"

/**
  * @internal
  *   @history 2016-08-26 Kelvin Rodriguez - Changed invalidValue varible to have
  *                           both an int and double version to avoid undefined behavior in
  *                           trying to convert double to int. Part of porting to OSX 10.11
 */

using namespace std;
using namespace Isis;

class MyProjection : public RingPlaneProjection {
  public:
    // create a child class
    MyProjection(Pvl &lab) : RingPlaneProjection(lab) {
    }
    // override pure virtual methods
    QString Name() const {
      return "None";
    }
    QString Version() const {
      return "1.0";
    }

    // override other virtual methods
    virtual double TrueScaleRingRadius() const {
      return 45.0;
    }
    bool SetGround(const double ringRadius, const double ringLongitude) {
      if (ringRadius <= 0.0) {
        m_good = false;
      }
      else {
        m_ringRadius = ringRadius;
        m_ringLongitude = ringLongitude;
        double x = ringLongitude * 10.0;
        double y = ringRadius + 90.0;
        SetComputedXY(x, y);
        m_good = true;
      }
      return m_good;
    }
    virtual bool SetCoordinate(const double x, const double y) {
      SetXY(x, y);
      m_ringLongitude = GetX() / 10.0;
      m_ringRadius = GetY() - 90.0;
      m_good = true;
      return m_good;
    }
    bool XYRange(double &minX, double &maxX, double &minY, double &maxY) {
      XYRangeCheck(Null, Null);
      minX = DBL_MAX;
      minY = DBL_MAX;
      maxX = -DBL_MAX;
      maxY = -DBL_MAX;
      if(!m_groundRangeGood) return false;
      XYRangeCheck(m_minimumRingRadius, m_minimumRingLongitude);
      XYRangeCheck(m_minimumRingRadius, m_maximumRingLongitude);
      XYRangeCheck(m_maximumRingRadius, m_minimumRingLongitude);
      XYRangeCheck(m_maximumRingRadius, m_maximumRingLongitude);
      minX = m_minimumX;
      minY = m_minimumY;
      maxX = m_maximumX;
      maxY = m_maximumY;
      return true;
    }

};

class EmptyProjection : public RingPlaneProjection {
  public:
    EmptyProjection(Pvl &lab) : RingPlaneProjection(lab) {
    }

    // pure virtuals, must be overriden, no need to test since MyProjection will test these
    QString Name() const {
      return "None";
    }
    QString Version() const {
      return "1.0";
    }
};


class MyMapper : public WorldMapper {
  public:
    MyMapper() : WorldMapper() {};
    double ProjectionX(const double worldX) const {
      return worldX / 2.0;
    };
    double ProjectionY(const double worldY) const {
      return worldY / 3.0;
    };
    double WorldX(const double projectionX) const {
      return projectionX * 2.0;
    };
    double WorldY(const double projectionY) const {
      return projectionY * 3.0;
    };
    virtual double Resolution() const {
      return 0.5;
    }
};



// unitTest main
int main(int argc, char *argv[]) {
  Preference::Preferences(true);

  // create a MyProjection object with the given labels
  void Doit(Pvl & lab);

  cout.precision(13);
  cout << "Unit test for RingPlaneProjection ..." << endl << endl;
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << "Test Error Throws from the constructor...\n" << endl;

  cout << "Test for missing Mapping Group" << endl;
  Pvl lab;  // Error throws from Projection
  Doit(lab);
  cout << endl;

  lab.addGroup(PvlGroup("Mapping"));
  PvlGroup &mg = lab.findGroup("Mapping");
  Doit(lab);
  cout << endl;

  cout << "Test for missing ring longitude direction in the mapping group" << endl;
  Doit(lab);
  cout << endl;

  cout << "Test for invalid ring longitude direction value" << endl;
  mg += PvlKeyword("RingLongitudeDirection", "Up");
  Doit(lab);
  cout << endl;

  cout << "Test for missing ring longitude domain in the mapping group" << endl;
  mg["RingLongitudeDirection"] = "CounterClockwise";
  Doit(lab);
  cout << endl;

  cout << "Test for invalid ring longitude domain value in the mapping group" << endl;
  mg += PvlKeyword("RingLongitudeDomain", "75");
  Doit(lab);
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << endl;

  mg["RingLongitudeDomain"] = "360";
  mg += PvlKeyword("ProjectionName", "MyProjection");

  cout << "Projection Specifications" << endl;
  MyProjection p(lab);
  // test methods that return properties of the projection
  cout << "Is Equatorial Cylindrical: " << p.IsEquatorialCylindrical() << endl;
  cout << "Ring Longitude Direction:  " << p.RingLongitudeDirectionString() << endl;
  cout << "Is Clockwise:              " << p.IsClockwise() << endl;
  cout << "Is CounterClockwise:       " << p.IsCounterClockwise() << endl;
  cout << "Ring Longitude Domain:     " << p.RingLongitudeDomainString() << endl;
  cout << "Has 360 domain:            " << p.Has360Domain() << endl;
  cout << "Has 180 domain:            " << p.Has180Domain() << endl;
  cout << "Has ground range:          " << p.HasGroundRange() << endl;
  cout << "Rotation:                  " << p.Rotation() << endl;
  cout << "Scale:                     " << p.Scale() << endl;
  cout << endl;
 cout << endl;

  //Test exceptions

  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << "Test More Error Throws...\n" << endl;
  cout << "Testing invalid minimum ring radius..." << endl;
  mg += PvlKeyword("MinimumRingRadius", "-45.0");
  mg += PvlKeyword("MaximumRingRadius", "-80.0");
  mg += PvlKeyword("MinimumRingLongitude", "15.0");
  mg += PvlKeyword("MaximumRingLongitude", "-190.0");
  Doit(lab);
  cout << endl;

  cout << "Testing invalid maximum ring radius" << endl;
  mg["MinimumRingRadius"] = "80.0";
  Doit(lab);
  cout << endl;

  cout << "Testing unordered ring radius range" << endl;
  mg["MaximumRingRadius"].setValue("45.0", "units");
  Doit(lab);
  cout << endl;

  cout << "Testing unordered ring longitude range" << endl;
  mg["MaximumRingRadius"].setValue("180.0", "units");
  Doit(lab);
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << endl;

  mg["MaximumRingLongitude"] = "190.0";

  cout << "Testing xyRange methods...\n" << endl;
  MyProjection p2(lab);
  cout << "Get ground range from the labels...  " << endl;
  cout << "Has as ring longitude range:  " << p2.HasGroundRange() << endl;
  cout << "Minimum ring radius:          " << p2.MinimumRingRadius() << endl;
  cout << "Maximum ring radius:          " << p2.MaximumRingRadius() << endl;
  cout << "Minimum ring longitude:       " << p2.MinimumRingLongitude() << endl;
  cout << "Maximum ring longitude:       " << p2.MaximumRingLongitude() << endl;

  double minX, maxX, minY, maxY;
  if (p2.XYRange(minX, maxX, minY, maxY)) {
    cout << "Find coordinate range ...  " << endl;
    cout << "Minimum X:              " << minX << endl;
    cout << "Maximum X:              " << maxX << endl;
    cout << "Minimum Y:              " << minY << endl;
    cout << "Maximum Y:              " << maxY << endl;
    cout << endl;
  }

  cout << "Testing Ground coordinate routines" << endl;
  cout << "Setting ring radius to (91,  0):       " << p2.SetGround(91.0, 0.0) << endl;
  cout << "Is Good:                               " << p2.IsGood() << endl;
  cout << "Setting ring longitude to ( 0,  91):   " << p2.SetGround(0., 91.0) << endl;
  cout << "Is Good:                               " << p2.IsGood() << endl;
  cout << "Setting position to (60,  -5):         " << p2.SetGround(60.0, -5.0) << endl;
  cout << "Is Good:                               " << p2.IsGood() << endl;
  cout << "Ring Radius:                           " << p2.RingRadius() << endl;
  cout << "Local Ring Radius:                     " << p2.LocalRadius() << endl;
  cout << "Ring Longitude:                        " << p2.RingLongitude() << endl;
  cout << "XCoord:                                " << p2.XCoord() << endl;
  cout << "YCoord:                                " << p2.YCoord() << endl;
  cout << "Universal Ring Radius:                 " << p2.UniversalRingRadius() << endl;
  cout << "Universal Ring Longitude:              " << p2.UniversalRingLongitude() << endl;
  cout << endl;


  cout << "Testing Universal Ground coordinate routines" << endl;
  cout << "Setting position to (57.3920057293825,  355):  " << p2.SetUniversalGround(57.3920057293825, 355.0) << endl;
  cout << "Is Good:                                       " << p2.IsGood() << endl;
  cout << "Ring Radius:                                   " << p2.RingRadius() << endl;
  cout << "Ring Longitude:                                " << p2.RingLongitude() << endl;
  cout << "XCoord:                                        " << p2.XCoord() << endl;
  cout << "YCoord:                                        " << p2.YCoord() << endl;
  cout << "Universal Ring Radius:                         " << p2.UniversalRingRadius() << endl;
  cout << "Universal Ring Longitude:                      " << p2.UniversalRingLongitude() << endl;
  cout << "Setting bad position..." << p2.SetUniversalGround((double) Null, (double) Null) << endl;
  cout << endl;

  /* The following projection is used to test the ToPlanetographic() methods
   *   at the ring radius boundaries (2000 and 20000 meters). qFuzzyCompare() methods
   *   were added to accommodate for double imprecission.
   */
  Isis::Pvl radRangeTest;
  radRangeTest.addGroup(Isis::PvlGroup("Mapping"));
  Isis::PvlGroup &radTestGroup = radRangeTest.findGroup("Mapping");
  radTestGroup += Isis::PvlKeyword("TargetName", "Saturn");
  radTestGroup += Isis::PvlKeyword("ProjectionName", "Planar");
  radTestGroup += Isis::PvlKeyword("RingLongitudeDirection", "Clockwise");
  radTestGroup += Isis::PvlKeyword("RingLongitudeDomain", "180");
  radTestGroup += Isis::PvlKeyword("Scale", "5.0");
  radTestGroup += Isis::PvlKeyword("MinimumRingRadius", "2000.0");
  radTestGroup += Isis::PvlKeyword("MaximumRingRadius", "20000.0");
  radTestGroup += Isis::PvlKeyword("MinimumRingLongitude", "0.0");
  radTestGroup += Isis::PvlKeyword("MaximumRingLongitude", "360.0");
  radTestGroup += Isis::PvlKeyword("CenterRingRadius", "12000.0");
  radTestGroup += Isis::PvlKeyword("CenterRingLongitude", "0.0");
  Isis::Planar *radTestProjection = (Isis::Planar *) Isis::ProjectionFactory::Create(radRangeTest);

  cout << "Planar Projection Specifications" << endl;
  // test methods that return properties of the projection
  cout << "Is Equatorial Cylindrical: " << radTestProjection->IsEquatorialCylindrical() << endl;
  cout << "Ring Longitude Direction:  " << radTestProjection->RingLongitudeDirectionString() << endl;
  cout << "Is Clockwise:              " << radTestProjection->IsClockwise() << endl;
  cout << "Is CounterClockwise:       " << radTestProjection->IsCounterClockwise() << endl;
  cout << "Ring Longitude Domain:     " << radTestProjection->RingLongitudeDomainString() << endl;
  cout << "Has 360 domain:            " << radTestProjection->Has360Domain() << endl;
  cout << "Has 180 domain:            " << radTestProjection->Has180Domain() << endl;
  cout << "Has ground range:          " << radTestProjection->HasGroundRange() << endl;
  cout << "Rotation:                  " << radTestProjection->Rotation() << endl << endl;
  try {
    cout << "Setting position to (9000.0, 0.0)" << endl;
    radTestProjection->SetUniversalGround(9000.0, 0.0);
    cout << "Is Good:                     "
         << radTestProjection->IsGood() << endl;
    cout << "Ring Radius:                 "
         << radTestProjection->RingRadius() << endl;
    cout << "Ring Longitude:              "
         << radTestProjection->RingLongitude() << endl;
    cout << "XCoord:                      "
         << radTestProjection->XCoord() << endl;
    cout << "YCoord:                      "
         << radTestProjection->YCoord() << endl;
    cout << "Universal Ring Radius:       "
         << radTestProjection->UniversalRingRadius() << endl;
    cout << "Universal Ring Longitude:    "
         << radTestProjection->UniversalRingLongitude() << endl;
    cout << endl;
  }
  catch(IException &error) {
    error.print();
  }

  try {
    radTestProjection->SetUniversalGround(9000.0, 360.0);
    cout << "Setting position to (9000.0, 360.0)" << endl;
    cout << "Is Good:                     "
         << radTestProjection->IsGood() << endl;
    cout << "Ring Radius:                 "
         << radTestProjection->RingRadius() << endl;
    cout << "Ring Longitude:              "
         << radTestProjection->RingLongitude() << endl;
    cout << "XCoord:                      "
         << radTestProjection->XCoord() << endl;
    cout << "YCoord:                      "
         << radTestProjection->YCoord() << endl;
    cout << "Universal Ring Radius:       "
         << radTestProjection->UniversalRingRadius() << endl;
    cout << "Universal Ring Longitude:    "
         << radTestProjection->UniversalRingLongitude() << endl;
    cout << endl;
  }
  catch(IException &error) {
    error.print();
  }

  cout << "Testing == operator Projection conditions..."  << p.Name() << endl;
  cout << "Projection 1 name and resolution = " << p.Name() << " " << p.Resolution() << endl;
  cout << "Projection 2 name and resolution = " << p2.Name() << " " << p2.Resolution() << endl;
  cout << "Projection 3 name and resolution = " << radTestProjection->Name() << " " << radTestProjection->Resolution() << endl;

  if (p == p2)
     cout << "Projection 1 = Projection 2" << endl;
  else
    cout << "Projection 1 != Projection 2" << endl;

  if (p == *radTestProjection)
     cout << "Projection 1 = Projection3" << endl;
  else
    cout << "Projection 1 != Projection3" << endl;
  cout << endl;

  cout << "Testing projection coordinate routines" << endl;
  cout << "Setting x/y position to (-90,15):    " << p2.SetCoordinate(-90.0, 15.0) << endl;
  cout << "Is Good:                             " << p2.IsGood() << endl;
  cout << "Ring Radius:                         " << p2.RingRadius() << endl;
  cout << "Ring Longitude:                      " << p2.RingLongitude() << endl;
  cout << "XCoord:                              " << p2.XCoord() << endl;
  cout << "YCoord:                              " << p2.YCoord() << endl;
  cout << "Universal Ring Radius:               " << p2.UniversalRingRadius() << endl;
  cout << "Universal Ring Longitude:            " << p2.UniversalRingLongitude() << endl;
  cout << "WorldX:                              " << p2.WorldX() << endl;
  cout << "WorldY:                              " << p2.WorldY() << endl;
  cout << endl;

  p2.SetWorldMapper(new MyMapper());

  cout << "Testing world coordinate routines" << endl;
  cout << "Setting world x/y position to (-45,45):    " << p2.SetWorld(-45.0, 45.0) << endl;
  cout << "Is Good:                                   " << p2.IsGood() << endl;
  cout << "Ring Radius:                               " << p2.RingRadius() << endl;
  cout << "Ring Longitude:                            " << p2.RingLongitude() << endl;
  cout << "XCoord:                                    " << p2.XCoord() << endl;
  cout << "YCoord:                                    " << p2.YCoord() << endl;
  cout << "Universal Ring Radius:                     " << p2.UniversalRingRadius() << endl;
  cout << "Universal Ring Longitude:                  " << p2.UniversalRingLongitude() << endl;
  cout << "WorldX:                                    " << p2.WorldX() << endl;
  cout << "WorldY:                                    " << p2.WorldY() << endl;
  // cout << "ToProjectionX (-4500):                     " << p2.ToProjectionX(-4500.0) << endl;
  // cout << "ToProjectionY (45):                        " << p2.ToProjectionY(45.0) << endl;
  // cout << "ToWorldX:                                  " << p2.ToWorldX(p2.ToProjectionX(-4500.0)) << endl;
  // cout << "ToWorldY:                                  " << p2.ToWorldY(p2.ToProjectionY(45.0)) << endl;
  cout << "Resolution:                                " << p2.Resolution() << endl;
  cout << "Scale:                                     " << p2.Scale() << endl;
  cout << "True Scale Ring Radius:                    " << p2.TrueScaleRingRadius() << endl;
  cout << endl;

  cout << "Testing IsSky method" << endl;
  cout << p2.IsSky() << endl;
  mg += PvlKeyword("TargetName", "SKY");
  mg["RingLongitudeDirection"] = "Clockwise";
  Doit(lab);
  MyProjection p3(lab);
  cout << p3.IsSky() << endl;
  cout << endl;

  cout << "Testing == operator condition in class..." << endl;
  cout << "Projection 1 name and resolution             = " << p.Name() << " " << p.Resolution() << endl;
  cout << "Projection 1 ring longitude direction        = " << p.RingLongitudeDirectionString() << endl;
  cout << "Projection 4 name and resolution             = " << p3.Name() << " " << p3.Resolution() << endl;
  cout << "Projection 4 ring longitude direction string = " << p3.RingLongitudeDirectionString() << endl;
  if (p == p3)
     cout << "Projection 1 = Projection 4" << endl;
  else
    cout << "Projection 1 != Projection 4" << endl;

  cout << endl;

  cout << "Testing string routines" << endl;
  cout << p2.RingLongitudeDirectionString() << endl;
  cout << p2.RingLongitudeDomainString() << endl;
  cout << endl;

  cout << "Testing Name and comparision routines" << endl;
  cout << "Name:        " << p2.Name() << endl;
  cout << "Version:     " << p2.Version() << endl;
  cout << "operator==:  " << (p == p2) << endl;
  cout << "operator!=:  " << (p != p2) << endl;

  mg["RingLongitudeDirection"] = "CounterClockwise";
  mg["RingLongitudeDomain"] = "180";
  EmptyProjection noproj(lab);
  cout << endl;

  cout << "Testing no projection" << endl;
  noproj.SetUniversalGround(45.0, 270.0);
  cout << "Ring Radius:               " << noproj.RingRadius() << endl;
  cout << "Ring Longitude:            " << noproj.RingLongitude() << endl;
  cout << "Is clockwise?              " << noproj.IsClockwise() << endl;
  cout << "Is counterclockwise?       " << noproj.IsCounterClockwise() << endl;
  cout << "Ring Longitude direction = " << noproj.RingLongitudeDirectionString() << endl;
  cout << "Has 180 domain?            " << noproj.Has180Domain() << endl;
  cout << "Has 360 domain?            " << noproj.Has360Domain() << endl;
  cout << "Ring Longitude domain    = " << noproj.RingLongitudeDomainString() << endl;
  cout << "True scale ring radius   = " << noproj.TrueScaleRingRadius() << endl;
  double badvalue = Null;
  if (noproj.XYRange(badvalue, badvalue, badvalue,badvalue))
    cout << "Bad range" << endl;
  cout << endl;

  cout << "Testing ring radius methods " << endl;
  cout << noproj.LocalRadius() << endl;
  cout << endl;
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << endl;

  cout << "Testing bad coordinates " << endl;
  cout << "Testing bad ring radius/ring longitude... Is good?  " << noproj.SetGround(Null, Null) << endl;
  cout << "Testing bad x/y... Is good?  " << noproj.SetCoordinate(Null, Null) << endl;
  cout << endl;
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << endl;

  cout << endl;
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << "Test Error Throws for invalid inputs to conversion methods " << endl;

  // Keep an double and an int for used for invalid data.
  // Seperating the two prevents undefined behavior from trying to
  // convert Isis::Null to an integer.
  double invalidDouble = Null;
  int invalidInt = -INT_MAX;
  try {
    RingPlaneProjection::To180Domain(invalidDouble);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    RingPlaneProjection::To360Domain(invalidDouble);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    RingPlaneProjection::ToClockwise(invalidDouble, 180);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    RingPlaneProjection::ToClockwise(0, invalidInt);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    RingPlaneProjection::ToClockwise(invalidDouble, 360);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    RingPlaneProjection::ToCounterClockwise(0, invalidInt);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    RingPlaneProjection::ToCounterClockwise(invalidDouble, 360);
  }
  catch(IException &error) {
    error.print();
  }
  cout << endl;
  cout << "///////////////////////////////////////////////////////////" << endl;

  cout << "Testing conversion routines with valid inputs..." << endl;
  try {
    cout << "60 clockwise converted to " << p.ToCounterClockwise(60., 360) << " in 360 domain. " << endl;
    cout << "60 clockwise converted to " << p.ToCounterClockwise(60., 180) << " in 180 domain. " << endl;
  }
  catch(IException &error) {
    error.print();
  }
  try {
    cout << "60 counterclockwise converted to " << p3.ToClockwise(60., 360) << " in 360 domain. " << endl;
    cout << "60 counterclockwise converted to " << p3.ToClockwise(60., 180) << " in 180 domain. " << endl;
  }
  catch(IException &error) {
    error.print();
  }
  try {
    p.ToWorldX(invalidDouble);
  }
  catch(IException &error) {
    error.print();
  }
  try {
    p.ToWorldY(invalidDouble);
  }
  catch(IException &error) {
    error.print();
  }
  cout << "///////////////////////////////////////////////////////////" << endl;
  cout << endl;
  cout << endl;

  // Add remaining keywords for Mapping() test
  mg += PvlKeyword("PixelResolution", "1.0");
  mg += PvlKeyword("Scale", "1.0");
  mg += PvlKeyword("UpperLeftCornerX", "1.0");
  mg += PvlKeyword("UpperLeftCornerY", "1.0");

  cout << "Rotation Tests" << endl;
  mg += PvlKeyword("Rotation", "90.0");
  mg["RingLongitudeDirection"] = "Clockwise";
  MyProjection p4(lab);
  cout << "Rotation:   " << p4.Rotation() << endl;
  cout << "Testing Ground coordinate routines" << endl;
  cout << "Setting ring radius to (-91,  0):    " << p4.SetGround(-91.0, 0.0) << endl;
  cout << "Is Good:                             " << p4.IsGood() << endl;
  cout << "Setting ring radius to ( 9001,  0):  " << p4.SetGround(9001.0, 0.0) << endl;
  cout << "Is Good:                             " << p4.IsGood() << endl;
  cout << "Setting position to (60,  -5):       " << p4.SetGround(60.0, -5.0) << endl;
  cout << "Is Good:                             " << p4.IsGood() << endl;
  cout << "Ring Radius:                         " << p4.RingRadius() << endl;
  cout << "Ring Longitude:                      " << p4.RingLongitude() << endl;
  cout << "XCoord:                              " << p4.XCoord() << endl;
  cout << "YCoord:                              " << p4.YCoord() << endl;
  cout << "Universal Ring Radius:               " << p4.UniversalRingRadius() << endl;
  cout << "Universal Ring Longitude:            " << p4.UniversalRingLongitude() << endl;
  cout << endl;

  cout << "Testing projection coordinate routines" << endl;
  cout << "Setting x/y position to (150,50):    " << p4.SetCoordinate(150.0, 50.0) << endl;
  cout << "Is Good:                             " << p4.IsGood() << endl;
  cout << "Ring Radius:                         " << p4.RingRadius() << endl;
  cout << "Ring Longitude:                      " << p4.RingLongitude() << endl;
  cout << "XCoord:                              " << p4.XCoord() << endl;
  cout << "YCoord:                              " << p4.YCoord() << endl;
  cout << "Universal Ring Radius:               " << p4.UniversalRingRadius() << endl;
  cout << "Universal Ring Longitude:            " << p4.UniversalRingLongitude() << endl;
  cout << "WorldX:                              " << p4.WorldX() << endl;
  cout << "WorldY:                              " << p4.WorldY() << endl;
  cout << endl;

  Pvl mapping;
  mapping.addGroup(p4.Mapping());
  cout << "Testing Mapping() methods" << endl;
  cout << "Mapping() = " << endl;
  cout << mapping << endl;
  mapping.deleteGroup("Mapping");
  mapping.addGroup(p4.MappingRingRadii());
  cout << "MappingRingRadii() = " << endl;
  cout << mapping << endl;
  mapping.deleteGroup("Mapping");
  mapping.addGroup(p4.MappingRingLongitudes());
  cout << "MappingRingLongitudes() = " << endl;
  cout << mapping << endl;
  mapping.deleteGroup("Mapping");
  cout << endl;

  //SetUpperLeftCorner(Displacement x, Displacement y)
}


void Doit(Pvl &lab) {
  try {
    MyProjection p(lab);
  }
  catch(IException &error) {
    error.print();
  }
}
