
#ifndef PORYGONLANG_DIAGNOSTICSHOLDER_HPP
#define PORYGONLANG_DIAGNOSTICSHOLDER_HPP

#include <vector>
#include <string>
#include <sstream>
#include "DiagnosticSeverity.hpp"
#include "DiagnosticCode.hpp"
#include "Diagnostic.hpp"

using namespace std;

namespace Porygon::Diagnostics {
    class DiagnosticsHolder {
        bool _hasErrors;
        vector<Diagnostic> _diagnostics;
        vector<size_t> _lineStarts;
        vector<size_t> _lineLength;

    public:
        explicit DiagnosticsHolder(const u16string& str) :_hasErrors(false), _lineStarts(vector<size_t>{0}) {
            size_t lineLength = 0;
            for (size_t i = 0; i < str.size(); i++){
                lineLength++;
                if (str[i] == '\n'){
                    _lineStarts.push_back(i + 1);
                    _lineLength.push_back(lineLength);
                    lineLength = 0;
                }
            }
        }

        ~DiagnosticsHolder() {
            _diagnostics.clear();
        }

        void Log(DiagnosticSeverity severity, DiagnosticCode code, unsigned int start, unsigned int length, const std::vector<string>& arguments = {});

        void LogError(DiagnosticCode code, unsigned int start, unsigned int length, const std::vector<string>& arguments = {});

        void LogWarning(DiagnosticCode code, unsigned int start, unsigned int length, const std::vector<string>& arguments = {});

        void LogInfo(DiagnosticCode code, unsigned int start, unsigned int length, const std::vector<string>& arguments = {});

        bool HasErrors();

        vector<Diagnostic> GetDiagnostics();

        inline int DiagnosticsCount();

        Diagnostic *GetDiagnosticAt(int position);

        size_t GetLineFromPosition(size_t i);
        [[nodiscard]]
        inline size_t GetStartPositionForLine(size_t i){
            return _lineStarts[i];
        }

        std::string* GetFullDiagnostic(Diagnostic* diagnostic);
    };
}

#endif //PORYGONLANG_DIAGNOSTICSHOLDER_HPP
