//--------------------------------------------------------------------------------
// <copyright file="LqrSMACFileSetSettings.cpp" 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>
//   Implementation of the FileSetSettings class, a boost serializable entity that
//   holds the confiugration values for the FileSet class
// </summary>
//
// <owner>Mike Cookson</owner>
//--------------------------------------------------------------------------------

#include "LqrSMACFileSetSettings.h"
#include "LqrSMACLoadSaveBoostXml.h"
#include <unistd.h>

using namespace std;

namespace LiquidRobotics {
namespace SMACFramework {

inline string CurrentDirectory()
{
    char buffer[PATH_MAX+1];

    if (getcwd(buffer, sizeof(buffer)));

    string result = buffer;
    return result;
}

FileSetSettings::FileSetSettings()
: archiveCompressionType(ECT_NONE)
//, archiveDirectory("")
, extension(".DAT")
, keepWritesTogether(true)
, maxBytesQueued(10000)
, maxFileSize(1000000)
, maxFiles(10)
, maxRetainTime(boost::posix_time::seconds(0))
, prefix("FILE")
, purgeStrategy(EPS_OLDEST)
, workingDirectory(CurrentDirectory())
{
}

FileSetSettings::FileSetSettings(const string& _workingDirectory, const string& _prefix, const string& _extension, SizeType _maxFiles, FileSizeType _maxFileSize)
: archiveCompressionType(ECT_NONE)
//, archiveDirectory("")
, extension(_extension)
, keepWritesTogether(true)
, maxBytesQueued(10000)
, maxFileSize(_maxFileSize)
, maxFiles(_maxFiles)
, maxRetainTime(boost::posix_time::seconds(0))
, prefix(_prefix)
, purgeStrategy(EPS_OLDEST)
, workingDirectory(_workingDirectory)
{
}

FileSetSettings::FileSetSettings(const FileSetSettings& rhs)
: archiveCompressionType(rhs.archiveCompressionType)
, archiveDirectory(rhs.archiveDirectory)
, extension(rhs.extension)
, keepWritesTogether(rhs.keepWritesTogether)
, maxBytesQueued(rhs.maxBytesQueued)
, maxFileSize(rhs.maxFileSize)
, maxFiles(rhs.maxFiles)
, maxRetainTime(rhs.maxRetainTime)
, prefix(rhs.prefix)
, purgeStrategy(rhs.purgeStrategy)
, workingDirectory(rhs.workingDirectory)
{
}

FileSetSettings::~FileSetSettings()
{
}

FileSetSettings& FileSetSettings::operator=(const FileSetSettings& rhs)
{
    if (this != &rhs)
    {
        archiveCompressionType = rhs.archiveCompressionType;
        archiveDirectory = rhs.archiveDirectory;
        extension = rhs.extension;
        keepWritesTogether = rhs.keepWritesTogether;
        maxBytesQueued = rhs.maxBytesQueued;
        maxFiles = rhs.maxFiles;
        maxRetainTime = rhs.maxRetainTime;
        prefix = rhs.prefix;
        purgeStrategy = rhs.purgeStrategy;
        workingDirectory = rhs.workingDirectory;
    }

    return *this;
}

void FileSetSettings::Load(const string& fileName)
{
    LoadBoostXml(fileName, *this);
}

void FileSetSettings::Save(const string& fileName) const
{
    SaveBoostXml(fileName, *this);
}

// 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
FileSetSettings::ECompressionType FileSetSettings::GetArchiveCompressionType() const
{
    return archiveCompressionType;
}

void FileSetSettings::SetArchiveCompressionType(ECompressionType newValue)
{
    archiveCompressionType = 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
const string& FileSetSettings::GetArchiveDirectory() const
{
    return archiveDirectory;
}

void FileSetSettings::SetArchiveDirectory(const string& newValue)
{
    archiveDirectory = newValue;
}

// Extension is appended to the prefix and any additional characters when creating
// files
const string& FileSetSettings::GetExtension() const
{
    return extension;
}

void FileSetSettings::SetExtension(const string& newValue)
{
    extension = 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)
bool FileSetSettings::GetKeepWritesTogether() const
{
    return keepWritesTogether;
}

void FileSetSettings::SetKeepWritesTogether(bool newValue)
{
    keepWritesTogether = newValue;
}

// MaxBytesQueue determines the number of bytes that can be held between the caller's
// thread and the file write thread without causing hte calling to block; if the number
// is zero, there is no background thread spawned.
FileSetSettings::SizeType FileSetSettings::GetMaxBytesQueued() const
{
    return maxBytesQueued;
}

void FileSetSettings::SetMaxBytesQueued(SizeType newValue)
{
    maxBytesQueued = 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.
FileSetSettings::FileSizeType FileSetSettings::GetMaxFileSize() const
{
    return maxFileSize;
}

void FileSetSettings::SetMaxFileSize(FileSizeType newValue)
{
    maxFileSize = newValue;
}

// MaxFiles determines the maximum number of files (current working file + archives) that
// will be retained.
FileSetSettings::SizeType FileSetSettings::GetMaxFiles() const
{
    return maxFiles;
}

void FileSetSettings::SetMaxFiles(SizeType newValue)
{
    maxFiles = newValue;
}

// MaxRetainTime is the maximum time to retain files; a zero-length retain time is ignored
FileSetSettings::TimeSpan FileSetSettings::GetMaxRetainTime() const
{
    return maxRetainTime;
}

void FileSetSettings::SetMaxRetainTime(TimeSpan newValue)
{
    maxRetainTime = newValue;
}

// Prefix is the first part of the filename that will be used for working files and archives
const string& FileSetSettings::GetPrefix() const
{
    return prefix;
}

void FileSetSettings::SetPrefix(const string& newValue)
{
    prefix = newValue;
}

// PurgeStrategy defines whether and how old archive files are purged
FileSetSettings::EPurgeStrategy FileSetSettings::GetPurgeStrategy() const
{
    return purgeStrategy;
}

void FileSetSettings::SetPurgeStrategy(EPurgeStrategy newValue)
{
    purgeStrategy = newValue;
}

// WorkingDirectory is where data files are accumulated and the default
// directory for archives if ArchiveDirectory is blank or not usable
const string& FileSetSettings::GetWorkingDirectory() const
{
    return workingDirectory;
}

void FileSetSettings::SetWorkingDirectory(const string& newValue)
{
    workingDirectory = newValue;
}

string FileSetSettings::ToString() const
{
    stringstream stm;
    stm << *this;

    return stm.str();
}

ostream& operator<<(ostream& out, const FileSetSettings& settings)
{
    out << "archiveCompressionType=" << FileSetSettings::CompressionTypeToString(settings.GetArchiveCompressionType())
        << " archiveDirectory='" << settings.GetArchiveDirectory() << "'"
        << " extension='" << settings.GetExtension() << "'"
        << " keepWritesTogether=" << settings.GetKeepWritesTogether()
        << " maxBytesQueued=" << settings.GetMaxBytesQueued()
        << " maxFileSize=" << settings.GetMaxFileSize()
        << " maxRetainTime=" << FileSetSettings::TimeSpanToString(settings.GetMaxRetainTime())
        << " prefix='" << settings.GetPrefix() << "'"
        << " purgeStrategy=" << FileSetSettings::PurgeStrategyToString(settings.GetPurgeStrategy())
        << " workingDirectory='" << settings.GetWorkingDirectory() << "'";

    return out;
}

string FileSetSettings::TimeSpanToString(TimeSpan ts)
{
    stringstream stm;
    stm << ts;

    string result = stm.str();
    return result;
}

FileSetSettings::TimeSpan FileSetSettings::TimeSpanFromString(const string& str)
{
    stringstream stm(str);
    FileSetSettings::TimeSpan result;

    stm >> result;
    return result;
}

}
}
