#include "jes.h"
#include "jes/FileLoader.h"
#include "jes/FileReader.h"
#include "jes/Text.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

namespace jes
{
    FileLoader::FileLoader()
    {
        m_buf = NULL;
        m_line_endings = LINE_ENDING_COUNT;
        m_lines = NULL;
    }

    FileLoader::~FileLoader()
    {
        if (m_buf != NULL)
        {
            delete[] m_buf;
            m_buf = NULL;
        }
    }

    bool FileLoader::load(const char * fname)
    {
        size_t size;

        if (!FileReader::load(fname, &m_buf, &size))
        {
            return false;
        }

        load_buf(size);

        return true;
    }

    void FileLoader::load_buf(size_t size)
    {
        LineIndexPairVectorRef lines[LINE_ENDING_COUNT];
        size_t line_start[LINE_ENDING_COUNT] = {0};
        unsigned int n_cr = 0;
        unsigned int n_lf = 0;
        bool crlf = true;
        for (size_t i = 0; i < LINE_ENDING_COUNT; i++)
        {
            lines[i] = new LineIndexPairVector();
        }
        for (size_t i = 0; i < size; i++)
        {
            if (m_buf[i] == '\r')
            {
                lines[LINE_ENDING_CR]->push_back(LineIndexPair(&m_buf[line_start[LINE_ENDING_CR]], i - line_start[LINE_ENDING_CR]));
                n_cr++;
                line_start[LINE_ENDING_CR] = i + 1;
                if (crlf)
                {
                    if ((i < (size - 1)) && (m_buf[i + 1] == '\n'))
                    {
                        lines[LINE_ENDING_CRLF]->push_back(LineIndexPair(&m_buf[line_start[LINE_ENDING_CRLF]], i - line_start[LINE_ENDING_CRLF]));
                        n_lf++;
                        i++;
                        line_start[LINE_ENDING_CRLF] = i + 1;
                    }
                    else
                    {
                        crlf = false;
                    }
                }
            }
            else if (m_buf[i] == '\n')
            {
                lines[LINE_ENDING_LF]->push_back(LineIndexPair(&m_buf[line_start[LINE_ENDING_LF]], i - line_start[LINE_ENDING_LF]));
                crlf = false;
                n_lf++;
                line_start[LINE_ENDING_LF] = i + 1;
            }
        }

        if (crlf && (n_lf > 0u))
        {
            m_line_endings = LINE_ENDING_CRLF;
            m_lines = lines[LINE_ENDING_CRLF];
        }
        else if ((n_cr > 0u) && (n_lf == 0u))
        {
            m_line_endings = LINE_ENDING_CR;
            m_lines = lines[LINE_ENDING_CR];
        }
        else
        {
            m_line_endings = LINE_ENDING_LF;
            m_lines = lines[LINE_ENDING_LF];
        }
    }

    TextRef FileLoader::get_line(unsigned int line_no)
    {
        return new Text((*m_lines)[line_no].first, (*m_lines)[line_no].second);
    }
}
