// Copyright (c) 1997  
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel).  All rights reserved. 
//
// This file is part of CGAL (www.cgal.org); 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.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: https://github.com/CGAL/cgal/blob/releases/CGAL-4.14.3/Stream_support/include/CGAL/IO/Generic_writer.h $
// $Id: Generic_writer.h 0698f79 2017-10-20T23:34:14+02:00 Sébastien Loriot
// SPDX-License-Identifier: LGPL-3.0+
// 
//
// Author(s)     : Lutz Kettner  <kettner@mpi-sb.mpg.de>

#ifndef CGAL_IO_GENERIC_WRITER_H
#define CGAL_IO_GENERIC_WRITER_H 1

#include <CGAL/basic.h>
#include <iterator>

namespace CGAL {

template <class Writer>
class I_Generic_writer_vertex_proxy {
    Writer&  m_writer;
public:
    typedef typename Writer::Point Point;
    I_Generic_writer_vertex_proxy( Writer& w) : m_writer(w) {}
    void operator= ( const Point& p) { m_writer.write_vertex(p); }
};

template <class Writer>
class I_Generic_writer_vertex_iterator
{
    Writer&  m_writer;
public:
    typedef std::output_iterator_tag  iterator_category;
    typedef typename Writer::Point    value_type;
    typedef std::ptrdiff_t            difference_type;
    typedef value_type*               pointer;
    typedef value_type&               reference;

    typedef I_Generic_writer_vertex_proxy< Writer>    Proxy;
    typedef I_Generic_writer_vertex_iterator< Writer> Self;

    I_Generic_writer_vertex_iterator( Writer& w) : m_writer(w) {}
    Self& operator++()      { return *this; }
    Self& operator++(int)   { return *this; }
    Proxy operator*() const { return Proxy( m_writer); }
};

template <class Writer>
class I_Generic_writer_facet_proxy {
    Writer&  m_writer;
public:
    I_Generic_writer_facet_proxy( Writer& w) : m_writer(w) {}
    void operator= ( std::size_t i) { m_writer.write_facet_index(i); }
};

template <class Writer>
class I_Generic_writer_facet_iterator
{
    Writer& m_writer;
public:
    typedef std::output_iterator_tag  iterator_category;
    typedef std::size_t               value_type;
    typedef std::ptrdiff_t            difference_type;
    typedef value_type*               pointer;
    typedef value_type&               reference;

    typedef  I_Generic_writer_facet_proxy<Writer>    Proxy;
    typedef  I_Generic_writer_facet_iterator<Writer> Self;

    I_Generic_writer_facet_iterator( Writer& w) : m_writer(w) {}
    Self& operator++()      { return *this; }
    Self& operator++(int)   { return *this; }
    Proxy operator*() const { return Proxy( m_writer); }
};

// The Generic_writer class contains also the state necessary for all
// its iterators. Since these iterators are of the category
// output_iterator, they could not be used more than once and their
// positional state can be kept in Generic_writer, which simplifies
// the situation where the iterators are copied by value.

template < class Writer, class Pt >
class Generic_writer {
    Writer       m_writer;
    std::size_t  m_vertices;
    std::size_t  m_halfedges;
    std::size_t  m_facets;

    std::size_t  m_vcnt;
    std::size_t  m_fcnt;
    std::size_t  m_icnt;
public:
    typedef Pt                                      Point;
    typedef Generic_writer< Writer, Pt>             Self;
    typedef I_Generic_writer_vertex_iterator<Self>  Vertex_iterator;
    typedef I_Generic_writer_facet_iterator<Self>   Facet_iterator;

    Generic_writer( const Writer& writer, std::ostream& out,
                    std::size_t v, std::size_t h, std::size_t f)
        : m_writer( writer), m_vertices(v), m_halfedges(h), m_facets(f),
          m_vcnt(0), m_fcnt(0), m_icnt(0)
    {
        m_writer.write_header( out, v, h, f);
    }
    const Writer& writer()            const  { return m_writer;    }
    std::size_t   size_of_vertices()  const  { return m_vertices;  }
    std::size_t   size_of_halfedges() const  { return m_halfedges; }
    std::size_t   size_of_facets()    const  { return m_facets;    }

    Vertex_iterator  vertices_begin() { return Vertex_iterator( *this); }
    Facet_iterator   facets_begin() {
        if ( m_vcnt != m_vertices) {
            std::cerr << "error: Generic_writer: wrong number of "
                         "vertices written, " << m_vcnt << " instead of "
                      << m_vertices << "." << std::endl;
            m_writer.out().clear( std::ios::badbit);
        }
        m_writer.write_facet_header();
        if ( m_facets == 0)
            m_writer.write_footer();
        return Facet_iterator( *this);
    }

    // Interface used by the iterators and their proxies.
    void write_vertex( const Point& p) {
        ++m_vcnt;
        m_writer.write_vertex( ::CGAL::to_double( p.x()),
                               ::CGAL::to_double( p.y()),
                               ::CGAL::to_double( p.z()));
    }
    void write_facet_index( std::size_t i) {
        if ( m_fcnt > m_facets) {
            std::cerr << "error: Generic_writer: too many facets written."
                      << std::endl;
            m_writer.out().clear( std::ios::badbit);
        }
        if ( m_icnt == 0) {
            m_writer.write_facet_begin( i);
            m_icnt = i;
        } else {
            m_writer.write_facet_vertex_index( i);
            m_icnt --;
            if ( m_icnt == 0) {
                m_writer.write_facet_end();
                m_fcnt ++;
                if (m_fcnt == m_facets)
                    m_writer.write_footer();
            }
        }
    }
};

} //namespace CGAL
#endif // CGAL_IO_GENERIC_WRITER_H //
// EOF //
