ArrayMultipleDimensionPrototype
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © RicardoSantos

//@version=5

// @description A prototype library for Multiple Dimensional array methods
library(title="ArrayMultipleDimensionPrototype")

import RicardoSantos/DebugConsole/2 as console
[__T, __C] = console.init(20)

export index_md_to_1d (float[] dimensions, float[] indices) => //{
    int _size_d = array.size(dimensions)
    int _size_i = array.size(indices)
    //
    switch
        (_size_d < 2) => runtime.error('... -> index_md_to_1d(): "dimensions" must be have atleast 2 dimensions.')
        (_size_i < 2) => runtime.error('... -> index_md_to_1d(): "indices" must be have atleast 2 dimensions.')
        (_size_d != _size_i) => runtime.error('... -> index_md_to_1d(): "dimensions" and "indices" must be the same size.')
    //
    int _idx = int(array.get(indices, _size_d-1))
    int _cum_d = int(array.get(dimensions, _size_d-1))
    //
    if _idx >= _cum_d
        runtime.error(str.format('... -> index_md_to_1d(): "indices" out of bounds. expected indice under: {0}, found: {1}', _cum_d, _idx))
    //
    for _i = _size_d - 2 to 0
        int _current_i = int(array.get(indices, _i))
        int _current_d = int(array.get(dimensions, _i))
        //
        if _current_i >= _current_d
            runtime.error(str.format('... -> index_md_to_1d(): "indices" out of bounds. expected indice under: {0}, found: {1}', _current_d, _current_i))
        //
        _idx += _current_i * _cum_d
        _cum_d *= _current_d
    _idx
//{ usage:
console.queue_one(__C, str.format('{0}', str.tostring(index_md_to_1d(array.from(2, 4), array.from(0, 3) ))))
console.queue_one(__C, str.format('{0}', str.tostring(index_md_to_1d(array.from(2, 4), array.from(0, 1) ))))
console.queue_one(__C, str.format('{0}', str.tostring(index_md_to_1d(array.from(2, 4), array.from(0, 2) ))))
console.queue_one(__C, str.format('{0}', str.tostring(index_md_to_1d(array.from(2, 4), array.from(1, 0) ))))
console.queue_one(__C, str.format('{0}', str.tostring(index_md_to_1d(array.from(2, 4), array.from(1, 1) ))))
console.queue_one(__C, str.format('{0}', str.tostring(index_md_to_1d(array.from(2, 4), array.from(1, 2) ))))
//}}

// @function Creates a variable size multiple dimension array.
// @param dimensions int array, dimensions of array.
// @param initial_size float, default=na, initial value of the array.
// @returns float array
export new_float(int[] dimensions, float initial_value=na) => //{
    int _size_s = array.size(dimensions)
    //
    switch
        (_size_s < 2) => runtime.error('ArrayMDim -> new_float(): "dimensions" must be have atleast 2 dimensions.')
    //
    int _size = 1
    float[] _head = array.new_float(_size_s + 1, float(_size_s))
    for _i = 0 to (_size_s - 1)
        _size *= array.get(dimensions, _i)
        array.set(_head, _i + 1, array.get(dimensions, _i))
    array.concat(_head, array.new_float(_size, initial_value))
//{ usage:
console.queue_one(__C, str.format('{0}', str.tostring(new_float(array.from(2, 3), 1))))
console.queue_one(__C, str.format('{0}', str.tostring(new_float(array.from(3, 3), 1))))
console.queue_one(__C, str.format('{0}', str.tostring(new_float(array.from(4, 3), 1))))
console.queue_one(__C, str.format('{0}', str.tostring(new_float(array.from(2, 2, 2), 1))))
//}}


// @function set value of a element in a multiple dimensions array.
// @param id float array, multiple dimensions array.
// @param value float, new value.
// @returns float.
export dimensions (float[] id) => //{
    int _size_h = int(array.get(id, 0)) + 1
    //
    // TODO: errors
    //
    float[] _dims = array.slice(id, 1, _size_h)
//{ usage
var float[] test_222 = array.from(
     3, 2, 2, 2, 
     0.00,  0.01, 
     0.10,  0.11, 
     1.00,  1.01, 
     1.10,  1.11
     ) 
var float[] test_43 = array.from(2, 4, 3, 0.0, 0.1,  0.2,  1.0,  1.1, 1.2,  2.0,  2.1,  2.2, 3.0, 3.1, 3.2) 
console.queue_one(__C, str.format('test_222 has {0} dimensions', str.tostring(dimensions(test_222), '#0')))
//}}

// @function get value of a multiple dimensions array.
// @param id float array, multiple dimensions array.
// @returns float.
export get (float[] id, int[] indices) => //{
    int _size_a = array.size(id)
    int _size_h = int(array.get(id, 0)) + 1
    //
    //
    array.get(id, _size_h + index_md_to_1d(dimensions(id), indices))
//{ usage
string temp_str = '['
for _i = 0 to 1
    for _j = 0 to 1
        for _k = 0 to 1
            temp_str += str.tostring(get(test_222, array.from(_i, _j, _k)), '#0.00')
            if (_i == 1 and _j == 1 and _k == 1)
                temp_str += ']'
            else
                temp_str += ', '
console.queue_one(__C, str.format('get test_222 = {0}', str.tostring(temp_str)))
//}}

// @function set value of a element in a multiple dimensions array.
// @param id float array, multiple dimensions array.
// @returns float.
export set (float[] id, int[] indices, float value) => //{
    int _size_a = array.size(id)
    int _size_h = int(array.get(id, 0)) + 1
    //
    // TODO: errors
    //
    float[] _dims = array.slice(id, 1, _size_h)
    array.set(id, _size_h + index_md_to_1d(_dims, indices), value)
//{ usage
test_set = new_float(array.from(4, 3), 1)
console.queue_one(__C, str.format('{0}', str.tostring(test_set)))
for _i = 0 to 3
    for _j = 0 to 2
        set(test_set, array.from(_i, _j), _i + _j * 0.1)
console.queue_one(__C, str.format('{0}', str.tostring(test_set, '#0.0')))
//}}



console.update(__T, __C)