/*
 * Copyright (c) 2010, Inmite s.r.o. (www.inmite.eu). All rights reserved.
 *
 * This source code can be used only for purposes specified by the given license contract
 * signed by the rightful deputy of Inmite s.r.o. This source code can be used only
 * by the owner of the license.
 *
 * Any disputes arising in respect of this agreement (license) shall be brought
 * before the Municipal Court of Prague.
 */

/*
 * This is general Marker Overlay layer.
 *
 * It's expected to be extended by concrete implementations.
 */

var immo_map = null;
var immo_overlays = [];

/**
 * Custom overlay holding array of markers.
 *
 * This doesn't represent only one marker, but whole marker layer. All
 * included markers are rendered into one huge DIV element which is reeealy fast.
 *
 * @param overlayId Id of this overlay. Can by any custom String. Not used internally, only for external identification.
 */
function IMapMarkerOverlay(overlayId, iconId, opts) {
    // ! markers array must be filled prior to adding overlay to map (and thus calling initialize) !
    this.markers = [];

    this.overlayId = overlayId;
    this.iconId = iconId ? iconId : overlayId;

    this.initialized = false;
    this.hidden = true;
    this.renderedMarkersCnt = 0;
    this.node = null;
    this.map = null;

    this.opts = opts ? opts : {
        showDescr: true
    };

    this.loadData = function() {
        alert('not implemented');
    };

    immo_overlays[overlayId] = this;
};

// IMapMarkerOverlay is extending GOverlay.
IMapMarkerOverlay.prototype = new GOverlay();

/**
 * Initialization of this overlay.
 *
 * @param map   Map to lay overlay over.
 */
IMapMarkerOverlay.prototype.initialize = function(map) {
    this.map = map;
    immo_map = map;

    // DIV element holding all markers
    this.node = document.createElement('div');
    this.map.getPane(G_MAP_MARKER_PANE).appendChild(this.node);

    // DIV element for description of marker
    if (!$('#im_descr_'+this.overlayId)[0]) {
        var descr = document.createElement('div');
            $(descr).attr('id', 'im_descr_'+this.overlayId);
            $(descr).attr('class', 'imap_descr');
            $(descr).css('display', 'none');
//            descr.innerHTML = '<div class="top">' +
//                                '<img class="loader" src="./img/loader.gif" height="32" width="32" />' +
//                                '<div class="content">Loading...</div>' +
//                              '</div>' +
//                              '<div class="bot"></div>';
        this.map.getPane(G_MAP_FLOAT_PANE).appendChild(descr);
    }

    this.hidden = false;
    this.initialized = this.redraw(true);
};

/**
 * Redraw method have to be critically fast. Draws all markers into parent node.
 *
 * @param force If false, nothing is done.
 */
IMapMarkerOverlay.prototype.redraw = function(force) {
    if (!force || this.hidden) return false;

    // hide descr
    var descr = $('#im_descr_'+this.overlayId);
    if (descr) {
        descr.hide();
    }

    var len = this.markers.length;
    var txt = [];

    var bounds = this.extendLLBounds(this.map.getBounds());
    var zoom = this.map.getZoom();

    this.renderedMarkersCnt = 0;
    while (len--) {
        var cm = this.markers[len];
        var ll = this.getLatLng(cm);
        // don't check bounds only in bigger zooms (in zoom < 4 we are in a world view)
        if (true) { // || zoom < 4 || bounds.containsLatLng(ll)) {
            this.renderedMarkersCnt++;
            var px = this.map.fromLatLngToDivPixel(ll);
            txt.push('\n<div id="im_');
            txt.push(this.overlayId);
            txt.push(this.getId(cm));
            txt.push('" class="imap_marker ');
            txt.push(cm.suff);
            if (cm.isActive) {
//                alert('a'+this.getId(cm));
                txt.push(' active');
            }
            txt.push('" onclick="im_cl(\'');
            txt.push(this.overlayId);
            txt.push('\',\'');
            txt.push(this.getId(cm));
            txt.push('\'); return false;" style="left:');
            txt.push(px.x - 10);
            txt.push('px; top:');
            txt.push(px.y - 20);
            txt.push('px; background-image: url(\'./img/');
            txt.push(this.getCustomMarkerIcon(cm));
            txt.push('.gif\');" onmouseover="im_ds(\'');
            txt.push(this.overlayId);
            txt.push('\',\'');
            txt.push(this.getId(cm));
            txt.push('\');" onmouseout="im_dh(\'');
            txt.push(this.overlayId);
            txt.push('\',\'');
            txt.push(this.getId(cm));
            txt.push('\');"></div>');
        } else {
//            alert(this.map.getBounds()+' VS '+ll);
//            return false;
        }
    }

    this.node.innerHTML = txt.join('');

    if (this.redrawCustom) {
        this.redrawCustom(bounds, zoom);
    }

    return true;// redrawed
};

IMapMarkerOverlay.prototype.getId = function(marker) {
    return marker.id;
};

IMapMarkerOverlay.prototype.getLatLng = function(marker) {
    return new GLatLng(marker.lat, marker.lng);
};

IMapMarkerOverlay.prototype.getLatLngById = function(markerId) {
    var m = this.getMarkerById(markerId);
    if (m) {
        return this.getLatLng(m);
    } else {
        return null;
    }
};

IMapMarkerOverlay.prototype.getCustomMarkerIcon = function(marker) {
    return marker.markerIcon ? marker.markerIcon : this.iconId;
};

IMapMarkerOverlay.prototype.getMarkerById = function(markerId) {
    for (var k = 0; k < this.markers.length; k++) {
        if (this.markers[k].id == markerId) {
            return this.markers[k];
        }
    }
    return null;
};

/**
 * Hides whole overlay.
 */
IMapMarkerOverlay.prototype.hide = function() {
    this.node.style.display = 'none';
    this.hidden = true;

    // store number of rendered markers
    this.renderedMarkersCntHidden = this.renderedMarkersCnt;
    this.renderedMarkersCnt = 0;
};

/**
 * Show overlay after hiding.
 */
IMapMarkerOverlay.prototype.show = function() {
    this.node.style.display = '';
    this.hidden = false;

    // restore saved number of rendered markers
    if (this.renderedMarkersCntHidden) {
        this.renderedMarkersCnt = this.renderedMarkersCntHidden;
    } else {
        this.renderedMarkersCnt = 0;
    }
};

/**
 * Extends given GLatLngBounds so that it contains not only given square but
 * also it's surrounding half/square around.
 *
 * !! We do expected to stay in same quadrant where Czech Republic is !!
 *
 * @param latLngBounds  Original GLatLng bounds to be extended.
 */
IMapMarkerOverlay.prototype.extendLLBounds = function(latLngBounds) {
    var sw = latLngBounds.getSouthWest();
    var ne = latLngBounds.getNorthEast();

    var halfLat = (ne.lat() - sw.lat()) / 2;
    var halfLng = (ne.lng() - sw.lng()) / 2;

    return new GLatLngBounds(
        new GLatLng(
            sw.lat() - halfLat,
            sw.lng() - halfLng
        ),
        new GLatLng(
            ne.lat() + halfLat,
            ne.lng() + halfLng
        )
    );
};

IMapMarkerOverlay.prototype.getRenderedMarkersCnt = function() {
    return this.renderedMarkersCnt;
};



/*
 * ! global functions !
 * FIXME (i don't like this either :)
 */



/**
 * Description Show - shows description for given marker from given category.
 * Description element is reused over whole category.
 *
 * @param overlayId
 * @param markerId
 */
function im_ds(overlayId, markerId, fromList) {
    if (immo_overlays[overlayId] && immo_overlays[overlayId].markerClicked) {
        immo_overlays[overlayId].markerOver(markerId, fromList);
    }
}

/**
 * Description Hide - hides description for given category.
 *
 * @param overlayId
 */
function im_dh(overlayId, markerId, fromList) {
    if (immo_overlays[overlayId] && immo_overlays[overlayId].markerClicked) {
        immo_overlays[overlayId].markerOut(markerId, fromList);
    }
}

/**
 * Marker clicked.
 *
 * @param overlayId ID of overlay
 * @param markerId      ID of marker within overlay
 */
function im_cl(overlayId, markerId, fromList) {
    if (immo_overlays[overlayId] && immo_overlays[overlayId].markerClicked) {
        immo_overlays[overlayId].markerClicked(markerId, fromList);
    }
}
