/**
 * @file
 * $Revision$ 
 * $Date$ 
 *
 *   Unless noted otherwise, the portions of Isis written by the USGS are public
 *   domain. See individual third-party library and package descriptions for
 *   intellectual property information,user agreements, and related information.
 *
 *   Although Isis has been used by the USGS, no warranty, expressed or implied,
 *   is made by the USGS as to the accuracy and functioning of such software
 *   and related material nor shall the fact of distribution constitute any such
 *   warranty, and no responsibility is assumed by the USGS in connection
 *   therewith.
 *
 *   For additional information, launch
 *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see
 *   the Privacy &amp; Disclaimers page on the Isis website,
 *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
 *   http://www.usgs.gov/privacy.html.
 */

#include <boost/foreach.hpp>
#include "opencv2/opencv.hpp"
#include "opencv2/xfeatures2d.hpp"

#include "SURFAlgorithm.h"
#include <QVariant>

namespace Isis {

  /**
   * Constructs a default SURFAlgorithm with default variables. 
   */
  SURFAlgorithm::SURFAlgorithm() : Feature2DAlgorithm("SURF", "Feature2D", SURFType::create()) {
    m_variables.merge( getAlgorithmVariables() );
  }


/**
 * Constructs a SURFAlgorithm with input variables. 
 * 
 * @param cvars Variables that are not included will be set to their default.
 * @param config The config string used to construct cvars.
 */
  SURFAlgorithm::SURFAlgorithm(const PvlFlatMap &cvars, const QString &config) :
                               Feature2DAlgorithm("SURF", "Feature2D", 
                                                  SURFType::create()) {
    setConfig(config);
    setAlgorithmVariables(cvars);
    PvlFlatMap defaults = getAlgorithmVariables();
    defaults.merge(cvars);
    m_variables.merge(defaults);
  }


/**
 * Default Destructor
 */
  SURFAlgorithm::~SURFAlgorithm() { }


/**
 * Returns a description of the DaisyAlgorithm. 
 * 
 * @return @b QString A description of the algorithm.
 */
  QString SURFAlgorithm::description() const {
    QString desc = "The OpenCV SURF Feature2D detector/extractor algorithm."
                   " See the documentation at "
     "http://docs.opencv.org/3.1.0/d5/df7/classcv_1_1xfeatures2d_1_1SURF.html";
    return (desc);
  }


/**
 * Creates and returns an instance of SURFAlgorithm.
 * 
 * @param vars PvlFlatMap containing algorithm parameters and their values
 * @param config A configuration string input by the user
 * 
 * @return Feature2DAlgorithm 
 */
  Feature2DAlgorithm *SURFAlgorithm::create(const PvlFlatMap &vars, const QString &config) {
    return ( new SURFAlgorithm(vars, config) );
  }


  /**
   * Returns true if the algorithm has a detector. 
   *  
   * @return @b true if the algorithm has a detector. 
   */
  bool SURFAlgorithm::hasDetector() const { 
    return true; 
  }


  /**
   * Returns true if the algorithm has an extractor. 
   *  
   * @return @b true if the algorithm has an extractor. 
   */
  bool SURFAlgorithm::hasExtractor() const { 
    return true; 
  }


  /**
   * Returns true if the algorithm has a matcher. 
   *  
   * @return @b true if the algorithm has a matcher. 
   */
  bool SURFAlgorithm::hasMatcher() const { 
    return false; 
  }



/**
 * @brief Retreive all SURF algorithm variable defaults and populate container 
 *  
 * This method will retreive the current values of all the variables as they 
 * are currently set in the algorithm. 
 *  
 * Typically, this is called upon instantiation of the algorithm which provides 
 * the default state of the variables. However, it is reentrant such that it 
 * will return the current state of all the variables. 
 * 
 * @author 2016-12-07 Kris Becker 
 * 
 * @return PvlFlatMap Container with all the SURF variables and values
 */
  PvlFlatMap SURFAlgorithm::getAlgorithmVariables( ) const {
    PvlFlatMap variables;
    SURFPtr v_ref = m_algorithm.dynamicCast<SURFType>();
    variables.add("HessianThreshold", toString(v_ref->getHessianThreshold()));
    variables.add("NOctaves",  toString(v_ref->getNOctaves()));
    variables.add("NOctaveLayers",  toString(v_ref->getNOctaveLayers()));
    variables.add("Extended", toString(v_ref->getExtended()));
    variables.add("Upright", toString(v_ref->getUpright()));
    return (variables);
  }

/**
 * @brief Set parameters as provided by the variables
 * 
 * @author  2016-12-06 Kris Becker
 * 
 * @param variables Container of parameters to set in the algorithm
 * 
 * @return int Number of variables actually set
 */
  int SURFAlgorithm::setAlgorithmVariables(const PvlFlatMap &variables) {

    SURFPtr v_ref = m_algorithm.dynamicCast<SURFType>();
    int nset(0);
    if ( variables.exists("HessianThreshold") ) { 
      v_ref->setHessianThreshold(toDouble(variables.get("HessianThreshold")));
      nset++;
    }

    if ( variables.exists("NOctaves") ) { 
      v_ref->setNOctaves(toInt(variables.get("NOctaves")));
      nset++;
    }

    if ( variables.exists("NOctaveLayers") ) { 
      v_ref->setNOctaveLayers(toInt(variables.get("NOctaveLayers")));
      nset++;
    }

    if ( variables.exists("Extended") ) { 
      v_ref->setExtended(toBool(variables.get("Extended")));
      nset++;
    }

    if ( variables.exists("Upright") ) { 
      v_ref->setUpright(toBool(variables.get("Upright")));
      nset++;
    }

    return (nset);
  }

};

