package scientific.matplot

import std.math.*
import std.unittest.*
import std.unittest.testmacro.*

import scientific.numbers.*
import scientific.linear.*
import scientific.stats.random.*
import scientific.stats.normal.*

/* Type for theta, rho, sz, colors: Float64 */
foreign func c_polarscatter(theta: CPointer<Unit>, theta_len: Int64, rho: CPointer<Unit>, rho_len: Int64, line_spec: CString):CPointer<Unit>
foreign func c_polarscatter_sz(theta: CPointer<Unit>, theta_len: Int64, rho: CPointer<Unit>, rho_len: Int64, sz: Float64, line_spec: CString):CPointer<Unit>
foreign func c_polarscatter_SZ_COL(theta: CPointer<Unit>, rho: CPointer<Unit>, sz: CPointer<Unit>, colors: CPointer<Unit>, len: Int64, line_spec: CString):CPointer<Unit>

public func polarscatter(theta: Vector<Float64>, rho: Vector<Float64>, line_spec!: String=""):Line {
    let size = theta.size()
    var cstr_line_spec = unsafe { LibC.mallocCString(line_spec) }
    let handle = unsafe { c_polarscatter(theta.ptr, size, rho.ptr, size, cstr_line_spec) }
    unsafe { LibC.free(cstr_line_spec) }
    return Line(handle)
}

public func polarscatter(theta: Vector<Float64>, rho: Vector<Float64>, point_sz: Float64, line_spec!: String="") {
    let size = theta.size()
    var cstr_line_spec = unsafe { LibC.mallocCString(line_spec) }
    let handle = unsafe { c_polarscatter_sz(theta.ptr, size, rho.ptr, size, point_sz, cstr_line_spec) }
    unsafe { LibC.free(cstr_line_spec) }
    return Line(handle)
}

public func polarscatter(theta: Vector<Float64>, rho: Vector<Float64>, sz: Vector<Float64>, color: Vector<Float64>, line_spec!: String="") {
    let size = theta.size()
    var cstr_line_spec = unsafe { LibC.mallocCString(line_spec) }
    let handle = unsafe { c_polarscatter_SZ_COL(theta.ptr, rho.ptr, sz.ptr, color.ptr, size, cstr_line_spec) }
    unsafe { LibC.free(cstr_line_spec) }
    return Line(handle)
}


public func testPolarScatter1() {
    let theta = linspace(Float64.getPI()/4.0, Float64.getPI()*2.0, num:8)
    let rho = vector([19.0, 6.0, 12.0, 18.0, 16.0, 11.0, 15.0, 15.0])

    polarscatter(theta, rho)
    save("./tests/imgs/polar_scatter/polarScatter_1.svg", "svg")
    clear()
}

public func testPolarScatter2() {
    let theta = linspace(0.0, 2.0 * Float64.getPI(), num:20)
    var m: Random = Random(0)
    let rho = randn(m, 20, 0.0, 1.0)
    let size = 10.0

    polarscatter(theta, rho, size, line_spec: "filled")
    save("./tests/imgs/polar_scatter/polarScatter_2.svg", "svg")
    clear()
}

public func testPolarScatter3() {
    let theta = linspace(Float64.getPI() / 4.0, 2.0 * Float64.getPI(), num: 8)
    let rho = linspace(10.0, 20.0, num:8)
    let sz = linspace(10.0, 30.0, num:8)
    let colors = vector<Float64>([1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0])

    polarscatter(theta, rho, sz, colors, line_spec: "filled")
    save("./tests/imgs/polar_scatter/polarScatter_3.svg", "svg")
    clear()
}

public func testPolarScatter4() {
    let theta = linspace(0.0, 360.0, num:50)
    let rho_deg = theta.apply({t => 0.0005 * t})
    let rho_rad = rho_deg.apply({t => t * Float64.getPI() / 180.0})

    polarscatter(theta, rho_rad)
    save("./tests/imgs/polar_scatter/polarScatter_4.svg", "svg")
    clear()
}

public func testPolarScatter5() {
    let theta = linspace(Float64.getPI() / 6.0, 2.0 * Float64.getPI(), num:12)
    var m: Random = Random(0)
    let rho = randn(m, 12, 0.0, 1.0)
    let ps = polarscatter(theta, rho, line_spec:"filled")
    ps.marker("square")
    ps.marker_size(20.0)
    ps.marker_color(0.5, 1.0, 0.0)

    save("./tests/imgs/polar_scatter/polarScatter_5.svg", "svg")
    clear()
}

public func testPolarScatter() {
    testPolarScatter1()
    testPolarScatter2()
    testPolarScatter3()
    testPolarScatter4()
    testPolarScatter5()
}