// writing representations

function addRepToView(rep) {
    // a div to locate it 
    var domElem = document.createElement('div')
    // dif. color for hardwares ?
    domElem.className = 'block'
    if (rep.description.isHardware) {
        domElem.classList.add('hardware')
    }
    domElem.style.left = lastPos.x + 'px'
    domElem.style.top = lastPos.y + 'px'

    // more html: the title
    var title = document.createElement('div')
    title.className = 'modname'
    title.innerHTML = rep.description.id
    title.alt = rep.description.alt
    // MOVEABOUT CODE 
    title.onmousedown = function(evt) {
        evt.preventDefault()
        evt.stopPropagation()

        offsetX = evt.clientX - domElem.getBoundingClientRect().left
        offsetY = evt.clientY - domElem.getBoundingClientRect().top

        function domElemMouseMove(evt) {
            evt.preventDefault()
            evt.stopPropagation()
            var cT = getCurrentTransform()
            domElem.style.left = parseFloat(domElem.style.left) + evt.movementX / cT.s + 'px'
            domElem.style.top = parseFloat(domElem.style.top) + evt.movementY / cT.s + 'px'
            redrawLinks()
        }

        function rmOnMouseUp(evt) {
            rep.description.position.left = parseInt(domElem.style.left, 10)
            rep.description.position.top = parseInt(domElem.style.top, 10)
            putPosition(rep)
            document.removeEventListener('mousemove', domElemMouseMove)
            document.removeEventListener('mouseup', rmOnMouseUp)
        }

        document.addEventListener('mousemove', domElemMouseMove)
        document.addEventListener('mouseup', rmOnMouseUp)
    }
    domElem.appendChild(title)

    var uiSetFlag
    // place in pos if info present 
    // the rep.dom object will store references to the module's related DOM elements
    if (rep.description.position != null) {
        uiSetFlag = false
        if (rep.description.position.left != null) {
            domElem.style.left = rep.description.position.left + 'px'
        }
        if (rep.description.position.top != null) {
            domElem.style.top = rep.description.position.top + 'px'
        }
    } else {
        uiSetFlag = true
        rep.description.position = {}
        rep.description.position.left = lastPos.x
        rep.description.position.top = lastPos.y
    }

    if (rep.dom == null) {
        rep.dom = {}
    }

    rep.dom.domElem = domElem

    // WRITE STATE ELEMENTS 
    var stateElem = document.createElement('div')
    stateElem.className = 'state'
    rep.dom.state = {}
    for (st in rep.state) {
        var inputItem = writeStateRep(stateElem, rep, st)
        rep.dom.state[st] = inputItem
    }

    // WRITE INPUTS 
    var inElem = document.createElement('div')
    inElem.className = 'inputs'
    rep.dom.inputs = {}
    for (ip in rep.inputs) {
        var li = writeEventRep(rep, 'input', ip)
        inElem.appendChild(li)
        rep.dom.inputs[ip] = li
    }

    // WRITE OUTPUTS 
    var outElem = document.createElement('div')
    outElem.className = 'outputs'
    rep.dom.outputs = {}
    for (op in rep.outputs) {
        var li = writeEventRep(rep, 'output', op)
        outElem.appendChild(li)
        rep.dom.outputs[op] = li
    }

    // HANDLE UNIQUE UIS
    if (rep.ui != null) {
        var uiElem = document.createElement('div')
        uiElem.className = 'uidiv'
        rep.dom.ui = {}
        for (ui in rep.ui) {
            writeUiElement(uiElem, rep, ui)
        }
    }

    // APPEND TO CONTAINER
    domElem.appendChild(inElem)
    domElem.appendChild(outElem)
    domElem.appendChild(stateElem)
    domElem.appendChild(uiElem)
    var clearElem = document.createElement('div')
    clearElem.className = 'clear'
    domElem.appendChild(clearElem)

    wrapper.appendChild(rep.dom.domElem)
    if (uiSetFlag) {
        putPosition(rep)
    }
}

function writeEventRep(rep, type, key) {
    var li = document.createElement('li')
    li.innerHTML = key.toString()
    li.id = rep.id + ' ' + type + ' ' + key
    li.addEventListener('click', (evt) => {
        var ipclk = {
            rep: rep,
            type: type,
            name: key,
            evt: evt
        }
        if (verbose) console.log('EVENT HOOKUP CLK: ', key)
        evtConnectHandler(ipclk)
    })
    li.addEventListener('mouseover', (evt) => {
        if (type == 'input') {
            rep.dom.inputs[key].isHovering = true
        } else if (type == 'output') {
            rep.dom.outputs[key].isHovering = true
        }
        redrawLinks()
        li.addEventListener('mouseout', (evt) => {
            if (type == 'input') {
                rep.dom.inputs[key].isHovering = false
            } else if (type == 'output') {
                rep.dom.outputs[key].isHovering = false
            }
            redrawLinks()
        })
    })
    return li
}

function writeStateRep(container, rep, key) {
    var variable = rep.state[key]
    switch (typeof variable) {
        case 'string':
            var li = document.createElement('li')
            li.appendChild(document.createTextNode(key))
            var input = document.createElement('input')
            input.type = 'text'
            input.size = 24
            input.value = variable
            input.addEventListener('change', function() {
                rep.state[key] = input.value
                putState(rep, key)
            })
            li.appendChild(input)
            container.appendChild(li)
            return input
            break
        case 'number':
            var li = document.createElement('li')
            li.appendChild(document.createTextNode(key))
            var input = document.createElement('input')
            input.type = 'text'
            input.size = 24
            input.value = variable.toString()
            input.addEventListener('change', function(evt) {
                rep.state[key] = parseFloat(input.value)
                putState(rep, key)
            })
            li.appendChild(input)
            container.appendChild(li)
            return input
            break
        case 'boolean':
            var li = document.createElement('li')
            li.innerHTML = key + ':\t\t' + variable.toString()
            // TODO: tag align-right? 
            li.addEventListener('click', function() {
                if (rep.state[key]) {
                    rep.state[key] = false
                } else {
                    rep.state[key] = true
                }
                putState(rep, key)
            })
            container.appendChild(li)
            return li
            // TODO : return what ? 
            break
        case 'object':
            // first, handle arrays 
            if (Array.isArray(variable)) {
                var li = document.createElement('li')
                li.appendChild(document.createTextNode(key))
                var input = document.createElement('input')
                input.type = 'text'
                input.size = 24
                if (typeof variable[0] == 'number') {
                    input.value = variable.toString()
                    input.addEventListener('change', function() {
                        var arr = input.value.split(',')
                        arr.forEach(function(element, index, array) {
                            array[index] = parseFloat(element)
                        })
                        rep.state[key] = arr
                        putState(rep, key)
                    })
                    li.appendChild(input)
                    container.appendChild(li)
                    return input
                } else if (typeof variable[0] == 'string') {
                    input.value = variable.toString()
                    input.addEventListener('change', function() {
                        var arr = input.value.split(',')
                        arr.forEach(function(element, index, array) {
                            array[index] = element
                        })
                        rep.state[key] = arr
                        putState(rep, key)
                    })
                    li.appendChild(input)
                    container.appendChild(li)
                    return input
                } else if (typeof variable[0] == 'object') {
                    throw 'ERR not going to handle object arrays'
                }
            } else {
                throw 'ERR not going to handle objects in state'
            }
            break
        default:
            console.log("ERR: state walked and no reciprocal code")
    }
}

function writeUiElement(container, rep, key) {
    // pull the representation object from what we were sent 
    var ui = rep.ui[key]
    console.log('write ui', ui)
    console.log('at rep', rep)

    //import script from ui.clientPath 

    // load this thing,
    
    ui.script = document.createElement('script')
    container.appendChild(ui.script)
    // it loads and executes when this is set 
    ui.script.src = ui.clientPath 
    // events 
    
    ui.script.onerror = function(err){
        console.log('ERR from ui script', err)
    }

    ui.script.onload = function(msg){
        console.log('UI script loaded')
        // each ui script writes this function to 
        // window. (global scope) on load,
        // so we can use it now to get hooks
        registerNewModule(rep.description.id, key)
        // that function will be used to append to
        console.log('UI script hooked, having lump at', program.modules[rep.description.id].ui[key].lump)
        container.appendChild(program.modules[rep.description.id].ui[key].lump.domElem)
    }
}

// bezier utilities

var svgns = 'http://www.w3.org/2000/svg'
var svg = {}

function newBezier(x1, y1, x2, y2, highlight) {
    var bz = {}
    bz.elem = document.createElementNS(svgns, 'path')
    if (highlight) {
        bz.elem.style.stroke = '#fcd17b'
    } else {
        bz.elem.style.stroke = '#1a1a1a'
    }
    bz.elem.style.fill = 'none'
    bz.elem.style.strokeWidth = '7px'
    bz.x1 = x1
    bz.y1 = y1
    bz.x2 = x2
    bz.y2 = y2
    redrawBezier(bz)
    svg.appendChild(bz.elem)
    return bz
}

function redrawBezier(bz) {
    var bl = Math.sqrt(Math.pow((bz.x1 - bz.x2), 2) + Math.pow((bz.y1 - bz.y2), 2)) * 0.6
    var ps = 'M ' + bz.x1 + ' ' + bz.y1 + ' C ' + (bz.x1 + bl) + ' ' + bz.y1
    var pe = ' ' + (bz.x2 - bl) + ' ' + bz.y2 + ' ' + bz.x2 + ' ' + bz.y2
    bz.elem.setAttribute('d', ps + pe)
}

function modifyBezierHead(bz, x1, y1) {
    bz.x1 = x1
    bz.y1 = y1
    redrawBezier(bz)
}

function modifyBezierTail(bz, x2, y2) {
    bz.x2 = x2
    bz.y2 = y2
    redrawBezier(bz)
}

function getOutputArrow(div) {
    var x = div.offsetParent.offsetLeft + div.offsetLeft + div.clientWidth
    var y = div.offsetParent.offsetTop + div.offsetTop + div.clientHeight / 2
    var pos = {
        x: x,
        y: y
    }

    return pos
}

function getInputArrow(div) {
    var x = div.offsetParent.offsetLeft
    var y = div.offsetParent.offsetTop + div.offsetTop + div.clientHeight / 2
    var pos = {
        x: x,
        y: y
    }

    return pos
}

function newLine(x1, y1, x2, y2, stroke, dashed) {
    var ln = {}
    ln.elem = document.createElementNS(svgns, 'line')
    ln.elem.style.stroke = '#1a1a1a'
    if (dashed) {
        ln.elem.setAttribute('stroke-dasharray', '21, 7, 7, 7')
    }
    ln.elem.style.fill = 'none'
    if (stroke) {
        ln.elem.style.strokeWidth = stroke + 'px'
    } else {
        ln.elem.style.strokeWidth = '6px'
    }
    ln.x1 = x1
    ln.y1 = y1
    ln.x2 = x2
    ln.y2 = y2
    redrawLine(ln)
    svg.appendChild(ln.elem)
    return ln
}

function redrawLine(ln) {
    ln.elem.setAttribute('x1', ln.x1)
    ln.elem.setAttribute('y1', ln.y1)
    ln.elem.setAttribute('x2', ln.x2)
    ln.elem.setAttribute('y2', ln.y2)
}

function getLeftWall(div) {
    var x = div.offsetLeft + 25
    var y = div.offsetTop + 25
    var pt = {
        x: x,
        y: y
    }
    return pt
}

function getRightWall(div) {
    var x = div.offsetLeft + div.clientWidth - 25
    var y = div.offsetTop + div.clientHeight - 25
    var pt = {
        x: x,
        y: y
    }
    return pt
}