 /*!
  * Copyright (C) 2008 TENSQUARE gmbh
  */

Function.prototype.bind = function(obj) 
{
    var method = this,
    temp = function() {
        return method.apply(obj, arguments);
    };
    return temp;
}

function MapAndRoute(mapElem, op, address)
{
    var MAPTYPE_ROADMAP = 1;
    var MAPTYPE_AIR     = 2;
    var MAPTYPE_HYBRID  = 3;

    var self = this;
    
    var DEFAULT_OPTIONS =
    {
        zoom  : 15,
        x     : 419365.41064700065,
        y     : 232254.3382559999,
        width : 246,
        height: 240,
        img   : "img/map_pin.gif",
        mouseoverimg : "img/map_pin_over.gif",
        mode  : "noedit",
        projection : "LCC_EUROPE", // WGS84
        pinWidth  : 20,
        pinHeight : 33
    }

    var options = $.extend(DEFAULT_OPTIONS, op);

    var _map = new IWMap(document.getElementById(mapElem));
    var mapOptions = _map.getOptions();

    switch(options.mode)
    {
        case "edit" :
                    IWEventManager.addListener(_map, 'afterinitialized', function(){
                        _map.getLayoutManager().getLayer(0).setBorder(0, 0);
                        _map.getLayoutManager().getLayer(0).addControl(new IWNavigationControl(_map), IWAlignment.LEFT, IWAlignment.TOP, 0, 0);
                        _map.getLayoutManager().getLayer(0).addControl(new IWSliderControl(_map), IWAlignment.RIGHT, IWAlignment.TOP, 0, 0);
                    });
                    mapOptions.setDoubleClickAction(IWMapOptions.CONTROL_ZOOM);
                    mapOptions.setMouseWheelAction(IWMapOptions.CONTROL_ZOOM);
                    mapOptions.setLeftMouseAction(IWMapOptions.CONTROL_MOVE);
                    break;
        case "nothing" :
                    mapOptions.setDoubleClickAction(IWMapOptions.CONTROL_NONE);
                    mapOptions.setMouseWheelAction(IWMapOptions.CONTROL_NONE);
                    mapOptions.setLeftMouseAction(IWMapOptions.CONTROL_NONE);
                    mapOptions.setRightMouseAction(IWMapOptions.CONTROL_NONE);
                    break;
        default:
                    mapOptions.setDoubleClickAction(IWMapOptions.CONTROL_ZOOM);
                    mapOptions.setMouseWheelAction(IWMapOptions.CONTROL_ZOOM);
                    mapOptions.setLeftMouseAction(IWMapOptions.CONTROL_MOVE);
    }

    function changeMapView(e)
    {
        switch(e.item.getName())
        {
            case 'roadmap' : setMapView(MAPTYPE_ROADMAP);
                             break;
            case 'hybrid'  : setMapView(MAPTYPE_HYBRID);
                             break;
            case 'aerial'  : setMapView(MAPTYPE_AIR);
                             break;
            default : setMapView(MAPTYPE_ROADMAP);
         }
    }
	mapOptions.setSize(new IWSize(options.width, options.height));


    this.imgPinSrc = options.img;
    var pinArray = new Hash();
    var pinKeys = [];

    var geocoder = new IWGeocoderClient();
    this.geocoder = geocoder;

    this.onclick = function(event)
    {
        if (typeof self.onStartGeocoding == 'function')
        {
            self.onStartGeocoding();
        }
        /* Wandelt die Cursorposition in gültige Koordinaten und setzt Marker */
        self.addMarkerFromCoordinate(_map.fromPixelToCoordinate(event.position));
    }

    /* Nach einer Geocoding oder Reverse-Geocoding Aktion */
    this.onafterGeoAction = function(event)
    {
        if(event.results.length > 0)
        {
            var result = event.results[0];
            var address = result.getAddress();
            if(address.getCountryCode() != 'D')
            {
                if (typeof self.onNoResult == 'function')
                {
                    self.onNoResult(true);
                }
            }
            else
            {
                var x = address.getLCC().getX();
                var y = address.getLCC().getY();
                if (self.currentMarker == null)
                    {
                        self.addMarkerToMap(x,y, address);
                    }
                else
                    {
                        self.currentMarker = null;
                        self.remLastLayer();
                        self.addMarkerToMap(x,y, address);
                    }
                var ac = new AddressContainer(result);
                if (typeof self.onGeocoded == 'function')
                {
                    self.onGeocoded(ac);
                }
            }

        }
        else
        {
            if (typeof self.onNoResult == 'function')
            {
                self.onNoResult(false);
            }
        }
    }

    this.onafterGeoAction.bind(this);
    this.onclick.bind(this);

    this.registerHandler = function()
    {
        IWEventManager.clearListeners(this.geocoder, 'onclick');
        IWEventManager.clearListeners(this.geocoder, 'aftergeocoded');
        IWEventManager.clearListeners(this.geocoder, 'afterreversegeocoded');
        switch(options.mode)
        {
            case "edit" :
                IWEventManager.addListener(_map, 'onclick', this.onclick);
                IWEventManager.addListener(this.geocoder, 'afterreversegeocoded', this.onafterGeoAction);
                IWEventManager.addListener(this.geocoder, 'aftergeocoded', this.onafterGeoAction);
                break;
            default:
        }
    }


    this.initialCenter = function(event)
    {
        if(event.results.length > 0)
        {
        _map.setCenter(new IWCoordinate(event.results[0].getAddress().getLCC().getX(),
                                         event.results[0].getAddress().getLCC().getY(),
                                         address.zoom
                                        )
                       );
         this.registerHandler();
        }
        else
        {
            if (typeof self.onNoResult == 'function')
            {
                self.onNoResult(false);
            }
        }
    }

    this.addMarkerFromCoordinate = function(coordinate, projection)
    {
       if (!projection)
          projection = options.projection;
        self.geocoder.reverseGeocode(projection, coordinate, 0, 1);
    }

    this.addMarkerFromPos = function(x,y,projection)
    {
        self.addMarkerFromCoordinate(new IWCoordinate(x,y), projection);
    }

    if(address)
    {
        IWEventManager.addListener(this.geocoder, 'aftergeocoded', function(event){self.initialCenter(event)});
        this.geocoder.geocodeAddressString(address.address, 'D', 1);
        if(address.view)
        {
            switch(address.view)
            {
               case MAPTYPE_ROADMAP : _map.setMapType(_map.getOptions().getMapTypeByName('roadmap')); break;
               case MAPTYPE_AIR     : _map.setMapType(_map.getOptions().getMapTypeByName('air'));     break;
               case MAPTYPE_HYBRID  : _map.setMapType(_map.getOptions().getMapTypeByName('hybrid'));  break;
            }
        }        
    }
    else
    {
        _map.setCenter(new IWCoordinate(options.x,options.y),options.zoom);
        this.registerHandler();
    }

    /* der Marker der durch einen Mausklick gesetzt und auch verschoben werden kann */
    this.currentMarker = null;

    this.setOnGeocoded = function(onGeocoded)
    {
        this.onGeocoded = onGeocoded;
    }
    this.setOnStartGeocoding = function(onStartGeocoding)
    {
        this.onStartGeocoding = onStartGeocoding;
    }
    this.setOnNoResult = function(onNoResult)
    {
        this.onNoResult = onNoResult;
    }
    this.setOnStaticPinMouseover = function(onStaticPinMouseover)
    {
        this.onStaticPinMouseover = onStaticPinMouseover;
    }
    this.setOnStaticPinMouseout = function(onStaticPinMouseout)
    {
        this.onStaticPinMouseout = onStaticPinMouseout;
    }
    this.setOnStaticPinClick = function(onStaticPinClick)
    {
        this.onStaticPinClick = onStaticPinClick;
    }

    this.addMarkerFromAddress = function(inputAddress)
    {
        self.geocoder.geocodeAddressString(inputAddress, 'D', 1);
    }

    this.addMarkerToMap = function(x,y,address)
    {
        var layerIdx = _map.getOverlayManager().getAllOverlays().length;
        _map.getOverlayManager().getLayer(layerIdx).addOverlay(generateMarker(x,y,address));
        _map.panTo(new IWCoordinate(x,y));
    }

    this.remLastLayer = function()
    {
        var layerIdx = _map.getOverlayManager().getAllOverlays().length-1;
        return _map.getOverlayManager().removeLayer(layerIdx);
    }

    this.setMapType = function(type)
    {
        setMapView(type);
    }
    
    /*'roadmap', 'air', 'hybrid' or 'birdsview'*/
    function setMapView(type)
    {
        
        switch(type) {
        case MAPTYPE_ROADMAP:
                    if (_map.getCurrentMapType().getName() != 'roadmap') {
                        _map.setMapType(_map.getOptions().getMapTypeByName('roadmap'));
                    }
                    break;

        case MAPTYPE_AIR:
                    if (_map.getCurrentMapType().getName() != 'air') {
                        _map.setMapType(_map.getOptions().getMapTypeByName('air'));
                    }
                    break;
        case MAPTYPE_HYBRID:
                    if (_map.getCurrentMapType().getName() != 'hybrid') {
                        _map.setMapType(_map.getOptions().getMapTypeByName('hybrid'));
                    }
                    break;
        default:    if (_map.getCurrentMapType().getName() != 'roadmap') {
                        _map.setMapType(_map.getOptions().getMapTypeByName('roadmap'));
                    }
        }
        
    }

    this.getAddressFromCoord = function(coordinate)
    {    
        self.geocoder.reverseGeocode(options.projection, coordinate, 0, 1);
    }

    /*TODO: die gespeicherten Marker muessen IMMER ALS ERSTES geladen werden, sonst entstehen Probleme beim neu Erstellen und dann verschieben eines Pins */
    this.setMarkers = function(locations, zoom)
    {
        var layerIdx = _map.getOverlayManager().getAllOverlays().length-1;
		if(locations.length > 0)
		{
            var maxX = locations[0].x;
            var minX = locations[0].x;

			var maxY = locations[0].y;
            var minY = locations[0].y;

            for(var i=0;i<locations.length;i++)
			{
				_map.getOverlayManager().getLayer(layerIdx).addOverlay(generateNoDragMarker(locations[i]));
                
                if(locations[i].x > maxX)
                    maxX = locations[i].x;
                if(locations[i].y > maxY)
                    maxY = locations[i].y;
                if(locations[i].x < minX)
                   minX = locations[i].x;
                if(locations[i].y < minY)
                   minY = locations[i].y;
                
			}
            var northWest = new IWCoordinate(minX,maxY);
            var southEast = new IWCoordinate(maxX,minY);
            var markerBounds = new IWBounds(northWest,southEast);

            _map.setZoom(zoom ? zoom : _map.getBoundsZoomlevel(markerBounds));
            _map.setCenter(markerBounds.getCenter());
		}
    }

    this.setZoom = function(value)
    {
        _map.setZoom(value);
    }
    this.getZoom = function(value)
    {
        return _map.getZoom();
    }

    this.getStatus = function()
    {
        var mapType = null;
        switch(_map.getCurrentMapType().getName())
        {
            case 'roadmap' : mapType = MAPTYPE_ROADMAP; break;
            case 'air'     : mapType = MAPTYPE_AIR;     break;
            case 'hybrid'  : mapType = MAPTYPE_HYBRID;  break;
        }

        var status =
        {
            x    : _map.getCenter().getX(),
            y    : _map.getCenter().getY(),
            zoom : _map.getZoom(),
            view : mapType
        }
        return status;
    }

    this.highlightPin = function(id)
    {
        openStaticPinTooltip(pinArray.getItem(id));
    }

    this.removeTooltip = function()
    {
        _map.removeTooltip();
        for(var i=0;i<pinArray.length;i++)
        {
            changePinImage(pinArray.getItem(pinKeys[i]).ID,options.img);
        }
    }

    function AddressContainer(result) {
        var address = result.getAddress();

        this.city = address.getCity();
        if(this.city == null || this.city === undefined)
            this.city = "";

        this.street = address.getStreet();
        if(this.street == null || this.street === undefined)
            this.street = "";

        this.houseNumber = address.getHouseNumber();
        if(this.houseNumber == null || this.houseNumber === undefined)
            this.houseNumber = "";

        this.zipCode = address.getZipCode();
        if(this.zipCode == null || this.zipCode === undefined)
            this.zipCode = "";

        this.country = address.getCountry();
        this.countryCode = address.getCountryCode();
        this.lcc_x = address.getLCC().getX();
        this.lcc_y = address.getLCC().getY();
        this.wgs84_x = address.getWGS84().getX();
        this.wgs84_y = address.getWGS84().getY();

        this.getCity = function(){return this.city};
        this.getStreet = function(){return this.street};
        this.getHouseNumber = function(){return this.houseNumber};
        this.getZipCode = function(){return this.zipCode};
        this.getCountry = function(){return this.country};
        this.getCountryCode = function(){return this.countryCode};
        this.getLCC_X = function(){return this.lcc_x};
        this.getLCC_Y = function(){return this.lcc_y};
        this.getWGS84_X = function(){return this.wgs84_x};
        this.getWGS84_Y = function(){return this.wgs84_y};

    }

     function Marker(map, coordinate, address)
     {
         IWOverlay.call(this, map, coordinate);
         var container = this.getContainer();
         var img = document.createElement('img');
         this.pinAddress = address;
         this.ID = _map.getOverlayManager().getAllOverlays().length;
         container.appendChild(img);
         img.ondrag = function() { return false; };
         img.src = self.imgPinSrc;
         this.setHotspot(new IWPoint(4, 33));
         this.setDraggable(true);
     }

    function generateMarker(x,y,address)
    {
        self.currentMarker = new Marker(_map, new IWCoordinate(x,y), address);
        IWEventManager.addListener(self.currentMarker, 'afterpositionupdated',
            function(e)  
            {
                /* nach dem Verschieben wird der Marker aktualisiert */
                self.getAddressFromCoord(self.currentMarker.getCoordinate());
            }  
        );
        return self.currentMarker;
    }

    function changePinImage(id, img)
    {
        var marker = pinArray.getItem(id);
        marker.img.src = img;
    }

     function NoDragMarker(location)
     {
         var coordinate = new IWCoordinate(location.x,location.y);
         var imgPath = location.img;
         IWOverlay.call(this, _map, coordinate);
         var container = this.getContainer();
         var img      = document.createElement('img');
         this.ID      = location.id;

         this.NICK    = location.nickname;
         if(this.NICK == null || this.NICK === undefined)
            this.NICK = "";

         this.STREET  = location.street;
         if(this.STREET == null || this.STREET === undefined)
            this.STREET = "";

         this.HOUSENO = location.houseno;
         if(this.HOUSENO == null || this.HOUSENO === undefined)
            this.HOUSENO = "";

         this.ZIPCODE = location.zipcode;
         if(this.ZIPCODE == null || this.ZIPCODE === undefined)
            this.ZIPCODE = "";

         this.CITY    = location.city;
         if(this.CITY == null || this.CITY === undefined)
            this.CITY = "";
        
         this.coordinate = coordinate;

         container.appendChild(img);
         img.ondrag = function() { return false; };
         if( (imgPath) && (imgPath!=''))
            img.src = imgPath;
         else
            img.src = self.imgPinSrc;

         this.setHotspot(new IWPoint(4, 33));
         this.setDraggable(false);
         this.img = img;
     }

    function openStaticPinTooltip(marker)
    {
        changePinImage(marker.ID,options.mouseoverimg);
        _map.openTooltip(marker.getCoordinate(),'<br>'+
                                                '<b>&nbsp;Aufnahmeort</b>'+
                                                '<br>&nbsp;'+marker.STREET+'&nbsp;'+marker.HOUSENO+
                                                '<br>&nbsp;'+marker.ZIPCODE+'&nbsp;'+marker.CITY+
                                                '<br>&nbsp'
                                                );
                                                
    }

    function generateNoDragMarker(location)
    {
        var id = location.id;
        var x  = location.x;
        var y  = location.y;

        var noDragMarker = new NoDragMarker(location);

        pinKeys.push(id);
        pinArray.setItem(id,noDragMarker);
        IWEventManager.addListener(noDragMarker, 'onclick', function(){self.onStaticPinClick(id)});
        IWEventManager.addListener(noDragMarker, 'onmouseover',
            function(e)
            {
                var tmpCoord = new IWCoordinate(x,y);
                for(var i=0;i<pinArray.length;i++)
                {
                    if(tmpCoord.equals(pinArray.getItem(pinKeys[i]).coordinate))
                    {
                        var Id = pinArray.getItem(pinKeys[i]).ID;
                        self.onStaticPinMouseover(Id);
                        changePinImage(Id,options.mouseoverimg); 
                    }
                }
                openStaticPinTooltip(this);
                var listener = IWEventManager.addListener(noDragMarker.getContainer(), 'onmouseout',
                    function(e)
                    {
                        for(var i=0;i<pinArray.length;i++)
                        {
                            //alert(pinArray.getItem(pinKeys[i]).img);
                            self.onStaticPinMouseout(pinArray.getItem(pinKeys[i]).ID);
                            changePinImage(Id,options.img);
                        }
                        _map.removeTooltip();
                        IWEventManager.removeListener(listener);
                    }.iwclosure(this)
                );
            }.iwclosure(noDragMarker)
        );

        return noDragMarker;
    }

    function AddressContainerNoDrag(x,y,city,zipCode,street,nr)
    {
        this.X = x;
        this.Y = y;
        this.City = city;
        this.ZipCode = zipCode;
        this.Street = street;
        this.HouseNumber = nr;
 
        this.getCity = function(){return this.City};
        this.getStreet = function(){return this.Street};
        this.getHouseNumber = function(){return this.HouseNumber};
        this.getX = function(){return this.X};
        this.getY = function(){return this.Y};
    }

    function Hash()
    {
        this.length = 0;

        this.items = new Array();

        this.setItem = function(in_key, in_value)
        {
            var tmp_previous;
            if (typeof(in_value) != 'undefined') {
                if (typeof(this.items[in_key]) == 'undefined') {
                    this.length++;
                }
                else {
                    tmp_previous = this.items[in_key];
                }

                this.items[in_key] = in_value;
            }

            return tmp_previous;
        }

        this.removeItem = function(in_key)
        {
            var tmp_previous;
            if (typeof(this.items[in_key]) != 'undefined') {
                this.length--;
                tmp_previous = this.items[in_key];
                delete this.items[in_key];
            }

            return tmp_previous;
        }

        this.getItem = function(in_key) {
            return this.items[in_key];
        }
}


}