#include "stdafx.h"
#include "FileInputBuffer.h"

FileInputBuffer::FileInputBuffer(void)
{
    this->uiCapacity = 0;
    this->uiPtrIndex = 0;
    this->caBuffer = NULL;
    this->caBufp = NULL;//Don't delete this, this is a pointer to caBuffer.
    this->pbuf = NULL;
}
FileInputBuffer::FileInputBuffer(unsigned int uiCapacity, ifstream* pifile)
{
    this->initialize(uiCapacity, pifile);
}
FileInputBuffer::~FileInputBuffer(void)
{
    delete [] this->caBuffer;
    //Don't delete this->caBufp.. it points to middle of caBuffer
    if (this->pbuf != NULL) {
        if (this->pbuf->is_open()) {
            // LOG_INFO("Info %d: Close file when FileInput is deleted\n", FINE_LOG);
            this->pbuf->close();//Reach the end of the file
        }
    }
    //this->pbuf is not new in class. This is return from ifstream class. Don't delete it.
    this->pbuf = NULL;
    // cout << "Delete File input Buffer" << endl;
}
void FileInputBuffer::initialize(unsigned int uiCapacity, ifstream* pifile)
{
    this->uiCapacity = uiCapacity;
    this->caBuffer = new char [uiCapacity];
    this->pbuf = pifile->rdbuf();
    this->uiPtrIndex = 0;
    //point to start
    this->caBufp = this->caBuffer;
    this->fflush();
}
void FileInputBuffer::fflush()
{
    //Load file directly to the buffer
    memset(this->caBuffer, 0x00, sizeof(char)*this->uiCapacity);
    //load this->uiCapacity - 1 character, so the last one will be 0
    pbuf->sgetn(this->caBuffer, this->uiCapacity - 1);
    this->caBufp = this->caBuffer;//Get new content from file
    this->uiPtrIndex = 0;
    if (this->caBuffer[this->uiCapacity - 2] == 0) { //this must be the end of the file
        if (this->pbuf->is_open())
            // LOG_INFO("Info %d: Close file when fflush to the end\n", FINE_LOG);
            this->pbuf->close();//Reach the end of the file
    }
}
unsigned int FileInputBuffer::Getline(char* caArray, unsigned int uiMax_Char_Per_Line)
{
    //If the file is not ended, return 1, if it is ended of the file return 0
    unsigned int i = uiPtrIndex, j = 0; //j is how many char has been read this time
    while (this->caBuffer[i] <= 126) { //if the character is not strange (The last character of the caBuffer should be 0.
        //If There is a new line or larger than the maximum output line, return current get string
        if (this->caBuffer[i] == '\n' || j >= uiMax_Char_Per_Line) {
            if (this->caBuffer[i] == '\n')
                i++;//next position to avoid '\n';
            this->uiPtrIndex = i;
            this->caBufp = &(this->caBuffer[i]);
            caArray[j] = '\0';
            return(1);//Successfully get a line
        } else if (this->caBuffer[i] == EOF ||
                   ((this->caBuffer[i] == 0) && (!this->pbuf->is_open()))) {		//The end of the file
            //this->caBufp=&(this->caBuffer[this->uiCapacity-1]); //Use less to point to the end
            this->pbuf->close(); //close the file
            caArray[j] = '\0'; //put the end of the array
            this->uiPtrIndex = 0;
            return(0);
        } else if (i >= (uiCapacity - 1)  || this->caBuffer[i] == 0) {  //The buffer content is run out, try to refresh
            if (this->pbuf->is_open()) {
                this->fflush();
                i = 0;//Keep going
            } else {	//The end of the file
                caArray[j] = '\0';
                return(0);//It is end of the file, but it is end of the buffer and end of file
            }
        } else { //Copy the string to buffer
            caArray[j++] = this->caBuffer[i++];
        }
    }
    cout << "sChracter " << caBuffer[i] << "Regard as EOF" << endl;
    // Put the file pointer at the end
    this->caBufp = &(this->caBuffer[this->uiCapacity-1]);
    this->pbuf->close();
    caArray[j] = '\0';//Return null array
    this->uiPtrIndex = 0;
    return(0);
}
bool FileInputBuffer::ready2Read()
{
    bool isReady2Read = false;
    //if the buffer is not empty or the file is still open to read
    isReady2Read = (this->caBufp[0] != 0 || this->pbuf->is_open()); //should test if not come to EOF
    return(isReady2Read);
}

// return the file size in bytes
unsigned long long getFileSize(const char* fileName)
{
// TODO Fix the potential bug that has file size larger than long
    unsigned long long filesize = 0;
// If compiled by Microsoft visual c++
#ifdef __MSVC__
    // Copy from others and need to be test
    bool fOk;
    WIN32_FILE_ATTRIBUTE_DATA   fileInfo;
    if (NULL == fileName)
        return -1;
    fOk = GetFileAttributesEx(fileName, GetFileExInfoStandard, (void*) & fileInfo);
    if (!fOk)
        return -1;
    assert(0 == fileInfo.nFileSizeHigh);
    return (unsigned long long)fileInfo.nFileSizeLow;
#elif defined _MSC_VER
    FILE * stream = fopen(fileName, "r");
    fseek(stream, 0L, SEEK_END);
    filesize = (unsigned long long)ftell(stream);
    fclose(stream);
#endif
#ifdef __GNUC__
    FILE * stream = fopen(fileName, "r");
    fseek(stream, 0L, SEEK_END);
    filesize = (unsigned long long)ftell(stream);
    fclose(stream);
#endif
    return(filesize);
}

unsigned long long getNumberOfLineInAFile(const char* fileName)
{
    unsigned long long estimatedNoOfLines = 1;
    // count how many lines are there
    ifstream ifile;
    ifile.open(fileName, ifstream::in);
    char BUFFER[MAX_INPUT_BUFFER_SIZE];
    memset(BUFFER, 0x00, sizeof(char)*MAX_INPUT_BUFFER_SIZE);
    ifile.getline(BUFFER, MAX_INPUT_BUFFER_SIZE);
    if (ifile.bad()) {
        cout << " Can't open file " << fileName << endl;
    }
    (ifile.rdbuf())->sgetn(BUFFER, MAX_INPUT_BUFFER_SIZE - 1);
    for (unsigned int i = 0; i < MAX_INPUT_BUFFER_SIZE; i++) {
        if (BUFFER[i] == EOF || !ifile.good()) {
            cout << "Total No of lines:" << (int)estimatedNoOfLines << endl;
            break;
        } else if (BUFFER[i] == '\n') {
            estimatedNoOfLines++;
        } else if (BUFFER[i] == 0) {
            if (i ==  MAX_INPUT_BUFFER_SIZE - 1) {
                memset(BUFFER, 0x00, sizeof(char)*MAX_INPUT_BUFFER_SIZE);
                (ifile.rdbuf())->sgetn(BUFFER, MAX_INPUT_BUFFER_SIZE - 1);
                i = 0;
            } else {
                break;
            }
        } else {
            //DO nothing;
        }
    }
    ifile.close();
    return(estimatedNoOfLines);
}

