//
// anyRemote
// a wi-fi or bluetooth remote for your PC.
//
// Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
//
// This program 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

#include <stdlib.h>
#include "list.h"

//
// Single/double linked lists
//


#ifndef USE_GLIB

SingleList* listSingleNew()
{
    SingleList* l = (SingleList*) malloc(sizeof(SingleList));
    l->next = NULL;
    l->data = NULL;
    return l;
}

unsigned int listSingleLength(SingleList* list)
{
    unsigned int cnt = 0;
    SingleList* ptr = list;
    while (ptr) {
        ptr = ptr->next;
        cnt++;
    }
    return cnt;
}

SingleList* listSingleNext(SingleList* list)
{
    return (list ? list->next : NULL);
}

SingleList* listSingleNth(SingleList* list, unsigned int n)
{
    unsigned int cnt = 0;
    SingleList* ptr = list;
    while (ptr && cnt < n) {
        ptr = ptr->next;
        cnt++;
    }
    return ptr;
}

SingleList* listSingleRemove(SingleList* list, void* data)
{
    SingleList *tmp, *prev = NULL;

    tmp = list;
    while (tmp) {
        if (tmp->data == data) {
            if (prev) {
                prev->next = tmp->next;
            } else {
                list = tmp->next;
            }
        
            listSingleFreeNode(tmp);
            break;
        }
    
        prev = tmp;
        tmp = prev->next;
    }

    return list;
}

void  listSingleFreeNode(SingleList* list)
{
    if (list) {
        // list->data is not property of the list
        free(list);
    }
}

void  listSingleFree(SingleList* list)
{
    while (list) {
        SingleList* ptr = list->next;
        listSingleFreeNode(list);
        list = ptr;
    }
}

SingleList* listSingleAppend(SingleList* list, void* data)
{
    SingleList* l = listSingleNew();
    l->next = NULL;
    l->data = data;
    
    if (!list) {
        return l;
    }
    
    SingleList* ptr = list;
    while (ptr) {
        if (!ptr->next) {
            ptr->next = l;
            break;
        }
        ptr = ptr->next;
    }

    return list;
}

#endif

void listSingleFullFree(SingleList *list, DestroyCallback free_func)
{
    SingleList *item = list;
    while (item) {
        if (item->data) {
            free_func(item->data);
        }
        item = listSingleNext(item);
    }
    listSingleFree(list);
}


DoubleList* listDoubleNew()
{
    DoubleList* l = (DoubleList*) malloc(sizeof(DoubleList));
    l->next = NULL;
    l->prev = NULL;
    l->data = NULL;
    return l;
}

void listDoubleFreeNode(DoubleList* list)
{
    if (list) {
        // list->data is not property of the list
        free(list);
    }
}

void listDoubleFree(DoubleList* list)
{
    while (list) {
        DoubleList* ptr = list->next;
        listDoubleFreeNode(list);
        list = ptr;
    }
}

DoubleList* listDoublePrepend(DoubleList* list, void* data)
{
    DoubleList* l = listDoubleNew();
    l->next = list;
    l->data = data;
    
    if (list) {
        l->prev = list->prev;
        if (list->prev) {
        list->prev->next = l;
        }
    list->prev = l;
    } else {
        l->prev = NULL;
    }
    
    return l;
}

DoubleList* listDoubleNext(DoubleList* list)
{
    return (list ? list->next : NULL);
}

void listDoubleFullFree(DoubleList *list, DestroyCallback free_func)
{
    DoubleList *item = list;
    while (item) {
        if (item->data) {
            free_func(item->data);
        }
        item = listDoubleNext(item);
    }
    listDoubleFree(list);
}

