// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
//   BodgeMaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

#pragma once

#include <cstdint>
#include <string>
#include <fstream>
#include <vector>
#include <tinyutf8/tinyutf8.h>

#include "error.hpp"


class File {
    private:
        //TODO: add other necessary internals to this section as needed
        char mode;
        std::fstream fileStream;
        //TODO: add other necessary details to the constructor as needed
        // For example, the fstream (or whatever mechanism is used) needs
        // to be handed over from File::open() to the File object.
        //
        // Remember to add a destructor to the public section if pointers
        // are to be used.
        File(std::string path, char mode, uint64_t cursorPosition);
    public:
        bool isOpen;
        std::string path;
        uint64_t cursorPosition;
        // may be error if not a regular file or size cannot be determined
        ErrorOr<uint64_t> size;

        File() {};
        ~File();

        void open();
        void close();

        bool eof();

        // only applicable to read and edit modes
        // moves the cursor to the right of the read section
        ErrorOr<uint8_t> readByte();
        ErrorOr<std::vector<uint8_t>> read(uint64_t bytes);
        ErrorOr<tiny_utf8::string> readString(uint64_t bytes);

        // only applicable to write, modify, append, and edit modes
        // in modify and edit modes, overwrite whatever is at the
        // cursor position if there is anything there
        // moves the cursor to the right of the written section
        ErrorOrVoid writeByte(uint8_t byte);
        ErrorOrVoid write(std::vector<uint8_t> data);
        ErrorOrVoid writeString(tiny_utf8::string string);

        // only applicable to modify and edit modes
        // insert at cursor position and move other contents to the right
        // moves the cursor to the right of the inserted section
        ErrorOrVoid insertByte(uint8_t byte);
        ErrorOrVoid insert(std::vector<uint8_t> data);
        ErrorOrVoid insertString(tiny_utf8::string string);

        // only applicable to edit mode
        // return the cut section, remove cut section from file
        // moves the cursor to the right of where it happened
        ErrorOr<uint8_t> cutByte();
        ErrorOr<std::vector<uint8_t>> cut(uint64_t length);
        ErrorOr<tiny_utf8::string> cutString(uint64_t length);

        // modes:
        //  r (read)
        //  w (write: overwrite file deleting its previous contents)
        //  a (append: write to end of file)
        //  m (modify: write to file modifying its previous contents)
        //
        // A startPosition of 0xFFFFFFFF is considered to be the end of
        // the file whatever its size.
        static ErrorOr<File*> open(std::string path, char mode, uint64_t startPosition=0);
};
