/*
# This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
#
# This file is part of the PyMite VM.
# The PyMite VM is free software: you can redistribute it and/or modify
# it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
#
# The PyMite VM 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.
# A copy of the GNU GENERAL PUBLIC LICENSE Version 2
# is seen in the file COPYING in this directory.
*/


#undef __FILE_ID__
#define __FILE_ID__ 0x07


/**
 * \file
 * \brief Image routines
 *
 * Created to eliminate a circular include
 * among mem, string and obj.
 */


#include "pm.h"


/*
 * Searches for a module's name in a contiguous array of images
 * in the given namespace starting at the given address.
 * A module's name is stored in the last index of the names tuple of an image.
 */
static PmReturn_t
img_findInPath(uint8_t *cname, uint8_t cnamelen, PmMemSpace_t memspace,
               uint8_t const **paddr)
{
    uint8_t const *imgtop;
    PmType_t type;
    uint16_t len;
    int16_t size = 0;
    uint8_t i = 0;

    /* Addr is top of img */
    imgtop = *paddr;

    /* Get img's type byte */
    type = (PmType_t)mem_getByte(memspace, paddr);

    /* Search all sequential images */
    while (type == OBJ_TYPE_CIM)
    {
        /* Use size field to calc addr of next potential img */
        size = mem_getWord(memspace, paddr);

        /* Point to names tuple */
        *paddr = imgtop + CI_NAMES_FIELD;

        /* Ensure it's a tuple */
        type = (PmType_t)mem_getByte(memspace, paddr);
        C_ASSERT(type == OBJ_TYPE_TUP);

        /* Scan to last name in tuple (it's the module's name) */
        i = mem_getByte(memspace, paddr) - (uint8_t)1;
        for (; i > 0; i--)
        {
            /* Ensure obj is a string */
            type = (PmType_t)mem_getByte(memspace, paddr);
            C_ASSERT(type == OBJ_TYPE_STR);

            /* Skip the length of the string */
            len = mem_getWord(memspace, paddr);
            (*paddr) += len;
        }

        /* Ensure it's a string */
        type = (PmType_t)mem_getByte(memspace, paddr);
        C_ASSERT(type == OBJ_TYPE_STR);

        /* If strings match, return the address of this image */
        if ((cnamelen == mem_getWord(memspace, paddr))
            && (PM_RET_OK == mem_cmpn(cname, cnamelen, memspace, paddr)))
        {
            *paddr = imgtop;
            return PM_RET_OK;
        }

        /* Calc imgtop for next iteration */
        imgtop += size;

        /* Point to next potential img */
        *paddr = imgtop;

        /* Check if another img follows this one */
        type = (PmType_t)mem_getByte(memspace, paddr);
    }
    return PM_RET_NO;
}


PmReturn_t
img_findInPaths(pPmObj_t pname, PmMemSpace_t *r_memspace,
                uint8_t const **r_imgaddr)
{
    uint8_t i;
    PmReturn_t retval = PM_RET_NO;

    /* Search in each path in the paths */
    for (i = 0; i < gVmGlobal.imgPaths.pathcount; i++)
    {
        *r_imgaddr = gVmGlobal.imgPaths.pimg[i];
        *r_memspace = gVmGlobal.imgPaths.memspace[i];
        retval = img_findInPath(((pPmString_t)pname)->val,
                                ((pPmString_t)pname)->length,
                                *r_memspace, r_imgaddr);
        if (retval == PM_RET_NO)
        {
            continue;
        }
        else if (retval == PM_RET_OK)
        {
            break;
        }
        else
        {
            return retval;
        }
    }

    return retval;
}


PmReturn_t
img_appendToPath(PmMemSpace_t memspace, uint8_t const * const paddr)
{
    uint8_t i;

    if (gVmGlobal.imgPaths.pathcount >= PM_NUM_IMG_PATHS)
    {
        return PM_RET_NO;
    }

    i = gVmGlobal.imgPaths.pathcount;

    gVmGlobal.imgPaths.memspace[i] = memspace;
    gVmGlobal.imgPaths.pimg[i] = paddr;
    gVmGlobal.imgPaths.pathcount++;

    return PM_RET_OK;
}