/* Copyright 1998 Acorn Computers Ltd
 *
 * 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.
 */
/*---------------------------------------------------------------------------*/
/* File:    pinboard.c                                                       */
/* Purpose: Non WIMP, but Pinboard specific code                             */
/* Author:  Richard Leggett                                                  */
/* History: 31-Oct-97: RML: Begun.                                           */
/*          16-Apr-98: RML: No longer uses full path for standard textures.  */
/*          01-Jul-98: RML: Tidied up.                                       */
/*          21-Jul-98: RML: Fixed bug with plotting into sprites in          */
/*                          rectangular pixel modes.                         */
/*                                                                           */
/* Copyright  1997 Acorn Computers Ltd., Cambridge, UK.                     */
/*---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "swis.h"
#include "Global/Sprite.h"
#include "Global/FileTypes.h"
#include "Interface/HighFSI.h"
#include "toolbox.h"
#include "sprite.h"
#include "msgtrans.h"
#include "main.h"
#include "settings.h"
#include "mystring.h"
#include "flex.h"

/*---------------------------------------------------------------------------*
 * pinboard_plot_texture_into_sprite                                         *
 *                                                                           *
 * Plot a texture sprite into one of the sprites contained within the client *
 * sprite area of this application (eg. std_tile, cust_tile etc.).           *
 *                                                                           *
 * In: client_sprite_area -> application's client_sprite_area                *
 *     filename -> name of spritefile containing the texture sprite.         *
 *     name -> name of sprite we want to plot.                               *
 *     sprite_into -> name of sprite  we want to plot into.                  *
 *---------------------------------------------------------------------------*/

_kernel_oserror* pinboard_plot_texture_into_sprite(int *client_sprite_area,
                                                   char *filename,
                                                   char *name,
                                                   char *sprite_into)
{
    _kernel_oserror *e;
    int             *tile;
    char            *dest_sprite;
    char            *tile_sprite;
    char            *ctrans;
    int              areasize;
    int              x;
    int              y;
    int              xeig;
    int              yeig;
    int              tile_w;
    int              tile_h;
    int              into_w;
    int              into_h;

    /* Should really find xeig and yeig of the sprite we're plotting into
       But for now, we know it will always be 1 and 1 */
    xeig = 1;
    yeig = 1;

    /* Grab memory for the new sprite file (the sprite we're plotting into the texture sprite) */
    e = sprite_size_of_spritearea(filename, &areasize);
    if (e) return e;
    if (!flex_alloc((flex_ptr)&tile,areasize)) return msgtrans_errorlookup("NoMem");

    /* Load the sprite */
    e = sprite_init_and_load(filename, tile, areasize);
    if (e) {
      flex_free((flex_ptr)&tile);
      return e;
    }

    /* If a name was specified, use that tile, else assume the first sprite in the file */
    if (name == 0) tile_sprite = (char*)tile + 16;
    else e = sprite_find_address_of(tile, name, &tile_sprite);

    /* Find address of sprite we're plotting into */
    if (!e) e = sprite_find_address_of(client_sprite_area, sprite_into, &dest_sprite);

    /* Find size of sprite we're plotting and of sprite we're plotting into */
    if (!e) e = sprite_return_size((char*)tile, tile_sprite, &tile_w, &tile_h);
    if (!e) e = sprite_return_size(client_sprite_area, dest_sprite, &into_w, &into_h);

    /* Generate a colour translation table and switch output to the destination sprite */
    if (!e) e = sprite_generate_colourtrans32((char*)tile, tile_sprite, &ctrans);
    if (!e) e = sprite_output_to_sprite(client_sprite_area, dest_sprite);

    if (e)
    {
        if (ctrans) flex_free((flex_ptr)&ctrans);
        flex_free((flex_ptr)&tile);
        return e;
    }

    /* Tile the tile (!) into the sprite */
    for (y=0; y<into_h; y+=tile_h)
    {
        for (x=0; x<into_w; x+=tile_w)
        {
            error(_swix(OS_SpriteOp, _INR(0,7),
                                          512+SpriteReason_PutSpriteScaled,
                                          (char*)tile, tile_sprite,
                                          x<<xeig, y<<yeig, 32, 0, ctrans) ,0);
        }
    }

    /* Direct vdu output back to screen */
    error(sprite_output_back_to_screen(), 0);
    flex_free((flex_ptr)&ctrans);
    flex_free((flex_ptr)&tile);

    return NULL;
}


/*---------------------------------------------------------------------------*
 * pinboard_do_custom_image_sprite                                           *
 *                                                                           *
 * Plots a copy of the user's custom image (if a sprite) into a sprite. It   *
 * will also tile, scale, centre etc.                                        *
 *                                                                           *
 * In: client_sprite_area -> application's client sprite area.               *
 *     custom_filename -> filename of the custom image.                      *
 *     type = type of backdrop (scaled, tiled, centred).                     *
 *     bgcol = colour of background chosen.                                  *
 *---------------------------------------------------------------------------*/

_kernel_oserror* pinboard_do_custom_image_sprite(int *client_sprite_area,
                                                 char *custom_filename,
                                                 custom_type type,
                                                 unsigned int bgcol)
{
    _kernel_oserror *e;
    int             *tile;
    char            *dest_sprite;
    char            *ctrans;
    int             *sprite_data;
    int              areasize;
    int              tile_w;
    int              tile_h;
    int              into_w;
    int              into_h;
    int              i;
    int              scale_factor[4];

    /* If the user hasn't yet dragged on a file, then we do nothing */
    if (custom_filename == NULL) return NULL;
    if (custom_filename[0] == 0) return NULL;

    /* Claim memory needed for spritefile */
    e = sprite_size_of_spritearea(custom_filename, &areasize);
    if (e) return e;
    if (!flex_alloc((flex_ptr)&tile,areasize)) return msgtrans_errorlookup("NoMem");

    /* Load the file, find the size of the two sprites we're dealing with, */
    /* generate a colourtrans table and direct output to the destination sprite */
    e = sprite_init_and_load(custom_filename, tile, areasize);
    if (!e) e = sprite_return_size((char*)tile, (char*)tile+16, &tile_w, &tile_h);
    if (!e) e = sprite_find_address_of(client_sprite_area, "cust_tile", &dest_sprite);
    if (!e) e = sprite_return_size(client_sprite_area, dest_sprite, &into_w, &into_h);
    if (!e) e = sprite_generate_colourtrans32((char*)tile, (char*)tile + 16, &ctrans);
    if (!e) e = sprite_output_to_sprite(client_sprite_area, dest_sprite);

    /* Fill in the background of the sprite */
    sprite_data = (int*) (dest_sprite + 44);
    for (i=0; i < (into_w*into_h); i++) sprite_data[i] = bgcol>>8;

    if (e)
    {
        if (ctrans) flex_free((flex_ptr)&ctrans);
        flex_free((flex_ptr)&tile);
        return e;
    }

    /* If tiling the backdrop... */
    if (type == CUSTOM_TILED)
    {
        int x, y, xeig, yeig;

        /* Should really find xeig and yeig of the sprite we're plotting into
           But for now, we know it will always be 1 and 1 */
        xeig = 1;
        yeig = 1;

        for (y=0; y<into_h; y+=tile_h)
        {
            for (x=0; x<into_w; x+=tile_w)
            {
                error(_swix(OS_SpriteOp, _INR(0,7),
                                              512+SpriteReason_PutSpriteScaled,
                                              (char*)tile, (char*)tile + 16,
                                              x<<xeig, y<<yeig, 32+8, 0, ctrans) ,0);
            }
        }
    }

    /* If scaling the backdrop... */
    else if (type == CUSTOM_SCALED || type == CUSTOM_FULLSCREEN)
    {
        scale_factor[0] = into_w;
        scale_factor[1] = into_h;
        scale_factor[2] = tile_w;
        scale_factor[3] = tile_h;
        error(_swix(OS_SpriteOp, _INR(0,7),
                                      512+SpriteReason_PutSpriteScaled,
                                      (char*)tile, (char*)tile + 16,
                                      0, 0, 32+8, scale_factor, ctrans) ,0);
    }

    /* If centred image on backdrop... */
    else if (type == CUSTOM_CENTRED)
    {
        /* Plot the image in the centre of the sprite, scaled to leave a small border */
        scale_factor[0] = into_w-16;
        scale_factor[1] = into_h-16;
        scale_factor[2] = tile_w;
        scale_factor[3] = tile_h;
        error(_swix(OS_SpriteOp, _INR(0,7),
                                      512+SpriteReason_PutSpriteScaled,
                                      (char*)tile, (char*)tile + 16,
                                      16, 16, 32+8, scale_factor, ctrans) ,0);

    }

    /* Direct output back to screen and free memory */
    error(sprite_output_back_to_screen(), 0);
    flex_free((flex_ptr)&ctrans);
    flex_free((flex_ptr)&tile);

    return NULL;
}


/*---------------------------------------------------------------------------*
 * pinboard_do_custom_image_jpeg                                             *
 *                                                                           *
 * Plots a copy of the user's custom image (if a JPEG) into a sprite. It     *
 * will also tile, scale, centre etc.                                        *
 *                                                                           *
 * In: client_sprite_area -> application's client sprite area.               *
 *     custom_filename -> filename of the custom image.                      *
 *     type = type of backdrop (scaled, tiled, centred).                     *
 *     bgcol = colour of background chosen.                                  *
 *---------------------------------------------------------------------------*/

_kernel_oserror* pinboard_do_custom_image_jpeg(int *client_sprite_area,
                                               char *custom_filename,
                                               custom_type type,
                                               unsigned int bgcol)
{
    _kernel_oserror *e;
    char            *dest_sprite;
    int             *sprite_data;
    int              into_w;
    int              into_h;
    int              tile_w;
    int              tile_h;
    int              i;
    int              scale_factor[4];

    /* If the user hasn't yet dragged on a file, then we do nothing */
    if (custom_filename[0] == 0) return NULL;

    e = sprite_find_address_of(client_sprite_area, "cust_tile", &dest_sprite);
    if (!e) e = sprite_return_size(client_sprite_area, dest_sprite, &into_w, &into_h);
    if (!e) e = _swix(JPEG_FileInfo, _INR(0,1)|_OUTR(2,3), 1, custom_filename, &tile_w, &tile_h);
    if (!e) e = sprite_output_to_sprite(client_sprite_area, dest_sprite);
    if (e) return e;

    /* If tiling the backdrop... */
    if (type == CUSTOM_TILED)
    {
        int x, y, xeig, yeig;

        /* Should really find xeig and yeig of the sprite we're plotting into
           But for now, we know it will always be 1 and 1 */
        xeig = 1;
        yeig = 1;

        for (y=0; y<into_h; y+=tile_h)
        {
            for (x=0; x<into_w; x+=tile_w)
            {
                error(_swix(JPEG_PlotFileScaled, _INR(0,4), custom_filename, x<<xeig, y<<yeig, 0, 0), 0);
            }
        }
    }

    /* If scaling the backdrop... */
    else if (type == CUSTOM_SCALED || type == CUSTOM_FULLSCREEN)
    {
        scale_factor[0] = into_w;
        scale_factor[1] = into_h;
        scale_factor[2] = tile_w;
        scale_factor[3] = tile_h;
        error(_swix(JPEG_PlotFileScaled, _INR(0,4), custom_filename, 0, 0, scale_factor, 0), 0);
    }

    /* If centred image on backdrop... */
    else if (type == CUSTOM_CENTRED)
    {
        /* Fill in the background of the sprite */
        sprite_data = (int*) (dest_sprite + 44);
        for (i=0; i < (into_w*into_h); i++) sprite_data[i]=bgcol>>8;

        /* Plot the image in the centre of the sprite, scaled to leave a small border */
        scale_factor[0] = into_w-16;
        scale_factor[1] = into_h-16;
        scale_factor[2] = tile_w;
        scale_factor[3] = tile_h;
        error(_swix(JPEG_PlotFileScaled, _INR(0,4), custom_filename, 16, 16, scale_factor, 0), 0);
    }

    error(sprite_output_back_to_screen(), 0);

    return NULL;
}


/*---------------------------------------------------------------------------*
 * pinboard_get_tile_filename                                                *
 *                                                                           *
 * Produce the filename of the tile specified by number 'num' and flag       *
 * 'lighter'. If the lighter is 1, but the lighter version of the tile       *
 * doesn't exist, the darker version will be used and vice versa.            *
 *                                                                           *
 * In: num = tile number                                                     *
 *     num_std_tiles = counted theme generic tiles                           *
 *     is_lighter = 1 if lighter version required, 0 otherwise               *
 *                                                                           *
 * On exit: path -> filename of tile sprite                                  *
 * Returns: 1 if succesful, 0 if tile not found.                             *
 *---------------------------------------------------------------------------*/

int pinboard_get_tile_filename(int num, int num_std_tiles, int is_lighter, char *path)
{
    char texture_string[64];
    char darker_string[128];
    char lighter_string[128];
    int  darker_exists;
    int  lighter_exists;

    if (num > num_std_tiles)
    {
        /* See if there are any theme specific tiles to choose from. The theme is expanded
         * with GSTrans so that the backdrop is preserved over a theme change (though
         * on next running this plugin it would subsequently be reset).
         */
        num = num - num_std_tiles;
        sprintf(texture_string, TextureThemePrefix"T%d", num);
        _swix(OS_GSTrans, _INR(0,2),
                          texture_string, darker_string, sizeof(darker_string));
        sprintf(texture_string, TextureThemePrefix"T%dL", num);
        _swix(OS_GSTrans, _INR(0,2),
                          texture_string, lighter_string, sizeof(lighter_string));
    }
    else
    {
        /* Choose from the set [1...num_std_tiles] */
        sprintf(darker_string, TexturePrefix"T%d", num);
        sprintf(lighter_string, TexturePrefix"T%dL", num);
    }

    error(_swix(OS_File, _INR(0,1)|_OUT(0), OSFile_ReadNoPath, darker_string, &darker_exists), 0);
    error(_swix(OS_File, _INR(0,1)|_OUT(0), OSFile_ReadNoPath, lighter_string, &lighter_exists), 0);

    if ((!lighter_exists) && (!darker_exists)) return 0;

    if ((is_lighter) && (!lighter_exists)) is_lighter = 0;
    if ((!is_lighter) && (!darker_exists)) is_lighter = 1;

    if (is_lighter) strcpy(path, lighter_string);
    else strcpy(path, darker_string);

    return 1;
}


/*---------------------------------------------------------------------------*
 * pinboard_query_standard_texture                                           *
 *                                                                           *
 * Given a pathname, decide if it is one of the standard textures.           *
 *                                                                           *
 * In: path -> pathname.                                                     *
 *     num_std_tiles = counted theme generic tiles                           *
 *                                                                           *
 * Returns: 1 if a standard texture, 0 otherwise.                            *
 *                                                                           *
 * On exit: num -> number of this texture (if a standard texture)            *
 *          is_lighter -> value of lighter (if a standard texture)           *
 *---------------------------------------------------------------------------*/

int pinboard_query_standard_texture(int *num, int num_std_tiles, int *is_lighter, const char *path)
{
    const char *ptr;
    char  selected[128];
    int   n;
    char  l;

    /* If the base path is wrong, stop now */
    if (strncasecmp((char *)path, TextureResPath, strlen(TextureResPath)) != 0) return 0;
    ptr = path + strlen(TextureResPath);

    if (strchr(ptr, '.') != NULL)
    {
        /* In a subdirectory (maybe for a theme) of the texture resources */
        _swix(OS_GSTrans, _INR(0,2),
                          TextureThemePrefix, selected, sizeof(selected));
        if (strncasecmp((char *)path, selected, strlen(selected)) != 0)
        {
            /* The theme has changed since last run, use default */
            strcpy(selected, DefaultTexture);
            ptr = selected + strlen(TexturePrefix);
            num_std_tiles = 0;
        }
        else
        {
            ptr = path + strlen(selected);
        }
        sscanf(ptr, "T%d%c", &n, &l);
        n = n + num_std_tiles;
    }
    else
    {
        sscanf(ptr, "T%d%c", &n, &l);
    }

    *num = n;
    *is_lighter = (l == 'L') ? 1 : 0;

    return 1;
}


/*---------------------------------------------------------------------------*
 * count_standard_textures                                                   *
 *                                                                           *
 * Find out how many standard textures are available on this machine.        *
 *---------------------------------------------------------------------------*/

int pinboard_count_standard_textures(void)
{
    char texture_string[64];
    int  darker_exists;
    int  lighter_exists;
    int  n;

    for (n = 1; n; n++)
    {
        sprintf(texture_string, TexturePrefix"T%d", n);
        error(_swix(OS_File, _INR(0,1) | _OUT(0), OSFile_ReadNoPath, texture_string, &darker_exists), 0);
        sprintf(texture_string, TexturePrefix"T%dL", n);
        error(_swix(OS_File, _INR(0,1) | _OUT(0), OSFile_ReadNoPath, texture_string, &lighter_exists), 0);
        if ((!lighter_exists) && (!darker_exists)) break;
    }

    return n - 1;
}
