/**
 * @file file_list.c
 * @author Chen Jihang (embedded@eseaoptics.com)
 * @brief 文件列表
 * @version 1.0
 * @date 2022-08-25
 * 
 * @copyright ESEA (c) 2020
 * 
 */
#include "file_list.h"
/**
 * @brief 从文件中读取链表头
 * 
 * @param p_list file_list描述符
 * @param p_head 链表头
 * @return int 0:成功 非0:失败
 */
int file_list_get_head(struct file_list *p_list,struct file_list_head *p_head)
{
    FRESULT ret;
    UINT btr;
    UINT br;
    ret=f_lseek(&p_list->fp,0);
    if(ret!=FR_OK){
        return -1;
    }
    btr=sizeof(struct file_list_head);
    ret=f_read(&p_list->fp,p_head,btr,&br);
    if(ret!=FR_OK || btr!=br){
        return -2;
    }
    return 0;
}
/**
 * @brief 将链表头写入文件
 * 
 * @param p_list file_list描述符
 * @param p_head 链表头
 * @return int 0:成功 非0:失败
 */
int file_list_put_head(struct file_list *p_list,struct file_list_head *p_head)
{
    FRESULT ret;
    UINT btw;
    UINT bw;
    ret=f_lseek(&p_list->fp,0);
    if(ret!=FR_OK){
        return -1;
    }
    btw=sizeof(struct file_list_head);
    ret=f_write(&p_list->fp,p_head,btw,&bw);
    if(ret!=FR_OK || btw!=bw){
        return -2;
    }
    return 0;
}
/**
 * @brief 从文件中获取链表节点
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @param file_pointer 文件指针
 * @return int 0:成功 非0:失败
 */
int file_list_get_node(struct file_list *p_list,struct file_list_node *p_node,uint64_t file_pointer)
{
    FRESULT ret;
    UINT btr;
    UINT br;
    ret=f_lseek(&p_list->fp,file_pointer);
    if(ret!=FR_OK){
        return -1;
    }
    btr=sizeof(struct file_list_node);
    ret=f_read(&p_list->fp,p_node,btr,&br);
    if(ret!=FR_OK || btr!=br){
        return -2;
    }
    return 0;
}
/**
 * @brief 将链表节点写入文件
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @return int 0:成功 非0:失败
 */
int file_list_put_node(struct file_list *p_list,struct file_list_node *p_node)
{
    FRESULT ret;
    UINT btw;
    UINT bw;
    ret=f_lseek(&p_list->fp,p_node->file_pointer_this);
    if(ret!=FR_OK){
        return -1;
    }
    btw=sizeof(struct file_list_node);
    ret=f_write(&p_list->fp,p_node,btw,&bw);
    if(ret!=FR_OK || btw!=bw){
        return -2;
    }
    return 0;
}
/**
 * @brief 从指定链表节点中获取数据
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @param p_data 数据缓冲区
 * @param base_addr 数据在链表节点中的基地址
 * @param size 要获取的数据长度
 * @return int 0:成功 非0:失败
 */
int file_list_get_data(struct file_list *p_list,struct file_list_node *p_node,uint8_t *p_data,uint64_t base_addr,uint64_t size)
{
    FRESULT ret;
    UINT btr;
    UINT br;
    ret=f_lseek(&p_list->fp,p_node->file_pointer_this+sizeof(struct file_list_node)+base_addr);
    if(ret!=FR_OK){
        return -1;
    }
    btr=size;
    ret=f_read(&p_list->fp,p_data,btr,&br);
    if(ret!=FR_OK || btr!=br){
        return -2;
    }
    return 0;
}
/**
 * @brief 将数据写入指定链表节点中
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @param p_data 要写入的数据
 * @param base_addr 数据在链表节点中的基地址
 * @param size 要写入的数据长度
 * @return int 0:成功 非0:失败
 */
int file_list_put_data(struct file_list *p_list,struct file_list_node *p_node,uint8_t *p_data,uint64_t base_addr,uint64_t size)
{
    FRESULT ret;
    UINT btw;
    UINT bw;
    ret=f_lseek(&p_list->fp,p_node->file_pointer_this+sizeof(struct file_list_node)+base_addr);
    if(ret!=FR_OK){
        return -1;
    }
    btw=size;
    ret=f_write(&p_list->fp,p_data,btw,&bw);
    if(ret!=FR_OK || btw!=bw){
        return -2;
    }
    return 0;
}
/**
 * @brief 使用指定字符填充链表节点数据
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @param data_to_fill 要填充的字符
 * @return int 0:成功 非0:失败
 */
int file_list_fill_data(struct file_list *p_list,struct file_list_node *p_node,uint8_t data_to_fill)
{
    FRESULT ret;
    UINT btw;
    UINT bw;
    uint64_t i;
    ret=f_lseek(&p_list->fp,p_node->file_pointer_this+sizeof(struct file_list_node));
    if(ret!=FR_OK){
        return -1;
    }
    for(i=0;i<p_node->size;i++){
        btw=1;
        ret=f_write(&p_list->fp,&data_to_fill,btw,&bw);
        if(ret!=FR_OK || btw!=bw){
            return -2;
        }
    }
    return 0;
}
/**
 * @brief 使用指定文件路径创建链表
 * 
 * @param p_list file_list描述符
 * @param path 文件路径
 * @return struct file_list* 成功:p_list 失败:NULL
 */
struct file_list *file_list_create(struct file_list *p_list,char *path)
{
    FRESULT ret;
    ret=f_open(&p_list->fp,path,FA_CREATE_ALWAYS|FA_READ|FA_WRITE);
    if(ret!=FR_OK){
        return NULL;
    }
    p_list->list_head.file_pointer_used_first=0;
    p_list->list_head.file_pointer_used_last=0;
    p_list->list_head.file_pointer_free_first=sizeof(struct file_list_head);
    p_list->list_head.file_pointer_free_last=p_list->list_head.file_pointer_free_first;
    p_list->free_node_now.file_pointer_last=0;
    p_list->free_node_now.file_pointer_next=0;
    p_list->free_node_now.file_pointer_this=p_list->list_head.file_pointer_free_last;
    p_list->free_node_now.size=0xffffffffffffffff;
    p_list->used_node_now.size_used=0;
    p_list->used_node_now.file_pointer_last=0;
    p_list->used_node_now.file_pointer_next=0;
    p_list->used_node_now.file_pointer_this=0;
    p_list->used_node_now.size=0;
    p_list->used_node_now.size_used=0;
    if(file_list_put_head(p_list,&p_list->list_head)!=0){
        return NULL;
    }
    if(file_list_put_node(p_list,&p_list->free_node_now)!=0){
        return NULL;
    }
    f_sync(&p_list->fp);
    return p_list;
}
/**
 * @brief 使用指定文件路径打开链表,若文件不存在则创建新的链表
 * 
 * @param p_list file_list描述符
 * @param path 文件路径
 * @return struct file_list* 成功:p_list 失败:NULL
 */
struct file_list *file_list_open(struct file_list *p_list,char *path)
{
    FRESULT ret;
    ret=f_open(&p_list->fp,path,FA_READ|FA_WRITE);
    if(ret!=FR_OK){
        return file_list_create(p_list,path);
    }
    if(file_list_get_head(p_list,&p_list->list_head)!=0){
        return NULL;
    }
    if(p_list->list_head.file_pointer_used_first!=0){
        if(file_list_get_node(p_list,&p_list->used_node_now,p_list->list_head.file_pointer_used_first)!=0){
            return NULL;
        }
    }
    else{
        p_list->used_node_now.file_pointer_last=0;
        p_list->used_node_now.file_pointer_next=0;
        p_list->used_node_now.file_pointer_this=0;
        p_list->used_node_now.size=0;
    }
    if(file_list_get_node(p_list,&p_list->free_node_now,p_list->list_head.file_pointer_free_first)!=0){
        return NULL;
    }
    f_sync(&p_list->fp);
    return p_list;
}
/**
 * @brief 关闭链表
 * 
 * @param p_list file_list描述符
 * @return int 0:成功 非0:失败
 */
int file_list_close(struct file_list *p_list)
{
    FRESULT ret;
    ret=f_sync(&p_list->fp);
    if(ret!=FR_OK){
        return -1;
    }
    ret=f_close(&p_list->fp);
    if(ret!=FR_OK){
        return -1;
    }
    return 0;
}
/**
 * @brief 合并未使用的链表节点
 * 
 * @param p_list file_list描述符
 * @param p_free_node 未使用的链表节点
 * @return int 0:成功 非0:失败
 */
int file_list_merge_free_node(struct file_list *p_list,struct file_list_node *p_free_node)
{
    struct file_list_node last_free_node;
    struct file_list_node next_free_node;
    struct file_list_node this_free_node;
    this_free_node.size=p_free_node->size;
    this_free_node.file_pointer_last=p_free_node->file_pointer_last;
    this_free_node.file_pointer_next=p_free_node->file_pointer_next;
    this_free_node.file_pointer_this=p_free_node->file_pointer_this;
    if(p_free_node->file_pointer_last!=0){
        if(file_list_get_node(p_list,&last_free_node,p_free_node->file_pointer_last)!=0){
            return -1;
        }
        if(last_free_node.file_pointer_this+last_free_node.size+sizeof(struct file_list_node)==last_free_node.file_pointer_next){
            // printf("<Merge [%llX,%llX]-->%llX,Size [%llX,%llX]-->%llX\n",last_free_node.file_pointer_this,this_free_node.file_pointer_this,last_free_node.file_pointer_this,last_free_node.size,this_free_node.size,this_free_node.size+last_free_node.size+sizeof(struct file_list_node));
            this_free_node.file_pointer_last=last_free_node.file_pointer_last;
            this_free_node.file_pointer_this=last_free_node.file_pointer_this;
            this_free_node.size+=last_free_node.size+sizeof(struct file_list_node);
        }
        
    }
    if(p_free_node->file_pointer_next!=0){
        if(file_list_get_node(p_list,&next_free_node,p_free_node->file_pointer_next)!=0){
            return -1;
        }
        if(this_free_node.file_pointer_this+this_free_node.size+sizeof(struct file_list_node)==this_free_node.file_pointer_next){
            // printf(">Merge [%llX,%llX]-->%llX,Size [%llX,%llX]-->%llX\n",this_free_node.file_pointer_this,next_free_node.file_pointer_this,this_free_node.file_pointer_this,this_free_node.size,next_free_node.size,this_free_node.size+next_free_node.size+sizeof(struct file_list_node));
            this_free_node.file_pointer_next=next_free_node.file_pointer_next;
            this_free_node.size+=next_free_node.size+sizeof(struct file_list_node);
            if(this_free_node.file_pointer_next!=0){
                if(file_list_get_node(p_list,&next_free_node,this_free_node.file_pointer_next)!=0){
                    return -1;
                }
                next_free_node.file_pointer_last=this_free_node.file_pointer_this;
                if(file_list_put_node(p_list,&next_free_node)!=0){
                    return -1;
                }
            }
            else{
                p_list->list_head.file_pointer_free_last=this_free_node.file_pointer_this;
                if(file_list_put_head(p_list,&p_list->list_head)!=0){
                    return -1;
                }
            }
        }
        else{
            next_free_node.file_pointer_last=this_free_node.file_pointer_this;
        }
    }
    if(file_list_put_node(p_list,&this_free_node)!=0){
        return -1;
    }
    if(this_free_node.file_pointer_next!=0){
        if(file_list_put_node(p_list,&next_free_node)!=0){
            return -1;
        }
    }
    p_list->free_node_now.file_pointer_last=this_free_node.file_pointer_last;
    p_list->free_node_now.file_pointer_next=this_free_node.file_pointer_next;
    p_list->free_node_now.file_pointer_this=this_free_node.file_pointer_this;
    p_list->free_node_now.size=this_free_node.size;
    return 0;
}
/**
 * @brief 分配一个新的链表节点
 * 
 * @param p_list file_list描述符
 * @param size 要存储的数据大小
 * @return struct file_list_node* 成功:新的链表节点 失败:NULL
 */
struct file_list_node *file_list_alloc(struct file_list *p_list,uint64_t size)
{
    struct file_list_node last_free_node;
    struct file_list_node this_free_node;
    struct file_list_node next_free_node;
    uint64_t file_pointer;
    this_free_node.file_pointer_last=0;
    this_free_node.file_pointer_next=0;
    this_free_node.file_pointer_this=0;
    this_free_node.size=0;
    file_pointer=p_list->list_head.file_pointer_free_first;
    do{
        last_free_node.file_pointer_last=this_free_node.file_pointer_last;
        last_free_node.file_pointer_next=this_free_node.file_pointer_next;
        last_free_node.file_pointer_this=this_free_node.file_pointer_this;
        last_free_node.size=this_free_node.size;
        if(file_list_get_node(p_list,&this_free_node,file_pointer)!=0){
            return NULL;
        }
        file_pointer=this_free_node.file_pointer_next;
    }while(this_free_node.size<size);
    p_list->used_node_now.size=this_free_node.size;
    p_list->free_node_now.file_pointer_last=this_free_node.file_pointer_last;
    p_list->free_node_now.file_pointer_next=this_free_node.file_pointer_next;
    p_list->free_node_now.file_pointer_this=this_free_node.file_pointer_this;
    p_list->free_node_now.size=this_free_node.size;
    p_list->used_node_now.file_pointer_this=this_free_node.file_pointer_this;
    p_list->used_node_now.file_pointer_next=0;
    p_list->used_node_now.size_used=size;
    if(this_free_node.file_pointer_last!=0){
        if(file_list_get_node(p_list,&last_free_node,this_free_node.file_pointer_last)!=0){
            return NULL;
        }
        if(this_free_node.size>=size+sizeof(struct file_list_node)){
            p_list->free_node_now.file_pointer_last=last_free_node.file_pointer_this;
            p_list->free_node_now.file_pointer_this=p_list->used_node_now.file_pointer_this+size+sizeof(struct file_list_node);
            last_free_node.file_pointer_next=p_list->free_node_now.file_pointer_this;
        }
        else{
            last_free_node.file_pointer_next=this_free_node.file_pointer_next;

        }
        if(file_list_put_node(p_list,&last_free_node)!=0){
            return NULL;
        }
    }
    else{
        if(this_free_node.size>=size+sizeof(struct file_list_node)){
            p_list->free_node_now.file_pointer_this=p_list->used_node_now.file_pointer_this+size+sizeof(struct file_list_node);
            p_list->list_head.file_pointer_free_first=p_list->free_node_now.file_pointer_this;
        }
        else{
            p_list->list_head.file_pointer_free_first=this_free_node.file_pointer_next;
        }
    }
    if(this_free_node.file_pointer_next!=0){
        if(file_list_get_node(p_list,&next_free_node,this_free_node.file_pointer_next)!=0){
            return NULL;
        }
        if(this_free_node.size>=size+sizeof(struct file_list_node)){
            p_list->free_node_now.file_pointer_this=p_list->used_node_now.file_pointer_this+size+sizeof(struct file_list_node);
            p_list->free_node_now.file_pointer_next=next_free_node.file_pointer_this;
            next_free_node.file_pointer_last=p_list->free_node_now.file_pointer_this;
        }
        else{
            next_free_node.file_pointer_last=this_free_node.file_pointer_last;
        }
        if(file_list_put_node(p_list,&next_free_node)!=0){
            return NULL;
        }
    }
    else{
        if(this_free_node.size>=size+sizeof(struct file_list_node)){
            p_list->free_node_now.file_pointer_this=p_list->used_node_now.file_pointer_this+size+sizeof(struct file_list_node);
            p_list->list_head.file_pointer_free_last=p_list->free_node_now.file_pointer_this;
        }
        else{
            p_list->list_head.file_pointer_free_last=this_free_node.file_pointer_last;
        }
    }
    if(this_free_node.size>=size+sizeof(struct file_list_node)){
        p_list->used_node_now.size=size;
        p_list->free_node_now.size-=size+sizeof(struct file_list_node);
        if(file_list_put_node(p_list,&p_list->free_node_now)!=0){
            return NULL;
        }
    }
    if(file_list_put_head(p_list,&p_list->list_head)!=0){
        return NULL;
    }
    return &p_list->used_node_now;
}
/**
 * @brief 释放链表节点
 * 
 * @param p_list file_list描述符
 * @param p_node_to_free 要释放的链表节点
 * @return int 0:成功 非0:失败
 */
int file_list_free_node(struct file_list *p_list,struct file_list_node *p_node_to_free)
{
    struct file_list_node last_free_node;
    struct file_list_node next_free_node;
    uint64_t file_pointer;
    next_free_node.file_pointer_this=0;
    next_free_node.file_pointer_last=0;
    next_free_node.size=0;
    file_pointer=p_list->list_head.file_pointer_free_first;
    do{
        last_free_node.file_pointer_last=next_free_node.file_pointer_last;
        last_free_node.file_pointer_this=next_free_node.file_pointer_this;
        last_free_node.size=next_free_node.size;
        if(file_list_get_node(p_list,&next_free_node,file_pointer)!=0){
            return -1;
        }
        file_pointer=next_free_node.file_pointer_next;
    }while(next_free_node.file_pointer_this<p_node_to_free->file_pointer_this);
    if(last_free_node.file_pointer_this!=0){
        last_free_node.file_pointer_next=p_node_to_free->file_pointer_this;
        if(file_list_put_node(p_list,&last_free_node)!=0){
            return -1;
        }
    }
    else{
        p_list->list_head.file_pointer_free_first=p_node_to_free->file_pointer_this;
    }
    next_free_node.file_pointer_last=p_node_to_free->file_pointer_this;
    p_node_to_free->file_pointer_last=last_free_node.file_pointer_this;
    p_node_to_free->file_pointer_next=next_free_node.file_pointer_this;
    if(file_list_put_node(p_list,&next_free_node)!=0){
        return -1;
    }
    if(file_list_put_node(p_list,p_node_to_free)!=0){
        return -1;
    }
    return file_list_merge_free_node(p_list,p_node_to_free);
}
/**
 * @brief 从链表中删除指定节点
 * 
 * @param p_list file_list描述符
 * @param p_used_node 要删除的节点
 * @return int 0:成功 非0:失败
 */
int file_list_del_node(struct file_list *p_list,struct file_list_node *p_used_node)
{
    struct file_list_node last_used_node;
    struct file_list_node next_used_node;
    if(p_used_node->file_pointer_last!=0){
        if(file_list_get_node(p_list,&last_used_node,p_used_node->file_pointer_last)!=0){
            return -1;
        }
        last_used_node.file_pointer_next=p_used_node->file_pointer_next;
        if(file_list_put_node(p_list,&last_used_node)!=0){
            return -1;
        }
    }
    else{
        p_list->list_head.file_pointer_used_first=p_used_node->file_pointer_next;
    }
    if(p_used_node->file_pointer_next!=0){
        if(file_list_get_node(p_list,&next_used_node,p_used_node->file_pointer_next)!=0){
            return -1;
        }
        next_used_node.file_pointer_last=p_used_node->file_pointer_last;
        if(file_list_put_node(p_list,&next_used_node)!=0){
            return -1;
        }
    }
    else{
        p_list->list_head.file_pointer_used_last=p_used_node->file_pointer_last;
    }
    if(file_list_put_head(p_list,&p_list->list_head)!=0){
        return -1;
    }
    return file_list_free_node(p_list,p_used_node);
}
/**
 * @brief 向链表最后插入新的节点
 * 
 * @param p_list file_list描述符
 * @param size 要存储的数据大小
 * @return struct file_list_node* 成功:新的节点 失败:NULL
 */
struct file_list_node *file_list_add_node(struct file_list *p_list,uint64_t size)
{
    struct file_list_node last_used_node;
    struct file_list_node *pnode;
    pnode=file_list_alloc(p_list,size);
    if(pnode==NULL){
        return NULL;
    }
    pnode->file_pointer_last=0;
    pnode->file_pointer_next=0;
    if(p_list->list_head.file_pointer_used_last!=0){
        pnode->file_pointer_last=p_list->list_head.file_pointer_used_last;
        if(file_list_get_node(p_list,&last_used_node,pnode->file_pointer_last)!=0){
            return NULL;
        }
        last_used_node.file_pointer_next=pnode->file_pointer_this;
        if(file_list_put_node(p_list,&last_used_node)!=0){
            return NULL;
        }
    }
    p_list->list_head.file_pointer_used_last=pnode->file_pointer_this;
    if(p_list->list_head.file_pointer_used_first==0){
        p_list->list_head.file_pointer_used_first=pnode->file_pointer_this;
    }
    if(file_list_put_head(p_list,&p_list->list_head)!=0){
        return NULL;
    }
    if(file_list_put_node(p_list,pnode)!=0){
        return NULL;
    }
    f_sync(&p_list->fp);
    return pnode;
}
/**
 * @brief 获取链表中第一个节点
 * 
 * @param p_list file_list描述符
 * @return struct file_list_node* 成功:第一个节点 失败:NULL
 */
struct file_list_node *file_list_get_first_node(struct file_list *p_list)
{
    if(p_list->list_head.file_pointer_used_first==0){
        return NULL;
    }
    if(file_list_get_node(p_list,&p_list->used_node_now,p_list->list_head.file_pointer_used_first)!=0){
        return NULL;
    }
    return &p_list->used_node_now;
}
/**
 * @brief 获取链表中下一个节点
 * 
 * @param p_list file_list描述符
 * @return struct file_list_node* 成功:下一个节点 失败:NULL
 */
struct file_list_node *file_list_get_next_node(struct file_list *p_list)
{
    if(p_list->used_node_now.file_pointer_next==0){
        return NULL;
    }
    if(file_list_get_node(p_list,&p_list->used_node_now,p_list->used_node_now.file_pointer_next)!=0){
        return NULL;
    }
    return &p_list->used_node_now;
}
/**
 * @brief 获取链表中最后一个节点
 * 
 * @param p_list file_list描述符
 * @return struct file_list_node* 成功:最后一个节点 失败:NULL
 */
struct file_list_node *file_list_get_last_node(struct file_list *p_list)
{
    if(p_list->used_node_now.file_pointer_last==0){
        return NULL;
    }
    if(file_list_get_node(p_list,&p_list->used_node_now,p_list->used_node_now.file_pointer_last)!=0){
        return NULL;
    }
    return &p_list->used_node_now;
}
/**
 * @brief 获取链表中数据大小
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @return uint64_t 改节点中的数据大小
 */
uint64_t file_list_get_node_size(struct file_list *p_list,struct file_list_node *p_node)
{
    return p_node->size_used;
}
/**
 * @brief 获取指定节点中的数据
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @param buf 数据缓冲区
 * @param base_addr 要获取的数据在链表节点中的基地址
 * @param size 要获取的数据大小
 * @return uint64_t 实际获取的数据大小
 */
uint64_t file_list_get_node_data(struct file_list *p_list,struct file_list_node *p_node,void *buf,uint64_t base_addr,uint64_t size)
{
    size=(base_addr+size>p_node->size_used)?p_node->size_used-base_addr:size;
    if(file_list_get_data(p_list,p_node,buf,base_addr,size)!=0){
        return 0;
    }
    return size;
}
/**
 * @brief 向指定节点中写入数据
 * 
 * @param p_list file_list描述符
 * @param p_node 链表节点
 * @param buf 要写入的数据
 * @param base_addr 要写入的数据的基地址
 * @param size 要写入的数据大小
 * @return uint64_t 实际写入的数据大小
 */
uint64_t file_list_put_node_data(struct file_list *p_list,struct file_list_node *p_node,void *buf,uint64_t base_addr,uint64_t size)
{
    size=(base_addr+size>p_node->size_used)?p_node->size_used-base_addr:size;
    if(file_list_put_data(p_list,p_node,buf,base_addr,size)!=0){
        return 0;
    }
    f_sync(&p_list->fp);
    return size;
}