/*
 * Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co., Ltd.
 *
 * Author:     zhangsheng<zhangsheng@uniontech.com>
 *
 * Maintainer: max-lv<lvwujun@uniontech.com>
 *             xushitong<xushitong@uniontech.com>
 *             dengkeyun<dengkeyun@uniontech.com>
 *
 * 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
 * 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, see <http://www.gnu.org/licenses/>.
 */
#include "udffs.h"

#include <string.h>
#include <assert.h>
#include <stdlib.h>

#include "udferr.h"

static images_context context;

void context_init(images_context *context)
{
    assert(context);

    memset(context, 0, sizeof (images_context));
}

int context_append(images_context *context, udf_image *img)
{
    assert(context);
    assert(img);

    int i = 0;
    int c = context->count;

    if (context->count == 0)
        context_init(context);

    if (context->count >= MAX_FD_COUNT)
        return CONTEXT_FULL;

    for (; i < MAX_FD_COUNT; i++) {
        if (context->img_array[i] == NULL) {
            context->img_array[i] = img;
            img->index = i;
            context->count++;
            break;
        }
    }

    if (c == context->count)
        return CONTEXT_NO_CHANGE;

    return CONTEXT_OK;
}

int context_remove(images_context *context, udf_image *img)
{
    assert(context);
    assert(img);

    uint32_t i = 0;
    uint32_t j = 0;
    uint32_t k = 0;
    int c = context->count;

    if (c == 0)
        return CONTEXT_EMPTY;

    for (; i < MAX_FD_COUNT; i++) {
        udf_image *img = context->img_array[i];
        int fd = context_get_fd(img);
        if (img && fd == img->fd) {
            uint32_t cur_count = img->cur_file_count;
            for (; j < cur_count; j++) {
                free(img->inner_files[j].file_name);
                img->inner_files[j].file_name = NULL;
                img->cur_file_count--;
            }
            if (img->inner_files) {
                free(img->inner_files);
                img->inner_files = NULL;
            }
            // free extent
            udf_extent *ext = img->head;
            while (ext) {
                udf_extent *next_ext = ext->next;
                udf_desc *desc = ext->head;
                // free desc
                while (desc) {
                    udf_desc *next_desc = desc->next;
                    udf_data *data = desc->data;
                    // free file
                    if (desc->prev && desc->next && desc->fcount > 0) {
                        for (; k < desc->fcount; k++) {
                            if (desc->file && desc->file[k].file_name)
                                free(desc->file[k].file_name);
                        }
                        free(desc->file);
                    }

                    // free data
                    while (data) {
                        udf_data *next_data = data->next;
                        if (data->buffer)
                            free(data->buffer);
                        if (data->prev)
                            free(data);
                        data = next_data;
                    }
                    free(desc);
                    desc = next_desc;
                }
                free(ext);
                ext = next_ext;
            }
            img->head = img->tail = NULL;

            free(img);
            context->img_array[i] = NULL;
            context->count--;

            break;
        }
    }

    if (c == context->count)
        return CONTEXT_NO_CHANGE;

    return CONTEXT_OK;
}

udf_image *context_query_image(images_context *context, int fd)
{
    udf_image *img = NULL;
    int i = 0;

    for (; i < MAX_FD_COUNT; i++) {
        if (context->img_array[i] && fd == context->img_array[i]->fd) {
            img = context->img_array[i];
            break;
        }
    }

    return img;
}

int context_get_fd(const udf_image *img)
{
    assert(img);

    return img->fd;
}

int context_get_index(const udf_image *img)
{
    assert(img);

    return img->index;
}


images_context *context_get_default()
{
    return &context;
}
