/* Tst.hh

Copyright © 2003 David Reveman.

This file is part of Waimea.

Waimea is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

Waimea 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 General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Waimea; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */

#ifndef __Tst_hh
#define __Tst_hh

#define DEFAULT_TST_NODE_LINE_WIDTH 100

template<class _Tp>
class TstNode {
public:
    unsigned char value;
    
    TstNode<_Tp> *left;
    TstNode<_Tp> *middle;
    TstNode<_Tp> *right;

    _Tp data;
};

template<class _Tp>
class TstNodeLines {
public:
   TstNode<_Tp> *node_line;
   TstNodeLines<_Tp> *next;
};

template<class _Tp>
class Tst {
public:
    Tst(void);
    Tst(int);
    Tst(const char **);
    ~Tst();

    void clean(void);
    void insert(char *, _Tp);
    void remove(char *);

    class iterator {
    public:
        inline iterator(void) {
            current_node = NULL;
        }
        inline iterator(TstNode<_Tp> *node) {
            current_node = node;
        }
        inline iterator(Tst *_tst) {
            tst = _tst;
            line = tst->node_lines;
            pos = 0;
            current_node = tst->nextNode(&line, &pos);
        }
        
        inline _Tp operator*(void) {
            return (_Tp) current_node->data;
        }
        inline _Tp *operator->(void) {
            return (_Tp *) &current_node->data;
        }
        inline iterator & operator++(void) {
            current_node = tst->nextNode(&line, &pos);
            return *this;
        }
        inline iterator operator++(int) {
            iterator tmp (*this); ++(*this); return tmp;
        }
        inline bool operator==(const iterator &x) {
            return (current_node == x.current_node);
        }
        inline bool operator!=(const iterator &x) {
            return (current_node != x.current_node);
        }

        Tst *tst;
        TstNode<_Tp> *current_node;
        TstNodeLines<_Tp> *line;
        int pos;
    };

    iterator begin(void) { return iterator(this); }
    iterator end(void) { return iterator(); }
    iterator find(char *key) {
        TstNode<_Tp> *current_node;
        int key_index;
   
        if (key[0] == 0)
            return iterator();
   
        if (head[(int) key[0]] == NULL)
            return iterator();
   
        current_node = head[(int) key[0]];
        key_index = 1;
   
        while (current_node != NULL) {
            if (key[key_index] == current_node->value) {
                if (current_node->value == 0) {
                    if (current_node->middle) {
                        return iterator(current_node);
                    } else
                        return iterator();
                } else {
                    current_node = current_node->middle;
                    key_index++;
                    continue;
                }
            } else if (((current_node->value == 0) && (key[key_index] < 64)) ||
                       ((current_node->value != 0) && (key[key_index] <
                                                       current_node->value))) {
                current_node = current_node->left;
                continue;
            } else {
                current_node = current_node->right;
                continue;
            }
        }
        return iterator();
    }

    TstNode<_Tp> *nextNode(TstNodeLines<_Tp> **, int *);
    TstNodeLines<_Tp> *node_lines;
    
private:
    void clear(void);
    void init(int);
    void growNodeFreeList(void);
    
    int node_line_width;
    TstNode<_Tp> *free_list;
    TstNode<_Tp> *head[256];
};

template<class _Tp>
Tst<_Tp>::Tst(void) {
    init(DEFAULT_TST_NODE_LINE_WIDTH);
}

template<class _Tp>
Tst<_Tp>::Tst(int width) {
    init(width);
}

template<class _Tp>
Tst<_Tp>::Tst(const char **attr) {
    init(DEFAULT_TST_NODE_LINE_WIDTH);
    if (attr) {
        for (int i = 0; attr[i]; i += 2)
            insert((char *) attr[i], (char *) attr[i + 1]);
    }
}

template<class _Tp>
Tst<_Tp>::~Tst(void) {
    clear();
}

template<class _Tp>
void Tst<_Tp>::clear(void) {
    TstNodeLines<_Tp> *current_line;
    TstNodeLines<_Tp> *next_line;
    
    next_line = node_lines;
    
    do {
        current_line = next_line;
        next_line = current_line->next;
        delete [] current_line->node_line;
        delete current_line;
    } while (next_line != NULL);
}

template<class _Tp>
void Tst<_Tp>::clean(void) {
    clear();
    init(node_line_width);
}

template<class _Tp>
void Tst<_Tp>::init(int width) {
    TstNode<_Tp> *current_node;

    memset(head, 0, sizeof(TstNode<_Tp> *) * 256);

    node_lines = new TstNodeLines<_Tp>;
    memset(node_lines, 0, sizeof(TstNodeLines<_Tp>));
   
    node_line_width = width;
    node_lines->next = NULL;
    node_lines->node_line = new TstNode<_Tp>[node_line_width];
    memset(node_lines->node_line, 0, sizeof(TstNode<_Tp>) * node_line_width);
   
    current_node = node_lines->node_line;
    free_list = current_node;
    
    for (int i = 1; i < node_line_width; i++) {
        current_node->middle = &(node_lines->node_line[i]);
        current_node = current_node->middle;
    }

    current_node->middle = NULL;
}

template<class _Tp>
void Tst<_Tp>::growNodeFreeList(void) {
    TstNode<_Tp> *current_node;
    TstNodeLines<_Tp> *new_line;

    new_line = new TstNodeLines<_Tp>;
    memset(new_line, 0, sizeof(TstNodeLines<_Tp>));

    new_line->node_line = new TstNode<_Tp>[node_line_width];
    memset(new_line->node_line, 0, sizeof(TstNode<_Tp>) * node_line_width);
    
    new_line->next = node_lines;
    node_lines = new_line;
   
    current_node = node_lines->node_line;
    free_list = current_node;
    
    for (int i = 1; i < node_line_width; i++) {
        current_node->middle = &(node_lines->node_line[i]);
        current_node = current_node->middle;
    }

    current_node->middle = NULL;
}

template<class _Tp>
TstNode<_Tp> *Tst<_Tp>::nextNode(TstNodeLines<_Tp> **line, int *pos) {
    do {
        while (*pos < node_line_width) {
            TstNode<_Tp> *node = (*line)->node_line + (*pos)++;
            if (node == free_list) break;
            if (node->value == 0 && node->middle)
                return node;
        }
        *line = (*line)->next;
        *pos = 0;
    } while (*line);

    return NULL;
}

template<class _Tp>
void Tst<_Tp>::insert(char *key, _Tp data) {
    TstNode<_Tp> *current_node;
    TstNode<_Tp> *new_node_tree_begin = NULL;
    int key_index;
    bool perform_loop = true;
   
    if (key == NULL || key[0] == 0) {
        return;
    }

    if (head[(int) key[0]] == NULL) {
        if (free_list == NULL) growNodeFreeList();
        
        head[(int) key[0]] = free_list;
      
        free_list = free_list->middle;
        current_node = head[(int) key[0]];
        current_node->value = key[1];
        if (key[1] == 0) {
            current_node->middle = (TstNode<_Tp> *) 1;
            current_node->data = data;
            return;
        } else
            perform_loop = false;
    }
        
    current_node = head[(int) key[0]];

    key_index = 1;
    if (perform_loop) {
        for (;;) {
            if (key[key_index] == current_node->value) {
                if (key[key_index] == 0) {
                    current_node->middle = (TstNode<_Tp> *) 1;
                    current_node->data = data;
                    return;
                } else {
                    if (current_node->middle == NULL) {
                        if (free_list == NULL) growNodeFreeList();
                        
                        current_node->middle = free_list;
               
                        free_list = free_list->middle;
                        new_node_tree_begin = current_node;
                        current_node = current_node->middle;
                        current_node->value = key[key_index];
                        break;
                    } else {
                        current_node = current_node->middle;
                        key_index++;
                        continue;
                    }
                }
            }
            
            if (((current_node->value == 0) && (key[key_index] < 64)) ||
                ((current_node->value != 0) && (key[key_index] <
                                                current_node->value))) {
                if (current_node->left == NULL) {
                    if (free_list == NULL) growNodeFreeList();
                    
                    current_node->left = free_list;
            
                    free_list = free_list->middle;
                    new_node_tree_begin = current_node;
                    current_node = current_node->left;
                    current_node->value = key[key_index];
                    if (key[key_index] == 0) {
                        current_node->middle = (TstNode<_Tp> *) 1;
                        current_node->data = data;
                        return;
                    } else
                        break;
                } else {
                
                    current_node = current_node->left;
                    continue;
                }
            } else {
                if (current_node->right == NULL) {
                    if (free_list == NULL) growNodeFreeList();
                    
                    current_node->right = free_list;
            
                    free_list = free_list->middle;
                    new_node_tree_begin = current_node;
                    current_node = current_node->right;
                    current_node->value = key[key_index];
                    break;
                } else {
                    current_node = current_node->right;
                    continue;
                }
            }
        }
    }
        
    do {
        key_index++;
   
        if (free_list == NULL) growNodeFreeList();
            
        current_node->middle = free_list;
            
        free_list = free_list->middle;
        current_node = current_node->middle;
        current_node->value = key[key_index];
    } while (key[key_index] != 0);

    current_node->middle = (TstNode<_Tp> *) 1;
    current_node->data = data;
}

template<class _Tp>
void Tst<_Tp>::remove(char *key) {
    TstNode<_Tp> *current_node;
    TstNode<_Tp> *current_node_parent;
    TstNode<_Tp> *last_branch;
    TstNode<_Tp> *last_branch_parent;
    TstNode<_Tp> *next_node;
    TstNode<_Tp> *last_branch_replacement;
    TstNode<_Tp> *last_branch_dangling_child;
    int key_index;

    if (key[0] == 0)
        return;
    
    if (head[(int) key[0]] == NULL)
        return;
    
    last_branch = NULL;
    last_branch_parent = NULL;
    current_node = head[(int) key[0]];
    current_node_parent = NULL;
    key_index = 1;
    while (current_node != NULL) {
        if (key[key_index] == current_node->value) {
            if ((current_node->left != NULL) ||
                (current_node->right != NULL)) {
                last_branch = current_node;
                last_branch_parent = current_node_parent;
            }
            if (key[key_index] == 0)
                break;
            else {
                current_node_parent = current_node;
                current_node = current_node->middle;
                key_index++;
                continue;
            }
        } else if (((current_node->value == 0) && (key[key_index] < 64)) ||
                   ((current_node->value != 0) && (key[key_index] <
                                                   current_node->value))) {
            last_branch_parent = current_node;
            current_node_parent = current_node;
            current_node = current_node->left;
            last_branch = current_node;
            continue;
        } else {
            last_branch_parent = current_node;
            current_node_parent = current_node;
            current_node = current_node->right;
            last_branch = current_node;
            continue;
        }
    }

    if (current_node == NULL)
        return;
   
    if (last_branch == NULL) {
        next_node = head[(int) key[0]];
        head[(int) key[0]] = NULL;
    } else if ((last_branch->left == NULL) && (last_branch->right == NULL)) {
        if (last_branch_parent->left == last_branch)
            last_branch_parent->left = NULL;
        else
            last_branch_parent->right = NULL;
       
        next_node = last_branch;
    } else {
        if ((last_branch->left != NULL) && (last_branch->right != NULL)) {
            last_branch_replacement = last_branch->right;
            last_branch_dangling_child = last_branch->left;
        } else if(last_branch->right != NULL) {
            last_branch_replacement = last_branch->right;
            last_branch_dangling_child = NULL;
        } else {
            last_branch_replacement = last_branch->left;
            last_branch_dangling_child = NULL;
        }
       
        if (last_branch_parent == NULL)
            head[(int) key[0]] = last_branch_replacement;
        else {
            if (last_branch_parent->left == last_branch)
                last_branch_parent->left = last_branch_replacement;
            else if (last_branch_parent->right == last_branch)
                last_branch_parent->right = last_branch_replacement;
            else
                last_branch_parent->middle = last_branch_replacement;
        }
       
        if (last_branch_dangling_child != NULL) {
            current_node = last_branch_replacement;
           
            while (current_node->left != NULL)
                current_node = current_node->left;
           
            current_node->left = last_branch_dangling_child;
        }
        next_node = last_branch;
    }
   
    do {
        current_node = next_node;
        next_node = current_node->middle;
       
        current_node->left = NULL;
        current_node->right = NULL;
        current_node->middle = free_list;
        free_list = current_node;
    } while (current_node->value != 0);
}

#endif // __Tst_hh


syntax highlighted by Code2HTML, v. 0.9.1