#include "pylonwrapper.h"

PylonWrapper::PylonWrapper(const std::string &fullName):
  valid(false), fullName(fullName) {
  Pylon::PylonInitialize();
  camera = new Pylon::CInstantCamera();
  // std::cerr << "Wrapper:camera is open" << camera->IsOpen() << std::endl;
  // std::cerr << "Wrapper:is valid" << valid << std::endl;
}

PylonWrapper::~PylonWrapper() {
  Pylon::PylonTerminate();
}

void PylonWrapper::terminate() {
  try {
    //Pylon::PylonTerminate();
  } catch (const Pylon::GenericException &e) {
    std::cerr << e.GetDescription() << std::endl;
  }
}

bool PylonWrapper::isOpen() {
  return valid;
}

double PylonWrapper::maxFrameRate() {
  double max_rate = -1;
  if (valid) {
     GenApi::INodeMap& nodemap = camera->GetNodeMap();
     GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRate" );
     Pylon::CFloatParameter framerate( n );
     return framerate.GetMax();
  }
  return max_rate;
}

bool PylonWrapper::frameRate(uint new_framerate) {
  if (valid) {
      GenApi::INodeMap& nodemap = camera->GetNodeMap();
      GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" );
      Pylon::CBooleanParameter enableframerate(n);
      enableframerate.SetValue(true);

      n = nodemap.GetNode( "AcquisitionFrameRate" );
      Pylon::CFloatParameter framerate( n );
      framerate.SetValue( new_framerate );
      return true;
    }
  return false;
}

double PylonWrapper::frameRate() {
  double rate = -1.;
  if (valid) {
      GenApi::INodeMap& nodemap = camera->GetNodeMap();
      GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRate" );
      Pylon::CFloatParameter framerate( n );
      rate = framerate.GetValue();
    }
  return rate;
}

double PylonWrapper::exposureTime() {
  double time = -1.;
  if (valid) {
      GenApi::INodeMap& nodemap = camera->GetNodeMap();
      GenApi::INode* n = nodemap.GetNode( "ExposureTime" );
      Pylon::CFloatParameter exposure_time( n );
      time = exposure_time.GetValue();
    }
  return time;
}

bool PylonWrapper::exposureTime(double exposure_time) {
    if (valid) {
        GenApi::INodeMap& nodemap = camera->GetNodeMap();
        double d = GenApi::CFloatPtr(nodemap.GetNode("ExposureTime"))->GetValue();
        GenApi::INode* n = nodemap.GetNode( "ExposureTime" );
        try {
            GenApi::CEnumerationPtr(nodemap.GetNode( "ExposureTimeMode" ))->FromString("Standard");
        } catch (...) {
            // setting the exposure mode fails with certain cameras.
        }
        Pylon::CFloatParameter exp_time( n );
        exp_time.SetValue( exposure_time );
        return true;
      }
    return false;
}

double PylonWrapper::gain() {
  double gain = -1.;
  if (valid) {
      GenApi::INodeMap& nodemap = camera->GetNodeMap();
      GenApi::INode* n = nodemap.GetNode( "Gain" );
      Pylon::CFloatParameter detector_gain( n );
      gain = detector_gain.GetValue();
    }
  return gain;
}

bool PylonWrapper::gain(double gain_db) {
    if (valid) {
        GenApi::INodeMap& nodemap = camera->GetNodeMap();
        GenApi::CFloatPtr(nodemap.GetNode("Gain"))->SetValue(gain_db);
        return true;
      }
    return false;
}

ImageSettings PylonWrapper::getImageSettings() {
  ImageSettings settings;
  if (valid) {
      Pylon::CIntegerParameter width( camera->GetNodeMap(), "Width");
      Pylon::CIntegerParameter height( camera->GetNodeMap(), "Height");
      Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat");
      Pylon::CPixelTypeMapper pixelTypeMapper(&pixelFormat);
      settings.pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue(pixelFormat.GetIntValue());
      settings.width = width.GetValue();
      settings.height = height.GetValue();
      settings.orientation = Pylon::EImageOrientation::ImageOrientation_TopDown;
    }
  return settings;
}

bool PylonWrapper::grabFrame(MyImage &img) {
  Pylon::CGrabResultPtr frame;
  if (valid) {
      camera->StartGrabbing();
      camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
      camera->StopGrabbing();
    }
  img.setFrame(frame);
  return frame.IsValid();
}

bool PylonWrapper::openCamera(std::string &message) {
  std::cerr << "open Camera" << std::endl;
  try {
    // Pylon::CInstantCamera camera( pTl->CreateDevice( lstDevices[0] );
    camera->Attach(Pylon::CTlFactory::GetInstance().CreateFirstDevice());
    camera->Open();
    valid = camera->IsOpen();
    message = "Successfully opened camera!";
    std::cerr << message << std::endl;

  } catch (const Pylon::GenericException &e) {
    message = e.GetDescription();
    std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
    valid = false;
  }
  return valid;
}

void PylonWrapper::closeCamera() {
  std::cerr << "camera close !" << std::endl;
  if (camera->IsOpen()) {
      try {
        camera->Close();
        valid = false;
      } catch (const Pylon::GenericException &e) {
        std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
      }
    }
}

Pylon::CInstantCamera *PylonWrapper::getCamera() {
  return camera;
}