/* textstorage.h
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2005-2023 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef TEXTSTORAGE_H
#define TEXTSTORAGE_H

#include "aguixdefs.h"
#include <vector>
#include <string>
#include <utility>
#include <cstdint>
#include "awidth.h"
#include "refcount.hh"

class TextStorage
{
 public:
  virtual ~TextStorage() {}
  virtual int getNrOfLines() const = 0;
  virtual int getLine( int line_nr, unsigned int offset, int len, std::string &return_line ) const = 0;
  virtual int getLine( int line_nr, unsigned int offset, std::string &return_line ) const = 0;
  virtual int getMaxLineWidth() const = 0;
  virtual int getLineWidth( int line_nr ) const = 0;
  virtual void setLineLimit( int new_limit ) = 0;
  virtual int getLineLimit() = 0;
  virtual std::pair<int,int> getRealLinePair( int line_nr ) const = 0;
  virtual int findLineNr( std::pair<int,int> real_line ) const = 0;
  virtual AWidth &getAWidth() = 0;
  virtual void setAWidth( const RefCount<AWidth> &lencalc ) = 0;

  virtual int getNrOfUnwrappedLines() const = 0;
  virtual int getUnwrappedLine( int line_nr,
                                unsigned int offset,
                                int len,
                                std::string &return_line ) const = 0;
  virtual int getUnwrappedLine( int line_nr,
                                unsigned int offset,
                                std::string &return_line ) const = 0;
  virtual int getUnwrappedLineRaw( int line_nr,
                                   unsigned int offset,
                                   int len,
                                   std::string &return_line ) const = 0;
  virtual int getUnwrappedLineRaw( int line_nr,
                                   unsigned int offset,
                                   std::string &return_line ) const = 0;
  virtual std::pair< std::pair< int, int >, int > getLineForOffset( int unwrapped_line_nr, int line_offset ) const = 0;
};

class TextStorageString : public TextStorage
{
 public:
    enum text_storage_converion {
        NO_CHARACTER_CONVERSION,
        CONVERT_NON_PRINTABLE_SIMPLE,
        CONVERT_NON_PRINTABLE_HEX
    };
    
  TextStorageString &operator=( TextStorageString &&other ) = default;
  TextStorageString( const std::string &content,
                     const RefCount<AWidth> &lencalc,
                     int line_limit = -1,
                     enum text_storage_converion convert = NO_CHARACTER_CONVERSION );
  TextStorageString( const char *buf,
                     int len,
                     const RefCount<AWidth> &lencalc,
                     int line_limit = -1,
                     enum text_storage_converion convert = NO_CHARACTER_CONVERSION );

  int getNrOfLines() const;
  int getLine( int line_nr, unsigned int offset, int len, std::string &return_line ) const;
  int getLine( int line_nr, unsigned int offset, std::string &return_line ) const;
  int getMaxLineWidth() const;
  int getLineWidth( int line_nr ) const;
  void setLineLimit( int new_limit );
  int getLineLimit();
  std::pair<int,int> getRealLinePair( int line_nr ) const;
  int findLineNr( std::pair<int,int> real_line ) const;
  AWidth &getAWidth();
  void setAWidth( const RefCount<AWidth> &lencalc ) override;

  int getNrOfUnwrappedLines() const;
  int getUnwrappedLine( int line_nr,
                        unsigned int offset,
                        int len,
                        std::string &return_line ) const;
  int getUnwrappedLine( int line_nr,
                        unsigned int offset,
                        std::string &return_line ) const;
  int getUnwrappedLineRaw( int line_nr,
                           unsigned int offset,
                           int len,
                           std::string &return_line ) const;
  int getUnwrappedLineRaw( int line_nr,
                           unsigned int offset,
                           std::string &return_line ) const;
  std::pair< std::pair< int, int >, int > getLineForOffset( int unwrapped_line_nr, int line_offset ) const;

  void setContent( const std::string &content );

    void setConvertMode( enum text_storage_converion convert );
 private:
  void initBuffer( int line_limit_width = -1 );
    unsigned int getTokenLen( unsigned int start_offset, int limit );
    std::string getReplacementString( unsigned char ch, size_t column ) const;
  
    void convertRawData();

    enum text_storage_converion m_convert;
    std::string m_raw_buffer;   // this is the unmodified original data

    // ( converted_pos, raw_pos, column )
    std::vector< std::tuple< size_t, size_t, uint8_t > > m_converted_pos_to_raw_snapshots;

  std::string buffer;                      // stores text file
  std::vector< size_t > line_offsets;  // stores offset for each line (can be outside of buffer
                                           // for last line)
  std::vector<std::pair<int,int> > _real_lines;
  int getLineCharacters( int line_nr ) const;
  RefCount<AWidth> m_lencalc;

  /* stores offset for each real line (can be outside of buffer
   * for last line) (no wrapping!)
   */
  std::vector< size_t > m_unwrapped_line_offsets;
  int getUnwrappedLineCharacters( int line_nr ) const;
  int getUnwrappedLine( int line_nr,
                        unsigned int offset,
                        int len,
                        std::string &return_line,
                        bool raw ) const;
    size_t getRawPosition( size_t pos ) const;

    void storePosToRaw( size_t raw_pos, size_t converted_pos, uint8_t column );
    int convert_symbol( const char *in, uint8_t *column,
                        char **out, size_t *out_rem ) const;

  //TODO better remove const modifier from getLineWidth and co?
  //     instead of declaring the cache mutable?
  mutable std::vector<int> m_line_width_cached;
  int m_current_line_limit;

    size_t m_pos_to_raw_stepping = 1 * 1024 * 1024;

    mutable std::tuple< size_t, size_t, uint8_t > m_last_raw_lookup;
};

#endif

/* Local Variables: */
/* mode:c++ */
/* End: */
