#ifndef IMAGEIOWIZARDMODEL_H
#define IMAGEIOWIZARDMODEL_H

#include <string>

#include "AbstractModel.h"
#include "GuidedNativeImageIO.h"
#include "Registry.h"
#include "ImageIODelegates.h"

class GlobalUIModel;

namespace itk {
  class GDCMSeriesFileNames;
}

/**
 This class provides a model for the ImageIO wizards. This allows the wizard
 to be distanced from the program logic. The wizard is just a collection of
 buttons and callbacks, but very little state

 This class is subclassed by specific dialogs, to allow customization. For
 example, save/load dialog behavior is handled this way.
 */
class ImageIOWizardModel : public AbstractModel
{
public:

  irisITKObjectMacro(ImageIOWizardModel, AbstractModel)

  typedef GuidedNativeImageIO::FileFormat FileFormat;
  enum Mode { LOAD, SAVE };

  enum SummaryItem {
    SI_FILENAME, SI_DIMS, SI_SPACING, SI_ORIGIN, SI_ORIENT,
    SI_ENDIAN, SI_COMPONENTS, SI_DATATYPE, SI_FILESIZE
  };

  // Initialize the wizard for load operations. Note that the delegate,
  // which specializes the behavior of this class, is stored internally
  // using a smart pointer, so its ownership can be relinquished to the
  // wizard.
  void InitializeForLoad(GlobalUIModel *parent,
                         AbstractLoadImageDelegate *delegate,
                         const char *name, const char *dispName);

  void InitializeForSave(GlobalUIModel *parent,
                         AbstractSaveImageDelegate *delegate,
                         const char *dispName);

  irisGetMacro(Parent, GlobalUIModel *)
  irisGetMacro(GuidedIO, GuidedNativeImageIO *)

  // Does the model support loading
  bool IsLoadMode() const { return m_Mode == LOAD; }

  // Does the model support loading
  bool IsSaveMode() const { return m_Mode == SAVE; }

  /** Access the IO delegate used for loading */
  irisGetMacro(LoadDelegate, AbstractLoadImageDelegate *)

  /** Access the IO delegate used for saving */
  irisGetMacro(SaveDelegate, AbstractSaveImageDelegate *)

  // Whether we can save or load a file format
  virtual bool CanHandleFileFormat(FileFormat fmt);

  // This another method that checks if a loaded image is valid
  virtual bool CheckImageValidity();

  // Default extension for saving files
  virtual std::string GetDefaultFormatForSave() const
    { return std::string("NiFTI"); }

  /**
    Create a filter string for file IO dialogs. The lineEntry is in the
    printf format, with first %s being the title of the format, and the
    second being the list of extensions. extEntry is similar, used to print
    each extension. The examples for Qt are "%s (%s)" for lineEntry and
    "*.%s" for extEntry. For FLTK it would be "%s *.{%s}" for lineEntry
    and "%s" for extEntry. The separators are used to separate extensions
    per entry and rows in the filter string.
   */
  std::string GetFilter(const char *lineEntry,
                        const char *extEntry,
                        const char *extSeparator,
                        const char *rowSeparator);

  /**
    Guess the format for the file. In load mode, if the file does not exist,
    this will return FORMAT_COUNT, i.e., failure to determine format. If it
    exists, the format will be determined using registry information (if open
    before), magic number, and extension, in turn. If in save mode, format
    is detected using registry and extension only. The last parameter is only
    considered in Load mode.
    */
  FileFormat GuessFileFormat(const std::string &fname, bool &fileExists);

  /** Get the file format from file format name */
  FileFormat GetFileFormatByName(const std::string &formatName) const;

  /** Get the name of a file format */
  std::string GetFileFormatName(FileFormat fmt) const;

  /**
    Get the directory where to browse, given a currently entered file
    */
  std::string GetBrowseDirectory(const std::string &file);

  /**
    Get the size of the file in bytes
    */
  unsigned long GetFileSizeInBytes(const std::string &file);

  /**
    Get the history of filenames
    */
  irisGetMacro(HistoryName, std::string)

  /**
    Get the display name to show in the dialog
    */
  std::string GetDisplayName() const;

  /**
    * Reset the state of the model
    */
  void Reset();

  /**
    Set the format selected by the user
    */
  void SetSelectedFormat(FileFormat fmt);

  FileFormat GetSelectedFormat();

  /**
    Load the image from filename, putting warnings into a warning list. This
    may also fire an exception (e.g., if validation failed)
    */
  void LoadImage(std::string filename);

  /**
   Save the image to a filename
   */
  void SaveImage(std::string filename);

  /**
    Get the warnings generated by LoadImage
    */
  irisGetMacro(Warnings, IRISWarningList)

  /**
    Whether an image was loaded
    */
  bool IsImageLoaded() const;

  /**
    Get summary items to display for the user
    */
  std::string GetSummaryItem(SummaryItem item);

  /**
    Load relevant information from DICOM directory
    */
  void ProcessDicomDirectory(const std::string &filename);

  /**
    Get the DICOM directory contents
    */
  irisGetMacro(DicomContents, const GuidedNativeImageIO::RegistryArray &)

  /**
    Load n-th series from DICOM directory
    */
  void LoadDicomSeries(const std::string &filename, int series);


  irisGetSetMacro(SuggestedFilename, std::string)

  /**
    Access the registry stored in the model and used for providing hints to
    the image IO.
    */
  Registry &GetHints()
    { return m_Registry; }

  /**
    Called just before exiting the wizard. Should update history, etc.
    */
  virtual void Finalize();

protected:

  // Standard ITK protected constructors
  ImageIOWizardModel();
  virtual ~ImageIOWizardModel();

  // State of the model
  Mode m_Mode;

  // Delegate that does the actual loading or saving
  SmartPtr<AbstractLoadImageDelegate> m_LoadDelegate;

  // Delegate than handles saving
  SmartPtr<AbstractSaveImageDelegate> m_SaveDelegate;

  // The history list associated with the model
  std::string m_HistoryName, m_DisplayName;

  // Parent model
  GlobalUIModel *m_Parent;
  SmartPtr<GuidedNativeImageIO> m_GuidedIO;

  // Warnings generated during IO
  IRISWarningList m_Warnings;

  // Registry containing auxiliary info
  Registry m_Registry;

  // Suggested filename
  std::string m_SuggestedFilename;

  // DICOM support
  GuidedNativeImageIO::RegistryArray m_DicomContents;
};

#endif // IMAGEIOWIZARDMODEL_H
