// (C) Copyright Jonathan Turkanis 2004
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)

// See http://www.boost.org/libs/iostreams for documentation.

#ifndef BOOST_IOSTREAMS_TEST_FILES_HPP_INCLUDED
#define BOOST_IOSTREAMS_TEST_FILES_HPP_INCLUDED

#include <cctype>                             // toupper, tolower
#include <cstdio>                             // tmpname, TMP_MAX, remove
#include <cstdlib>                            // rand, toupper, tolower (VC6)
#include <fstream>
#include <string>
#if defined(__CYGWIN__)
# include <boost/random/linear_congruential.hpp>
# include <boost/random/uniform_smallint.hpp>
#endif
#include "./constants.hpp"

#ifdef BOOST_NO_STDC_NAMESPACE
# undef toupper
# undef tolower
# undef remove
# undef rand
namespace std {
    using ::toupper; using ::tolower; using ::remove; using ::rand;
}
#endif

namespace boost { namespace iostreams { namespace test {

// Represents a temp file, deleted upon destruction.
class temp_file {
public:

    // Constructs a temp file which does not initially exist.
    temp_file() { set_name(); }
    ~temp_file() { std::remove(name_.c_str()); }
    const ::std::string name() const { return name_; }
    operator const ::std::string() const { return name_; }
private:
    void set_name() {
    // Windows CreateFileMapping API function doesn't accept some
    // names generated by std::tmpnam.
    #if defined(_WIN32) || defined(__WIN32__) || \
        defined(WIN32) || defined(__CYGWIN__) \
        /**/
        for (int z = 0; z < 5; ++z)
            name_ += static_cast<char>('0' + rand());
    #else
        using namespace std;
        char tmp[L_tmpnam]; name_ = tmpnam(tmp);
    #endif
    }
    #if defined(__CYGWIN__)
        int rand()
        {
            static rand48                random_gen;
            static uniform_smallint<int> random_dist(0, 9);
            return random_dist(random_gen);
        }
    #else
    # if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
        int rand() 
        { 
            return (std::rand() * 10) / RAND_MAX; 
        }
    # endif
    #endif
    ::std::string name_;
};

struct test_file : public temp_file {
    test_file()
        {
            BOOST_IOS::openmode mode = 
                BOOST_IOS::out | BOOST_IOS::binary;
            ::std::ofstream f(name().c_str(), mode);
            const ::std::string n(name());
            const char* buf = narrow_data();
            for (int z = 0; z < data_reps; ++z)
                f.write(buf, data_length());
        }
};


struct uppercase_file : public temp_file {
    uppercase_file()
        {
            BOOST_IOS::openmode mode = 
                BOOST_IOS::out | BOOST_IOS::binary;
            ::std::ofstream f(name().c_str(), mode);
            const char* buf = narrow_data();
            for (int z = 0; z < data_reps; ++z)
                for (int w = 0; w < data_length(); ++w)
                    f.put((char) std::toupper(buf[w]));
        }
};

struct lowercase_file : public temp_file {
    lowercase_file()
        {
            BOOST_IOS::openmode mode = 
                BOOST_IOS::out | BOOST_IOS::binary;
            ::std::ofstream f(name().c_str(), mode);
            const char* buf = narrow_data();
            for (int z = 0; z < data_reps; ++z)
                for (int w = 0; w < data_length(); ++w)
                    f.put((char) std::tolower(buf[w]));
        }
};

//----------------------------------------------------------------------------//

} } } // End namespaces test, iostreams, boost.

#endif // #ifndef BOOST_IOSTREAMS_TEST_FILES_HPP_INCLUDED
