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

// @version=5

// @description easytable is an easy way to create tables, change colors, insert arrays to tables, remove rows/columns, and format tables.

library(title="easytable")

import MA_PT/json/1

//##############################################################################
//######################    1 - Internal Functions  ############################
//##############################################################################

// @function Generate colors to recreate a striped pattern
stripped_style(int i, int j, color odd_row, color even_row, color text_c,bool oritation)=>
    bg_color = oritation ? (i%2 == 0) ? odd_row: even_row : (j%2 == 0) ? odd_row: even_row
    array.from(bg_color,text_c)



//______________________________________________________________________________	
// @function Generate colors to color headers only. 
header_style(int i, int j, color cells, color header, color text_c,int style)=>
    color bg_color = switch style
        1 => (i==0) ? header:cells
        2 => (j==0) ? header:cells
        3 => (j==0 or i==0) ? header:cells
        => na
        
    array.from(bg_color,text_c)

    
//______________________________________________________________________________	
// @function Generate colors to recreate chess pattern.
chezz_style(int i, int j, color odd_row, color even_row, color text_c)=>
    bg_color = (i%2 == 0 and j%2 == 0) or (i%2 != 0 and j%2 != 0) ? odd_row: even_row
    array.from(bg_color,text_c)


//Fetch tables array and nº of tables found.
fetch_tbl_and_size()=>
    found_tables = table.all
    [found_tables, array.size(found_tables)]


//##############################################################################
//######################    2 - Export Functions    ############################
//##############################################################################


// @function Identifies all tables ID number in each cell(0,0).
export indentify_table_id()=>
    [found_tables, n_found] = fetch_tbl_and_size()
    
    if n_found<1
        runtime.error('(easytable) → indentify_table_id()      "No table  was found."')
        
    for i=0 to n_found - 1
        table.cell(array.get(found_tables, i),0,0,
                     str.tostring(i),
                     bgcolor = color.black,
                     text_color=color.yellow,
                     text_size=size.huge)



//______________________________________________________________________________
// @function Get table object by ID number.
// @param id_number (int) ID number of the table to fetch.
// @returns table.
export get_table_by_id(int id_number = 0) => 
    [found_tables, n_found] = fetch_tbl_and_size()
    
    if n_found<1
        runtime.error('(easytable) → get_table_by_id()       "No table  was found."')
        
    if id_number  > n_found - 1
        runtime.error('(easytable) → get_table_by_id()       The ID number does not exist. Available 0' + (n_found==1 ? na: " to " +str.tostring(n_found-1)))

    table tbl_return = array.get(found_tables, id_number)
        

	
//______________________________________________________________________________	
// @function Change cells background colors.
// @param table_object (table) table object to be changed.
// @param cells_color (color) Cells color.
// @param start_column (int) Start column.
// @param end_column (int) End column.
// @param start_row (int) Start Row.
// @param end_row (int) End Row to change.
// @returns Void.
export change_cells_color(table table_object, 
                          color cells_color, 
                          int   start_column, 
                          int   end_column, 
                          int   start_row = 0,
                          int   end_row=0) => 
                          
    for i = start_column to end_column
        for j = start_row to end_row
            table.cell_set_bgcolor(table_object, i, j, cells_color)



//______________________________________________________________________________	
// @function Change cells text colors.
// @param table_object (table) table object to be changed.
// @param text_color (color) Text color.
// @param start_column (int) Start column.
// @param end_column (int) End column.
// @param start_row (int) Start Row.
// @param end_row (int) End Row.
// @returns Void.
export change_cells_text_color(table table_object, 
                               color text_color, 
                               int   start_column, 
                               int   end_column, 
                               int   start_row = 0,
                               int   end_row = 0) =>
                               
    for i = start_column to end_column
        for j = start_row to end_row
            table.cell_set_text_color(table_object, i, j, text_color)



//______________________________________________________________________________	
// @function Change All table text color.
// @param table_object (table) table object to be changed.
// @param text_color (color) Text color.
// @param table_column_size (int) Size of the table columns.
// @param table_row_size (int) Size of the table rows.
// @returns Void.
export change_all_table_text_color(table table_object, 
                               color text_color, 
                               int   table_column_size, 
                               int   table_row_size) =>
                               
    for i = 0 to table_column_size-1
        for j = 0 to table_row_size-1
            table.cell_set_text_color(table_object, i, j, text_color)




// @function Change table size.
// @param table_object (table) table object to be changed.
// @param n_of_columns (int) Size of the table columns.
// @param n_of_rows (int) Size of the table rows.
// @param tbl_size (string) size of the table.
// @returns Void.
export change_table_size(table table_object,int n_of_columns,int n_of_rows,string tbl_size)=>
    for i_rows=0 to n_of_rows-1
        for i_cols=0 to n_of_columns-1
            table.cell_set_text_size(table_object, i_cols, i_rows, tbl_size)


//______________________________________________________________________________	
// @function Change table cells text size .
// @param text_size (string) Text size.
// @param start_column (int) Start column.
// @param end_column (int)(optional) End column.
// @param start_row (int)(optional) Start Row.
// @param end_row (int)(optional) End Row.
// @param table_id (int)(optional) Number of the ID of the table.
// @returns Void.
export change_cells_text_size(table  table_object, 
                              string text_size, 
                              int    start_column, 
                              int    end_column = na, 
                              int    start_row  = 0,
                              int    end_row    = na) => 
    
    
    for i = start_column to na(end_column) ? start_column : end_column
        for j = start_row to na(end_row) ? start_row : end_row
            table.cell_set_text_size(table_object, i, j, text_size)



//______________________________________________________________________________	
// @function Delete specified rows from table.
// @param table_object (table) table object to be changed.
// @param table_column_size (int) Table columns max size.
// @param start_row (int) Start row to delete.
// @param end_row (int)(optional) End row to delete (optional — Assumes start_row value).
// @returns Void.
export table_delete_row( table table_object, 
                         int   table_column_size, 
                         int   start_row, 
                         int   end_row = na) => 

    table.clear(table_object,0,start_row, table_column_size, na(end_row) ? start_row : end_row )



//______________________________________________________________________________	
// @function Delete specified columns from table.
// @param table_object (table) table object to be changed.
// @param table_row_size (int) Table rows max size.
// @param start_column (int) Start column to delete.
// @param end_column (int)(optional) End column to delete (optional — Assumes start_column value).
// @returns Void.
export table_delete_column(table table_object, 
                           int   table_row_size, 
                           int   start_column, 
                           int   end_column = na) => 
                           
    table.clear(table_object, start_column,0,na(end_column)? start_column:end_column,table_row_size)    
    


//______________________________________________________________________________	
// @function Insert string array to table column without passing table object.
// @param column_to_insert (int) Column to be inserted.
// @param array_to_insert (string array) Start column to delete.
// @param table_id (int)(optional) Number of the ID of the table.
// @returns Void.
export array_to_table_column_auto(int      column_to_insert,
                                  string[] array_to_insert, 
                                  int      table_id = na) => 
                                  
    table_object = get_table_by_id(na(table_id)? 0:table_id)
    int i = 0
    for element in array_to_insert
        table.cell_set_text(table_object, column_to_insert, i, element)
        i+=1



//______________________________________________________________________________	
// @function Insert string array to table row without passing table object.
// @param row_to_insert (int) Column to be inserted.
// @param array_to_insert (string array) Start column to delete.
// @param table_id (int)(optional) Number of the ID of the table.
// @returns Void.
export array_to_table_row_auto(int      row_to_insert,
                               string[] array_to_insert, 
                               int      table_id = na) => 
                               
    table_object = get_table_by_id(na(table_id)? 0:table_id)
    for i = 0 to array.size(array_to_insert) -1
        table.cell_set_text(table_object, i, row_to_insert, array.get(array_to_insert,i))
        

        
//______________________________________________________________________________	
// @function Insert string array to table row by passing table object.
// @param table_object (table) table object to be changed.
// @param row_to_insert (int) Row to be inserted.
// @param array_to_insert (string array) Start column to delete.
// @returns Void.        
export array_to_table_row(table    table_object , 
                          int      row_to_insert,
                          string[] array_to_insert) => 
                          
    for i = 0 to array.size(array_to_insert) -1
        table.cell_set_text(table_object, i, row_to_insert, array.get(array_to_insert,i))



//______________________________________________________________________________	
// @function Insert string array to table column by passing table object.
// @param table_object (table) table object to be changed.
// @param column_to_insert (int) Column to be inserted.
// @param array_to_insert (string array) Start column to delete.
// @returns Void.         
export array_to_table_column(table    table_object,
                             int      column_to_insert, 
                             string[] array_to_insert) => 
    
                             
    for i = 0 to array.size(array_to_insert) -1
        table.cell_set_text(table_object, column_to_insert, i, array.get(array_to_insert,i))
        


//______________________________________________________________________________	
// @function Changes cell color at set intervals (blink).
// @param cell_column (int) Cell column position.
// @param cell_row (int) Cell row position.
// @param c_color (color) Color to blink.
// @param blink_interval_ms (int)(opt) Interval in milliseconds.
// @param table_id (int)(opt) Table ID number.
export blink_cell(int cell_column,
                  int cell_row,
                  color c_color,
                  int blink_interval_ms=1000, 
                  int table_id = na)=>
                  
    varip bool state = false
    varip  time_n = timenow
    if (timenow - time_n) > blink_interval_ms
        time_n := timenow
        state := not(state)
        color_state = state? c_color: color.rgb(color.r(c_color),color.g(c_color),color.b(c_color),10)
        table_object = get_table_by_id(na(table_id)? 0:table_id)

        table.cell_set_bgcolor(table_object,cell_column,cell_row,color_state)
                     

 
//______________________________________________________________________________	
// @function Changes table pre-style by selecting a pre-style number.
// @param table_object (table) table object to be changed.
// @param number_of_columns (int) Table column size.
// @param number_of_rows (int) Table row size.
// @param color 1 (color) Color of .
// @returns Void.
export change_table_style(table table_object,
                          int   number_of_columns,
                          int   number_of_rows,
                          int style_number=0,
                          color color_1 = color.black,
                          color color_2 = color.gray, 
                          color color_3_txt = color.white)=>
                          
    if na(style_number)
        runtime.error('(easytable) → Must provide style number 0 to 15')
        
    for i = 0 to number_of_rows -1 
        for j=0 to  number_of_columns -1
            
            c_bg_and_txt_c = switch style_number
                0 => stripped_style(i,j,color_1,color_2,color_3_txt,true)
                1 => stripped_style(i,j,color_1,color_2,color_3_txt,false)
                2 => header_style(i,j,color_1,color_2,color_3_txt,1)
                3 => header_style(i,j,color_1,color_2,color_3_txt,2)
                4 => header_style(i,j,color_1,color_2,color_3_txt,3)
                5 => chezz_style(i,j,color_2,color_1,color_3_txt)
                => array.from(color.blue,color.white)  
            if not na(array.get(c_bg_and_txt_c,0))
                table.cell_set_bgcolor(table_object,j,i,array.get(c_bg_and_txt_c,0))
            table.cell_set_text_color(table_object,j,i,array.get(c_bg_and_txt_c,1))
            


//______________________________________________________________________________	
// @function Create a simple(blank) table without any styling.
// @param n_of_columns (int) Numbers of columns in the table.
// @param n_of_rows (int) Number of rows in the table.
// @param position (string) table position.
// @returns table object.
export create_table_clean( int    n_of_columns,
                     int    n_of_rows,
                     string position = position.top_right) => 
                     
    if n_of_columns <= 0
	    runtime.error("(easytable) → create_table() Cannot create table with nº row less than 1")
    if n_of_rows <= 0
	    runtime.error("(easytable) → create_table() Cannot create table with nº column less than 1")                     
                     
    table tbl = table.new(position, n_of_columns , n_of_rows)

    for i = 0 to n_of_rows -1
        for j = 0 to n_of_columns - 1
            table.cell(tbl, j , i)
	tbl



//______________________________________________________________________________	
// @function Create table with a pre-set style.
// @param n_of_columns (int) Numbers of columns in the table.
// @param n_of_rows (int) Number of rows in the table.
// @param style_number (int) Style number.
// @param position (string) table position.
// @returns table object.
export create_table_with_style( int    n_of_columns,
                     int    n_of_rows,
                     int    style_number = 1,
                     string position = position.top_right) => 
                     
	table tbl = create_table_clean(n_of_columns,n_of_rows,position)
	change_table_style(tbl, n_of_columns, n_of_rows,style_number)
	tbl
	


// @function Create table based on input raw json string.
// @param raw_json (int) Raw json string.
// @returns table object.
export json_to_table(string raw_json)=>
    [n_rows, n_columns] = json.size_of_json_string(raw_json)
    
    table table_plot = create_table_with_style(n_columns,n_rows+1,2) //+1 title  
    // table table_plot = create_table_clean(n_columns,n_rows+1) //+1 title  
    
    key_names = json.get_json_keys_names(raw_json)
    int i = 0
    for key_name in key_names
        array_to_push = json.get_values_by_id_name(raw_json,key_name)
        array.unshift(array_to_push,key_name)
        array_to_table_column(table_plot,i,array_to_push)
        i+=1

    table_plot


//##############################################################################
//######################        3 - Examples        ############################
//##############################################################################

// @function Example function that display a table based on a json 
export json_example()=>
    var string json_example = '[{"ticker":"MSFT","%":"6.33%"},{"ticker":"AAPL","%":"5.88%"},{"ticker":"Amazon","%":"3.83%"},{"ticker":"Alphabet","%":"2.22%"},{"ticker":"Tesla","%":"2.19%"},{"ticker":"Alphabet","%":"2.09%"},{"ticker":"Meta Platforms","%":"1.98%"},{"ticker":"NVIDIA","%":"1.92%"},{"ticker":"Berkshire Hathaway","%":"1.34%"},{"ticker":"JPMorgan Chase & Co.","%":"1.27%"}]'
    var tbl = json_to_table(json_example)

export example_create_table()=>
    var n_row = 9
    var n_col = 5
    var style = 0
    // var tbl = create_table_with_style(n_row,n_col,style,position.bottom_right)
    
    var tbl = create_table_with_style(n_of_columns = 9,
                                      n_of_rows = 9,
                                      style_number = 5,
                                      position = position.bottom_right) 
    table.set_border_width(tbl,1)
    
    var array_text = array.from('e','a','s','y','t','a','b','l','e')
    array_to_table_row(tbl,0,array_text)
    array_to_table_column(tbl,0,array_text)
    
    blink_cell(int(math.random(0,n_row-1)),int(math.random(0,n_col-1)),color.red,table_id = 1)


if barstate.islast
    json_example()    
    example_create_table()