/// OutputterBase.h
/**
 */

#ifndef OUTPUTTER_BASE_H_
#define OUTPUTTER_BASE_H_

#include <map>
#include <string>
#include <iostream>

#include <wx/filename.h>
#include <wx/filename.h>
#include <wx/config.h>

#include "OutputList.h"
#include "SeriesHandler.h"
#include "ConfigValues.h"

namespace jcs {

  /// Container for output options.
  class Options {
  public:
    /// Pathname for config file.
    std::string pathname;
    /// Boolean options.
    std::map <std::string, bool> boolOptions;
    /// Integer options.
    std::map <std::string, int> intOptions;
    /// String options.
    std::map <std::string, wxString> stringOptions;
    /// Double options.
    std::map <std::string, double> doubleOptions;
    /// Read option values from configuration file.
    void ReadConfig();
    /// Write option values to configuration file.
    void WriteConfig();
  };

  /// Base class for all Outputter classes.
  /** Provides functionality common to all Outputters, including the loading
      and saving of configuration options.
  */
  class OutputterBase {

  public :

    /// Constructor
    OutputterBase(const Options& options);
    virtual ~OutputterBase();

    virtual void UpdateOutputForSeries(SeriesHandler* handler) = 0;
    virtual void RemoveSeries(const std::string& seriesUid) = 0;
    virtual int ConvertSeries(SeriesHandler* handler) = 0;
    ImageFileName GetImageFileName(const std::string& series_uid, const std::string& name);

    wxFileName GetFileName(const std::string& series_uid);

    void ChangeFileName(const std::string& series_uid, const std::string& new_name);
    void ChangeDirName(const std::vector<std::string>& series_uids, const std::string& new_name, int position);
    /// Pure virtual since OutputterBase has no integer options.
    virtual void SetOption(const std::string& name, int value) {}
    virtual void SetOption(const std::string& name, bool value);
    ///
    /** Sets the boolOption 'split' to 'value'.
        \param value True means to save series in separate directories.
    */
    void SetSplit(bool value) { mOptions.boolOptions["split_dir"] = value; }
    bool GetSplit() { return mOptions.boolOptions["split_dir"]; }

    void SetSplitSubj(bool value) { mOptions.boolOptions["split_subj"] = value; }
    bool GetSplitSubj() { return mOptions.boolOptions["split_subj"]; }

    void SetFlexFormat(bool value) { fnFlexFormat = value; }
    bool GetFlexFormat() { return fnFlexFormat; }

    void fnAppendComponent(wxString component) { fnComponents.Add(component); }

    OutputList mOutputList;

    // For management of output file naming.
    struct NameField
    {
      /// Name of the field, should follow canonical DICOM standard.
      std::string name;
      /// Indicates whether instance should be included in the output filename.
      bool value;
      /// Abbreviation, used by mcverter filename formatting string.
      wxString abbr;
      // Constructors
      NameField() {}
      NameField(std::string n, bool v) : name(n), value(v) {}
      NameField(std::string n, bool v, wxString a) : name(n), value(v), abbr(a) {}
    };
    
    /// DICOM field names used for naming output files.
    enum {
      PatientName,
      PatientId,
      SeriesDate,
      SeriesTime,
      StudyId,
      StudyDescription,
      SeriesNumber,
      SequenceName,
      ProtocolName,
      SeriesDescription
    };

    typedef std::map<int, NameField> FieldMap;
    FieldMap defaultNameFields;
    // Use dfn to avoid using literal strings in code. Use
    // the above enum to provide keys.
    typedef std::map<int, std::string> NameFields;
    NameFields dfn;
    NameFields abbr;

  protected :
    // Determines what kind of formatting to use for output filenames,
    // specifically in GenerateDefaultPrefix.
    bool fnFlexFormat;
    wxArrayString fnComponents;
    std::map<VolId, std::string> volKeyMap;
    Options mOptions;
    std::map<std::string, Options> overrides;

    virtual void FillInDefaultDirs(ImageFileName& name, SeriesHandler* series);
    std::string GenerateDefaultPrefix(SeriesHandler* series);
    static Options GetBaseOptions();
    bool FindIntInOverrides(const std::string& series_uid, const std::string& seek, int& value);
    bool FindBoolInOverrides(const std::string& series_uid, const std::string& seek, bool& value);

  };
}

#endif
