#include <stdio.h>
#include <stdlib.h>
#include "osp_type_def.h"
#include "err_num.h"
#include "osp_heap.h"
#include "smartos.h"

#if 0
#define DDR_ALIGN(x, align)  (((unsigned int)(x)+(align -1))&~(align-1))

typedef struct DoubleLinkNode
{
    uint32_t len;
    int32_t  IsBusy;
    struct DoubleLinkNode *prev;
    struct DoubleLinkNode *next;
}osp_heap_node;

#define OSP_HEAP_NODE_SIZE          sizeof(osp_heap_node)
#define OSP_HEAP_BUF_TO_HEAD(pbuf)  (osp_heap_node *)((UINTPTR)pbuf - OSP_HEAP_NODE_SIZE)

typedef struct heap_mem
{
    osp_heap_node *root;
    osp_heap_node *cur_avaliable;
}osp_heap_mem_cb;

osp_heap_mem_cb g_st_osp_heap_mem;

osp_heap_node *osp_search_heap_node(osp_heap_node *head, uint32_t size)
{
    osp_heap_node *pddr_node = NULL;
    osp_heap_node im_node;

    pddr_node = head;

    while (pddr_node)
    {
        memcpy_ucp(&im_node, pddr_node, sizeof(osp_heap_node));
        if ((im_node.len > (size + OSP_HEAP_NODE_SIZE)) && (!im_node.IsBusy))
        {
            return pddr_node;
        }
        pddr_node = im_node.next;
    }
    return OSP_OK;
}

osp_heap_node *osp_split_heap_node(osp_heap_node *node, uint32_t size)
{
    osp_heap_node *new  = NULL;
    osp_heap_node *next = NULL;
    osp_heap_node im_node;
    osp_heap_node im_newnode;

    int32_t len;

    memcpy_ucp(&im_node, node, sizeof(osp_heap_node));

    if (im_node.len-size < OSP_HEAP_NODE_SIZE)
    {
        return node;
    }

    len = im_node.len;

    //node->len = size;
    do_write(node, size);
    new = (osp_heap_node *)((UINTPTR)node + size + OSP_HEAP_NODE_SIZE);

    //new->len = len - size - OSP_HEAP_NODE_SIZE;
    //new->IsBusy = 0;
    do_write(new, (len - size - OSP_HEAP_NODE_SIZE));   // len
    do_write(((int8_t*)new + 4), 0);                    // busy

    //new->next = node->next;
    do_write(((int8_t*)new + 12), im_node.next);        // next
    memcpy_ucp(&im_newnode, new, sizeof(osp_heap_node));

    next = im_newnode.next;
    if (next)
    {
        //next->prev = new;
        do_write(((int8_t*)next + 8), new); // prev
    }
    //new->prev = node;
    do_write(((int8_t*)new + 8), node);
    //node->next = new;
    do_write(((int8_t*)node + 12), new);
    return new;
}

int32_t osp_set_heap_node_busy(osp_heap_node *node)
{
    //node->IsBusy = 1;
    do_write(((int8_t*)node + 4), 1);
    return OSP_OK;
}

int32_t osp_clear_heap_node_busy(osp_heap_node *node)
{
    //node->IsBusy = 0;
    do_write(((int8_t*)node + 4), 0);
    return OSP_OK;
}

osp_heap_node *osp_get_next_heap_node(osp_heap_node *node)
{
    return node->next;
}

osp_heap_node *osp_get_pre_heap_node(osp_heap_node *node)
{
    return node->prev;
}

int32_t osp_heap_node_need_merge(osp_heap_node *node, osp_heap_node *nextnode)
{
    int32_t node_isbusy     = 0;
    int32_t nextnode_isbusy = 0;

    node_isbusy     = do_read((int8_t*)node + 4);
    nextnode_isbusy = do_read((int8_t*)nextnode + 4);
    if ((0 == node_isbusy)&&(0 == nextnode_isbusy))
    {
        return 1;
    }

    return 0;
}

int32_t osp_heap_node_merge(osp_heap_node *node, osp_heap_node *nextnode)
{
    osp_heap_node im_node;
    osp_heap_node im_nextnode;
    osp_heap_node *nextnext = NULL;

    memcpy_ucp(&im_node, node, sizeof(osp_heap_node));
    memcpy_ucp(&im_nextnode, nextnode, sizeof(osp_heap_node));

    nextnext = im_nextnode.next;

    //node->next = nextnext;
    do_write(((int8_t*)node + 12), nextnext);

    if (nextnext)
    {
        //nextnext->prev = node;
        do_write(((int8_t*)nextnext + 8), node);
    }

    //len = do_read(nextnode);
    //node->len += nextnode->len + OSP_HEAP_NODE_SIZE;
    do_write(node, (im_node.len + im_nextnode.len + OSP_HEAP_NODE_SIZE));

    if(nextnode == g_st_osp_heap_mem.cur_avaliable)
    {
        g_st_osp_heap_mem.cur_avaliable = node;
    }

    return OSP_OK;
}

int8_t osp_heap_mem_init(uint32_t addr, uint32_t size)
{
    osp_heap_node temp_node;

    if ((0 == addr) || (0 == size))
    {
        return -OSP_PAR_ILL;
    }

    memset(&g_st_osp_heap_mem, 0, sizeof(g_st_osp_heap_mem));

    g_st_osp_heap_mem.root = (osp_heap_node *)((void*)addr);
    memset(&temp_node, 0, sizeof(temp_node));
    if (size < OSP_HEAP_NODE_SIZE)
    {
        temp_node.len = 0;
        //g_st_osp_heap_mem.root->len = 0;
    }
    else
    {
        temp_node.len = size - OSP_HEAP_NODE_SIZE;
        //g_st_osp_heap_mem.root->len = size - OSP_HEAP_NODE_SIZE;
    }
    temp_node.IsBusy = 0;
    temp_node.next   = NULL;
    temp_node.prev   = NULL;
    memcpy_ucp(g_st_osp_heap_mem.root, &temp_node, sizeof(temp_node));
    //g_st_osp_heap_mem.root->IsBusy = 0;
    //g_st_osp_heap_mem.root->next   = NULL;
    //g_st_osp_heap_mem.root->prev   = NULL;
    g_st_osp_heap_mem.cur_avaliable = g_st_osp_heap_mem.root;

    return OSP_OK;
}

char *osp_malloc_ddr_mem(uint32_t size)
{
    osp_heap_node *node;
    uint32_t len = DDR_ALIGN(size, 4);

    node = osp_search_heap_node(g_st_osp_heap_mem.cur_avaliable, len);
    if(!node)
    {
        node = osp_search_heap_node(g_st_osp_heap_mem.root, len);
        if (!node)
        {
            return NULL;
        }
    }
    //osp_set_heap_node_busy(node);
    //node->IsBusy = 1;
    do_write(((int8_t*)node + 4), 1);

    //new = osp_split_heap_node(node, len);
    g_st_osp_heap_mem.cur_avaliable = osp_split_heap_node(node, len);

    return (char*)((UINTPTR)node + OSP_HEAP_NODE_SIZE);
}

char *osp_heap_malloc(uint32_t size)
{
    char *p;
    OS_ENTER_CRITICAL();
    p = osp_malloc_ddr_mem(size);
    OS_EXIT_CRITICAL();
    return p;
}

int osp_free_ddr_mem(char* pbuf)
{
    osp_heap_node *node = OSP_HEAP_BUF_TO_HEAD(pbuf);
    osp_heap_node *nextnode = NULL;
    osp_heap_node *prenode = NULL;
    osp_heap_node im_node;

    //osp_clear_heap_node_busy(node);
    //node->IsBusy = 0;
    do_write(((int8_t*)node + 4), 0);
    memcpy_ucp(&im_node, node, sizeof(osp_heap_node));
    //nextnode = osp_get_next_heap_node(node);
    //nextnode = node->next;
    nextnode = im_node.next;
    //prenode = osp_get_pre_heap_node(node);
    //prenode = node->prev;
    prenode = im_node.prev;

    if(nextnode){
        if(osp_heap_node_need_merge(node, nextnode)){
            osp_heap_node_merge(node, nextnode);
        }
    }

    if(prenode){
        if(osp_heap_node_need_merge(prenode, node)){
            osp_heap_node_merge(prenode, node);
        }
    }
    return 0;
}

void osp_heap_free(char *p)
{
    OS_ENTER_CRITICAL();
    osp_free_ddr_mem(p);
    p = NULL;
    OS_EXIT_CRITICAL();
    return ;
}

#endif

