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

//@version=5

// Algebraic functions
library("Algebra",overlay=true)

//----------------------------------------------------------------------------
// Private
//----------------------------------------------------------------------------

// Get the hypotenuse of a right triangle, given the lengths of its legs
rt_get_hyp(a,b) =>
    math.sqrt(a*a + b*b)

//----------------------------------------------------------------------------
// Public
//----------------------------------------------------------------------------

// @function Get line slope and y-intercept from coordinates
// @param x1 x coordinate 1 (int - bar index)
// @param y1 y coordinate 1 (float - price/value)
// @param x2 x coordinate 2 (int - bar index)
// @param y2 y coordinate 2 (float - price/value)
// @returns [slope, y-intercept] of line
//
export line_fromXy(int x1, float y1, int x2, float y2) =>
    slope = (y1-y2)/(x1-x2)
    yInt = y1 - slope*x1
    [slope,yInt]

// @function Get price at X coordinate, given line slope and y-intercept
// @param x x coordinate to solve for y (int - bar index)
// @param slope slope of line (float)
// @param yInt y-intercept of line (float)
// @returns y (price/value)
//
export line_getPrice(int x, float slope, float yInt) =>
    slope*x+yInt
    
// @function Get price at X coordinate, given two points on a line
// @param x x coordinate to solve for y (int - bar index)
// @param x1 x coordinate 1 (int - bar index)
// @param y1 y coordinate 1 (float - price/value)
// @param x2 x coordinate 2 (int - bar index)
// @param y2 y coordinate 2 (float - price/value)
// @returns y (price/value)
//
export line_getPrice_fromXy(int x, int x1, float y1, int x2, float y2) =>
    [slope,yInt] = line_fromXy(x1,y1,x2,y2)
    line_getPrice(x,slope,yInt)

// @function Get length of sides of a right triangle formed by a given line
// @param x1 x coordinate 1 (int - optional, required if argument l is not specified)
// @param y1 y coordinate 1 (float - optional, required if argument l is not specified)
// @param x2 x coordinate 2 (int - optional, required if argument l is not specified)
// @param y2 y coordinate 2 (float - optional, required if argument l is not specified)
// @param l line object (line - optional, required if x1, y1, x2, y2 agruments are not specified)
// @returns [a (Δy), b (Δx), c (Hypotenuse)]
//
export line_getRtSides(int x1=0, float y1=0.0, int x2=0, float y2=0.0, line l=na) =>
    x_1 = 0
    x_2 = 0
    y_1 = 0.0
    y_2 = 0.0
    if not na(l)
        x_1 := line.get_x1(l)
        x_2 := line.get_x2(l)
        y_1 := line.get_y1(l)
        y_2 := line.get_y2(l)
    else
        x_1 := x1
        x_2 := x2
        y_1 := y1
        y_2 := y2
    a = y_2-y_1
    b = x_2-x_1
    c = if a != 0 and b != 0
        rt_get_hyp(a,b)
    else
        0
    [a,b,c]

// @function Get length of line, given a line object or two sets of coordinates
// @param x1 x coordinate 1 (int - optional, required if argument l is not specified)
// @param y1 y coordinate 1 (float - optional, required if argument l is not specified)
// @param x2 x coordinate 2 (int - optional, required if argument l is not specified)
// @param y2 y coordinate 2 (float - optional, required if argument l is not specified)
// @param l line object (line - optional, required if x1, y1, x2, y2 agruments are not specified)
// @returns length of line (float)
//
export line_length(int x1=0, float y1=0.0, int x2=0, float y2=0.0, line l=na) =>
    [a,b,c] = line_getRtSides(x1,y1,x2,y2,l)
    if a == 0
        b
    else if b == 0
        a
    else
        c
