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

frizlabz =
 "\n 
	      ███████╗███████╗██████╗ ██╗███████╗███████╗
	  	  ██╔════╝██╔════╝██╔══██╗██║╚══███╔╝╚══███╔╝
	      █████╗  █████╗  ██████╔╝██║  ███╔╝   ███╔╝ 
	  	  ██╔══╝  ██╔══╝  ██╔══██╗██║ ███╔╝   ███╔╝  
	      ██║     ██║     ██║  ██║██║███████╗███████╗
	     '█████╗████╗ █╗████╗ █╗'╝╚═'███╗ ████╗ ████╗ 
         '██╔═══█╔══█╗█║╚══█║ █║    █╔══█╗█╔══█╗╚══█║
         '████╗ ████╔╝█║  █╔╝ █║    █████║████╔╝  █╔╝
         '██╔═╝ █╔══█╗█║ █╔╝  █║    █╔══█║█╔══█╗ █╔╝ 
         '██║   █║  █╗█║█╔╝   █║    █║  █║█║  █║█╔╝  
         '██║   █║  █║█║█████╗█████╗█║  █║████║ ████╗
         '╚═╝   ╚╝  ╚╝╚╝╚════╝╚════╝╚╝  ╚╝╚═══╝ ╚═══╝
          
 			    Line | Box | Label | Linefill
                             
                   Maker | Setter | Getter
                
		     import FFriZz/ObjectHelpers/1 as obj

 "



//@version=5
// @description Line | Box | Label | Linefill -- Maker, Setter, Getter Library
// TODO: add table functionality
library("ObjectHelpers")
import FFriZz/FrizLabz_Time_Utility_Methods/6 as Time
// import FFriZz/FrizBug/17 as p


// @function Get all of the location variables for `line`, `box`, `label` objects or the line objects from a `linefill`
//***
//## Overloaded
//***
//```
//method Get(line Line) => [int x1, float y1, int x2, float y2]
//```
//### Params 
//- **Line** `line` - line object | `required`
//***
//```
//method Get(box Box) => [int left, float top, int right, float bottom]
//```
//### Params 
//- **Box** `box` - box object | `required`
//***
//```
//method Get(label Label) => [int x, float y, string _text]
//```
//### Paramas 
//- **Label** `label` - label object | `required`
//***
//```
//method Get(linefill Linefill) => [line line1, line line2]
//```
//### Params 
//- **Linefill** `linefill` - linefill object | `required`
// @param line `line` - line object 
// @returns [`int x1`,`float y1`,`int x2`,`float y2`]
export method Get(line Line) =>
    x1 = Line.get_x1()
    x2 = Line.get_x2()
    y1 = Line.get_y1()
    y2 = Line.get_y2()
    [x1,y1,x2,y2]

// @function Gets the location paramaters of a Box
// @param Box `box` - box object 
// @returns [`int left`,`float top`,`int right`,`float bottom`]
export method Get(box Box) =>
    left   = Box.get_left()
    top    = Box.get_top()
    right  = Box.get_right()
    bottom = Box.get_bottom()
    [left,top,right,bottom]

// @function Gets the `x`, `y`, `text` of a Label
// @param Label `label` - label object 
// @returns [`int x`,`float y`,`string _text`]
export method Get(label Label) =>
    txt = Label.get_text()
    x   = Label.get_x()
    y   = Label.get_y()
    [x,y,txt]


// @function Gets `line 1`, `line 2` from a Linefill
// @param Linefill `linefill` - linefill object
// @returns [`line line1`,`line line2`]
export method Get(linefill Linefill) =>
    line line1 = Linefill.get_line1()
    line line2 = Linefill.get_line2()
    [line1,line2]



// @function Set the `x1`, `x2` of a line
//***
//### Params
//- **Line** `line` - line object | `required`
//- **x1** `int` - value to set x1 | `required`
//- **x2** `int` - value to set x2 | `required`
// @param Line `line` - line object
// @param x1 `int` - value to set x1
// @param x2 `int` - value to set x2
// @returns `line`
export method Set_x(line Line, int x1, int x2) =>
    if not na(Line)
        Line.set_x1(x1)
        Line.set_x2(x2)
        Line


// @function Set `y1`, `y2` of a line
//***
//### Params
//- **Line** `line` - line object | `required`
//- **y1** `float` - value to set y1 | `required`
//- **y2** `float` - value to set y2 | `required`
// @param Line `line` - line object
// @param y1 `float` - value to set y1
// @param y2 `float` - value to set y2
// @returns `line`
export method Set_y(line Line, float y1, float y2) =>
    if not na(Line)
        Line.set_y1(y1)
        Line.set_y2(y2)
        Line




// @function Set all params for `line`, `box`, `label`, `linefill` objects with 1 function
//***
//## Overloaded
//***
//```
//method Set(line Line, int x1=na, float y1=na, int x2=na, float y2=na,string xloc=na,string extend=na,color color=na,string style=na,int width=na,bool update=na) => line
//```
//### Params 
//- **Line** `line` - line object | `required`
//- **x1** `int` - value to set x1
//- **y1** `float` - value to set y1
//- **x2** `int` - value to set x2
//- **y2** `float` - value to set y2
//- **xloc** `int` - value to set xloc
//- **yloc** `int` - value to set yloc
//- **extend** `string` - value to set extend
//- **color** `color` - value to set color
//- **style** `string` - value to set style
//- **width** `int` - value to set width
//- **update** `bool` - if true will update line side of box to next bar ever new bar
//***
//```
//method Set(box Box,int left=na,float top=na,int right=na, float bottom=na,color bgcolor=na,color border_color=na,string border_style=na,int border_width=na,string extend=na,string txt=na,color text_color=na,string text_font_family=na,string text_halign=na,string text_valign=na,string text_wrap=na,bool update=false) => box
//```
//### Params 
//- **Box** `box` - box object
//- **left** `int` - value to set left
//- **top** `float` - value to set top
//- **right** `int` - value to set right
//- **bottom** `float` - value to set bottom
//- **bgcolor** `color` - value to set bgcolor
//- **border_color** `color` - value to set border_color
//- **border_style** `string` - value to set border_style
//- **border_width** `int` - value to set border_width
//- **extend** `string` - value to set extend
//- **txt** `string` - value to set _text
//- **text_color** `color` - value to set text_color
//- **text_font_family** `string` - value to set text_font_family
//- **text_halign** `string` - value to set text_halign
//- **text_valign** `string` - value to set text_valign
//- **text_wrap** `string` - value to set text_wrap
//- **update** `bool` - if true will update right side of box to next bar ever new bar
//***
//```
//method Set(label Label,int x=na,float y=na, string txt=na,string xloc=na,color color=na,color textcolor=na,string size=na,string style=na,string textalign=na,string tooltip=na,string text_font_family=na,bool update=false) => label
//```
//### Paramas 
//- **Label** `label` - label object
//- **x** `int` - value to set x
//- **y** `float` - value to set y
//- **txt** `string` - value to set text add`"+++"` to the _text striing to have the current label text concatenated to the location of the "+++")
//- **textcolor** `color` - value to set textcolor
//- **size** `string` - value to set size
//- **style** `string` - value to set style (use "flip" ,as the style to have label flip to top or bottom of bar depending on if open > close and vice versa)
//- **text_font_family** `string` - value to set text_font_family
//- **textalign** `string` - value to set textalign
//- **tooltip** `string` - value to set tooltip
//- **update** `bool` - if true will update label to next bar ever new bar
//***
//```
//method Set(linefill Linefill=na,line line1=na,line line2=na,color color=na) => linefill
//```
//### Params 
//- **linefill** `linefill` - linefill object
//- **line1** `line` - line object
//- **line2** `line` - line object
//- **color** `color` - color
// @param Line `line` - line object | `required`
// @param x1 `int` - value to set x1
// @param y1 `float` - value to set y1
// @param x2 `int` - value to set x2
// @param y2 `float` - value to set y2
// @param xloc `int` - value to set xloc
// @param yloc `int` - value to set yloc
// @param extend `string` - value to set extend
// @param color `color` - value to set color
// @param style `string` - value to set style
// @param width `int` - value to set width
// @param update `bool` - if true will move x2 to next bar ever new bar
// @returns `line`
export method 
 Set(
   line    Line, 
   int     x1=na, 
   float   y1=na, 
   int     x2=na, 
   float   y2=na,
   
   string  xloc=na,
   string  extend=na,
   
   color   color=na,
   string  style=na,
   int     width=na,
   
   bool    update=na
 ) =>

    if not na(Line)
        M = 1000000
        get_x1 = Line.get_x1()
        get_x2 = Line.get_x2()
        int _x1 = na(x1) ? get_x1 : x1
        int _x2 = na(x2) ? get_x2 : x2

        if not na(xloc)
            if xloc == xloc.bar_time or xloc == xloc.bar_index
                na
            else
                runtime.error("Set xloc to either xloc.bar_time or xloc.bar_index for Line.set()")
            if xloc == xloc.bar_time
                Line.set_xloc(_x1 > M ?
                                     _x1:
                                     Time.index_to_time(_x1),
                              _x2 > M ? 
                                     _x2:
                                     Time.index_to_time(_x2),
                              xloc)
            if xloc == xloc.bar_index
                Line.set_xloc(_x1 > M ? 
                                     Time.time_to_index(_x1):
                                     _x1,
                              _x2 > M ?
                                     Time.time_to_index(_x2):
                                     _x2,
                              xloc)

            else if update and na(x2)
                if _x2 > M
                    Line.set_x2(_x2+Time.bar_time())
                if _x2 < M
                    Line.set_x2(_x2+1)
            else if not na(x2)
                Line.set_x2(x2)

        else if (_x1 < M and get_x1 > M) and not na(get_x1) and not na(_x1)
            runtime.error("Change x1 param to time based input or use xloc param")
        else if (_x2 < M and get_x2 > M) and not na(get_x2) and not na(_x2)
            runtime.error("Change x2 param to time based input or use xloc param")
        else if (_x1 > M and get_x1 < M) and not na(get_x1) and not na(_x1)
            runtime.error("Change x1 param to bar_index based input or use xloc param")
        else if (_x2 > M and get_x2 < M) and not na(get_x2) and not na(_x2)
            runtime.error("Change x2 param to bar_index based input or use xloc param")
        if x1 and na(xloc)    
            Line.set_x1(x1)
        if y1    
            Line.set_y1(y1)
        if y2    
            Line.set_y2(y2)
        if not na(extend) 
            Line.set_extend(extend)
        if not na(color)  
            Line.set_color(color)
        if not na(style)  
            Line.set_style(style)
        if not na(width)  
            Line.set_width(width)
    Line
         
// @function Set all params of a box with 1 function
// @param Box `box` - box object | `required`
// @param left `int` - value to set left
// @param top `float` - value to set top
// @param right `int` - value to set right
// @param bottom `float` - value to set bottom
// @param bgcolor `color` - value to set bgcolor
// @param border_color `color` - value to set border_color
// @param border_style `string` - value to set border_style
// @param border_width `int` - value to set border_width
// @param extend `string` - value to set extend
// @param txt `string` - value to set _text
// @param text_color `color` - value to set text_color
// @param text_font_family `string` - value to set text_font_family
// @param text_halign `string` - value to set text_halign
// @param text_valign `string` - value to set text_valign
// @param text_wrap `string` - value to set text_wrap
// @param update `bool` - if true will update right side of box to next bar every new bar
// @returns `box`
export method 
 Set(
     box     Box, 
     int     left=na, 
     float   top=na, 
     int     right=na, 
     float   bottom=na,
     
     color   bgcolor=na,
     color   border_color=na,
     string  border_style=na,
     int     border_width=na,
     
     string  extend=na,
     
     string  txt=na,
     color   text_color=na,
     string  text_font_family=na,
     string  text_halign=na,
     string  text_valign=na,
     string  text_wrap=na,
     
     bool    update=false
 ) =>
    
    if not na(Box)
        M = 1000000
        get_right  = Box.get_right()
        get_left   = Box.get_left()
        int _left  = na(left) ? get_left : left
        int _right = na(right) ? get_right : right


        if (_left < M and get_left > M) and not na(get_left) and not na(_left)
            runtime.error("Change left param to time based input")
        else if (_right < M and get_right > M) and not na(get_right) and not na(_right)  
            runtime.error("Change right param to time based input")
        else if (_left > M and get_left < M) and not na(get_left) and not na(_left) 
            runtime.error("Change left param to bar_index based input")
        else if (_right > M and get_right < M) and not na(get_right) and not na(_right) 
            runtime.error("Change right param to bar_index based input")
        else
            if update and na(right)
                if get_right > M
                    Box.set_right(_right+Time.bar_time())
                else
                    Box.set_right(_right+1)
            if not na(right)
                Box.set_right(right)  
        if _left            
            Box.set_left(_left)
        if top              
            Box.set_top(top)
        if bottom           
            Box.set_bottom(bottom)
        if not na(bgcolor)          
            Box.set_bgcolor(bgcolor)
        if not na(border_color)     
            Box.set_border_color(border_color)
        if not na(border_style)   
            Box.set_border_style(border_style)
        if border_width     
            Box.set_border_width(border_width)
        if not na(txt)            
            Box.set_text(txt)
        if not na(extend)         
            Box.set_extend(extend)
        if not na(text_color)       
            Box.set_text_color(text_color)
        if not na(text_halign)      
            Box.set_text_halign(text_halign)
        if not na(text_valign)      
            Box.set_text_valign(text_valign)
        if not na(text_font_family) 
            Box.set_text_font_family(text_font_family)
        if not na(text_wrap)        
            Box.set_text_wrap(text_wrap)
    Box



// @function Set all params of a label with 1 function
// @param Label `label` | `required`
// @param x `int` - value to set x
// @param y `float` - value to set y
// @param txt `string` - value to set text add`"+++"` to the _text striing to have the current label text concatenated to the location of the "+++")
// @param textcolor `color` - value to set textcolor
// @param size `string` - value to set size
// @param style `string` - value to set style (use "flip" ,as the style to have label flip to top or bottom of bar depending on if open > close and vice versa)
// @param text_font_family `string` - value to set text_font_family
// @param textalign `string` - value to set textalign
// @param tooltip `string` - value to set tooltip
// @param update `bool` - if true will move label ahead 1 bar every new bar
// @returns `label`
export method 
 Set(
     label Label,   
     int x=na, 
     float y=na, 
     string txt=na,

     string xloc=na,
     
     color color=na,
     color textcolor=na,
     
     string size=na,
     string style=na,
     
     string textalign=na,
     string tooltip=na,
     string text_font_family=na,
     
     bool update=false
 ) =>
    
    if not na(Label)
        M = 1000000
        [get_x, get_y, get_text] = Label.Get()
        _x = na(x) ? get_x : x 
        Txt = if not na(txt)
            if str.contains(txt, "+++")
                str.replace_all(txt, "+++", get_text)
            else 
                txt
        else
            na

        if not na(xloc)
            if xloc == xloc.bar_time or xloc == xloc.bar_index
                na
            else
                runtime.error("Set xloc to either xloc.bar_time or xloc.bar_index for Label.set()")
            if xloc == xloc.bar_time
                Label.set_xloc(_x > M ?
                                     _x:
                                     Time.index_to_time(_x),
                              xloc)
            if xloc == xloc.bar_index
                Label.set_xloc(_x > M ? 
                                     Time.time_to_index(x):
                                     _x,
                              xloc)
        else if _x < M and get_x > M 
            runtime.error("Change x param to time based input or set xloc param")
        else if _x > M and get_x < M
            runtime.error("Change x param to bar_index based input or set xloc param")
        else if na(xloc)
            if update and na(x) 
                if _x > M
                    Label.set_x(_x+1)
                else
                    Label.set_x(_x+Time.bar_time())
            if not na(x)
                Label.set_x(x)
        if y
            Label.set_y(y)
        if not na(txt)
            Label.set_text(Txt)
        if not na(color)
            Label.set_color(color)
        if not na(textcolor)
            Label.set_textcolor(textcolor)
        if not na(size)
            Label.set_size(size)
        if style == "flip" and close > open
            Label.set_style(label.style_label_down), Label.set_yloc(yloc.abovebar)
        else if style == "flip" and close < open
            Label.set_style(label.style_label_up),   Label.set_yloc(yloc.belowbar)
        if not na(style) and style != "flip"
            Label.set_style(style), Label.set_yloc(yloc.price)
        if not na(textalign)
            Label.set_textalign(textalign)
        if not na(tooltip)
            Label.set_tooltip(tooltip)
        if not na(text_font_family)
            Label.set_text_font_family(text_font_family)
    Label


// @function change the 1 or 2 of the lines in a linefill object
// @param linefill `linefill` - linefill object | `required`
// @param line1 `line` - line object
// @param line2 `line` - line object
// @param color `color` - color
// @returns `linefill`
export method Set(linefill Linefill=na, line line1=na, line line2=na, color color=na) =>
	if not na(Linefill)
        _linefill = Linefill
        line _line1 = Linefill.get_line1()
        line _line2 = Linefill.get_line2()
	    color _color = na(color) ? #0000ff4b : color
	    if not na(line1) and not na(line2)
	    	_linefill := linefill.new(line1,line2,color)
	    else if na(line1)
	    	_linefill := linefill.new(_line1,line2,color)
	    else if na(line2)
	    	_linefill := linefill.new(line1,_line2,color)
	    if not na(color) 
	    	linefill.set_color(_linefill,_color)
	    Linefill.delete()
        _linefill

// @function Similar to `line.new()` but optimized for convenience
//***
//### Params
//- **x1** `int` - value to set 
//- **y1** `float` - value to set 
//- **x2** `int` - value to set 
//- **y2** `float` - value to set 
//- **extend** `string` - extend value to set line 
//- **color** `color` - color to set line 
//- **style** `string` - style to set line 
//- **width** `int` - width to set line 
// @param x1 `int` - value to set 
// @param y1 `float` - value to set 
// @param x2 `int` - value to set  
// @param y2 `float` - value to set 
// @param extend `string` - extend value to set line 
// @param color `color` - color to set line 
// @param style `string` - style to set line 
// @param width `int` - width to set line 
// @returns `line`
export method 
 Line(
   int x1 = na,
   float y1 = na,
   int x2 = na,
   float y2 = na,
   
   string extend = extend.none,
   color color = chart.fg_color,
   string style = line.style_solid,
   int width = 1
 ) =>
    
    xloc = na(x1) ? xloc.bar_index : x1>1000000 ? xloc.bar_time : xloc.bar_index

    var Line = line.new(
     xloc   = xloc,
     x1     = x1,
     y1     = y1,
     x2     = x2,
     y2     = y2,
     extend = extend,
     color  = color,
     style  = style,
     width  = width)
    

// @function similar to `box.new()` but optimized for convenience
//***
//### Params
//- **left** `int` - value to set 
//- **top** `float` - value to set 
//- **right** `int` - value to set 
//- **bottom** `float` - value to set 
//- **extend** `string` - extend value to set box 
//- **border_color** `color` - color to set border 
//- **bgcolor** `color` - color to set background
//- **text_color** `color` - color to set text 
//- **border_width** `int` - width to set border 
//- **border_style** `string` - style to set border 
//- **txt** `string` - text to set
//- **text_halign** `string` - horizontal alignment to set text 
//- **text_valign** `string` - vertical alignment to set text 
//- **text_size** `string` - size to set text 
//- **text_wrap** `string` - wrap to set text 
// @param left `int` - value to set 
// @param top `float` - value to set 
// @param right `int` - value to set 
// @param bottom `float` - value to set 
// @param extend `string` - extend value to set box 
// @param border_color `color` - color to set border 
// @param bgcolor `color` - color to set background
// @param text_color `color` - color to set text 
// @param border_width `int` - width to set border 
// @param border_style `string` - style to set border 
// @param txt `string` - text to set
// @param text_halign `string` - horizontal alignment to set text 
// @param text_valign `string` - vertical alignment to set text 
// @param text_size `string` - size to set text 
// @param text_wrap `string` - wrap to set text 
// @returns `box`
export method 
 Box(
   int left = na,
   float top = na,
   int right = na,
   float bottom = na,
   string extend = extend.none,

   color border_color = chart.fg_color,
   color bgcolor = na,
   color text_color = chart.bg_color,
   
   int border_width = 1,
   string border_style = line.style_solid,
   
   string txt = na,
   string text_halign = text.align_center,
   string text_valign = text.align_center,
   string text_size = size.normal,
   string text_wrap = text.wrap_none
 ) =>
    
    xloc = na(left) ? xloc.bar_index : left>1000000 ? xloc.bar_time : xloc.bar_index

    var Box = box.new(
     xloc         = xloc, 
     left         = left, 
     top          = top, 
     right        = right, 
     bottom       = bottom, 
     border_color = border_color, 
     border_width = border_width,
     border_style = border_style,
     extend       = extend,  
     bgcolor      = bgcolor,
     text         = txt,
     text_size    = text_size, 
     text_color   = text_color,
     text_halign  = text_halign,
     text_valign  = text_valign,
     text_wrap    = text_wrap)


// @function Similar to `label.new()` but optimized for convenience
//***
//### Params
//- **txt** `string` - string to set
//- **x** `int` - value to set
//- **y** `float` - value to set
//- **yloc** `string` - y location to set 
//- **color** `color` - label color to set
//- **textcolor** `color` - text color to set
//- **style** `string` - style to set
//- **size** `string` - size to set
//- **textalign** `string` - text alignment to set
//- **text_font_family** `string` - font family to set
//- **tooltip** `string` - tooltip to set
// @param txt `string` - string to set
// @param x `int` - value to set
// @param y `float` - value to set
// @param yloc `string` - y location to set
// @param color `color` - label color to set
// @param textcolor `color` - text color to set
// @param style `string` - style to set
// @param size `string` - size to set
// @param textalign `string` - text alignment to set
// @param text_font_family `string` - font family to set
// @param tooltip `string` - tooltip to set
// @returns `label`
export method 
 Label(
   string   txt = '',
   int      x = na, 
   float    y = na, 

   string   yloc = yloc.price,

   color    color = chart.fg_color,
   color    textcolor = chart.bg_color,

   string   style = label.style_label_down,
   string   size = size.normal,

   string   textalign = text.align_center,
   string   text_font_family = font.family_default,
   string   tooltip = na
 ) =>

    xloc = na(x) ? xloc.bar_index : x>1000000 ? xloc.bar_time : xloc.bar_index     
    
    var Label = label.new(
     xloc             = xloc,
     x                = x,
     y                = y,
     text             = txt,
     yloc             = yloc,
     color            = color,
     style            = style,
     textcolor        = textcolor,
     size             = size,
     textalign        = textalign,
     tooltip          = tooltip,
     text_font_family = text_font_family)



// if barstate.islast
// 	var LINE = Line(time[100],low*0.95,time,low*0.95)
// 	 .print("BEFORE set()", pos="1")
// 	 .Set(bar_index-30,x2=bar_index,color=color.rgb(82, 114, 255),width=6,xloc=xloc.bar_index,update=true)
// 	 .print("AFTER set()",pos="2")

// //     var BOX = Box(time[30],high,time[10],low)
// //      .print("BEFORE set()", pos="4")
// //      .set(top=high,bottom=low,txt="hello world",bgcolor=#000000,border_color=color.red,border_style=line.style_dashed,update=true)
// //      .print("AFTER set()",pos="5")

// 	var LABEL = Label("Pine",time[30],high*1.05)
// 	 .print("BEFORE set()", pos="7")
// 	 .Set(x=bar_index,txt="+++script",xloc=xloc.bar_index,textcolor=#00ff00,color=#000000,size=size.large,style=label.style_label_left,update=true)
// 	 .print("AFTER set()",pos="8")




// TODO: figure this out
// case1(_x1, _x2, M) => _x1 > M and _x2 < M
// case2(_x1, _x2, M) => _x1 < M and _x2 > M
// case3(_x1, _x2, M) => _x1 > M and _x2 > M
// case4(_x1, _x2, M) => _x1 < M and _x2 < M
// convertTime(_x1, _x2, get_x1, get_x2, M) =>
//     int newX1 = na, int newX2 = na, string xloc = na

//     if case1(_x1, _x2, M)
//         newX2 := Time.time_to_index(_x2)
//         xloc := xloc.bar_index
//     else if case2(_x1, _x2, M)
//         newX2 := Time.index_to_time(_x2)
//         xloc := xloc.bar_time
//     else if case3(_x1, _x2, M)
//         newX1 := Time.time_to_index(_x1)
//         xloc := xloc.bar_index
//     else if case4(_x1, _x2, M)
//         newX1 := Time.index_to_time(_x1)
//         xloc := xloc.bar_time

//     [newX1, newX2, xloc]