Interval.prototype = new Controller
Interval.prototype.constructor = Interval
Interval.prototype.super = Controller

function Interval(title, panel, nester, parent) {
    this.super.apply(this, arguments)

    this.min = 0
    this.max = 1

    this.board.set_slider(this.Controller)
    this.board.create_view("pointset", () => {
            this.nester.canvas.mark(
                this.get_active_data().points_at(this.get_active_pointset())
            )
    })
    this.board.create_view("vector", () => {
            var vector = this.get_active_vector()
            this.nester.canvas.view_in_place(vector[0], vector[1])
    })
    this.board.create_view("contour", () => {
            var res = this.get_active_contour()
            this.nester.canvas.encircle(res, res.r)
            this.nester.canvas.mark(res)
    })

    this.board.add_view("vector", "normal", null)
    this.board.add_view("vector", "tangent", null)

    this.board.add_action("walk", {
        step_distance: [0.05, 0.05, 0.01, 2]
    })

    /************* Punch *************/
    var contu
    var prad = [8.5, 0.05, 0.01, 2]
    prad.listeners = { change: (function (that){
        return function () {
            contu.argval[0].value = this.value
        }
    })(this) }
    var p = this.board.add_action("punch", {
        radius: prad,
        max_peek: [0.5, 0.005, 0.001, 0.2]
    })

    /*********** Contour ***********/
    var radius = [8.5, 0.05, 0.01, 2]
    radius.listeners = { change: (function (that){
        return function () {
            that.contour.radius = Number(this.value)
        }
    })(this) }
    var interi = [false]
    interi.listeners = { change: (function (that){
        return function () {
            that.contour.interior = this.checked
        }
    })(this) }

    this.contour_r = contu = this.board.add_action("contour", {
            radius: radius,
            interior: interi
        })

    /************* Evolute *************/
    var colors = ["#ccf", "#0071b8"]
    var color_n = 0
    this.evolute_bttn = this.board.add_action("evolute", {
        click: () => {
            var c = colors[ color_n++ % 2 ]
            this.evolute_bttn.button.style.backgroundColor = c
        }
    })

    this.contour = {interior: false, radius: 8.5}
}


Interval.prototype.cast = function(action, result) {

    switch (action) {
        case "walk":
            this.board.add_view("pointset", "walk", result)
            break
        case "punch":
            this.board.add_view("pointset", "punch", result)
            break
        case "contour":
            this.board.add_view("contour", "result", result)
            break
        case "evolute":
            var name = "evolute_" + this.title.underscore ()
            if (this.canvas_view[name])
                delete this.canvas_view[name]
            else
                this.canvas_view[name] = () => { 
                this.nester.canvas.view (this.get_active_data().evolute_at(this.get_active_pointset())) 
            }
            this.nester.cast("canvas_update")
            break
    }
    this.board.update_info(this.info())
    this.parent.cast("update_info")
    this.nester.cast("canvas_change")
}

Interval.prototype.mask = function(pointset_idx) {
    pointset_idx = pointset_idx.slice(0) /* Clone array */
    var i
    var data = this.get_active_data().p
    var len = data.S[data.S.length - 1]
    var from = this.range.lo * len
    var until = this.range.hi * len
    var start, end
    for (i = 0; data.S[i] < from && i < data.S.length; i++);
    start = i
    for (i = start; data.S[i] < until && i < data.S.length; i++);
    end = i
    while (pointset_idx[0] < start)
        pointset_idx.shift()
    for (i = 0; pointset_idx[i] < end && i < pointset_idx.length; i++);

    return pointset_idx.slice(0, i)

}

Interval.prototype.get_active_data = function() {
    return this.parent.get_active_data()
}

Interval.prototype.get_active_pointset = function() {
    if (this.active_pointset == "none" || !this.item.pointset[this.active_pointset])
        return []

    return this.mask(this.item.pointset[this.active_pointset].fx_data)
}

Interval.prototype.total_active_points = function () {
    return this.get_active_pointset().length
}

Interval.prototype.info = function () {
    var curve = this.get_active_data()
    var ap = this.get_active_pointset ()
    var distance = curve.p.S[ap[ap.length-1]] - curve.p.S[ap[0]]
    distance = parseInt (100 * distance) / 1000
    return { distance: distance, points: this.total_active_points() }
}

Interval.prototype.get_active_contour = function() {
    if (this.active_contour == "none" || !this.item.contour[this.active_contour])
        return []

    var data = this.get_active_pointset()
    var curv = this.get_active_data()
    if (this.active_contour != "result")
        return
    try {
        var res = []
        var interior = this.contour.interior ? 1 : -1
        var radius = this.contour.radius
        res.r = this.contour.radius
        for (var i = 0; i < data.length; i++)
            res.push(Vector.add(curv.p.p[data[i]], Vector.mul(interior * this.contour.radius, curv.n.p[data[i]])))
    } catch (e) {}

    res.shift()
    return res
}


Interval.prototype.get_active_vector = function() {
    if (this.active_vector == "none") // || !this.item [this.active_vector])
        return [
        [],
        []
    ]
    var active_set = this.get_active_data().points_at(this.get_active_pointset())
    var indices = []

    var j = 0
    var better_profile = this.get_active_data()
    if (active_set.p && active_set.p.S)
        for (var i = 0; i < active_set.p.S.length; i++) {
            while (active_set.p.S[i] > better_profile.p.S[j])
                j++;
            indices.push(j)
        } else
            for (var i = 0; i < active_set.length; i++) {
                while (active_set[i][0] != better_profile.p.p[j][0] ||
                    active_set[i][1] != better_profile.p.p[j][1])
                    j++;
                indices.push(j)
            }
    var vec = []
    var k = this.nester.canvas.width / this.nester.canvas.scale / 3
    for (var i = 0; i < indices.length; i++)
        vec.push(Vector.mul(k, better_profile[this.active_vector.charAt(0)].p[indices[i]]))
    if (active_set.p && active_set.p.p)
        active_set = active_set.p.p

    return [active_set, vec]
}
