


//----------------------------------------------------------
var smtMap=Class.create();
Object.extend(smtMap.prototype,EventDispatcher.prototype);
Object.extend(smtMap.prototype,{
    initialize:function(obj){
        Object.extend(this,{src:obj});
        this.dragHandle=new Draggable(this.src);

        this.markers=new smtMap.markers();
        with(this.markers){
            addEventListener("onMarkerAppend",this);
            addEventListener("onMarkerRemove",this);
        }

        this.layers=new smtMap.layers();
        this.layers.addEventListener("onLayerLoaded",this);

        this.sequence=new smtMap.sequence();
        this.sequence.addEventListener("afterSequence",this);

        with(this){
            addEventListener("beforeMove",markers);
            addEventListener("afterMove",markers);
            addEventListener("beforeZoom",markers);
            addEventListener("afterZoom",markers);
            addEventListener("beforeZoom",layers);
            addEventListener("afterZoom",layers);
        }
    },
    hide:function(){ Element.hide(this.src); },
    show:function(){ Element.show(this.src); },
    zoomIn :function(){ with(this){zoomTo(markers.current,layers.above());} },
    zoomOut:function(){ with(this){zoomTo(markers.current,layers.below());} },
    zoomTo:function(pos,nextLayer){
        if(!nextLayer) return;
        if(!pos) pos={src:{offsetLeft:this.layers.current.width/2,offsetTop:this.layers.current.height/2}};
        var scale=Math.round((nextLayer.width/this.layers.current.width)*1000)/10;
        with(this){
            sequence.append(zoomMotion(pos,scale,nextLayer));
            dispatchEvent({type:"beforeZoom"},pos,scale);
            afterSequence=function(){afterZoom(pos,scale,nextLayer);};
            sequence.start();
        }
    },
    zoomMotion:function(pos,scale,nextLayer){
        var base=this;
        var foo=[pos.src.offsetLeft,pos.src.offsetTop];
        var moo=[(foo[0]-(foo[0]*(scale/100))),(foo[1]-(foo[1]*(scale/100)))];
        return Object.extend({
            start:function(){
                this.dispatchEvent({type:"beforeAction"},this);
                return new Effect.Parallel([
                    new Effect.Scale(base.src,scale,{scaleContent:false}),
                    new Effect.MoveBy(base.src,moo[1],moo[0])
                ],{afterFinish:function(){
                    base.changeLayer(nextLayer);
                    this.dispatchEvent({type:"afterAction"},this);
                }.bind(this)});
            }
        },EventDispatcher.prototype);
    },
    afterZoom:function(obj,scale,next){
        this.dispatchEvent({type:"afterZoom"},obj,scale,next);
    },
    reset:function(){ with(this){moveTo(markers[0]);} },
    move :function(){ with(this){moveTo.apply(this,markers.getRange(arguments[0]));} },
    back :function(){ with(this){move(markers.prev());} },
    next :function(){ with(this){move(markers.next());} },
    moveTo:function(){
        if(arguments.length==0) return;
        with(this){
            var pos=$A(arguments);
            pos.each(function(a){sequence.append(moveMotion(a));}.bind(this));
            dispatchEvent({type:"beforeMove"});
            afterSequence=function(){afterMove(pos.last());};
            sequence.start();
        }
    },
    moveMotion:function(pos){
        var base=this;
        var target=this.layers.current;
        var offset=Position.cumulativeOffset(pos.src);
        with(this.src.parentNode){ var center=[offsetWidth/2,offsetHeight/2]; }
        return Object.extend({
            start:function(){
                this.dispatchEvent({type:"beforeAction"},this);
                return new Effect.MoveBy(base.src,center[1]-offset[1],center[0]-offset[0],
                    {duration:0.5,afterFinish:function(){this.dispatchEvent({type:"afterAction"},this);}.bind(this)}
                );
            }
        },EventDispatcher.prototype);
    },
    beforeMove:function(obj){
        this.dispatchEvent({type:"beforeMove"},obj);
        Draggables.unregister(this.dragHandle);
    },
    afterMove:function(obj){
        //Draggables.register(this.dragHandle);
        this.dispatchEvent({type:"afterMove"},obj);
    },
    afterSequence:function(){},
    onLayerLoaded:function(obj){ this.changeLayer(obj); },
    changeLayer:function(obj){
        with(Element){
            (new ClassNames(this.src)).set(obj.className);
            update(this.src,obj.src);
            setStyle(this.src,{width:obj.width+"px",height:obj.height+"px"});
        }
        this.markers.refresh();
    },
    onMarkerAppend:function(obj){
        with(obj){
            addEventListener("onMarkerClick",this);
            addEventListener("onMarkerDblClick",this);
            this.src.appendChild(src);
            show();
        }
    },
    onMarkerRemove:function(obj){
        with(obj){
            removeEventListener("onMarkerClick",this);
            removeEventListener("onMarkerDblClick",this);
            this.src.removeChild(src);
            remove();
        }
    },
    onMarkerClick   :function(){ this.markers.focus(arguments[0]); },
    onMarkerDblClick:function(){ this.move(arguments[0]); }
});

//----------------------------------------------------------
smtMap.Navigation=Class.create();
Object.extend(smtMap.Navigation.prototype,EventDispatcher.prototype);
Object.extend(smtMap.Navigation.prototype,{
    initialize:function(obj,target){
        Object.extend(this,{src:obj,target:target});
        new Draggable(this.src);
        ["reset","next","prev","zoomIn","zoomOut"].each(function(a){
            this[a]=function(){target[a]();};
        }.bind(this));
    },
    change:function(obj){ this.target=obj; }
});


//----------------------------------------------------------
smtMap.Info=Class.create();
Object.extend(smtMap.Info.prototype,EventDispatcher.prototype);
Object.extend(smtMap.Info.prototype,{
    initialize:function(obj){ this.src=obj; },
    place:function(obj){
        var temp=Position.cumulativeOffset(obj.src);
        Element.setStyle(this.src,{left:(temp[0]+24)+"px",top:(temp[1]+24)+"px"});
    },
    open:function(obj){
        with(Element){
            show(this.src);
            if(obj) update(this.src,obj);
        }
    },
    exit:function(){
        with(Element){
            //update(this.src,"");
            hide(this.src);
        }
    },
    beforeMove:function(obj){ this.exit(); },
    beforeZoom:function(obj){ this.exit(); },
    afterZoom:function(obj,scale){ with(this){ place(obj); open(); } }
});


//----------------------------------------------------------
smtMap.Marker=Class.create();
Object.extend(smtMap.Marker.prototype,EventDispatcher.prototype);
Object.extend(smtMap.Marker.prototype,{
    initialize:function(obj){
        this.src=this.create(obj);
        this.point(obj);
        with(this){
            src.onclick=singleClick.bindAsEventListener(this);
            src.ondblclick=doubleClick.bindAsEventListener(this);
            deactivate();
        }
    },
    singleClick:function(e){
        Event.stop(e||event);
        this.dispatchEvent({type:"onMarkerClick"},this);
    },
    doubleClick:function(e){
        Event.stop(e||event);
        this.dispatchEvent({type:"onMarkerDblClick"},this);
    },
    hide:function(){ Element.hide(this.src); },
    show:function(){ Element.show(this.src); },
    write:function(str){
        this.src.getElementsByTagName("a")[0].innerHTML=str;
    },
    create:function(style){
        var obj=document.createElement("div");
        with(Element){
            addClassName(obj,"marker");
            update(obj,"<a></a><span class=\"label\"></span>");
            setStyle(obj,style);
        }
        Element.setStyle(obj,{"position":"absolute","display":"block"});
        return obj;
    },
    point:function(pos,scale){
        if(pos) Object.extend(this,{x:pos.x,y:pos.y});
        if(!this.x) return;
        var temp=(scale||1);
        with(this){
            x*=temp; y*=temp;
            Element.setStyle(src,{left:x+"px",top:y+"px"});
        }
    },
    remove:function(){
        with(this){
            if((!src)||(!src.parentNode)) return;
            return src.parentNode.removeChild(src);
        }
    },
    beforeZoom:function(obj,scale){},
    afterZoom:function(obj,scale){},
    setLabel:function(str){
        this.label=str;
        Element.update(document.getElementsByClassName("label",this.src)[0],str);
    },
    detail:function(){
        this.dispatchEvent({type:"open"});
    },
    activate:function(){
        with(Element){
            removeClassName(this.src,"inactive");
            addClassName(this.src,"active");
            setStyle(this.src,{"z-index":"9999"});
        }
        this.dispatchEvent({type:"onMarkerActivate"},this);
if(this.openInfo) this.openInfo();
        return this;
    },
    deactivate:function(){
        with(Element){
            removeClassName(this.src,"active");
            addClassName(this.src,"inactive");
            setStyle(this.src,{"z-index":"99"});
        }
        this.dispatchEvent({type:"onMarkerDeactivate"},this);
if(this.exitInfo) this.exitInfo();
        return this;
    }
});



//----------------------------------------------------------
smtMap.markers=Class.create();
Object.extend(smtMap.markers.prototype,EventDispatcher.prototype);
Object.extend(smtMap.markers.prototype,{
    initialize:function(){ this.src=[]; },
    refresh:function(){
        this.src.each(function(a){this.dispatchEvent({type:"onMarkerAppend"},a);}.bind(this));
    },
    focus:function(obj){
        if(this.current) this.current.deactivate();
        this.current=obj.activate();
    },
    next:function(){
        with(this){ return (src.slice(src.indexOf(current)+1))[0]; }
    },
    prev:function(){
        with(this){ return (src.slice(0,src.indexOf(current)).reverse())[0]; }
    },
    append:function(obj){
        if(!obj) return;
        this.src.push(obj);
        obj.addEventListener("onMarkerActivate",this);
        return obj;
    },
    remove:function(obj){
        if(!obj) return;
        with(this){
            src.splice(src.indexOf(obj),1);
            dispatchEvent({type:"onMarkerRemove"},obj);
        }
        return obj;
    },
    getRange:function(obj){
        with(this){ var range=[src.indexOf(current||src.first()),src.indexOf(obj)]; }
        var len=range[1]-range[0];
        var temp=(len>=0);
        var start=range[!temp?1:0];
        return this.src.slice(start,Math.abs(len)+start+temp)[!temp?"reverse":"slice"]();
    },
    findByTitle:function(str){
        return this.src.find(function(a){return((a.title||".")==str);});
    },
    show:function(){ this.src.each(function(a){a.show();}); },
    hide:function(){ this.src.each(function(a){a.hide();}); },
    beforeMove:function(){ this.hide(); },
    afterMove :function(){ with(this){ show(); focus(arguments[0]); } },
    beforeZoom:function(){ this.hide(); },
    afterZoom:function(obj,scale){
        with(this){
            src.each(function(a){a.point(null,scale/100);});
            show();
        }
    },
    onMarkerActivate:function(obj){}
});



//----------------------------------------------------------
smtMap.Layer=Class.create();
Object.extend(smtMap.Layer.prototype,EventDispatcher.prototype);
Object.extend(smtMap.Layer.prototype,{
    initialize:function(parameter){
        Object.extend(this,parameter);
        this.src="";
        if(this.url) this.load();
    },
    load:function(){
        new Ajax.Request(this.url+"?dummy="+Math.floor(Math.random()*2000),{
            method:"get",
            onComplete:function(obj){
                this.src=obj.responseText;
                this.dispatchEvent({type:"onLayerLoad"},this);
            }.bind(this)
        });
    }
});



//----------------------------------------------------------
smtMap.layers=Class.create();
Object.extend(smtMap.layers.prototype,EventDispatcher.prototype);
Object.extend(smtMap.layers.prototype,{
    initialize:function(){ this.src=[]; },
    append:function(obj){
        if(!this.current) this.current=obj;
        obj.level=this.src.push(obj)-1;
        obj.addEventListener("onLayerLoad",this);
    },
    onLayerLoad:function(obj){
        if(this.current!=obj) return;
        this.dispatchEvent({type:"onLayerLoaded"},obj);
    },
    above:function(){ with(this){return src[current.level+1];} },
    below:function(){ with(this){return src[current.level-1];} },
    focus:function(obj){ this.current=obj; },
    beforeZoom:function(){},
    afterZoom:function(pos,scale,nextLayer){ this.focus(nextLayer); }
});

//----------------------------------------------------------
smtMap.sequence=Class.create();
Object.extend(smtMap.sequence.prototype,EventDispatcher.prototype);
Object.extend(smtMap.sequence.prototype,{
    initialize:function(){ this.src=[]; },
    beforeStart:function(){ this.dispatchEvent({type:"beforeAction"},this); },
    afterFinish:function(){ this.dispatchEvent({type:"afterAction"},this); },
    append:function(obj){
        this.src.push(obj);
        obj.addEventListener("afterAction",this);
        return obj;
    },
    start:function(){
        with(this){
            dispatchEvent({type:"beforeSequence"});
            return src.first().start();
        }
    },
    finish:function(){
        with(this){
            src.each(function(a){a.removeEventListener("afterAction",this);}.bind(this));
            src.clear();
            dispatchEvent({type:"afterSequence"});
        }
    },
    afterAction:function(obj){
        with(this){ var temp=src[src.indexOf(obj)+1]; }
        if((!obj)||(!temp)) return this.finish();
        temp.start();
    }
});





