/**
 *  \file cipConventions
 *  \ingroup common
 *  \brief This file contains CIP-specific enums within the cip
 *  namespace identifying chest regions, types, and exit codes for
 *  executables. Also defined in this file is the ChestConventions
 *  class which provides convenience methods for dealing with the
 *  chest region and type labels.
 *
 */

#ifndef __cipChestConventions_h
#define __cipChestConventions_h

#include <string>
#include <map>
#include <vector>
#include <cmath>
//#include <vnl/vnl_math.h>

#include <iostream>

#include "cipChestConventionsXmlAutoGenerated.h"

namespace cip {
  /**
   *  Define typedefs used throughout the cip
   */
  typedef std::vector< double >  PointType;
  typedef std::vector< double >  VectorType;




class ChestConventions
{
public:
  ChestConventions();
  ~ChestConventions();

  unsigned char GetNumberOfEnumeratedChestRegions() const;
  unsigned char GetNumberOfEnumeratedChestTypes() const;
  unsigned char GetNumberOfEnumeratedImageFeatures() const;
  unsigned char GetNumberOfEnumeratedPlanes() const;

  /** This method checks if the chest region 'subordinate' is within
   *  the chest region 'superior'. It assumes that all chest regions are
   *  within the WHOLELUNG lung region. TODO: extend to deal with
   *  chest, not just lung */
  bool CheckSubordinateSuperiorChestRegionRelationship( unsigned char subordinate, unsigned char superior );

  /** Given an unsigned short value, this method will compute the
   *  8-bit region value corresponding to the input */
  unsigned char GetChestRegionFromValue( unsigned short value ) const;

  /** The 'color' param is assumed to have three components, each in
   *  the interval [0,1]. All chest type colors will be tested until a
   *  color match is found. If no match is found, 'UNDEFINEDTYPYE'
   *  will be returned */
  unsigned char GetChestTypeFromColor( double* color ) const;

  /** The 'color' param is assumed to have three components, each in
   *  the interval [0,1]. All chest region colors will be tested until a
   *  color match is found. If no match is found, 'UNDEFINEDTYPYE'
   *  will be returned */
  unsigned char GetChestRegionFromColor(double* color) const;

  /** Given an unsigned short value, this method will compute the
   *  8-bit type value corresponding to the input */
  unsigned char GetChestTypeFromValue( unsigned short value ) const;

  /** A label map voxel value consists of a chest-region designation
   *  and a chest-type designation. For the purposes of representing a
   *  wild card entry (e.g. when using regions and types as keys for
   *  populating a database), this method is provided. */
  std::string GetChestWildCardName() const;

  /** Given an unsigned char value corresponding to a chest type, this
   *  method will return the string name equivalent. */
  std::string GetChestTypeName( unsigned char whichType ) const;

  /** Get the chest type color. 'color' param is assumed to be an
   * allocated 3 dimensional double pointer */
  void GetChestTypeColor( unsigned char whichType, double* color ) const;

  /** Get the chest region color. 'color' param is assumed to be an
   * allocated 3 dimensional double pointer */
  void GetChestRegionColor(unsigned char whichRegion, double* color) const;

  /** Get the color corresponding to the chest-region chest-pair pair. The
   * color is computed as the average of the two corresponding region and type
   * colors unless the region or type is undefined, in which case the color of
   * the defined region or type is returned. The 'color' param is assumed to be
   * an allocated 3 dimensional double pointer */
  void GetColorFromChestRegionChestType(unsigned char whichRegion, unsigned char whichType, double* color) const;

  /** Given an unsigned char value corresponding to a chest region, this
   *  method will return the string name equivalent. */
  std::string GetChestRegionName( unsigned char whichRegion ) const;

  /** Given an unsigned short value, this method will return the
   *  string name of the corresponding chest region */
  std::string GetChestRegionNameFromValue( unsigned short value ) const;

  /** Given an unsigned short value, this method will return the
   *  string name of the corresponding chest type */
  std::string GetChestTypeNameFromValue( unsigned short value ) const;

  unsigned short GetValueFromChestRegionAndType( unsigned char region, unsigned char type ) const;

  /** Given a string identifying one of the enumerated chest regions,
   * this method will return the unsigned char equivalent. If no match
   * is found, the method will raise an exception */
  unsigned char GetChestRegionValueFromName( std::string regionString ) const;

  /** Given a string identifying one of the enumerated chest types,
   * this method will return the unsigned char equivalent. If no match
   * is found, the method will raise an exception */
  unsigned char GetChestTypeValueFromName( std::string typeString ) const;

  /** Given a string identifying one of the enumerated chest types,
  * this method will return the unsigned char equivalent. If no match
  * is found, the method will raise an exception */
  unsigned char GetPlaneValueFromName( std::string key ) const;

  /** Get the ith chest region */
  unsigned char GetChestRegion( unsigned int i ) const;

  /** Get the ith chest type */
  unsigned char GetChestType( unsigned int i ) const;
  
  /** Get the ith image feature */
  unsigned char GetImageFeature( unsigned int i ) const;

  /** Get the ith plane */
  unsigned char GetPlane( unsigned int i ) const;
  
  /** Given an unsigned char value corresponding to a image feature, this
   *  method will return the string name equivalent. */
  std::string GetImageFeatureName( unsigned char whichFeature ) const;

  /** Given an unsigned char value corresponding to a plane, this
   *  method will return the string name equivalent. */
  std::string GetPlaneName( unsigned char whichPlane ) const;

  /** Returns true if the passed string name is among the allowed body composition
   *  phenotype names and returns false otherwise */
  bool IsBodyCompositionPhenotypeName( std::string ) const;

  /** Returns true if the passed string name is among the allowed parenchyma
   *  phenotype names and returns false otherwise */
  bool IsParenchymaPhenotypeName( std::string ) const;
  
  /** Returns true if the passed string name is among the allowed histogram
   *  phenotype names and returns false otherwise */
  bool IsHistogramPhenotypeName( std::string ) const;

  /** Returns true if the passed string name is among the allowed pulmonary vasculature
   *  phenotype names and returns false otherwise */
  bool IsPulmonaryVasculaturePhenotypeName( std::string ) const;

  /** Returns true if the passed string name is among the allowed pulmonary vasculature
  *  phenotype names and returns false otherwise */
  bool IsAirwayPhenotypeName( std::string ) const;

  /** Returns true if the passed string name is among the allowed pulmonary vasculature
  *  phenotype names and returns false otherwise */
  bool IsBiomechanicalPhenotypeName( std::string ) const;

  /** Returns true if the passed string name is among the allowed fissure completeness
  *  phenotype names and returns false otherwise */
  bool IsFissurePhenotypeName( std::string ) const;
  
    /** Returns true if the passed string name is among the allowed
   *  phenotype names and returns false otherwise */
  bool IsPhenotypeName( std::string ) const;

  /** Returns true if the passed string name is among the enumerated chest
   *  types and returns false otherwise */
  bool IsChestType( std::string ) const;

  /** Returns true if the passed string name is among the enumerated chest
   *  regions and returns false otherwise */
  bool IsChestRegion( std::string ) const;

private:
    ChestConventionsStatic s_ChestConventions;

    /**
     * Extract the value from a collection given a name
     * @param collectionValues. Collection that contains the values. Ex: ChestRegions
     * @param collectionNames. Collection that contains the names. Ex: ChestRegionNames
     * @param key. Name to search for
     * @return value of the element
     * @throws Key Not Found exception
     */
    unsigned char GetCollectionValueFromName(std::vector<unsigned char> collectionValues, std::vector<std::string> collectionNames,
                                             std::string key) const;
};

} // namespace cip


#endif
