arraybrowser
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © moebius1977
// Using © kaigouthro's beautiful matrixautotable library. Many thanks!
//@version=5

// ---- VERSIONS ----- {
// v49 published as import moebius1977/arraybrowser/5, added varip arrays support (previous version disrupted varip arrays functioning)
//
// ^^^ END OF versions ^^^ }


// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
// DESCRIPTION																										//{
// @description Array browser. 
// Copy the "ARRAY BROWSER" commented code section below to your script and uncomment. 
// Use - see DEMO section below. Basically:
// -------
// import moebius1977/arraybrowser/1			as arDbgLib 		// this alias is used in the copied section, so better keep it  
// arDbg.clear()													// clears all rows and deletes the table 
// arDbg.add(arrayFloat, format = "0.00")							// adds an array with title
// arDbg.add(arrayInt)												// adds an array without title
// arDbg.add(arrayTimes, "array of times 1",  "date\ntime")			// format date and time so as to fit in the cell.
// arDbg.add(arrayTimes, "array of times 2", "{0, time, HH:mm}")	// format date and time so as to fit in the cell.
// arDbg.add(arrayString)											// adds an array
// arDbg.add(arrayLine, "arrayLines", "(x1, y1)\n(x2,y2)")			// adds an array
// arDbg.add(arrayLabel, "arrayLabel", "txt")						// adds an array
// arDbg.add(arrayBox, showIds = true)								// adds an array Ids can be shown only for selected arrays (see respective input option)
// arDbg.draw()														// shows the table with arrays
// -------
// Change offset in the input settings to scroll left/right.
//
// Formatting options
//
// For float/int] you can always use format string like "{0, time, HH:mm:ss}" or "{0.00}".
// Additional options are 
// - --- Number formats ---
// - "number" 
// - "0"      
// - "0.0"
// - "0.00"
// - "0.000"
// - "0.0000"
// - "0.00000"
// - "0.000000"
// - "0.0000000"
// - --- Date formats ---
// - "date" 
// - "date : time"
// - "dd.MM"
// - "dd" 
// - --- Time formats ---
// - "time" 
// - "HH:mm"
// - "mm:ss"
// - "date time"
// - "date, time"
// - "date,time"
//
// For line and box: Empty `format` returns coordinates as "(x1, y1) - (x2, y2)". Otherwise "x1", "x2", "y1", "y2" in `format` string are replaced by values. (e.g. toS(line, "x1, x2") will only return  x1 and x2 separated by comma).
//
// For label: Empty `format` returns coordinates and text as "(x, y): text = text". Otherwise "x1", "y1", "txt" in `format` string are replaced by values. (e.g. toS(label, "txt") will only return text of the label)//
// END OF DESCRIPTION }
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
library("arraybrowser", overlay = true)



// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// //                                              ARRAY BROWSER                                                  //
// //                                   <<COPY THIS PART TO YOUR SCRIPT  >>			    					  	   //{
//
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// //   INPUTS - ARRAY BROWSER 																					  //{

// var ARDBGT = "Array Browser Window"
// var NAVIGATION = "Navigation"	
// var BGCOLOR = "Format"

// i_maxCols			= input.int		(group=NAVIGATION	, inline = "IdOrOffset"	, title="Show"	, defval = 6)			
// i_bIdOrOffset		= input.string	(group=NAVIGATION	, inline = "IdOrOffset"	, title="items", defval = "up to offset", options = ["up to offset", "starting from id"], tooltip="") 				 
// i_n					= input.int		(group=NAVIGATION	, inline = "IdOrOffset"	, title=""			, defval = 0, tooltip="The window will show array starting from this item (id) or up to this item (offset). Change this value to scroll the array(s) left or right. Arrays are aligned to the left if \"starting from id\" is selected and to the right if \"up to offset\" is selected.")	
// i_showIds			= input.string	(group=BGCOLOR		, inline = ""		, title="Show id's"				, defval = "always", options = ["always", "never", "individually"], tooltip="Disabling overrides individual showID settings of each array.")			
// i_defaultxt         = input.color   (group=BGCOLOR		, inline = 'text color'	, title = "Text color"		, defval = #000000f5)
// i_bgClrNormal		= input.color	(group=BGCOLOR		, inline = "BgColor"	, title="Background: Normal"			, defval = #fff7d3)
// i_bgClrNa			= input.color	(group=BGCOLOR		, inline = "BgColor"	, title="NA"				, defval = #000000bd)

// var string  group_table    = 'ARRAY BROWSER WINDOW'
// i_maxRows			= input.int		(group = group_table, inline = "", defval = 10, title="Max rows")			
// i_tblShrink         = input.int     (group = group_table, inline = 'size', defval = 50, title = "Shrink, %" )
// i_textSize          = input.int     (group = group_table, inline = 'size', defval = 2           , title = 'Table Text Size' )
// i_cellsizeW         = input.int     (group = group_table, inline = 'size', defval = 100           , title = 'Scale W, % ' )
// i_cellsizeH         = input.int     (group = group_table, inline = 'size', defval = 100           , title = 'scale H, %' )
// i_fit               = input.bool    (group = group_table, inline = 'place', defval = false, title = "Fit")
// i_tableYpos         = input.string  (group = group_table, inline = 'place', defval =  'bottom'  , title = '↕'              , options=['top', 'middle', 'bottom'])
// i_tableXpos         = input.string  (group = group_table, inline = 'place', defval =  'left'    , title = '↔'              , options=['left', 'center', 'right'], tooltip='Position on the chart.')

// // END OF INPUTS }
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// //   INIT ARRAY DEBUG TABLE																							//{
// varip arbr = arraybrowser.arrayBrowser.new().init(
// 	  i_bIdOrOffset				= i_bIdOrOffset
// 	  , i_n						= i_n
// 	  , i_maxRows				= i_maxRows
// 	  , i_showIds				= i_showIds
// 	  , i_maxCols				= i_maxCols
// 	  , i_bgClrNormal			= i_bgClrNormal
// 	  , i_bgClrNa				= i_bgClrNa	  
// 	  , i_tblShrink				= i_tblShrink
// 	  , i_textSize 				= i_textSize 
// 	  , i_cellsizeW				= i_cellsizeW
// 	  , i_cellsizeH				= i_cellsizeH
// 	  , i_fit      				= i_fit      
// 	  , i_tableYpos				= i_tableYpos
// 	  , i_tableXpos				= i_tableXpos
// 	  , i_defaultxt				= i_defaultxt
// 	  )
// // END OF INIT }
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
// 
// // END OF THE PART TO BE INSERTED																					}
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import moebius1977/toString/4
import kaigouthro/matrixautotable/14                as mtt
// import moebius1977/matrixautotable/2					as mtt

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//   HELPER FUNCTIONS																								//{

// import moebius1977/arraymethods/2
// -----   array_new()  ------ {
// @function Creates a new array of size `n` filled with `val`.
array_new(int n, bool     val) => array.new<bool    >(n, val)
array_new(int n, box      val) => array.new<box     >(n, val)
array_new(int n, color    val) => array.new<color   >(n, val)
array_new(int n, float    val) => array.new<float   >(n, val)
array_new(int n, int      val) => array.new<int     >(n, val)
array_new(int n, label    val) => array.new<label   >(n, val)
array_new(int n, line     val) => array.new<line    >(n, val)
array_new(int n, linefill val) => array.new<linefill>(n, val)
array_new(int n, string   val) => array.new<string  >(n, val)
array_new(int n, table    val) => array.new<table   >(n, val)
// END OF array_new() }

// ----------- growR() ----------- {
//@function Grows array up to size szTo (if it is smaller) by adding val to the end
_agrowR(a,szTo, val) =>
    //naItem =  a.tona() 
    growBy = szTo-a.size()
    if growBy > 0
        a.concat(array_new(growBy, val))
    else
        a 

//@function Grows array up to size szTo (if it is smaller) by adding val to the end
method growR(int       [] arr, int sizeTo,int      val=na)=>_agrowR(arr, sizeTo, val)
method growR(float     [] arr, int sizeTo,float    val=na)=>_agrowR(arr, sizeTo, val)
method growR(bool      [] arr, int sizeTo,bool     val=na)=>_agrowR(arr, sizeTo, val)
method growR(string    [] arr, int sizeTo,string   val=na)=>_agrowR(arr, sizeTo, val)
method growR(color     [] arr, int sizeTo,color    val=na)=>_agrowR(arr, sizeTo, val)
method growR(line      [] arr, int sizeTo,line     val=na)=>_agrowR(arr, sizeTo, val)
method growR(label     [] arr, int sizeTo,label    val=na)=>_agrowR(arr, sizeTo, val)
method growR(box       [] arr, int sizeTo,box      val=na)=>_agrowR(arr, sizeTo, val)
method growR(table     [] arr, int sizeTo,table    val=na)=>_agrowR(arr, sizeTo, val)
method growR(linefill  [] arr, int sizeTo,linefill val=na)=>_agrowR(arr, sizeTo, val)
// END OF growR() }

// ----------- growL() ----------- {
//@function Grows array up to size szTo (if it is smaller) by adding val to the beginning
_agrowL(a,szTo, val) =>
    growBy = szTo-a.size()
    if growBy > 0
        (array_new(growBy, val)).concat(a)
    else
        a 

//@function Grows array up to size szTo (if it is smaller) by adding val to the beginning
method growL(int       [] arr, int sizeTo,int      val=na)=>_agrowL(arr, sizeTo, val)
method growL(float     [] arr, int sizeTo,float    val=na)=>_agrowL(arr, sizeTo, val)
method growL(bool      [] arr, int sizeTo,bool     val=na)=>_agrowL(arr, sizeTo, val)
method growL(string    [] arr, int sizeTo,string   val=na)=>_agrowL(arr, sizeTo, val)
method growL(color     [] arr, int sizeTo,color    val=na)=>_agrowL(arr, sizeTo, val)
method growL(line      [] arr, int sizeTo,line     val=na)=>_agrowL(arr, sizeTo, val)
method growL(label     [] arr, int sizeTo,label    val=na)=>_agrowL(arr, sizeTo, val)
method growL(box       [] arr, int sizeTo,box      val=na)=>_agrowL(arr, sizeTo, val)
method growL(table     [] arr, int sizeTo,table    val=na)=>_agrowL(arr, sizeTo, val)
method growL(linefill  [] arr, int sizeTo,linefill val=na)=>_agrowL(arr, sizeTo, val)
// END OF growL() }

// import moebius1977/typeandcast/5
//----------- _type_item () -----------{
// @function Returns type of variable or the element for array/matrix.
// ```
// int n = 0
// n._type_item()    // returns "int"
// arr = array.new<int>()
// arr._type_item()  // returns "int" 
// ```
method _type_item(int                _temp)=> na(_temp) ? 'int'               : 'int'     
method _type_item(float              _temp)=> na(_temp) ? 'float'             : 'float'   
method _type_item(bool               _temp)=> na(_temp) ? 'bool'              : 'bool'    
method _type_item(string             _temp)=> na(_temp) ? 'string'            : 'string'  
method _type_item(color              _temp)=> na(_temp) ? 'color'             : 'color'   
method _type_item(line               _temp)=> na(_temp) ? 'line'              : 'line'    
method _type_item(label              _temp)=> na(_temp) ? 'label'             : 'label'   
method _type_item(box                _temp)=> na(_temp) ? 'box'               : 'box'     
method _type_item(table              _temp)=> na(_temp) ? 'table'             : 'table'   
method _type_item(linefill           _temp)=> na(_temp) ? 'linefill'          : 'linefill'
method _type_item(int      []        _temp)=> na(_temp) ? 'int'               : 'int'     
method _type_item(float    []        _temp)=> na(_temp) ? 'float'             : 'float'   
method _type_item(bool     []        _temp)=> na(_temp) ? 'bool'              : 'bool'    
method _type_item(string   []        _temp)=> na(_temp) ? 'string'            : 'string'  
method _type_item(color    []        _temp)=> na(_temp) ? 'color'             : 'color'   
method _type_item(line     []        _temp)=> na(_temp) ? 'line'              : 'line'    
method _type_item(label    []        _temp)=> na(_temp) ? 'label'             : 'label'   
method _type_item(box      []        _temp)=> na(_temp) ? 'box'               : 'box'     
method _type_item(table    []        _temp)=> na(_temp) ? 'table'             : 'table'   
method _type_item(linefill []        _temp)=> na(_temp) ? 'linefill'          : 'linefill'
method _type_item(matrix   <int>     _temp)=> na(_temp) ? 'int'               : 'int'                 
method _type_item(matrix   <float>   _temp)=> na(_temp) ? 'float'             : 'float'               
method _type_item(matrix   <bool>    _temp)=> na(_temp) ? 'bool'              : 'bool'                
method _type_item(matrix   <string>  _temp)=> na(_temp) ? 'string'            : 'string'              
method _type_item(matrix   <color>   _temp)=> na(_temp) ? 'color'             : 'color'               
method _type_item(matrix   <line>    _temp)=> na(_temp) ? 'line'              : 'line'                
method _type_item(matrix   <label>   _temp)=> na(_temp) ? 'label'             : 'label'               
method _type_item(matrix   <box>     _temp)=> na(_temp) ? 'box'               : 'box'                 
method _type_item(matrix   <table>   _temp)=> na(_temp) ? 'table'             : 'table'               
method _type_item(matrix   <linefill>_temp)=> na(_temp) ? 'linefill'          : 'linefill'                
// END OF _type_item }



//   END OF HELPER FUNCTIONS																						//}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//   TYPE AND METHODS - ARRAY BROWSER 																				//{


//----------- tblRow TYPE -----------{

export type tblRow
	varip string			title
	varip string			arType
	varip int				arId
	varip bool 				showId
	varip string			format
	varip string[]			arDataS
	varip string[]			arTitleS
	varip string[]			arStrBgColor // `varip color[] arrayColors` is not supported as at 29 May 2023
	varip int				dataArSize

// END OF type tblRow }


//----------- +++++++++++++++++++++ -----------
//----------- ARRAY CONTAINERS TYPE GROUP ----------- {

//----------- array containers arsF, arsS,...  TYPE -----------{
export type arsB
	varip bool[] 					ar0		= na
	varip bool[] 					ar1		= na
	varip bool[] 					ar2		= na
	varip bool[] 					ar3		= na
	varip bool[] 					ar4		= na
	varip bool[] 					ar5		= na
	varip bool[] 					ar6		= na
	varip bool[] 					ar7		= na
	varip bool[] 					ar8		= na
	varip bool[] 					ar9		= na
export type arsF
	varip float[] 				ar0		= na
	varip float[] 				ar1		= na
	varip float[] 				ar2		= na
	varip float[] 				ar3		= na
	varip float[] 				ar4		= na
	varip float[] 				ar5		= na
	varip float[] 				ar6		= na
	varip float[] 				ar7		= na
	varip float[] 				ar8		= na
	varip float[] 				ar9		= na
export type arsS
	varip string[] 				ar0		= na
	varip string[] 				ar1		= na
	varip string[] 				ar2		= na
	varip string[] 				ar3		= na
	varip string[] 				ar4		= na
	varip string[] 				ar5		= na
	varip string[] 				ar6		= na
	varip string[] 				ar7		= na
	varip string[] 				ar8		= na
	varip string[] 				ar9		= na
export type arsBx
	box[] 					ar0		= na
	box[] 					ar1		= na
	box[] 					ar2		= na
	box[] 					ar3		= na
	box[] 					ar4		= na
	box[] 					ar5		= na
	box[] 					ar6		= na
	box[] 					ar7		= na
	box[] 					ar8		= na
	box[] 					ar9		= na
export type arsLn
	line[] 					ar0		= na
	line[] 					ar1		= na
	line[] 					ar2		= na
	line[] 					ar3		= na
	line[] 					ar4		= na
	line[] 					ar5		= na
	line[] 					ar6		= na
	line[] 					ar7		= na
	line[] 					ar8		= na
	line[] 					ar9		= na
export type arsLb
	label[] 				ar0		= na
	label[] 				ar1		= na
	label[] 				ar2		= na
	label[] 				ar3		= na
	label[] 				ar4		= na
	label[] 				ar5		= na
	label[] 				ar6		= na
	label[] 				ar7		= na
	label[] 				ar8		= na
	label[] 				ar9		= na


// END OF array containers type }


//----------- array container functions -----------{

// --- _clear(arCont) --- {
// @funcction Frees all array slots of the container (deletes all references to arrays)
_clear(arCont) =>
	arCont.ar0 := na
	arCont.ar1 := na
	arCont.ar2 := na
	arCont.ar3 := na
	arCont.ar4 := na
	arCont.ar5 := na
	arCont.ar6 := na
	arCont.ar7 := na
	arCont.ar8 := na
	arCont.ar9 := na
// END OF clear(azrCont) }

// --- _clear(arCont,  slotId) --- {
// @function Frees a particular slot in the container
_clear(arCont, int slotId) => 
	switch slotId
		0 => arCont.ar0 := na, 1
		1 => arCont.ar1 := na, 1
		2 => arCont.ar2 := na, 1
		3 => arCont.ar3 := na, 1
		4 => arCont.ar4 := na, 1
		5 => arCont.ar5 := na, 1
		6 => arCont.ar6 := na, 1
		7 => arCont.ar7 := na, 1
		8 => arCont.ar8 := na, 1
		9 => arCont.ar9 := na, 1
		=> 
			runtime.error(str.format("_clear(array of {0}): n = {1} out of range (0 to 9)", arCont.ar1._type_item(), slotId))	
			1	// dummy return

// END OF _clear(arCont,  slotId) }


// --- _get(arCont,  slotId) --- {
// @function Returns a reference to array in slot slotId
_get(arCont, int slotId) => 
	switch slotId
		0 => arCont.ar0 
		1 => arCont.ar1 
		2 => arCont.ar2 
		3 => arCont.ar3 
		4 => arCont.ar4 
		5 => arCont.ar5 
		6 => arCont.ar6 
		7 => arCont.ar7 
		8 => arCont.ar8 
		9 => arCont.ar9 
		=> 
			runtime.error(str.format("_get(array of {0}): n = {1} out of range (0 to 9)", arCont.ar1._type_item(), slotId))	
			arCont.ar1	// dummy return
// END OF _get(arCont,  slotId) }

// --- _set(arCont,  slotId, ar) --- {
// @function Returns a reference to array in slot slotId
_set(arCont, slotId, ar) => 
	switch slotId
		0 => arCont.ar0 := ar, 1 
		1 => arCont.ar1 := ar, 1 
		2 => arCont.ar2 := ar, 1 
		3 => arCont.ar3 := ar, 1 
		4 => arCont.ar4 := ar, 1 
		5 => arCont.ar5 := ar, 1 
		6 => arCont.ar6 := ar, 1 
		7 => arCont.ar7 := ar, 1 
		8 => arCont.ar8 := ar, 1 
		9 => arCont.ar9 := ar, 1 
		=> 
			runtime.error(str.format("_set(array of {0}): n = {1} out of range (0 to 9)", arCont.ar1._type_item(), slotId))	
			1	// dummy return

// END OF _set(arCont,  slotId) }


// --- _get_free_slot (arCont) --- {
// @function Returns a reference to array in slot slotId
_get_free_slot (arCont) => 
	i = 0
	while i <= 9
		if na(_get(arCont,i)) 
			break
		i+=1
	i > 9 ? na : i
// END OF _set(arCont,  slotId) }

// --- _get_free_slot (arCont) --- {
// @function Returns a reference to array in slot slotId
_count_free_slots (arCont) => 
	c = 0 
	for i = 0 to 9
		if na(_get(arCont,i)) 
			c+=1
	c
// END OF _set(arCont,  slotId) }


// END OF  array container functions}

// END OF ARRAY CONTAINERS TYPE GROUP ----------- }
//----------- +++++++++++++++++++++ -----------




//-----------  arrayBrowser TYPE -----------{
// @type Array browser object, declare as `var`.
export type arrayBrowser
	varip tblRow[]				arRows		// rows index 
	// matrix<string>			mxDataS			// matrix of cell text strings for the table 
	// matrix<string>			mxTitlesS		// matrix of cell text strings for the table 
	// matrix<color>			mxBgColor		// matrix of bgcolor  for the table 
	table					tbl			
	varip int						cols		// actual number of columns
	varip string					message = ""

	// --- navigation --- 
	// string					masterArType
	// int						masterArId
	bool					bIdOrOffset // true - id, false - offset 
	int						n
	bool					windowDirection // true - normal (to the right of Id and to the left of offset, false - reverse)
	string					syncAlign // align other arrays to the master array
	string					showIds 

	//--- params --- 
	int						maxRows
	int						maxCols
	// color 					bgClrMaster = #fbff26b0
	color 					bgClrNormal = #fff7d3
	color 					bgClrNa		= #000000bd
	int    					tblShrink 	
	int    					textSize  	
	int    					cellsizeW 	
	int    					cellsizeH 	
	bool   					fit       	
	string 					tableYpos 	
	string 					tableXpos 	
	color  					defaultxt 	

	// --- array references --- 
	varip arsB					b
	varip arsF					f
	varip arsS					s
	arsBx						bx
	arsLn						ln
	arsLb						lb

// END OF type arrayBrowser }


//----------- init() export  -----------{
export method init(arrayBrowser this
			  , string		i_bIdOrOffset // true - id, false - offset 
			  , int			i_n
			//   , string		i_windowDirection // true - normal (to the right of Id and to the left of offset, false - reverse)
			  , int			i_maxRows
			  , string		i_showIds
			  , int			i_maxCols
			//   , color 		i_bgClrMaster 	= #fbff26b0
			  , color 		i_bgClrNormal 	= #fff7d3
			  , color 		i_bgClrNa		= #000000bd
			  , int		    i_tblShrink 	= 50
			  , int		    i_textSize  	= 2
			  , int		    i_cellsizeW 	= 1
			  , int		    i_cellsizeH 	= 1
			  , bool		i_fit       	= false
			  , string		i_tableYpos 	=  "bottom"
			  , string		i_tableXpos 	=  "left"
			  , color		i_defaultxt 	= #000000f5
			  ) =>
	this.arRows := array.new<tblRow>()
	this.b		:= arsB		.new()
	this.f		:= arsF		.new()
	this.s		:= arsS		.new()
	this.bx		:= arsBx	.new()
	this.ln		:= arsLn	.new()
	this.lb		:= arsLb	.new()


	this.bIdOrOffset			:= (i_bIdOrOffset == "starting from id") ? true : false
	this.n						:= i_n
	// this.windowDirection		:= (i_windowDirection == "normal") ? true : false
	this.maxRows				:= i_maxRows
	this.showIds				:= i_showIds
	this.maxCols				:= i_maxCols
	// this.bgClrMaster			:= i_bgClrMaster
	this.bgClrNormal			:= i_bgClrNormal
	this.bgClrNa				:= i_bgClrNa
	this.tblShrink 				:= i_tblShrink 
	this.textSize  				:= i_textSize  
	this.cellsizeW 				:= i_cellsizeW / 100
	this.cellsizeH 				:= i_cellsizeH / 100
	this.fit       				:= i_fit       
	this.tableYpos 				:= i_tableYpos 
	this.tableXpos 				:= i_tableXpos 
	this.defaultxt 				:= i_defaultxt 
	this.message				:= ""
	this
// END OF init() }


//----------- deleteRow() -----------{
method deleteRow(arrayBrowser t,  int i) =>
	_arRows = t.arRows

	if i < 0 or i > _arRows.size()-1
		runtime.error(str.format("deleteRow: i out of bounds = {0}, t.arRows.size()= {1}", i, t.arRows.size()))
	r = t.arRows.get(i)
	switch r.arType
		"bool" => 
			_clear(t.b, r.arId)
		"float" => 
			_clear(t.f, r.arId)
		"string" => 
			_clear(t.s, r.arId)
		"box" => 
			_clear(t.bx, r.arId)
		"line" => 
			_clear(t.ln, r.arId)
		"label" => 
			_clear(t.lb, r.arId)
	_arRows.remove(i)


// END OF deleteRow }



//----------- pushRow() -----------{
method pushRow(arrayBrowser t,  string arType, int arId, string title = "", string format = "",  bool showId = false) =>
	newRow = tblRow.new(
							  title = title
							  , arType = arType
							  , arId = arId
							  , showId = showId
							  , format = format
							  )
	t.arRows.push(newRow)

	// if over masxRows delete top row if not master array, otherwise delete the second row
	if t.arRows.size() > t.maxRows 
		t.deleteRow(0)
	1
// END OF setAr }


//-----------  _add(arCont, ar) -----------{
_add(arCont, ar, arrayBrowser t, string title = "", string format = "",  bool showId = false) =>
	if na(ar)
		runtime.error("_add: ar is na")
	i = _get_free_slot(arCont)
	if t.arRows.size() < t.maxRows
		if not na(i) // if slot found
			// plug array into the slot
			_set(arCont, i, ar)
			// register the new array in the catalogue
			t.pushRow(ar._type_item(), i, title, format, showId)
		else
			t.message += (t.message == "" ? "" : "\n") + "No free slot for the array " + title + " found.", 1
			if str.length(t.message) > 3096
				t.message := str.substring(t.message, 100)
		1
	else
		t.message += (t.message == "" ? "" : "\n") + str.format("No free rows for array {0}, maxRows = {1}", title, t.maxRows), 1
		if str.length(t.message) > 3096
			t.message := str.substring(t.message, 100)
		// runtime.error(str.format("arraybrowser._add(): t.arRows.size() {0} is over t.maxRows {1},  ar._type_item() = {2}", t.arRows.size(), t.maxRows, ar._type_item()))
		1


// END OF _add(arCont, ar) }

//----------- add(bool[]) export -----------{
export method add(arrayBrowser t, bool[] arr, string title = "", string format = "",  bool showId = false) 
	  =>	_add(t.b, arr, t, title, format,  showId)
// END OF  add() }

//----------- add(float[]) export -----------{
export method add(arrayBrowser t, float[] arr, string title = "", string format = "",  bool showId = false) 
	  =>	_add(t.f, arr, t, title, format,  showId)
// END OF  add() }

//----------- add(string[]) export -----------{
export method add(arrayBrowser t, string[] arr, string title = "", string format = "", bool showId = false) 
	  =>	_add(t.s, arr, t, title, format, showId)
// END OF  add() }

//----------- add(line[]) export -----------{
export method add(arrayBrowser t, line[] arr, string title = "", string format = "", bool showId = false) 
	  =>	_add(t.ln, arr, t, title, format, showId)
// END OF  add() }

//----------- add(label[]) export -----------{
export method add(arrayBrowser t, label[] arr, string title = "", string format = "", bool showId = false) 
	  =>	_add(t.lb, arr, t, title, format, showId)
// END OF  add() }

//----------- add(box[]) export -----------{
export method add(arrayBrowser t, box[] arr, string title = "", string format = "", bool showId = false) 
	  =>	_add(t.bx, arr, t, title, format, showId)
// END OF  add() }



//----------- _sliceToString() -----------{
// slices the required part (as defined by navigation input settings) out of array, and converts to string array (does nothing to size).
// @returns <void>>
_sliceToString(ar, arrayBrowser t, tblRow r) =>
	startId = 100
	endId = -100
	if na(ar)
		r.arDataS		 := array.new<string>()
		r.arTitleS		 := array.new<string>()
		r.arStrBgColor	 := array.new<string>()
		int(na)
	else if t.n >= 0 and t.n < ar.size()
		// if t.windowDirection // window to the right of id and to the left of offset
		if t.bIdOrOffset // if t.n is Id
			startId := t.n
			endId := math.min(ar.size()-1, startId+(t.maxCols-1))
		else // if t.n is offset 
			endId := ar.size()-1-t.n
			startId := math.max(0, endId-(t.maxCols-1))
		// else // window to the left of id an
		// 	if t.bIdOrOffset // if t.n is Id
		// 		endId := t.n
		// 		startId := math.max(0, endId-(t.maxCols-1))
		// 	else // if t.n is offset 
		// 		startId := ar.size()-1-t.n
		// 		endId := math.min(ar.size()-1, startId+(t.maxCols-1))

	if startId <= endId
		r.arDataS := ar.slice(startId, endId+1).toStringAr(r.format)
		// populate titles (id's) and bgcolors
		r.arTitleS := array.new<string>() 
		for i = startId to endId
			r.arTitleS.push(((r.showId and t.showIds == "individually") or t.showIds == "always" )? "id=" + str.tostring(i) : "")
		r.arStrBgColor := array.new<string>(r.arDataS.size(), "bgClrNormal")
		r.dataArSize := ar.size()
	else
		r.arDataS		 := array.new<string>()
		r.arTitleS		 := array.new<string>()
		r.arStrBgColor	 := array.new<string>()
		int(na)

// END OF  _sliceToString1 }



//----------- populateRows() -----------{
// populate row string arrays 
method populateRows(arrayBrowser t) =>
	i = 0 
	cols = 0 
	while i < t.arRows.size()
		r = t.arRows.get(i)
		// populate row's string arrays with data from its data array
		switch r.arType
			"bool" =>
				a = _sliceToString(_get(t.b		, r.arId), t, r)
			"float" =>	
				a = _sliceToString(_get(t.f		, r.arId), t, r)
			"string" =>	
				a = _sliceToString(_get(t.s		, r.arId), t, r)
			"line" =>	
				a = _sliceToString(_get(t.ln	, r.arId), t, r)
			"label" =>	
				a = _sliceToString(_get(t.lb	, r.arId), t, r)
			"box" =>	
				a = _sliceToString(_get(t.bx	, r.arId), t, r)

		cols := math.max(nz(cols), r.arDataS.size())
		i+=1

	// expand rows and add title and size
	for r in t.arRows
		// expan arrays to match the longest or maxCols
		if t.bIdOrOffset == true 							// to the right
			r.arDataS		:= r.arDataS		.growR(cols)
			r.arTitleS		:= r.arTitleS		.growR(cols)
			r.arStrBgColor	:= r.arStrBgColor	.growR(cols, "bgClrNa")
		else 												// or to the left
			r.arDataS		:= r.arDataS		.growL(cols)
			r.arTitleS		:= r.arTitleS		.growL(cols)
			r.arStrBgColor	:= r.arStrBgColor	.growL(cols, "bgClrNa")

		// add array size
		r.arDataS.unshift(str.tostring(r.dataArSize))	
		r.arTitleS.unshift("size")	
		r.arStrBgColor.unshift("clrHeaderColumns")
		// add title
		r.arDataS.unshift(r.title)	// array titles
		r.arTitleS.unshift("")	
		r.arStrBgColor.unshift("clrHeaderColumns")
		// dbgPrintf(r.title + "
		// 				  , r.arDataS.size() = {0
		// 				  , r.arTitleS.size() = {1
		// 				  , r.arBgColor.size() = {2
		// 				  , cols = {3
		// 				  "
		// 				  , r.arDataS.size()
		// 				  , r.arTitleS.size() 
		// 				  , r.arBgColor.size()
		// 				  , cols
		// 				  )

	t.cols := cols+2 // set max array length (table width capped with maxCols input )


// END OF  populateRows }

//----------- clear() -----------{
// @function Clears the array browser window/table (deletes all rows / removes all arrays) 
export method clear(arrayBrowser t) =>
	while  t.arRows.size() > 0
		tp = t.arRows.get(0).arType
		i = t.arRows.get(0).arId
		t.deleteRow(0)
	t.tbl.delete()


// END OF  populateRows }



method toColor(arrayBrowser t, string strColor) =>
	switch strColor 
		"clrHeaderColumns" => #ffce8a
		"bgClrNormal" =>t.bgClrNormal
		"bgClrNa" => t.bgClrNa


//----------- draw() export -----------{
// @function Displays array browser table. Should be called on barstate.islast
export method draw(arrayBrowser t) =>

	// --- populate rows with slices from data arrays--- 
	t.populateRows()

	// --- init table and its matrices --- 
	messageRows = t.message == "" ? 0 : 1 // prepare a row for the message if any 
	rows =  t.arRows.size() + messageRows
	if rows > 0 
		t.tbl.delete()

		matrix<string>  mxTitleS   		= matrix.new<string>  	(rows, t.cols,  "")
		matrix<string>  mxDataS   		= matrix.new<string>  	(rows, t.cols,  "")
		matrix<color>  mxBgColor	    = matrix.new<color>  	(rows, t.cols,  t.bgClrNormal)
		matrix<color>  mxTextColor		= matrix.new<color>  	(rows, t.cols,  t.defaultxt  )
		// // // matrix<string> _tooltipmatrix   = matrix.new<string> (rows, t.cols,   string(na) )
		
		// --- print rows to the table aligning and expanding as necessary ---  
		i = 0
		while i < t.arRows.size()
			r = t.arRows.get(i)
			for j = 0 to t.cols-1
				mxDataS			.set(i+ messageRows,j, r.arDataS.get(j))
				mxTitleS		.set(i+ messageRows,j, r.arTitleS.get(j))
				mxBgColor		.set(i+ messageRows,j, t.toColor(r.arStrBgColor.get(j)))
			i+=1

		
		t.tbl := mtt.matrixtable(mxDataS, mxTitleS, mxBgColor 
		// t.tbl := mtt.matrixtable(mxDataS, mxTitleS, mxBgColor, mxTextColor // no such signature in kaigouthro/matrixautotable/14 unfortunately
				  	  	  , _textSize       = t.textSize   
				  	  	  , tableYpos       = t.tableYpos
				  	  	  , tableXpos       = t.tableXpos 
				  	  	  , _fit            = t.fit
				  	  	  , _shrink 		= t.tblShrink
				  	  	  , _w 				= t.cellsizeW
				  	  	  , _h 				= t.cellsizeH
				  	  	  , _defaultbg 		= t.bgClrNormal
				  	  	  , _defaultxt 		= color.black
				  	  	  ) 

		// print message
		if t.message !=""
			t.tbl.merge_cells(0, 0, t.cols-1, 0)
			table.cell_set_text(t.tbl,0,0,t.message)
			table.cell_set_bgcolor(t.tbl,0,0,color.rgb(255, 163, 151))

// END OF  draw() }

// END OF TYPE AND METHODS  }
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 


// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//   INPUTS - ARRAY BROWSER 																										//{

var ARDBGT = "Array Browser Window"
var NAVIGATION = "Navigation"	
var BGCOLOR = "Format"


i_maxCols			= input.int		(group=NAVIGATION	, inline = "IdOrOffset"	, title="Show"	, defval = 6)			
i_bIdOrOffset		= input.string	(group=NAVIGATION	, inline = "IdOrOffset"	, title="items", defval = "up to offset", options = ["up to offset", "starting from id"], tooltip="") 				 
i_n					= input.int		(group=NAVIGATION	, inline = "IdOrOffset"	, title=""			, defval = 0, tooltip="The window will show array starting from this item (id) or up to this item (offset). Change this value to scroll the array(s) left or right. Arrays are aligned to the left if \"starting from id\" is selected and to the right if \"up to offset\" is selected.")	
i_showIds			= input.string	(group=BGCOLOR		, inline = ""		, title="Show id's"				, defval = "always", options = ["always", "never", "individually"], tooltip="Disabling overrides individual showID settings of each array.")			
i_defaultxt         = input.color   (group=BGCOLOR		, inline = 'text color'	, title = "Text color"		, defval = #000000f5)
i_bgClrNormal		= input.color	(group=BGCOLOR		, inline = "BgColor"	, title="Background: Normal"			, defval = #fff7d3)
i_bgClrNa			= input.color	(group=BGCOLOR		, inline = "BgColor"	, title="NA"				, defval = #000000bd)



// // demo 
var string  group_table    = 'ARRAY BROWSER WINDOW'
i_maxRows			= input.int		(group = group_table, inline = "", defval = 10, title="Max rows")			
i_tblShrink         = input.int     (group = group_table, inline = 'size', defval = 50, title = "Shrink, %" )
i_textSize          = input.int     (group = group_table, inline = 'size', defval = 2           , title = 'Table Text Size' )
i_cellsizeW         = input.int     (group = group_table, inline = 'size', defval = 100           , title = 'Scale W, % ' )
i_cellsizeH         = input.int     (group = group_table, inline = 'size', defval = 100           , title = 'scale H, %' )
i_fit               = input.bool    (group = group_table, inline = 'place', defval = false, title = "Fit")
i_tableYpos         = input.string  (group = group_table, inline = 'place', defval =  'bottom'  , title = '↕'              , options=['top', 'middle', 'bottom'])
i_tableXpos         = input.string  (group = group_table, inline = 'place', defval =  'left'    , title = '↔'              , options=['left', 'center', 'right'], tooltip='Position on the chart.')

// END OF INPUTS }
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//   INIT ARRAY BROWSER TABLE																							//{
var t = arrayBrowser.new().init(
	  i_bIdOrOffset				= i_bIdOrOffset
	  , i_n						= i_n
	//   , i_windowDirection		= i_windowDirection
	  , i_maxRows				= i_maxRows
	  , i_showIds				= i_showIds
	  , i_maxCols				= i_maxCols
	//   , i_bgClrMaster			= i_bgClrMaster
	  , i_bgClrNormal			= i_bgClrNormal
	  , i_bgClrNa				= i_bgClrNa	  
	  , i_tblShrink				= i_tblShrink
	  , i_textSize 				= i_textSize 
	  , i_cellsizeW				= i_cellsizeW
	  , i_cellsizeH				= i_cellsizeH
	  , i_fit      				= i_fit      
	  , i_tableYpos				= i_tableYpos
	  , i_tableXpos				= i_tableXpos
	  , i_defaultxt				= i_defaultxt
	  )
// END OF INIT }
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 


// @function Helper for converting series to array.
// @param source float, data series.
// @param length int, size.
// @returns float array.
series_to_array (float source, int length) =>
    float[] _data = array.new_float(length, float(na))
    for _i = (length-1) to 0
        if bar_index[_i] >= 0
            array.set(_data, _i, source[_i])
    _data


// ++++++++++++++ ++++++++++++++  ---- ++++++++++++++ ++++++++++++++ 
// ||  ||  ||  ||  ||  ||  ||     DEMO    ||  ||  ||  ||  ||  ||  ||  {

ar1 = array.from(100, 200, 300 )
ar2 = array.from(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
arTDS = series_to_array(time, 5).toStringAr("date\ntime")
arTS = series_to_array(time, 5).toStringAr("time")
arT = series_to_array(time, 5)
arB = array.from(true, false, false, true, false)

// array of times of 500000 last calculations
varip arCalcTimes = array.new<int>()
varip arCalcBarIndices = array.new<int>()
arCalcTimes.push(timenow)
arCalcBarIndices.push(bar_index)
while arCalcTimes.size() > 50000 
	arCalcTimes.shift()
while arCalcBarIndices.size() > 50000 
	arCalcBarIndices.shift()



if bar_index < 1  
	t.add(ar1.toStringAr(), title = "!!! WILL NOT SHOW")



if barstate.islast
	lnB = line.new(bar_index - 3, low[3], bar_index, low, color = color.yellow)
	lnT = line.new(time[6], low[6], time[3], low[3], color = color.rgb(255, 148, 134), xloc = xloc.bar_time)
	lblB = label.new(bar_index,high, "test", color = color.yellow)
	lblT = label.new(time[6],high[6], "test", color = color.yellow, xloc = xloc.bar_time)
	bxB =  box.new(bar_index - 3, low[3], bar_index,low, text = "box", bgcolor = color.rgb(170, 237, 246, 57))
	bxT =  box.new(time[6], low[6], time[3], low[3], text = "box", bgcolor = color.rgb(243, 213, 169, 59), xloc = xloc.bar_time)



	arI = array.from(10,20)
	arF = array.from(30,40.)
	arS = array.from("AAA","BBB")
	arLn = array.from(lnB,lnT)
	arLb = array.from(lblB,lblT)
	arBx = array.from(bxB,bxT)
	



	t.clear()
	// t.add(ar2, title = "ar2")
	// t.add(arTDS, title = "arTDS")
	// t.add(arTS, title = "arTS")
	t.add(arT, title = "arT\n\"date\\ntime\"", format = "date\ntime")
	t.add(arT, title = "arT\n\"date: {0, date, dd MMM}\\ntime: {0, time, HH:mm:ss}\"", format = "date: {0, date, dd MMM}\ntime: {0, time, HH:mm:ss}")
	t.add(arCalcTimes, title = "arCalcTimes", format = "{0, time, HH:mm:ss:SSS}")
	t.add(arCalcBarIndices, title = "arCalcBarIndices")

	// t.add(ar1, title = "ar1 no id", showId = false)
	t.add(ar1, title = "ar1 show id", showId = true)
	t.add(arLn, "arLn\n\"(x1, y1)\\n(x2, y2)\"", format = "(x1, y1)\n(x2, y2)")
	t.add(arLb, "arLb\n\"text: txt\"", "text: txt", showId = true)
	t.add(arBx, "arBx \n\"bottomright:\\n(x2,y2)\"", "bottomright:\n(x2,y2)")
	t.add(ar2, title = "ar2")
	// t.add(ar1, title = "ar1-2")
	t.add(arB, title = "arB")

	// this is 11'th array whereas default input is 10 rows, so, this will produce an error message over the browser table
	t.add(array.from("aaa", "bbb"), title = "aaa-2")
	// t.add(array.from("aaa", "bbb"), title = "aaa-3")
	t.draw()





plotchar(ar1.size(), "ar1.size()",  "", location = location.bottom)
plotchar(t.arRows.size(), "t.arRows.size()",  "", location = location.bottom)


// END OF DEMO }
// ++++++++++++++ ++++++++++++++  ---- ++++++++++++++ ++++++++++++++ 


//======================================================================================
//   DEBUG PRINTS 																	//{

plotchar(false, "--- BAR INDEX ---",  "", location = location.bottom)
plotchar(bar_index, "bar_index",  "", location = location.bottom)

plotchar(false, "--- PINE's ARRAY SIZES ---",  "", location = location.bottom)
plotchar(array.size(label.all), "label.all size",  "", location = location.bottom)
plotchar(array.size(line.all), "line.all size",  "", location = location.bottom)
plotchar(array.size(box.all), "box.all size",  "", location = location.bottom)
plotchar(array.size(table.all), "table.all size",  "", location = location.bottom)

// ^^^^^^ END OF DEBUG PRINTS ^^^^^^}
//====================================================================================== 
