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

//@version=5
library("Console",overlay=true)

// @function    initialise: creates the message array
// @param       no parameters
// @returns     message array: this is assigned to the "console" identifier
export initialise()=>
    var arr_print_message = array.new<string>()

// @function    used to output the desired text string to the console
// @param       _consoleName : the message array
// @param       _message : the console message
// @returns     none
export print(string[] _consoleName, string _message)=>
    array.push(_consoleName,_message)
//--- end print array}

// @function    display: placed in the last section of code. Displays the console messages
// @param       _consoleName : the message array
// @param       _lineOffset : the setting of the scroll bar (time widget)
// @param       _rowsToDisplay : how many rows to show in the console table
// @param       _gotoMsg : which message to display from (default is 0)
// @param       _posn : where the console table will be displayed
// @returns     none
export display(string[] _consoleName, 
         int _lineOffset,
         int _rowsToDisplay, 
         int _gotoMsg=0, 
         string _posn="bottom_right")=>
    // check if the chart bar iteration has currency on the bar where the scroll handle (timestamp widget) is.
    // Use the offset value to represents the offset of the first display message in the print table
    // from the the first message in the print message array
    // ie table row 1 message is <offset> elements from the first element in the print array

    // declare persistant variables within scope of function
                                     
    var int scrollHandleIndex = na     // the bar_index of the timestamp handle 
    var int scrollOffset =  na         // integer offset of the handle from the last chart bar. 
    
    if time >= _lineOffset and time[1] < _lineOffset
        // chart bar has currency on the scroll handle. Set handle variables
        scrollHandleIndex := bar_index
        scrollOffset := (last_bar_index - scrollHandleIndex) + (_gotoMsg > 0 ? _gotoMsg - 1 : 0)

    if barstate.islast
        messageCount = array.size(_consoleName)
        displayRows = math.min(_rowsToDisplay, messageCount)
        line.new(_lineOffset, high, _lineOffset, low, extend = extend.both, 
                                         color = color.rgb(255, 255, 255, 58), width=10, xloc=xloc.bar_time)
        line.new(x1=_lineOffset, y1=high, x2=_lineOffset, y2=low, extend=extend.both, 
                                         color=color.orange, width=2, xloc=xloc.bar_time)

        var scroll_handle_label = label.new(x=scrollHandleIndex, y=low, color=color.rgb(255, 0, 0, 52), textcolor=color.white)
        var tbl_printMessage = table.new(position=_posn,
                                         columns=2,
                                         rows= _rowsToDisplay,
                                         bgcolor = color.rgb(255, 255, 255, 92))

        scrollHandleText = ""
        scrollHandleText := "Messages \n" + 
                             str.tostring(scrollOffset + 1) +
                             " to " + 
                             str.tostring(scrollOffset + displayRows) +
                             "\nof " + 
                             str.tostring(messageCount)

        if messageCount == 0
            scrollHandleText := "NO MESSAGES"
        else if (messageCount - scrollOffset) < displayRows
            scrollHandleText := "No more messages"
            scrollOffset := messageCount - displayRows

        label.set_text(scroll_handle_label, scrollHandleText)

        if messageCount > 0
            for i = 0 to displayRows - 1
                // column 1 display the message line number
                table.cell(tbl_printMessage,
                           column=0,
                           row=i,
                           text=str.tostring(i + scrollOffset + 1),
                           text_color = color.rgb(147, 147, 147),
                           text_halign = text.align_left)
                // column 2 display the message
                table.cell(tbl_printMessage,
                           column=1,
                           row=i,
                           text=array.get(_consoleName, i + scrollOffset),
                           text_color = color.white,
                           text_halign = text.align_left)
// display messages function start }



//***** COPY THIS BLOCK INTO SCRIPT THAT REQUIRES DEBUGGING{
// -- console setup input section
//
// Set the "SCROLLSTART" constant to YOUR time so the scroll bar is near the end of the chart...
// var string SCROLLSTART = "25 Dec 2022 14:30 +0000"   <<--- change this
//
// con1 and con2 are two console's that can be written to seperately the name is arbitrary but
// one MUST be specified 
// var con1=initialise() <--- must specify at least one 'console' name with the initialise function
// var con2=initialise()
//
// -- suggested last block of code...
// var bool printed = false // "printed" bool prevents messages being written 
//                          // to console every time there is a new last bar
// if barstate.islast and not printed
//     printed := true
//     if i_sampleInput 
//         print(con1,"summary" + str.tostring(1))
//
// this line is needed
// if i_showMessages
//     console(i_lineOffset, i_rowsToDisplay, i_gotoMsg, i_Posn)
//***** and optionally the logic to prevent aditional print messages on every last bar
//

var string SCROLLSTART = "25 Dec 2022 14:30 +0000"  // << update this constant to your date/time
var con1=initialise()
var con2=initialise()
// -- inputs 
var string g_message = "Console Settings"
i_lineOffset    = input.time(timestamp(SCROLLSTART), "scroll Bar position", confirm = false, group=g_message)
// i_lineOffset = input.time(timestamp("15 Sep 2022 13:30 +0000"), "scroll Bar position", confirm = false, group=g_message)
i_rowsToDisplay = input.int(defval=10,title="Rows to Display", minval=1, group=g_message, inline="a")
i_gotoMsg       = input.int(defval=0, title="Start Message", group=g_message, inline="a")
i_PosY          = input.string("bottom","Position",group=g_message, inline="posn", options=["bottom",
                                                                                             "middle",
                                                                                             "top"])
i_PosX          = input.string("right","",group=g_message, inline="posn", options=["right",
                                                                                   "center",
                                                                                   "left"])
var string posn = i_PosY + "_" + i_PosX
i_showMessages  = input.bool(defval=true, title="Show Messages", group=g_message,inline="display")
i_displayTable  = input.string("con1","Console Name:",["con1","con2","other (you decide)"])

// user code ... 
i_sampleInput  = input.bool(defval=true, title="Sample")
//      some more code here
//      some more code here
//      some more code here
//      some more code here
// some code below to illustrate.... THIS WOULD BE YOUR CODE
var count = 0, count +=1
if bar_index % 150 == 0
    print(con1,"bar_index = " + str.tostring(bar_index))  // only print bar_index numbers divisible by 150
//      some more code here
//      some more code here
//      some more code here
//      some more code here
// ... end of user code

// suggested summary code - make sure this is at the end of your code
var bool printed = false // "printed" bool prevents messages being written 
                         // to console every time there is a new last bar
if barstate.islast and not printed
    printed := true
    if i_sampleInput 
        print(con1,"THE END")
        print(con2,"total candles =" + str.tostring(count))

// last line of code (needed)
if i_showMessages
    if i_displayTable == "con1" 
        display(con1, i_lineOffset, i_rowsToDisplay, i_gotoMsg, posn)
    else
        display(con2, i_lineOffset, i_rowsToDisplay, i_gotoMsg, posn) 
//****** END OF COPY BLOCK }