json
// 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 Convert JSON strings to tradingview Pine Script
library("json")

var string msg_json_example = 'Example of json\n [{"ticker":"AAPL","price":"100"},{"ticker":"TSLA","price":"200"}]'
var string msg_incorrect_format = '(json)(ERROR) -> Did not find correct format '



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

// @function Check if JSON string is valid
check_json_format_is_correct(string raw_json)=>
    if raw_json== "" or raw_json == " " or na(raw_json)
        runtime.error("(json) Error -> Input json is empty")    
        
    array_open_bracket = str.split(raw_json,'{')
    array_closing_bracket = str.split(raw_json,'}')
    int a_size_opening = array.size(array_open_bracket)
    int a_size_closing = array.size(array_closing_bracket)
    
    if a_size_opening != a_size_closing or a_size_opening<=1 or a_size_closing<=1 
        runtime.error(msg_incorrect_format + " missing character { or } pair of brackets  :\n" + msg_json_example) 
    
    if array.size(str.split(raw_json,':')) <=1
        runtime.error(msg_incorrect_format + msg_json_example) 
    

// @function Clean input raw JSON and returns clean JSON
// @return (string) Clean JSON string
raw_to_clean_json(string raw_json)=> // Remove unnecessary symbols

    // Add extra brackets [] and Remove spaces
    string clean_json = str.replace_all('['+raw_json+']',' ','')
    
    // Remove tabs
    clean_json := str.replace_all(clean_json,'  ','')
    
    // Check if the JSON format is valid
    check_json_format_is_correct(clean_json)
    
    // Replace splicing character 
    clean_json := str.replace_all(clean_json,'","','";"')
    
    // Remove unnecessary characters
    var special_characters = array.from('[',']','"')
    clean_json := for symbol in special_characters
        clean_json := str.replace_all(clean_json,symbol,'')
    
    
    
//______________________________________________________________________________
// @function Returns array with each JSON elements  
// @param raw_json (string) Raw JSON string 
// @return (string array) array of JSON elements
split_json_to_array(string raw_json)=>

    string clean_json = raw_to_clean_json(raw_json)
    string clean_element = str.replace_all(clean_json,',','')
    clean_element := str.replace_all(clean_element,'}','')
    string[] elements_array = str.split(clean_element,"{")


    
//##############################################################################
//######################    2 - Export Functions    ############################
//##############################################################################
    
// @function Returns string array with all key names
// @param raw_json (string) Raw JSON string 
// @returns (string array) Array with all key names
export get_json_keys_names(string raw_json)=>

    split_json_array = split_json_to_array(raw_json)
    array_of_key_names = array.new_string()
    
    if array.size(split_json_array) >=1
        split_keys = str.split(array.get(split_json_array,0),";")
        for element_to_process in split_keys
            array.push(array_of_key_names,array.get(str.split(element_to_process,":"),0))
            
    array_of_key_names



// @function Returns string array with values of the input key name 
// @param raw_json (string) Raw JSON string 
// @param key_name (string) Name of the key to be fetched
// @returns (string array) Array with values of the input key name 
export get_values_by_id_name(string raw_json, string key_name)=>

    array_key_names = get_json_keys_names(raw_json)
    // Check if the searched element name exists (-1 not found)
    int key_index = array.indexof(array_key_names,key_name)
    if key_index<0
        str = str.tostring(array_key_names)
        runtime.error('(json)->get_values_by_id_name Key Name "'+key_name+ '" not found  |  Available ' + str)
        
        
    array_of_values = array.new_string()
    for element in split_json_to_array(raw_json)
        split_parts = str.split(element,";")
        split_value = str.split(array.get(split_parts,key_index),":")
        array.push(array_of_values,array.get(split_value,1))
        
    array_of_values


//___________________________size_of_json_string________________________________
// @function Returns size of raw JSON string [n_of_values, n_of_keys_names]
// @param raw_json (string) Raw JSON string 
// @returns [int, int] Size of n_of_values, size of n_of_keys_names
export size_of_json_string(string raw_json)=>
    array_of_elements = split_json_to_array(raw_json)
    
    int n_of_values = array.size(array_of_elements)
    int n_of_keys_names = array.size(str.split(array.get(array_of_elements,0),";"))
    
    [int(n_of_values), int(n_of_keys_names)]
    
 