//#####################################################################
// Copyright 2006, Geoffrey Irving, Eftychios Sifakis, Andrew Selle
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class TYPED_ISTREAM and TYPED_OSTREAM
//#####################################################################
// STREAM_TYPE:
//   Indicates whether a stream should be read as float or double.
// 
// TYPED_ISTREAM and TYPED_OSTREAM
//   Wrapper for std::istream and std::ostream that also knows whether
//   it is writing floats or doubles.  Generally should be passed by value.
// 
// FILE_ISTREAM and FILE_OSTREAM
//   Stream that represents a binary file.  When writing a file, creating
//   this object writes the use_doubles flag to the file.  When reading,
//   this flag is read from file.  Can be moved but not copied.  Owns its
//   stream.
// 
#ifndef __TYPED_STREAM__
#define __TYPED_STREAM__

#include <Core/Read_Write/READ_WRITE_FORWARD.h>
#include <Core/Read_Write/STREAM_TYPE.h>
#include <Core/Utilities/TYPE_UTILITIES.h>
#include <iosfwd>
#include <memory>
namespace PhysBAM{
class RAW_ISTREAM
{
public:
    std::istream& stream;
    RAW_ISTREAM(std::istream& stream):stream(stream){}
    RAW_ISTREAM(const RAW_ISTREAM& t)=delete;
    RAW_ISTREAM(RAW_ISTREAM&& t)=delete;
    RAW_ISTREAM& operator=(const RAW_ISTREAM& t)=delete;
    RAW_ISTREAM& operator=(RAW_ISTREAM&& t)=delete;
};
class RAW_OSTREAM
{
public:
    std::ostream& stream;
    bool need_space=false;
    RAW_OSTREAM(std::ostream& stream):stream(stream){}
    RAW_OSTREAM(const RAW_OSTREAM& t)=delete;
    RAW_OSTREAM(RAW_OSTREAM&& t)=delete;
    RAW_OSTREAM& operator=(const RAW_OSTREAM& t)=delete;
    RAW_OSTREAM& operator=(RAW_OSTREAM&& t)=delete;
};
template<class RW>
class UNTYPED_ISTREAM
{
public:
    RAW_ISTREAM& raw;
    UNTYPED_ISTREAM(RAW_ISTREAM& raw):raw(raw){}
    operator RAW_ISTREAM&(){return raw;}
};
template<class RW>
class UNTYPED_OSTREAM
{
public:
    RAW_OSTREAM& raw;
    UNTYPED_OSTREAM(RAW_OSTREAM& raw):raw(raw){}
    operator RAW_OSTREAM&(){return raw;}
};
class TYPED_ISTREAM
{
public:
    RAW_ISTREAM& raw;
    STREAM_TYPE type;
    TYPED_ISTREAM(RAW_ISTREAM& raw,STREAM_TYPE type):raw(raw),type(type){}
    operator RAW_ISTREAM&(){return raw;}
};
class TYPED_OSTREAM
{
public:
    RAW_OSTREAM& raw;
    STREAM_TYPE type;
    TYPED_OSTREAM(RAW_OSTREAM& raw,STREAM_TYPE type):raw(raw),type(type){}
    operator RAW_OSTREAM&(){return raw;}
};
class FILE_ISTREAM
{
    RAW_ISTREAM raw;
public:
    TYPED_ISTREAM stream;
    FILE_ISTREAM(const std::string& filename,bool binary=true);
    ~FILE_ISTREAM();
    operator TYPED_ISTREAM&(){return stream;}
    operator RAW_ISTREAM&(){return raw;}
};
class FILE_OSTREAM
{
    RAW_OSTREAM raw;
public:
    TYPED_OSTREAM stream;
    FILE_OSTREAM(STREAM_TYPE stream_type,const std::string& filename,
        bool binary=true,bool write_compressed_if_possible=true);
    ~FILE_OSTREAM();
    operator TYPED_OSTREAM&(){return stream;}
    operator RAW_OSTREAM&(){return raw;}
};
}
#endif
