/*  This file is part of the Vc library.

    Copyright (C) 2009-2011 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef VECIO_H
#define VECIO_H

#include "vector.h"
#include "Memory"
#include <iostream>

#if defined(__GNUC__) && !defined(_WIN32) && defined(_GLIBCXX_OSTREAM)
#define VC_HACK_OSTREAM_FOR_TTY 1
#endif

#ifdef VC_HACK_OSTREAM_FOR_TTY
#include <unistd.h>
#include <ext/stdio_sync_filebuf.h>
#endif

#include "internal/namespace.h"

namespace
{
    namespace AnsiColor
    {
        struct Type { const char *data; };
        static const Type green  = { "\033[1;40;32m" };
        static const Type yellow = { "\033[1;40;33m" };
        static const Type blue   = { "\033[1;40;34m" };
        static const Type normal = { "\033[0m" };
    } // namespace AnsiColor

#ifdef VC_HACK_OSTREAM_FOR_TTY
    class hacked_ostream : public std::ostream
    {
        public:
            using std::ostream::_M_streambuf;
    };
    __attribute__((__const__)) bool mayUseColor(const std::ostream &os)
    {
        std::basic_streambuf<char> *hack1 = const_cast<std::basic_streambuf<char> *>(os.*(&hacked_ostream::_M_streambuf));
        __gnu_cxx::stdio_sync_filebuf<char> *hack = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char> *>(hack1);
        if (!hack) {
            return false;
        }
        FILE *file = hack->file();
        return 1 == isatty(fileno(file));
    }
#else
    inline bool mayUseColor(const std::ostream &) { return false; }
#endif
} // anonymous namespace

namespace std
{
inline std::ostream &operator<<(std::ostream &out, const AnsiColor::Type &c)
{
    if (mayUseColor(out)) {
        out << c.data;
    }
    return out;
}

template<typename T>
inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Vector<T> &v)
{
    out << AnsiColor::green << "[";
    out << v[0];
    for (int i = 1; i < v.Size; ++i) {
        out << ", " << v[i];
    }
    out << "]" << AnsiColor::normal;
    return out;
}

inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Vector<char> &v)
{
    out << AnsiColor::green << "[";
    out << int(v[0]);
    for (int i = 1; i < v.Size; ++i) {
        out << ", " << int(v[i]);
    }
    out << "]" << AnsiColor::normal;
    return out;
}
inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Vector<unsigned char> &v)
{
    out << AnsiColor::green << "[";
    out << int(v[0]);
    for (int i = 1; i < v.Size; ++i) {
        out << ", " << int(v[i]);
    }
    out << "]" << AnsiColor::normal;
    return out;
}

#ifdef VC_HAVE_FMA
template<typename T>
inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::VectorMultiplication<T> &v)
{
    return out << VECTOR_NAMESPACE::Vector<T>(v);
}
#endif

#ifdef VC_IMPL_AVX
template<unsigned int VectorSize, size_t RegisterWidth>
inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Mask<VectorSize, RegisterWidth> &m)
#else
template<unsigned int VectorSize>
inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Mask<VectorSize> &m)
#endif
{
    out << AnsiColor::blue << "m[";
    for (unsigned int i = 0; i < VectorSize; ++i) {
        if (i > 0 && (i % 4) == 0) {
            out << " ";
        }
        if ( m[i] ) {
          out << AnsiColor::yellow << '1';
        } else {
          out << AnsiColor::blue << '0';
        }
    }
    out << AnsiColor::blue << "]" << AnsiColor::normal;
    return out;
}
#ifdef VC_IMPL_SSE
inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Float8Mask &m)
{
    out << AnsiColor::blue << "m[";
    for (unsigned int i = 0; i < 8; ++i) {
        if (i > 0 && (i % 4) == 0) {
            out << " ";
        }
        if ( m[i] ) {
          out << AnsiColor::yellow << '1';
        } else {
          out << AnsiColor::blue << '0';
        }
    }
    out << AnsiColor::blue << "]" << AnsiColor::normal;
    return out;
}
#endif

template<typename V, typename Parent, typename RM>
inline std::ostream &operator<<(std::ostream &out, const Vc::MemoryBase<V, Parent, 1, RM> &m )
{
    out << AnsiColor::blue << "{" << AnsiColor::normal;
    for (unsigned int i = 0; i < m.vectorsCount(); ++i) {
        out << V(m.vector(i));
    }
    out << AnsiColor::blue << "}" << AnsiColor::normal;
    return out;
}

template<typename V, typename Parent, typename RM>
inline std::ostream &operator<<(std::ostream &out, const Vc::MemoryBase<V, Parent, 2, RM> &m )
{
    out << AnsiColor::blue << "{" << AnsiColor::normal;
    for (size_t i = 0; i < m.rowsCount(); ++i) {
        if (i > 0) {
            out << "\n ";
        }
        const size_t vcount = m[i].vectorsCount();
        for (size_t j = 0; j < vcount; ++j) {
            out << V(m[i].vector(j));
        }
    }
    out << AnsiColor::blue << "}" << AnsiColor::normal;
    return out;
}
} // namespace std

#undef VECTOR_NAMESPACE

#endif // VECIO_H

// vim: ft=cpp
