//-------------------------------------------------------------------------------
// <copyright file="LqrSMACFileSetSettings.h" company="LiquidRobotics">
//
// Copyright (c) 2014 Liquid Robotics, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software is associated with a release.  Liquid Robotics makes no
// representation that the design, interfaces or component distribution will
// remain unchanged in future releases.
//
// </copyright>
//
// <summary>
//   Declarations for the FileSetSettings class, a boost serializable entity that
//   holds the confiugration values for the FileSet class
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------

#ifndef __LQRSMACFILESETSETTINGS_H__
#define __LQRSMACFILESETSETTINGS_H__

#include <iostream>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include "LqrSMACIFileSetSettings.h"

namespace LiquidRobotics {
namespace SMACFramework {

class SHARED_LIB_PUBLIC FileSetSettings : public IFileSetSettings
{
public:

    FileSetSettings();
    FileSetSettings(const string& _workingDirectory, const string& _prefix, const string& _extension, SizeType _maxFiles, FileSizeType _maxFileSize);
    FileSetSettings(const FileSetSettings& rhs);

    virtual ~FileSetSettings();

    FileSetSettings& operator=(const FileSetSettings& rhs);

    void Load(const string& fileName);
    void Save(const string& fileName) const;

    string ToString() const;

    static string TimeSpanToString(TimeSpan ts);
    static TimeSpan TimeSpanFromString(const string& str);

    //  === implementation of IFileSetSettings ===

    // ArchiveCompressionType configures whether and how the currently-accumulating
    // data file is compressed once it reaches its maximum size; the compression type
    // affects the extension of the file
    virtual ECompressionType GetArchiveCompressionType() const;
    virtual void SetArchiveCompressionType(ECompressionType newValue);

    // ArchiveDirectory is the directory where archives are stored; if blank or if
    // the named directory does not exist and cannot be created, files are stored in
    // WorkingDirectory
    virtual const string& GetArchiveDirectory() const;
    virtual void SetArchiveDirectory(const string& newValue);

    // Extension is appended to the prefix and any additional characters when creating
    // files
    virtual const string& GetExtension() const;
    virtual void SetExtension(const string& newValue);

    // KeepWritesTogether determines if file writes are always made to a file without
    // being subdivided (true) or if file writes can be split across files (false)
    virtual bool GetKeepWritesTogether() const;
    virtual void SetKeepWritesTogether(bool newValue);

    // MaxBytesQueue determines the number of bytes that can be held between the caller's
    // thread and the file write thread without causing the calling to block; if the number
    // is zero, there is no background thread spawned.
    virtual SizeType GetMaxBytesQueued() const;
    virtual void SetMaxBytesQueued(SizeType newValue);

    // MaxFileSize is the maximum number of bytes that can be written to a single file in
    // the set before compression; at least one write will be made in its entirety, even
    // if the maximum file size is too small.
    virtual FileSizeType GetMaxFileSize() const;
    virtual void SetMaxFileSize(FileSizeType newValue);

    // MaxFiles determines the maximum number of files (current working file + archives) that
    // will be retained; 0=no limit on the number of files (dangerous)
    virtual SizeType GetMaxFiles() const;
    virtual void SetMaxFiles(SizeType newValue);

    // MaxRetainTime is the maximum time to retain files; a zero-length retain time is ignored
    virtual TimeSpan GetMaxRetainTime() const;
    virtual void SetMaxRetainTime(TimeSpan newValue);

    // Prefix is the first part of the filename that will be used for working files and archives
    virtual const string& GetPrefix() const;
    virtual void SetPrefix(const string& newValue);

    // PurgeStrategy defines whether and how old archive files are purged
    virtual EPurgeStrategy GetPurgeStrategy() const;
    virtual void SetPurgeStrategy(EPurgeStrategy newValue);

    // WorkingDirectory is where data files are accumulated and the default
    // directory for archives if ArchiveDirectory is blank or not usable
    virtual const string& GetWorkingDirectory() const;
    virtual void SetWorkingDirectory(const string& newValue);

private:

	friend class boost::serialization::access;

	template<class Archive>
	void save(Archive& ar, const unsigned int version) const
	{
	    string archiveCompressionType_string = CompressionTypeToString(archiveCompressionType);
        ar & boost::serialization::make_nvp("archiveCompressionType", archiveCompressionType_string);

        ar & BOOST_SERIALIZATION_NVP(archiveDirectory);
        ar & BOOST_SERIALIZATION_NVP(extension);
        ar & BOOST_SERIALIZATION_NVP(keepWritesTogether);
        ar & BOOST_SERIALIZATION_NVP(maxBytesQueued);
        ar & BOOST_SERIALIZATION_NVP(maxFileSize);
        ar & BOOST_SERIALIZATION_NVP(maxFiles);

        string maxRetainTime_string = TimeSpanToString(maxRetainTime);
        ar & boost::serialization::make_nvp("maxRetainTime", maxRetainTime_string);

        ar & BOOST_SERIALIZATION_NVP(prefix);

        string purgeStrategy_string = PurgeStrategyToString(purgeStrategy);
        ar & boost::serialization::make_nvp("purgeStrategy", purgeStrategy_string);

        ar & BOOST_SERIALIZATION_NVP(workingDirectory);
	}

	template<class Archive>
	void load(Archive& ar, const int version)
	{
	    string archiveCompressionType_string;
        ar & boost::serialization::make_nvp("archiveCompressionType", archiveCompressionType_string);
        archiveCompressionType = CompressionTypeFromString(archiveCompressionType_string);

        ar & BOOST_SERIALIZATION_NVP(archiveDirectory);
        ar & BOOST_SERIALIZATION_NVP(extension);
        ar & BOOST_SERIALIZATION_NVP(keepWritesTogether);
        ar & BOOST_SERIALIZATION_NVP(maxBytesQueued);
        ar & BOOST_SERIALIZATION_NVP(maxFileSize);
        ar & BOOST_SERIALIZATION_NVP(maxFiles);

        string maxRetainTime_string;
        ar & boost::serialization::make_nvp("maxRetainTime", maxRetainTime_string);
        maxRetainTime = TimeSpanFromString(maxRetainTime_string);

        ar & BOOST_SERIALIZATION_NVP(prefix);

        string purgeStrategy_string;
        ar & boost::serialization::make_nvp("purgeStrategy", purgeStrategy_string);
        purgeStrategy = PurgeStrategyFromString(purgeStrategy_string);

        ar & BOOST_SERIALIZATION_NVP(workingDirectory);
	}

    BOOST_SERIALIZATION_SPLIT_MEMBER()

    ECompressionType archiveCompressionType;        // how and whether backups are compressed
    string archiveDirectory;                        // location of archive files (if non-blank)
    string extension;                               // extension of files before compression
    bool keepWritesTogether;                        // true=writes cannot be subdivided amongst files
    SizeType maxBytesQueued;                        // 0=single threaded, otherwise the max bytes to in interthread queue
    FileSizeType maxFileSize;                       // maximum number of bytes in each file (before compression)
    SizeType maxFiles;                              // maximum number of files to keep (working+archive)
    TimeSpan maxRetainTime;                         // maximum time to retain archive files (0=no maximum time)
    string prefix;                                  // starting part of files in the data set
    EPurgeStrategy purgeStrategy;                   // whether and how to purge archive files
    string workingDirectory;                        // localtion of working file, default location of archives
};

std::ostream& operator<<(std::ostream& out, const FileSetSettings& settings);

}
}

#endif // __LQRSMACFILESETSETTINGS_H__
