/* filesystem_dec.hpp - base classes for any (hierachic) DEC file system

  Copyright (c) 2022, Joerg Hoppe
  j_hoppe@t-online.de, www.retrocmp.com

  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  - Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  - Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  - Neither the name of the copyright holder nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


  06-jan-2022 JH      created
 */
#ifndef _SHAREDFILESYSTEM_DEC_HPP_
#define _SHAREDFILESYSTEM_DEC_HPP_

#include <stdio.h>
#include <queue>
#include <vector>
#include <sstream>

#include "utils.hpp"
#include "storageimage.hpp"
#include "storageimage_partition.hpp"
#include "filesystem_base.hpp"
#include "filesystem_host.hpp"

namespace sharedfilesystem {

class filesystem_host_event_c ;
class file_dec_c ;
class file_dec_stream_c ;

class filesystem_dec_event_c: public filesystem_event_c {
public:
    // host_path is the host host_path of the stream?

    //either the events is for a directory, or one of the data streams
    file_dec_stream_c *dec_stream ;
    filesystem_dec_event_c() ;
    filesystem_dec_event_c(          enum operation_e _operation,
                                     std::string _host_path, bool _is_dir, file_dec_stream_c *_stream)	 ;
    ~filesystem_dec_event_c() override {}
    virtual std::string as_text() override ;
} ;



// data of a file.
// stream of DEC file == file on host
class file_dec_stream_c: /*public file_base_c, */public byte_buffer_c {
public:
    std::string stream_name ; // empty for main data stream, additional filename extension for host file

    file_dec_stream_c(file_dec_c *file, std::string stream_name) ;
    virtual ~file_dec_stream_c() ;

    virtual void init() ;

    file_dec_c *file ; // if stream is part of a file:  uplink to parent

    bool	changed = false; // calc'd from image_changed_blocks[]
//	bool valid = false ; // in use

    // link to file in hostfilesystem.
    // - EITHER the orignal host name, if stream imported from host
    //   the host has different rules for filenames than the DEC side,
    //   so the hostname can not be recreated on the DEC side, we must save it.
    // - OR generated by get_host_path() if stream created by DEC
    std::string host_path ;

    virtual std::string get_host_path() = 0;
} ;

// a typical file has only one file stream, so a "file" is a "stream"
// RT11 files also have directory prefixes and "fixed" streams
class file_dec_c: public virtual file_base_c {
public:
    file_dec_c(): file_base_c() {}
    // clone constructor. only metadata
    file_dec_c(file_dec_c *f) : file_base_c(f    ) 	{
        internal = f->internal ;
    }


    bool internal ; // file is system area of DEC filesystem
    // like boot block, monitor or volume info. Goes not to DEC user directory.


    // a "file" may have several fixed data streams
    // RT11: parentdir prefix, internal, normal
    // XXDP: only single file data
    // Files-11: data file + file attributes in text form
    // for DEC<->host conversion, enumerate them linear
    // stream[0] can be is link to parent file itself, which is also a "stream"
    // streams[1..] are other stream instances
//    vector<file_dec_stream_c *> stream ;  // addresses of those streams
    // "data" in host_file_streams[] is only a link to inherited class stream members

    // enumerate streams
    virtual unsigned get_stream_count() = 0;
    virtual file_dec_stream_c *get_stream(unsigned index) = 0 ;


    void produce_event_for_all_streams(filesystem_event_queue_c *target_event_queue, filesystem_event_c::operation_e operation, bool is_dir) ;

} ;

class directory_dec_c: public virtual directory_base_c, public virtual file_dec_c 	{
public:
    directory_dec_c(): directory_base_c() {}
    // clone constructor. only metadata
    directory_dec_c(directory_dec_c *d) : directory_base_c(d) 	{	}
    // recursive duplicate copy file tree with basic metadata only to other_dir
    virtual void copy_metadata_to(directory_base_c *other_dir) = 0;

};


class filesystem_dec_c: public filesystem_base_c {

public:

    // decoded/to-encode DEC filesystems are kept in-memory
    // only part of image is used for filesystem.
    // currently: start until begin of STD144 bad block table
    storageimage_partition_c *image_partition ;


    filesystem_dec_c(   storageimage_partition_c *image_partition) ;

    virtual ~filesystem_dec_c() override ;

    virtual void copy_metadata_to(filesystem_base_c *metadata_copy) = 0;

    bool readonly ;

    virtual void init() = 0 ;

    virtual unsigned get_block_size() = 0 ; // != drive sector, filesystem specific
    unsigned blockcount ; // actual size of filesystem, corrects static layout info and partition size

    unsigned needed_blocks(uint64_t byte_count) ;
    unsigned needed_blocks(unsigned block_size, uint64_t byte_count) ;


    // todo: recursive file iterator over dir struct, including filesystem special files. C+17 ?
    virtual unsigned file_count()     = 0;
    virtual file_dec_c *file_get(int fileidx)   = 0;

    virtual void parse() = 0 ;

    virtual void import_host_file(file_host_c *host_file) = 0 ;
    virtual void delete_host_file(std::string host_path) = 0 ;

//	virtual file_dec_c &file_get(int fileidx) = 0 ;
private:
    void produce_event_for_all_streams(file_dec_c *f,
                                       filesystem_event_queue_c *event_queue, filesystem_event_c::operation_e operation, bool is_dir) ;

    void compare_directories(directory_dec_c *a, directory_dec_c *b,
                             filesystem_event_queue_c *target_event_queue,
                             filesystem_event_c::operation_e event_op_missing,
                             bool produce_delete_create_pair_on_difference) ;
public:

    virtual void calc_change_flags() = 0 ; // only the file system knows

    void produce_events(filesystem_dec_c *metadata_snapshot) ;

    virtual void consume_event(filesystem_host_event_c *event) ;


    virtual void sort() = 0 ; // sort all files, view filesystem_base::sort

    virtual void render() = 0 ;

    virtual std::string filename_from_host(std::string *hostfname, std::string *result_filnam, std::string *result_ext) = 0 ;

	std::string volume_info_host_path ;

	virtual void produce_volume_info(std::stringstream &buffer) = 0 ;

	virtual void update_host_volume_info(std::string rootpath) ;

    virtual	void print_directory(FILE *stream) = 0 ;
    virtual	void print_diag(FILE *stream) = 0 ;

};


} // namespace
#endif // _SHAREDFILESYSTEM_DEC_HPP_


