function TextMark(man,id,span,zoneid) {
    this.manager = man ;
    this.id = id ;
    this.span = span  ;
    this.zoneid = zoneid ;
    
    this.over = false ;
    this.selected = false ; 
}

TextMark.prototype.highlight = function() {
    this.span.className = 
        (this.manager.editable ? 'text_mark ' : 'text_mark_invisible ') +
        (this.over ? 'text_mark_over ' : '') + 
        (this.selected ? 'text_mark_selected ' : '') ;
}

TextMark.prototype.addHandlers = function(instance) {
    var tm = this ;
    this.span.onmouseover = function(evt) {
        tm.over = true ;
        tm.highlight() ;
        instance.fireSelection(tm,'over',tm.zoneid) ;
    }
    this.span.onmouseout = function(evt) {
        tm.over = false ;
        tm.highlight() ;
        instance.fireSelection(tm,'out',tm.zoneid) ;
    }
    this.span.onclick = function(evt) {
        if(!instance.editable) {
            instance.selectOver() ;
        } else if(!tm.selected) {
            instance.clearSelection(true) ;
            tm.selected = true ; 
            tm.highlight() ;
            instance.fireSelection(tm,'selected',tm.zoneid) ;
        }
    }
}

function TextSelectionManager() {
    
    var instance = this ;
    
    this.editable = false ;
    this.listenersList = new Array() ;
    
    this.marks = new Array() ;
    
    this.blinkCounter = 0 ;
    
    this.getCharPosition=(function() {
        
        function getSel() {
            var sel=null ;
            if(typeof document.selection!="undefined" && document.selection && document.selection.type=="Text") {
                sel=document.selection ;
            } else if(window.getSelection && window.getSelection().rangeCount>0) {
                sel=window.getSelection() ;
            }
            return sel ;
        }
        
        function createRangeFromSel(sel) {
            var rng=null;
            if(sel.createRange) {
                rng=sel.createRange() ;
            } else if(sel.getRangeAt) {
                rng=sel.getRangeAt(0) ;
                if(rng.toString()=="")
                    rng=null;
            }
            return rng;
        }
        
        return function(evt) {
        
            evt = evt ? evt : window.event ;

            var el = instance.rootElement ;
            
            instance.start = -1 ;
            instance.end = -1 ;
            
            var sel=getSel(), rng, r2, ret=null ;
            if(sel) {
                
                rng=createRangeFromSel(sel);
                if(rng){
                    
                    //IE
                    if(rng.parentElement) {
                        
                        r2=document.body.createTextRange();
                        r2.moveToElementText(el);
                        r2.collapse(true);
                        r2.setEndPoint("EndToStart", rng);
                        var s = new String(r2.text) ;
                        var re = new RegExp("\r\n","g") ;
                        instance.start = s.replace(re,'').length ;
                        instance.end = instance.start + rng.text.replace(re,'').length ;
                        
                    //Firefox
                    } else {
                        
                        instance.computeSelectionRangesFirefox(rng) ;
                        
                    }
                }
                
            }
            
            //clear&fire solo se no selez
            if(instance.end-instance.start==0)
                instance.selectOver() ;
            
            return ret ;//non impostato e non usato per ora
        } ;
        
    }) () ;
    
}

TextSelectionManager.prototype.setLayer = function(layer) {
    
    this.start = -1 ;
    this.end = -1 ;
    this.rootElement = layer ;

    this.marks = new Array() ;

    this.parseMarks() ;

    this.refreshHandlers(layer) ;
}

TextSelectionManager.prototype.refreshHandlers = function(layer) {
    if(layer) {
        if(this.editable) {
            layer.onmouseup=this.getCharPosition ;
            layer.onmousedown=function() {
                if(layer.normalize)
                    layer.normalize() ;
            }
        } else {
            layer.onmouseup = null ;
            layer.onmousedown = null ;
        }
        this.refreshSelections() ;
    }
}

TextSelectionManager.prototype.setEditable = function(editable) {
    if(this.editable!=editable) {
        this.editable = editable ;
        this.editableChanged = true ;
        this.clearSelection() ;
        this.refreshHandlers(this.rootElement) ;
    }
}
    
TextSelectionManager.prototype.parseMarks = function() {
    var spans = this.rootElement.getElementsByTagName("span") ;
    var i ;
    var instance = this ;
    for(i=0;i<spans.length;i++) {
        var span = spans[i] ;
        if(span.className == "text_mark") {
            var id = span.id ;
            var zid = 0 ;
            var name = span.getAttribute("name") ;
            if(name && name.substring(0,1)=='z')
                zid = parseInt(name.substring(1)) ;
            var tm = new TextMark(instance,id,span,zid) ;
            tm.addHandlers(instance) ;
            this.marks.push(tm) ;
        }
    }
}

TextSelectionManager.prototype.getSelectedMarks = function() {
    var ret = new Array() ;
    var i ;
    for(i=0;i<this.marks.length;i++)
        if(this.marks[i].selected)
            ret.push(this.marks[i]) ;
    return ret ;
}

TextSelectionManager.prototype.selectOver = function() {
    var i ;
    if(this.editable) {
        for(i=0;i<this.marks.length;i++) {
            var m = this.marks[i] ;
            if(m.over) {
                if(!m.selected) {
                    m.selected = true ;
                    m.highlight() ;
                    this.fireSelection(m, "selected", m.zoneid) ;
                }
            } else {
                if(m.selected) {
                    m.selected = false ;
                    m.highlight() ;
                    this.fireSelection(m, "deselected", m.zoneid) ;
                }
            }
        }
        //alert(this.getSelectedMarks()) ;
    } else {
        for(i=0;i<this.marks.length;i++) {
            var m = this.marks[i] ;
            if(m.over)
                this.fireSelection(m, "links", m.zoneid) ;
        }
    }
}

TextSelectionManager.prototype.clearSelection = function() {
    var i ;
    for(i=0;i<this.marks.length;i++) {
        var m = this.marks[i] ;
        if(m.selected) {
            m.selected = false ;
            m.highlight() ;
            this.fireSelection(m, "deselected", m.zoneid) ;
        }
    }
}
    
/** Seleziona la marcatura secondo l'evento passato e rllancia un'evento! */
TextSelectionManager.prototype.highlightByZone = function(source,evtType,zid) {
    //this.clearSelection() ;
    if(zid) {
        var i ;
        for(i=0;i<this.marks.length;i++) {
            var m = this.marks[i] ;
            if(m.zoneid==zid) {
                switch(evtType) {
                    case 'out':       m.over = false ;      break ;
                    case 'over':      m.over = true ;       break ;
                    case 'deselected':m.selected = false ;  break ;
                    case 'selected':  m.selected = true ;   break ;
                }
                m.highlight() ;
                if(m!=source)
                    this.fireSelection(source, evtType, zid) ;
            }
        }
    }
}

TextSelectionManager.prototype.computeSelectionRangesFirefox = function(rng) {
    
    var stack = new Array() ;
    stack.push(this.rootElement) ;
    
    var ended = false ;
    var started = false ;
    this.start = 0 ;
    var length = 0 ;
    
    var c1 = rng.startContainer ;
    var c2 = rng.endContainer ;
    
    var re = new RegExp("\n","g") ;
    
    while(stack.length) {
        
        var el = stack.pop() ;
        if(el.nodeType==3) {
            
            var s = new String(el.nodeValue).replace(re,"") ;
            
            if(el==c2) {
                
                length += started ? rng.endOffset : rng.endOffset-rng.startOffset ;
                //alert("C2: "+length) ;
                ended = true ;
                
            } else if(started && !ended) {
                
                length += s.length ;
                //alert("!C2: "+length) ;
                
            }
            
            if(el==c1) {
                
                started = true ;
                this.start += rng.startOffset ;
                if(el!=c2)
                    length += s.length - rng.startOffset ;
                
            }

            if(!started)
                this.start += s.length ;
            
        }
        
        var i ;
        for(i=el.childNodes.length-1;i>=0;i--)
            stack.push(el.childNodes.item(i)) ;
        
    }
    
    this.end = this.start+length ;
    
}

TextSelectionManager.prototype.blink = function(man) {
    if(!man.blinkStopper)
        if(man.blinkCounter<7) {
            man.blinkCounter++ ;
            man.editable = man.blinkCounter%2 == 0 ;
            man.highlight() ;
            window.setTimeout(man.blink,125,man) ;
        } else {
            man.blinkCounter = 0 ;
            man.editable = false ;
            man.highlight() ;
        }
    man.blinkStopper = false ;
}

TextSelectionManager.prototype.highlight = function() {
    var i ;
    for(i=0;i<this.marks.length;i++)
        this.marks[i].highlight() ;
}

TextSelectionManager.prototype.refreshSelections = function() {
    this.blinkStopper = false ;
    if(!this.editable)
        window.setTimeout(this.blink,500,this) ;
    else {
        this.highlight() ;
        if(this.blinkCounter)
            this.blinkStopper = true ;
    }
}

TextSelectionManager.prototype.addSelectionListener = function(listener) {
    this.listenersList.push(listener) ;
}

TextSelectionManager.prototype.fireSelection = function(source,evtType,id) {
    var i ;
    for(i=0;i<this.listenersList.length;i++)
        this.listenersList[i](source,evtType,id) ;
}

/*TextSelectionManager.prototype.selectByName = function(name) {
    var spans = this.rootElement.getElementsByTagName("span") ;
    var i ;
    for(i=0;i<spans.length;i++) {
        if(spans[i].getAttribute("name") == name)
            spans[i].className = "text_selection" ;
        else
            spans[i].className = "text_mark" ;
    }
}*/
