/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * or you may search the http://www.gnu.org website for the version 3 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <streambuf>
#include <istream>
#include <string>
#include <git2.h>

#include <richio.h>


class BLOB_BUFFER_STREAM : public std::streambuf
{
    public:
        BLOB_BUFFER_STREAM( git_blob* aBlob )
        {
            // Yay C++
            setg( const_cast<char*>( static_cast<const char*>( git_blob_rawcontent( aBlob ) ) ),
                  const_cast<char*>( static_cast<const char*>( git_blob_rawcontent( aBlob ) ) ),
                  const_cast<char*>( static_cast<const char*>( git_blob_rawcontent( aBlob ) ) ) + git_blob_rawsize( aBlob ) );
        }

        ~BLOB_BUFFER_STREAM() override
        {
        }

        int overflow( int c ) override
        {
            return traits_type::eof();
        }

        std::streamsize xsputn( const char* s, std::streamsize n ) override
        {
            return 0;
        }
};

// Build a class that implements LINE_READER for git_blobs
class BLOB_READER : public LINE_READER
{
    public:
        BLOB_READER( git_blob* aBlob ) : m_blob( aBlob )
        {
            m_stream = new BLOB_BUFFER_STREAM( m_blob );
            m_istream = new std::istream( m_stream );
            m_line = nullptr;
            m_lineNum = 0;
        }

        ~BLOB_READER() override
        {
            delete m_istream;
            delete m_stream;
        }

        char* ReadLine() override
        {
            getline( *m_istream, m_buffer );

            m_buffer.append( 1, '\n' );

            m_length = m_buffer.size();
            m_line = (char*) m_buffer.data(); //ew why no const??

            // lineNum is incremented even if there was no line read, because this
            // leads to better error reporting when we hit an end of file.
            ++m_lineNum;

            return m_istream->eof() ? nullptr : m_line;
        }

    private:
        git_blob* m_blob;
        BLOB_BUFFER_STREAM* m_stream;
        std::istream* m_istream;
        std::string   m_buffer;
};