/*
 * Copyright (C) 2023 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __IA_CSS_PSYS_PROGRAM_MANIFEST_IMPL_H
#define __IA_CSS_PSYS_PROGRAM_MANIFEST_IMPL_H

#include <ia_css_psys_program_manifest.h>
#include <ia_css_psys_program_group_manifest.h>
/* for ia_css_kernel_bitmap_t, ia_css_kernel_bitmap_print */
#include <ia_css_kernel_bitmap.h>

#include <vied_nci_psys_system_global.h>
#include "ia_css_psys_program_group_private.h"
#include "ia_css_psys_static_trace.h"

#include <error_support.h>
#include <misc_support.h>
#include <storage_class.h>
#include <math_support.h>

/** Function only to be used in FW */
IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
ia_css_program_manifest_ext_t *ia_css_program_manifest_get_extension(const ia_css_program_manifest_t *program)
{
    DECLARE_ERRVAL
    verifexitval(program != NULL, EFAULT);
    if (program->program_extension_offset != 0) {
        return (ia_css_program_manifest_ext_t *)((uint8_t *)program + program->program_extension_offset);
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
            "ia_css_program_manifest_get_extension invalid argument\n");
    }
    return NULL;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_size_t ia_css_program_manifest_get_int_mem_size(
    const ia_css_program_manifest_t *manifest,
    const vied_nci_mem_type_ID_t     mem_type_id)
{
    (void)manifest;
    (void)mem_type_id;
    IA_CSS_TRACE_0(PSYSAPI_STATIC, INFO,
            "ia_css_program_manifest_get_int_mem_size always returns 0"
            "(internally memory feature not used).\n");
    return 0;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_input_terminal_id(
    ia_css_program_manifest_t *manifest,
    unsigned char              idx)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
               "ia_css_program_manifest_get_input_stream_id(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(idx < IA_CSS_MAX_INPUT_DEC_RESOURCES, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
EXIT:
    if (!noerror()) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
#if IA_CSS_MAX_INPUT_DEC_RESOURCES > 0
    return manifest_ext->dec_resources_input_terminal[idx];
#else
    (void) idx;
    return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
#endif
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_output_terminal_id(
    ia_css_program_manifest_t *manifest,
    unsigned char              idx)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
               "ia_css_program_manifest_get_output_terminal_id(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(idx < IA_CSS_MAX_OUTPUT_DEC_RESOURCES, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
EXIT:
    if (!noerror()) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
#if IA_CSS_MAX_OUTPUT_DEC_RESOURCES > 0
    return manifest_ext->dec_resources_output_terminal[idx];
#else
    (void) idx;
    return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
#endif

}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_input_stream_id(
    ia_css_program_manifest_t  *manifest,
    unsigned char               idx)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
               "ia_css_program_manifest_get_input_stream_id(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(idx < IA_CSS_MAX_INPUT_DEC_RESOURCES, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
EXIT:
    if (!noerror()) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
#if IA_CSS_MAX_INPUT_DEC_RESOURCES > 0
    return manifest_ext->dec_resources_input[idx];
#else
    (void) idx;
    return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
#endif
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_output_stream_id(
    ia_css_program_manifest_t *manifest,
    unsigned char              idx)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
               "ia_css_program_manifest_get_output_stream_id(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(idx < IA_CSS_MAX_OUTPUT_DEC_RESOURCES, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
EXIT:
    if (!noerror()) {
        return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
    }
#if IA_CSS_MAX_OUTPUT_DEC_RESOURCES > 0
    return manifest_ext->dec_resources_output[idx];
#else
    (void) idx;
    return IA_CSS_PROGRAM_INVALID_DEC_CONFIG;
#endif
}

#if HAS_DFM
IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_is_dfm_relocatable(
    const ia_css_program_manifest_t *manifest,
    const vied_nci_dev_dfm_id_t      dfm_type_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_is_dfm_relocatable(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(dfm_type_id < VIED_NCI_N_DEV_DFM_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_is_dfm_relocatable invalid argument\n");
        return 0;
    }
    return manifest_ext->is_dfm_relocatable[dfm_type_id];
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_bitmap_t ia_css_program_manifest_get_dfm_port_bitmap(
    const ia_css_program_manifest_t  *manifest,
    const vied_nci_dev_dfm_id_t       dfm_type_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_dfm_port_bitmap(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(dfm_type_id < VIED_NCI_N_DEV_DFM_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_dfm_port_bitmap invalid argument\n");
        return 0;
    }
    return manifest_ext->dfm_port_bitmap[dfm_type_id];
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_bitmap_t ia_css_program_manifest_get_dfm_active_port_bitmap(
    const ia_css_program_manifest_t  *manifest,
    const vied_nci_dev_dfm_id_t       dfm_type_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_dfm_active_port_bitmap(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(dfm_type_id < VIED_NCI_N_DEV_DFM_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_dfm_active_port_bitmap invalid argument\n");
        return 0;
    }
    return manifest_ext->dfm_active_port_bitmap[dfm_type_id];
}
#endif /* HAS_DFM */

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_size_t ia_css_program_manifest_get_ext_mem_size(
    const ia_css_program_manifest_t *manifest,
    const vied_nci_mem_type_ID_t     mem_type_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
               "ia_css_program_manifest_get_ext_mem_size(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(mem_type_id < VIED_NCI_N_DATA_MEM_TYPE_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_ext_mem_size invalid argument\n");
        return 0;
    }
    return manifest_ext->ext_mem_size[mem_type_id];
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_size_t ia_css_program_manifest_get_ext_mem_offset(
    const ia_css_program_manifest_t *manifest,
    const vied_nci_mem_type_ID_t     mem_type_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
               "ia_css_program_manifest_get_ext_mem_offset(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(mem_type_id < VIED_NCI_N_DATA_MEM_TYPE_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_ext_mem_offset invalid argument\n");
         return 0;
    }
    return manifest_ext->ext_mem_offset[mem_type_id];
}

#if HAS_DFM
IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_size_t ia_css_program_manifest_get_dev_chn_size(
    const ia_css_program_manifest_t *manifest,
    const vied_nci_dev_chn_ID_t      dev_chn_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_dev_chn_size(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(dev_chn_id < VIED_NCI_N_DEV_CHN_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_dev_chn_size invalid argument\n");
        return 0;
    }
    return manifest_ext->dev_chn_size[dev_chn_id];
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_resource_size_t ia_css_program_manifest_get_dev_chn_offset(
    const ia_css_program_manifest_t *manifest,
    const vied_nci_dev_chn_ID_t      dev_chn_id)
{
    DECLARE_ERRVAL
    ia_css_program_manifest_ext_t *manifest_ext = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_dev_chn_offset(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    verifexitval(dev_chn_id < VIED_NCI_N_DEV_CHN_ID, EFAULT);
    manifest_ext = ia_css_program_manifest_get_extension(manifest);
    if (manifest_ext == NULL) {
        return 0;
    }
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
         "ia_css_program_manifest_get_dev_chn_offset invalid argument\n");
         return 0;
    }
    return manifest_ext->dev_chn_offset[dev_chn_id];
}
#endif /* HAS_DFM */

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
size_t ia_css_program_manifest_get_size(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_size(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
            "ia_css_program_manifest_get_size invalid argument\n");
        return 0;
    }

    return manifest->size;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
ia_css_program_ID_t ia_css_program_manifest_get_program_ID(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_program_ID(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_program_ID invalid argument\n");
        return IA_CSS_PROGRAM_INVALID_ID;
    }
    return manifest->ID;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
ia_css_program_group_manifest_t *ia_css_program_manifest_get_parent(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL
    char *base = NULL;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_parent(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);

    base = (char *)((char *)manifest + manifest->parent_offset);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_parent invalid argument\n");
        return NULL;
    }
    return (ia_css_program_group_manifest_t *)(base);
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
vied_nci_cell_type_ID_t ia_css_program_manifest_get_cell_type_ID(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_cell_type_ID(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_cell_type_ID invalid argument\n");
        return VIED_NCI_N_CELL_TYPE_ID;
    }
    return manifest->cell_type_id;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
ia_css_program_type_t ia_css_program_manifest_get_type(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_type(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_type invalid argument\n");
        return IA_CSS_N_PROGRAM_TYPES;
    }
    return manifest->program_type;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_terminal_dependency_count(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_terminal_dependency_count(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_terminal_dependency_count invalid argument\n");
        return 0;
    }
    return manifest->terminal_dependency_count;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_terminal_dependency(
    const ia_css_program_manifest_t *manifest,
    const unsigned int index)
{
    DECLARE_ERRVAL
    uint8_t *terminal_dep_ptr = NULL;
    uint8_t terminal_dependency_count;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_terminal_dependency(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
    terminal_dependency_count =
        ia_css_program_manifest_get_terminal_dependency_count(manifest);
    verifexitval(index < terminal_dependency_count, EFAULT);

    terminal_dep_ptr = (uint8_t *)((uint8_t *)manifest +
            manifest->terminal_dependency_offset + index);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
            "ia_css_program_manifest_get_terminal_dependency invalid argument\n");
        return IA_CSS_PROGRAM_INVALID_DEPENDENCY;
    }
    return *terminal_dep_ptr;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
bool ia_css_is_program_manifest_singular_program_type(
    const ia_css_program_manifest_t *manifest)
{
    ia_css_program_type_t        program_type;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_is_program_manifest_singular_program_type(): enter:\n");

    program_type = ia_css_program_manifest_get_type(manifest);

/* The error return is the limit value, so no need to check on the manifest
 * pointer
 */
    return (program_type == IA_CSS_PROGRAM_TYPE_SINGULAR);
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_program_dependency_count(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_program_dependency_count(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_program_dependency_count invalid argument\n");
        return 0;
    }
    return manifest->program_dependency_count;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
uint8_t ia_css_program_manifest_get_program_dependency(
    const ia_css_program_manifest_t *manifest,
    const unsigned int index)
{
    DECLARE_ERRVAL
    uint8_t *program_dep_ptr = NULL;
    uint8_t program_dependency_count;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_program_dependency(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);

    program_dependency_count =
        ia_css_program_manifest_get_program_dependency_count(manifest);

    verifexitval(index < program_dependency_count, EFAULT);
    program_dep_ptr =  (uint8_t *)((uint8_t *)manifest +
            manifest->program_dependency_offset +
            index * sizeof(uint8_t));
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_program_dependency invalid argument\n");
        return IA_CSS_PROGRAM_INVALID_DEPENDENCY;
    }
    return *program_dep_ptr;
}

IA_CSS_PSYS_STATIC_STORAGE_CLASS_C
ia_css_kernel_bitmap_t ia_css_program_manifest_get_kernel_bitmap(
    const ia_css_program_manifest_t *manifest)
{
    DECLARE_ERRVAL

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_manifest_get_kernel_bitmap(): enter:\n");
    verifexitval(manifest != NULL, EFAULT);
EXIT:
    if (!noerror()) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
          "ia_css_program_manifest_get_kernel_bitmap invalid argument\n");
        return ia_css_kernel_bitmap_clear();
    }
    return manifest->kernel_bitmap;
}

#endif /* __IA_CSS_PSYS_PROGRAM_MANIFEST_IMPL_H */
