/*
** Copyright (C) 2015-2017 Alexander Borisov
**
** This file is a part of PurC (short for Purring Cat), an HVML parser
** and interpreter.
** 
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program.  If not, see <https://www.gnu.org/licenses/>.
**
** Author: lex.borisov@gmail.com (Alexander Borisov)
*/

#include "mycore/charef.h"
#include "charef_resource.h"

const charef_entry_t * mycore_charef_find(const char *begin, size_t *offset, size_t size, size_t *data_size)
{
    unsigned const char* u_begin = (unsigned const char*)begin;
    size_t pos = (size_t)(*u_begin);
    
    while (named_character_references[pos].ch)
    {
        if(named_character_references[pos].ch == u_begin[*offset])
        {
            (*offset)++;
            
            if(named_character_references[pos].next == 0 || *offset >= size) {
                if(data_size)
                    *data_size = named_character_references[pos].codepoints_len;
                
                return &named_character_references[pos];
            }
            
            pos = named_character_references[pos].next;
        }
        else if(u_begin[*offset] > named_character_references[pos].ch) {
            pos++;
        }
        else {
            break;
        }
    }
    
    if(data_size)
        *data_size = named_character_references[pos].codepoints_len;
    
    return &named_character_references[pos];
}

const charef_entry_t * mycore_charef_get_first_position(const char begin)
{
    return &named_character_references[ (unsigned const char)begin ];
}

const charef_entry_t * mycore_charef_find_by_pos(size_t pos, const char *begin, size_t *offset, size_t size, charef_entry_result_t *result)
{
    unsigned const char* u_begin = (unsigned const char*)begin;
    
    if(u_begin[*offset] == '&') {
        result->is_done = 1;
        
        if(result->curr_entry->codepoints_len)
            return result->curr_entry;
        else if(result->last_entry) {
            *offset = result->last_offset;
            return result->last_entry;
        }
        
        return &named_character_references[0];
    }
    
    result->is_done = 0;
    
    while (named_character_references[pos].ch)
    {
        if(named_character_references[pos].ch == u_begin[*offset])
        {
            if(u_begin[*offset] == ';') {
                result->is_done = 1;
                
                result->curr_entry = &named_character_references[pos];
                return result->curr_entry;
            }
            
            (*offset)++;
            
            if(named_character_references[pos].next == 0) {
                result->is_done = 1;
                return &named_character_references[pos];
            }
            
            if(*offset >= size)
            {
                result->curr_entry = &named_character_references[pos];
                
                if(named_character_references[pos].codepoints_len) {
                    result->last_offset = *offset;
                    result->last_entry = &named_character_references[pos];
                }
                
                return result->curr_entry;
            }
            
            if(u_begin[*offset] == '&') {
                result->is_done = 1;
                result->curr_entry = &named_character_references[pos];
                
                if(result->curr_entry->codepoints_len)
                    return result->curr_entry;
                else if(result->last_entry) {
                    *offset = result->last_offset;
                    return result->last_entry;
                }
                
                return &named_character_references[0];
            }
            
            if(named_character_references[pos].codepoints_len) {
                result->last_offset = *offset;
                result->last_entry = &named_character_references[pos];
            }
            
            pos = named_character_references[pos].next;
        }
        else if(u_begin[*offset] > named_character_references[pos].ch) {
            pos++;
        }
        else {
            break;
        }
    }
    
    result->is_done = 1;
    
    if(result->last_entry) {
        *offset = result->last_offset;
        return result->last_entry;
    }
    
    return &named_character_references[0];
}


