﻿/* TileMan.js*/
/* 2009.03.31 타일레이어 width, height한정하지 않고 구현하도록 바꾸기 완료 */

function _TileMan() {
    var tmpNumber = 0;

    var TileMan = Class.create({
        initialize: function(parent, container) {  //parent는 BaseMan, container는 this.BaseLayer
            this.container = container;
            this.parent = parent;
            this.TileLayer = WSpec.getBaseLayer(20, 'TileLayer'); //new Element('DIV');
            this.TileLayer.style.overflow = 'visible';
            this.container.appendChild(this.TileLayer);
            this.TileBuffer = null;

            this.imgHash = {};

            this.highestdepth = 10;
            this.level = WSpec.initlevel;
            this.baselon = WSpec.baselon;
            this.baselat = WSpec.baselat;
            this.minlon = WSpec.minlon;
            this.minlat = WSpec.minlat;
            this.maxlon = WSpec.maxlon;
            this.maxlat = WSpec.maxlat;

            this.divcount = WSpec.divcount; //사용안할꺼.

            this.tilesize = WSpec.tilesize;
            this.viewportwidth = WSpec.viewportwidth; //stage
            this.viewportheight = WSpec.viewportheight;
            this.slon = WSpec.slon;  //이걸 this.centerCoord로 대체해서 사용할 예정 처음 위치 이동할때만 사용
            this.slat = WSpec.slat;
            this.baseurl = WSpec.baseurl;
            this.extratile = WSpec.extratile;
            this.zero = WSpec.zero; //타일번호 구하는 zero
            this.zerolength = WSpec.zerolength; //zero의 길이

            this.centerCoord = null; 	// 움직일때 현재 중점을 저장해 둔다... (resize 처리 시 사용함)
            this.centerPixel = null; 	// 현재의 중심좌표를 픽셀로 변경해서 저장
            this.canMoveID = 0;

            this.init();
        },
        init: function() { //initialize는 변수만 선언, init는 처음에 실행할 함수들을 모아놓은 함수
            this.makeDefaultLayers();
            this.setInnerEvent();

            if (!this.TileBuffer) {
                var bufWidth = Math.ceil(this.viewportwidth / this.tilesize) + (this.extratile * 2) + 1;
                var bufHeight = Math.ceil(this.viewportheight / this.tilesize) + (this.extratile * 2) + 1;
                this.TileBuffer = new TileBufferMan(this, this.imgLayer, bufWidth, bufHeight);
            }
            var crd = new WCoord(this.slon, this.slat);
            this.drawTiles(crd);
        },

        makeDefaultLayers: function() {
            var sTileLayer = new Element('DIV');
            this.TileLayer.appendChild(sTileLayer);
            sTileLayer.style.position = 'absolute';
            sTileLayer.style.border = '0px solid yellow';
            sTileLayer.style.width = '0px';
            sTileLayer.style.height = '0px';

            if (Prototype.Browser.IE) {
                sTileLayer.unselectable = "on";
                sTileLayer.onselectstart = function() { return false; }
            } else {
                sTileLayer.style.MozUserSelect = "none";
            }

            this.sTileLayer = sTileLayer;
            var imgLayer = new Element('DIV');
            imgLayer.id = 'imgLayer';
            imgLayer.style.position = 'absolute';
            imgLayer.style.top = '0px';
            imgLayer.style.left = '0px';
            imgLayer.style.border = '0px solid blue';
            imgLayer.style.zIndex = 0;
            imgLayer.style.width = '490px';
            imgLayer.style.height = '490px';
            this.sTileLayer.appendChild(imgLayer);

            WSpec.unselect(imgLayer);
            this.imgLayer = imgLayer;
        },
        setInnerEvent: function() {
            this.TileLayer.observe('mousedown', this.startMove.bindAsEventListener(this), false);
            this.TileLayer.observe('mousemove', this.processMove.bindAsEventListener(this), false);
            this.TileLayer.observe('mouseup', this.stopMove.bindAsEventListener(this), false);
            this.TileLayer.observe('mousewheel', this.wheel.bindAsEventListener(this));

            this.TileLayer.observe('dblclick', this.dblClick.bindAsEventListener(this));
            this.TileLayer.observe('mouseover', this.mouseOver.bindAsEventListener(this));
            this.TileLayer.observe('click', this.click.bindAsEventListener(this));
            if (this.TileLayer.addEventListener) this.TileLayer.addEventListener('DOMMouseScroll', this.wheel.bindAsEventListener(this), false); //for Mozilla	

            EventMan.addListener(this.parent, 'resizeWindow', this.reDrawMap.bindAsEventListener(this));
            // Listener for IndexMapLayer
            EventMan.addListener(this.parent, 'zoomInIndexMapLayer', this.zoomIn.bindAsEventListener(this));
            EventMan.addListener(this.parent, 'zoomOutIndexMapLayer', this.zoomOut.bindAsEventListener(this));
            EventMan.addListener(this.parent, 'moveIndexMapLayer', this.setCenter.bindAsEventListener(this));

            EventMan.addListener(this.parent, 'zoomInLevelBarLayer', this.zoomIn.bindAsEventListener(this));
            EventMan.addListener(this.parent, 'zoomOutLevelBarLayer', this.zoomOut.bindAsEventListener(this));
            EventMan.addListener(this.parent, 'moveLevelBarLayer', this.setMapLevel.bindAsEventListener(this));
            EventMan.addListener(this.parent, 'panLevelBarLayer', this.pan.bindAsEventListener(this));
            EventMan.addListener(this.parent, 'onCreate2', function() { alert('dd') });
        },

        reDrawMap: function() { //resize됐을때 다시 그리는것
            //중심좌표는 고정되어 있고, 그걸 중심으로 지도 다시 그려야 함.
            this.viewportwidth = WSpec.viewportwidth;
            this.viewportheight = WSpec.viewportheight;

            //this.visibleTiles();
            this.drawTiles(this.centerCoord);
            EventMan.trigger(this, 'redrawTileLayer');

        },

        /* 내부 이벤트 */
        startMove: function(event) {
            if (!Event.isLeftClick(event)) {
                this.click(event);
                return false;
            }
            var layer = this.sTileLayer; //[this.level - 1]; 	// 현재 레벨에 해당하는 지도 레이어를 가져온다. $('tileLayer'+level);

            this.dragStartLeft = Event.pointerX(event);
            this.dragStartTop = Event.pointerY(event);

            this.centerPixel = WSpec.coordToPixel(this.centerCoord, this.level); //중심 좌표를 pixel좌표로 변환. (레이어 이동을 중심좌표로)
            WSpec.setCursorMove(layer);

            this.dragging = true;
            this.moving = false;

            if (Prototype.Browser.IE) {
                layer.setCapture();
            }

        },
        processMove: function(event) {
            //Event.stop(event);		//  버블 방지		
            if (this.dragging) {
                this.moving = true;
                var layer = this.sTileLayer; //[this.level - 1];
                this.canMoveID++;

                var centerX = this.centerPixel.x - (Event.pointerX(event) - this.dragStartLeft);
                var centerY = this.centerPixel.y + (Event.pointerY(event) - this.dragStartTop);

                var coord = new WCoord();
                coord = WSpec.pixelToLonLat(this.level, centerX, centerY);
                this.drawTiles(coord);

                WSpec.setCursorMove(this.TileLayer);
                EventMan.trigger(this, 'moveTileLayer', { "coord": coord, "level": this.level });
                Event.stop(event);
            }
        },
        stopMove: function(event) {
            var layer = this.sTileLayer; //[this.level - 1];

            if (this.dragging) {
                this.dragging = false;
                if (Prototype.Browser.IE) {
                    layer.releaseCapture();
                }
            }
            WSpec.setCursorHand(layer);
            EventMan.trigger(this, 'stopTileLayer');
            if (this.moving) {
                EventMan.trigger(this, 'onMapMove', { "coord": this.centerCoord, "level": this.level });
                this.moving = false;
            }
        },
        mouseOver: function(event) {
            var layer = this.sTileLayer; //[this.level - 1];
            WSpec.setCursorHand(layer);
        },
        click: function(event) {
            var point = WSpec.getOffsetPoint(event, this.parent.container); //windowlayer전까지의 offset포함
            var layer = this.sTileLayer; //[this.level - 1];
            var mapX = WSpec.stripPx(layer.style.left);
            var mapY = WSpec.stripPx(layer.style.top);

            //windowLayer의 클릭좌표로 sTileLayer의 클릭좌표 구하기
            var tileX = point.x - mapX;
            var tileY = mapY - point.y;

            var coord = new WCoord(); //lon,lat좌표
            coord = WSpec.pixelToLonLat(this.level, tileX, tileY);

            Event.stop(event);
            EventMan.trigger(this, 'clickTileLayer', { "point": point, "coord": coord, "button": event.button });
        },
        wheel: function(event) {
            var delta = 0;
            if (event.wheelDelta) { //for IE
                delta = event.wheelDelta / 120;
            }
            else if (event.detail) { //for Mozilla
                delta = -event.detail / 3;
            }
            if (delta) this.mapZoom(delta);

            Event.stop(event);
        },
        mapZoom: function(delta) {
            //this.canMoveID++; //플래시에는 있는
            if (delta < 0) { //확대 (wheel을 아래로 내렸을때)
                this.zoomIn();
            }
            else if (delta > 0) { //축소 (wheel을 위로 올렸을때)
                this.zoomOut();
            }
        },
        dblClick: function(event) {
            var point = WSpec.getOffsetPoint(event, this.parent.container);
            var layer = this.sTileLayer; //[this.level - 1];
            var dblx = point.x; // - this.TileLayer.style.left;
            var dbly = point.y; // - this.TileLayer.style.top;  

            var movex = (this.viewportwidth / 2) - dblx; //이동할 거리
            var movey = (this.viewportheight / 2) - dbly;

            var left = WSpec.stripPx(layer.style.left);
            var top = WSpec.stripPx(layer.style.top);

            var n = 5; 	// 1 이상
            this.canMoveID++;
            this.elapseMove(this.canMoveID, layer, left, top, left + movex, top + movey, 1 / n);

        },
        elapseMove: function(moveid, layer, sx, sy, tx, ty, rate) {
            if (moveid != this.canMoveID) return;

            // 감속 효과 (0 < rate < 1)
            var ax = (sx + (tx - sx) * rate);
            var ay = (sy + (ty - sy) * rate);

            //ax, ay의 중심좌표 구하기
            var cx = (this.viewportwidth / 2) - ax;
            var cy = ay - (this.viewportheight / 2);

            var moveCenter = new WCoord();
            moveCenter = WSpec.pixelToLonLat(this.level, cx, cy);



            if (Math.abs(tx - sx) > 0.5 || Math.abs(ty - sy) > 0.5) {
                this.elapseMove.bind(this).delay(0.001, moveid, layer, ax, ay, tx, ty, rate);
            } else {
                cx = this.viewportwidth / 2 - tx;
                cy = ty - this.viewportheight / 2;
                moveCenter = WSpec.pixelToLonLat(this.level, cx, cy);
                this.stopMove();
                EventMan.trigger(this, 'onMapMove', { "coord": moveCenter, "level": this.level });
            }
            this.drawTiles(moveCenter);
            EventMan.trigger(this, 'moveTileLayer', { "coord": moveCenter, "level": this.level });
        },
        pan: function(id) {
            var x = 0; y = 0;
            var movex = this.viewportwidth / 2;
            var movey = this.viewportheight / 2;
            switch (id) {
                case 'panleft': x = -movex; y = 0; break;
                case 'panup': x = 0; y = -movey; break;
                case 'panright': x = movex; y = 0; break;
                case 'pandown': x = 0; y = movey; break;
            }
            var level = this.getMapLevel();
            this.setLayerPosition(level, x, y);
        },
        drawTiles: function(coord) {
            this.moveTileLayer(coord); //보여지고 싶은 부분이 화면에 보여지게
            var mapX = WSpec.stripPx(this.sTileLayer.style.left);
            var mapY = WSpec.stripPx(this.sTileLayer.style.top);

            var startX = Math.floor((0 - mapX) / this.tilesize); //Math.floor(Math.abs(mapX) / this.tilesize);
            var startY = Math.floor((mapY - this.viewportheight) / this.tilesize); //Math.floor(Math.abs(mapY) / this.tilesize);

            var tilesX = Math.ceil(this.viewportwidth / this.tilesize);
            var tilesY = Math.ceil(this.viewportheight / this.tilesize);

            this.TileBuffer.drawTiles(startX - this.extratile, (startX + tilesX) + this.extratile, startY - this.extratile, (startY + tilesY) + this.extratile, this.level); 	//(afterXa, afterXb, afterYa, afterYb)
        },
        moveTileLayer: function(coord) {
            this.centerCoord = coord;
            var point = WSpec.coordToPixel(coord, this.level);
            var pxdist = point.x;
            var pydist = point.y;
            var layer = this.sTileLayer;
            layer.style.left = (this.viewportwidth / 2) - pxdist;
            layer.style.top = (this.viewportheight / 2) + pydist;
        },
        removeLayer: function(visibleTilesMap, layer) {
            //사용하지 않는 타일 제거
            var child = layer.descendants();
            var imgH = this.imgHash;
            child.each(function(value, index) {
                if (!visibleTilesMap[value.id]) {
                    layer.removeChild(value);
                    imgH[value.id] = null;
                }
            });
        },

        stringTileNum: function(num) {
            var groupNum = 0;
            var remainderNum;
            var sNum;

            //그룹, 그룹내 번호 구하기
            if (num >= 100) {
                groupNum = Math.floor(num / 100);
                remainderNum = num % 100;
            }
            else {
                remainderNum = num;
            }

            //선택된 타일의 타일번호 구하기(string번호로)
            sNum = (this.zero.substr(0, this.zerolength - groupNum.toString().length) + groupNum.toString()) + (this.zero.substr(0, this.zerolength - remainderNum.toString().length) + remainderNum.toString());
            return sNum;
        },
        getHighestDepth: function() {
            return this.highestdepth++;
        },
        /* sTileLayer에 appendChild*/
        sTileAppend: function(level, layer) {
            this.sTileLayer.appendChild(layer);
        },
        getLayerPosition: function(level) {
            var position = new WPoint();
            position.x = WSpec.stripPx(this.sTileLayer.style.left);
            position.y = WSpec.stripPx(this.sTileLayer.style.top);
            return position;
        },
        setLayerPosition: function(level, x, y) {
            //this.canMoveID = 0;
            this.canMoveID++;
            var n = 3;
            var layer = this.sTileLayer; //[level - 1];
            var left = WSpec.stripPx(layer.style.left);
            var top = WSpec.stripPx(layer.style.top);
            this.elapseMove(this.canMoveID, layer, left, top, left - x, top - y, 1 / n);
        },
        /* 위치 지정 */
        getCenter: function() {
            return this.centerCoord;
        },

        setCenter: function(coord) {
            this.drawTiles(coord);
            EventMan.trigger(this, 'moveTileLayerFromIndexMap', { "coord": coord, "level": this.level });
            EventMan.trigger(this, 'onMapMove', { "coord": coord, "level": this.level });
        },

        setCenterAndZoom: function(coord, level) {
            this.setCenter(coord);
            this.setMapLevel(level);
        },
        getBound: function() {
            var boundary = new Array();
            boundary[0] = this.getDPtoCoord(0, this.viewportheight - 1);
            boundary[1] = this.getDPtoCoord(0, 0);
            boundary[2] = this.getDPtoCoord(this.viewportwidth - 1, 0);
            boundary[3] = this.getDPtoCoord(this.viewportwidth - 1, this.viewportheight - 1);
            return boundary;
        },
        getDPtoCoord: function(x, y) {	// (x, y) : 화면상의 pixel 좌표 (baseLayer 기준)
            var layer = this.sTileLayer; //[this.level - 1];
            var mapX = WSpec.stripPx(layer.style.left);
            var mapY = WSpec.stripPx(layer.style.top);

            var X = x - mapX;
            var Y = mapY - y;
            return WSpec.pixelToLonLat(this.level, X, Y);
        },

        /* level 메소드 */
        setMapLevel: function(level) {
            this.level = level;
            this.drawTiles(this.centerCoord);
            EventMan.trigger(this, 'zoomTileLayer', this.level);
            return this.level;
        },
        getMapLevel: function() {
            return this.level;
        },
        zoomIn: function() {
            var zoom = this.getMapLevel();
            if (zoom > WSpec.minlevel) {
                this.setMapLevel(zoom - 1);
            }
            return this.level;
        },
        zoomOut: function() {
            var zoom = this.getMapLevel();

            if (zoom < WSpec.maxlevel) {
                this.setMapLevel(zoom + 1);
            }
            return this.level;
        }
    });
    window.TileMan = TileMan;
};
_TileMan();	
