String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g,""); }
String.prototype.ltrim = function() { return this.replace(/^\s+/,""); }
String.prototype.rtrim = function() { return this.replace(/\s+$/,""); }

var gShopFinder_ResolveAddressError = 'Cannot resolve address';
var gShopFinder_ValidLocationError = 'Provide a valid location';
var gShopFinder_InvalidCityName = 'Provide a valid city';
var gShopFinder_InvalidShopName = 'Provide a valid shop';
var gShopFinder_InvalidZipCode = 'Provide a valid zip code';
var gShopFinder_InvalidStreetName = 'Provide a valid street';

var AcoatGManager = function(parm)
{
    var p = this;

    this.mapID = parm.mapID;
    this.streetID = parm.streetID;
    this.locationID = parm.locationID;
    this.zipID = parm.zipID;
    this.distanceID = parm.distanceID;
    this.unitID = parm.unitID;
    this.lnkID = parm.lnkID;
    this.searchID = parm.searchID;
    this.gLat = this.currentLat = parm.gLat;
    this.gLong = this.currentLong = parm.gLong;
    this.gZoom = this.currentZoom = parm.gZoom;
    this.markers = parm.markers;
    this.hdnID = parm.hdnID;
    this.popupTemplateID = parm.popupTemplateID;
    this.countryID = parm.countryID;
    this.shopNameID = parm.shopNameID;

    this.initParms = parm;

    this.ID = "AcoatGManager_" + this.mapID;

    document[this.ID] = this;

    this.map = null;
    this.geocoder = null;
    this.markerManager = null;
    this.isLoading = false;

    this.AddEvent (window, 'load', function() { p.OnWindowLoad(); });
    this.AddEvent (window, 'unload', function() { GUnload(); });
}

AcoatGManager.prototype.GetScriptInstance = function() { return 'document["' + this.ID + '"]'; }
AcoatGManager.prototype.GetScriptInstanceFromMapID = function(mapID) { return 'document["AcoatGManager_' + mapID + '"]'; }

AcoatGManager.GetInstanceFromMapID = function (mapID) { return document["AcoatGManager_" + mapID]; }

AcoatGManager.prototype.OnWindowLoad = function ()
{
    this.CreateMap ();
    this.SetMapEvents ();
    this.SetMarkers ();
    this.SetSearchHref();
};

AcoatGManager.prototype.ShowMarkerPopup = function (markerIdx)
{
    if (this.markers == null) return;
    if (markerIdx < 0 || markerIdx >= this.markers.length) return;

    this.markers[markerIdx].showPopup();
};

AcoatGManager.prototype.CreateMap = function ()
{
    if (GBrowserIsCompatible()) 
    {
        this.geocoder = new GClientGeocoder();
        this.map = new GMap2(document.getElementById(this.mapID));

        this.CorrectZoom();
        this.map.setCenter(new GLatLng(this.gLat, this.gLong), this.gZoom);

        this.map.addControl(new GSmallMapControl());
        this.map.addControl(new GScaleControl());
        //this.map.setUIToDefault();
        
        this.markerManager = new MarkerManager(this.map);
    }
}

AcoatGManager.prototype.CorrectZoom = function ()
{
    if (this.initParms && this.initParms.boxNorth)
    {
        var box = { north:this.initParms.boxNorth, south: this.initParms.boxSouth, east: this.initParms.boxEast, west: this.initParms.boxWest };
        var bounds = this.GetBoundsFromBox (box);
        var zoom = this.map.getBoundsZoomLevel(bounds);
        if (zoom < this.gZoom) this.gZoom = zoom;
    }
};

AcoatGManager.prototype.SetMapEvents = function ()
{
    if (this.map == null) return;
    var p = this;
    GEvent.addListener (this.map, "moveend", function()
    {
        var ll = p.map.getCenter ();
        p.currentLat = ll.lat();
        p.currentLong = ll.lng();
    });

    GEvent.addListener (this.map, "zoomend", function()
    {
        p.currentZoom = p.map.getZoom ();
    });
}

AcoatGManager.prototype.SetMarkers = function ()
{
    if (!this.markers) return;

    var baseIcon = new GIcon();
    baseIcon.image = "/_layouts/images/acoat-images/pin.png";
    baseIcon.iconAnchor = new GPoint(9, 34);
    baseIcon.infoWindowAnchor = new GPoint(9, 2);

    var markers = [];
    for (var i = 0; i < this.markers.length; i++)
    {
        var markerData = this.markers[i];
        var marker = this.CreateMarker(markerData, baseIcon);
        markers.push(marker);
    }
    this.markerManager.clearMarkers();
    this.markerManager.addMarkers(markers, 0);
    this.markerManager.refresh();
};

AcoatGManager.prototype.CreateMarker = function (markerData, baseIcon)
{
    var point = new GLatLng (Number (markerData.Lat), Number(markerData.Long));
    var cIcon = new GIcon(baseIcon);
    markerOptions = { icon:cIcon };
    var marker = new GMarker(point, markerOptions);

    var template = document.getElementById(this.popupTemplateID).innerHTML;
    for (var n in markerData)
    {
        var repl = new RegExp('{' + n + '}', 'g');
        template = template.replace (repl, markerData[n]);
    }
    var map = this.map;

    var showPopup = function ()
    {
        //marker.openInfoWindowHtml(template);
        MyOverlay.openMyOverlay (map, marker, template);
    };

    GEvent.addListener(marker, "click", showPopup);
    markerData.showPopup = showPopup;
    return marker;
};

AcoatGManager.prototype.SetSearchHref = function ()
{
    document.getElementById(this.lnkID).href = "javascript:" + this.GetScriptInstance() + ".OnSearch()";
};

AcoatGManager.prototype.OnSearch = function ()
{
    if (this.GetIsLoading()) return;
    if (!this.ClientValidate()) return;

    var street = this.GetTrimmedStreet();
    var location = this.GetTrimmedLocation ();
    var zip = this.GetTrimmedZip();
    var country = this.GetTrimmedCountry();

    var addressParts = [];
    if (street.length > 0) addressParts.push (street);
    if (zip.length > 0) addressParts.push (zip);
    if (location.length > 0) addressParts.push (location);
    if (country.length > 0) addressParts.push (country);

    var address = addressParts.join(', ');

    var dist = document.getElementById(this.distanceID);
    var forceCountry = (dist.value == 'country');

    this.CalcCoordinatesFromAddress (address, forceCountry);
}

AcoatGManager.prototype.CalcCoordinatesFromAddress = function (address, forceCountry)
{
    var p = this;
    p.SetIsLoading(true);
    this.geocoder.getLocations (address, function (response)
    {
        p.SetIsLoading(false);
        if (!p.ValidateLocation(response)) return;
        //p.DisplayLocation (response);

        var s = p.FormatLocation (response);
        
        if (forceCountry)
        {
            var obj = p.GetLocationData(response);
            if (Number(obj["accuracy"]) > 1)
            {
                setTimeout (function()
                {
                    p.CalcCoordinatesFromAddress (obj["country"], false);
                }, 200);
                return;
            }
        }

        document.getElementById(p.hdnID).value = s;
        var btn = document.getElementById(p.searchID);
        if (btn.click) btn.click ();
        else
        {
            var code = btn.href.replace("javascript:", "");
            eval (unescape(code));
        }
    });
};

AcoatGManager.prototype.GetLocationData = function (response)
{
    var obj = {};
    var place = response.Placemark[0];
    obj["gLat"] = place.Point.coordinates[1];
    obj["gLong"] = place.Point.coordinates[0];
    obj["country"] = place.AddressDetails.Country.CountryName;
    obj["countryCode"] = place.AddressDetails.Country.CountryNameCode;
    obj["currentZoom"] = this.currentZoom;
    obj["accuracy"] = place.AddressDetails.Accuracy;

    if (place.ExtendedData && place.ExtendedData.LatLonBox)
    {
        var box = place.ExtendedData.LatLonBox;
        var bounds = this.GetBoundsFromBox(box);
        var zoom = this.map.getBoundsZoomLevel(bounds);

        obj["boxNorth"] = box.north;
        obj["boxSouth"] = box.south;
        obj["boxEast"] = box.east;
        obj["boxWest"] = box.west;
        obj["gZoom"] = zoom;
    }
    return obj;
};

AcoatGManager.prototype.FormatLocation = function (response)
{
    var obj = this.GetLocationData (response);
    return this.SerializeSimpleObject(obj);
}

AcoatGManager.prototype.GetBoundsFromBox = function (box)
{
    var sw = new GLatLng(box.south, box.west);
    var ne = new GLatLng(box.north, box.east);
    var bounds = new GLatLngBounds (sw, ne);
    return bounds;
};

AcoatGManager.prototype.DisplayLocation = function (response)
{
    var place = response.Placemark[0];
    if (place.ExtendedData && place.ExtendedData.LatLonBox)
    {
        var box = place.ExtendedData.LatLonBox;
        var bounds = this.GetBoundsFromBox(box);
        var zoom = this.map.getBoundsZoomLevel(bounds);
        this.currentZoom = zoom;
    }
    var gll = new GLatLng(Number(place.Point.coordinates[1]), Number(place.Point.coordinates[0]));
    this.map.setCenter (gll, this.currentZoom);
};

AcoatGManager.prototype.ValidateLocation = function (response)
{
    //Changed the response.Placemark.length check. It was checking if the length was not equal to 1.
    //In this case if more then 1 objects where available in the array, it was going wrong. 
    //The check is only ment to look if the array contains a first object so the AddressDetails can be accessed.
    if (!response || !response.Status || !response.Status.code || response.Status.code != 200 || !response.Placemark || response.Placemark.length == 0 || !response.Placemark[0].AddressDetails || !response.Placemark[0].AddressDetails.Country)
    {
        alert (gShopFinder_ResolveAddressError);
        return false;
    }
    return true;
};

AcoatGManager.prototype.ClientValidate = function ()
{
    var street = this.GetTrimmedStreet();
    var location = this.GetTrimmedLocation ();
    var zip = this.GetTrimmedZip();
    var shopName = this.GetTrimmedShopName();

    var regAlpha20 = /^[\w]{1,20}$/;  
    var regAlpha40 = /[<>%$\?#!\&\*+=~\^\{\}\(\)\[\]\\@|]/;  

    if (!this.ValidateNonEmptyForSpecialSimbols(shopName, regAlpha40, gShopFinder_InvalidShopName)) return false;
    if (!this.ValidateNonEmptyForSpecialSimbols(street, regAlpha40, gShopFinder_InvalidStreetName)) return false;
    if (!this.ValidateNonEmptyForSpecialSimbols(location, regAlpha40, gShopFinder_InvalidCityName)) return false;
    if (!this.ValidateNonEmptyRE(zip, regAlpha20, gShopFinder_InvalidZipCode)) return false;


    return true;
};

AcoatGManager.prototype.ValidateNonEmptyRE = function (str, reg, errMsg)
{
    if (str.length > 0)
    {
        if (!str.match (reg))
        {
            alert (errMsg);
            return false;
        }
    }
    return true;
}

AcoatGManager.prototype.ValidateNonEmptyForSpecialSimbols = function (str, reg, errMsg)
{
    if (str.length > 0)
    {
        if (str.match (reg))
        {
            alert (errMsg);
            return false;
        }
    }
    return true;
}

AcoatGManager.prototype.SerializeSimpleObject = function (obj)
{
    var arr = [];
    for (var n in obj)
    {
        arr.push(n + '=' + obj[n]);
    }
    return arr.join ('||');
};

AcoatGManager.prototype.GetTrimmedStreet = function() { return document.getElementById(this.streetID).value.trim(); };
AcoatGManager.prototype.GetTrimmedLocation = function() { return document.getElementById(this.locationID).value.trim(); };
AcoatGManager.prototype.GetTrimmedZip = function() { return document.getElementById(this.zipID).value.trim(); };
AcoatGManager.prototype.GetTrimmedShopName = function() { return document.getElementById(this.shopNameID).value.trim(); };
AcoatGManager.prototype.GetTrimmedCountry = function() { return document.getElementById(this.countryID).value.trim(); };

AcoatGManager.prototype.GetIsLoading = function() { return this.isLoading; };
AcoatGManager.prototype.SetIsLoading = function(value) { this.isLoading = value; };

AcoatGManager.prototype.AddEvent = function(obj, evType, fn)
{ 
	if (obj.addEventListener) {  obj.addEventListener(evType, fn, false);  return true; }
	else if (obj.attachEvent) {  var r = obj.attachEvent('on'+evType, fn);  return r; } 
	else {  return false; } 
};

var AcoatGSmallFinderManager = function(parm)
{
    var p = this;

    this.inputID = parm.inputID;
    this.linkID = parm.linkID;
    this.hdnID = parm.hdnID;
    this.redirUrl = parm.redirUrl;
    this.contriesUrls = parm.countriesUrls;
    this.isLoading = false;

    document["AcoatGSmallFinderManager_" + this.linkID] = this;
    this.geocoder = null;

    AcoatGManager.prototype.AddEvent (window, 'load', function() { p.OnWindowLoad(); });
}

AcoatGSmallFinderManager.GetInstanceFromLinkID = function (linkID) { return document["AcoatGSmallFinderManager_" + linkID]; }

AcoatGSmallFinderManager.prototype.OnWindowLoad = function ()
{
    this.geocoder = new GClientGeocoder(); 
    var p = this;
    document.getElementById (this.inputID).onkeydown = function(ev)
    {
        p.OnKeyDown (ev);
    };
};

AcoatGSmallFinderManager.prototype.OnClick = function ()
{
    if (this.geocoder == null) return;
    if (this.GetIsLoading()) return;

    var location = document.getElementById(this.inputID).value.trim();
    if (location.length == 0)
    {
        alert(gShopFinder_ValidLocationError);
        return;
    }

    if (typeof(this.contriesUrls[location]) !== 'undefined' && this.contriesUrls[location] != null){
        window.open(this.contriesUrls[location]);
    } else {
        this.CalcCoordinatesFromAddress (location);
    }
};

AcoatGSmallFinderManager.prototype.OnKeyDown = function(e)
{
    if (!e) e = window.event;
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13))
    {
        this.OnClick(); return false;
    }
    else return true;
}

AcoatGSmallFinderManager.prototype.CalcCoordinatesFromAddress = function (address)
{
    var p = this;
    p.SetIsLoading(true);
    this.geocoder.getLocations (address, function (response)
    {
        p.SetIsLoading(false);
        if (!AcoatGManager.prototype.ValidateLocation(response)) return;

        var s = p.FormatLocation (response);
        document.getElementById(p.hdnID).value = s;

        var frm = document.forms[0];
        frm.action = p.redirUrl;
        frm.submit();
    });
};

AcoatGSmallFinderManager.prototype.FormatLocation = function (response)
{
    var obj = this.GetLocationData (response);
    obj["rawAddress"] = document.getElementById(this.inputID).value;
    return AcoatGManager.prototype.SerializeSimpleObject(obj);
}

AcoatGSmallFinderManager.prototype.GetLocationData = function (response)
{
    var obj = {};
    var place = response.Placemark[0];
    obj["gLat"] = place.Point.coordinates[1];
    obj["gLong"] = place.Point.coordinates[0];
    obj["country"] = place.AddressDetails.Country.CountryName;
    obj["countryCode"] = place.AddressDetails.Country.CountryNameCode;
    obj["accuracy"] = place.AddressDetails.Accuracy;

    if (place.ExtendedData && place.ExtendedData.LatLonBox)
    {
        var box = place.ExtendedData.LatLonBox;
        var bounds = AcoatGManager.prototype.GetBoundsFromBox(box);

        obj["boxNorth"] = box.north;
        obj["boxSouth"] = box.south;
        obj["boxEast"] = box.east;
        obj["boxWest"] = box.west;
    }

    obj["currentZoom"] = obj["gZoom"] = 0;
    
    return obj;
};

AcoatGSmallFinderManager.prototype.GetIsLoading = function() { return this.isLoading; };
AcoatGSmallFinderManager.prototype.SetIsLoading = function(value) { this.isLoading = value; };

var MyOverlay = function(marker, html) 
{
    this.marker = marker;
    this.html = html;
}

MyOverlay._current = null;

MyOverlay.prototype = new GOverlay();
MyOverlay.prototype.initialize = function(map) 
{
    var div = document.createElement("div");
    div.className = 'tooltip';
    div.innerHTML = this.html;
    div.onclick = function () { MyOverlay.closeMyOverlay(map); };

    this._map = map;
    this._div = div;
    this.setDivPosition ();

    map.getPane(G_MAP_FLOAT_PANE).appendChild(div);  
};

MyOverlay.prototype.setDivPosition = function()
{
    // offsets based on popup div dimensions
    offsetX = 39;
    offsetY = 215;

    var pixelP = this._map.fromLatLngToDivPixel(this.marker.getPoint());
    this._div.style.top = (pixelP.y - offsetY) + 'px';
    this._div.style.left = (pixelP.x - offsetX) + 'px';
};

MyOverlay.prototype.remove = function()
{
    this._div.parentNode.removeChild(this._div);
};

MyOverlay.prototype.redraw = function() 
{
    this.setDivPosition ();
};

MyOverlay.openMyOverlay = function(map, marker, html) 
{
    MyOverlay.closeMyOverlay(map);

    var overlay = new MyOverlay(marker, html);
    MyOverlay._current = overlay;

    var center = map.getCenter();
    var point = marker.getPoint();

    var centerP = map.fromLatLngToDivPixel(center);
    centerP.y += 92;
    var pointP = map.fromLatLngToDivPixel(point);
    map.panBy (new GSize(centerP.x - pointP.x, centerP.y - pointP.y));

    //map.panTo(new GLatLng(marker.getPoint().lat(), marker.getPoint().lng()));
    map.addOverlay(overlay);
};

MyOverlay.closeMyOverlay = function(map)
{
    if (MyOverlay._current != null)
    {
        map.removeOverlay(MyOverlay._current);
        MyOverlay._current = null;
    }
};

var AcoatRatingManager = function(par) 
{
    this.stars = par.stars;
    this.selClass = par.selClass;
    this.nonselClass = par.nonselClass;
    this.rating = par.rating;
    this.Init();
};

AcoatRatingManager.prototype.Init = function ()
{
    this.elements = [];
    for (var i = 0; i < this.stars.length; i++) 
    {
        var starEl = document.getElementById(this.stars[i]);
        this.elements.push (starEl);
        this.SetEventHandlers (starEl, i);
    }
};

AcoatRatingManager.prototype.SetEventHandlers = function (starEl, itemIdx)
{
    var p = this;
    starEl.onmouseover = function ()
    {
        p.SetRating (itemIdx + 1);
    };

    starEl.onmouseout = function ()
    {
        p.SetRating (p.rating);
    };
};

AcoatRatingManager.prototype.SetRating = function (rating)
{
    for (var i = 0; i < rating; i++)
    {
        this.elements[i].className = this.selClass;
    }
    for (var i = rating; i < this.elements.length; i++) 
    {
        this.elements[i].className = this.nonselClass;
    }
};
