function clsMap() {
    //var licznik = 0;
    var map;    
    var xmlPolylines;
    var xmlPolyIndex = 0;
    var lstPolylinesLength = 0;
    var addedPolylineCounter = 0;

    var closestLine;    
    var pointedLine;
    var selectedLine;

    var pointedVertexIndex;
    var editedPolylineVertices = new Array();
    var lstRecordedActions = new Array(); // przechowuje liste wykonanych akcji.
    var lstEditedLines = new Object(); // id linii - liczba zmian
    var lstSavedLines = new Object();
    var lstKeys;

    this.getMap = function() {return map;};
    this.getPointedLine = function() {return pointedLine;};
    this.setPointedLine = function(prmPointedLine) {pointedLine = prmPointedLine;};
    this.getSelectedLine = function() {return selectedLine;};
    this.setSelectedLine = function(prmSelectedLine) {selectedLine = prmSelectedLine;}

    var vMarker; // marker wyswietlany na polyline
    var isVMarkerDragged = false;
    //this.getVia = function() {return via;}

    var mouseLatLng; // wspolrzedne geograficzne kursora

    this.initialize = function() {
        // tworzy mape
        if (GBrowserIsCompatible()) {
            map = new GMap2(document.getElementById("map_canvas"));
            map.setCenter(new GLatLng(52.402523, 16.916542), 13);
            map.setUIToDefault();
            map.disableDoubleClickZoom();
        }
    };
    this.clear = function() {
        // czysci mape i zmienne
        map.clearOverlays();
        xmlPolylines = null;
        xmlPolyIndex = 0;
        lstPolylinesLength = 0;
        addedPolylineCounter = 0;

        closestLine = null;
        pointedLine = null;
        selectedLine = null;

        pointedVertexIndex = null;
        editedPolylineVertices = new Array();
        lstRecordedActions = new Array();
        lstEditedLines = new Object();
        lstSavedLines = new Object();

        isVMarkerDragged = false;
    };

    this.setCenter = function(latlng) {
        map.setCenter(latlng);
    }

    this.getPointedVertex = function(point) {
        var accuracy = 1;
        if (map.getZoom() <= 13)
            accuracy = 1.5;
        for (var i=0; i < selectedLine.polyline.getVertexCount(); i++) {
            //document.getElementById("echo").innerHTML = "TUTAJ " + point;
            if (point.distanceFrom(selectedLine.polyline.getVertex(i)) < 10*accuracy) {
                return i;
            }
        }
        return null;
    };
    this.getClosestPoint = function(latlng, line) {
        // zwraca wspolrzedne punktu najblizszego konkretnej polyline gdy poly != null
        // lub ustala wskazywana poly i zwraca wspolrzedne punktu gdy poly == null

        var minDist = 999;
        var xBest; // wspolrzedna x punktu na segmencie nablizej lezacego kursora
        var yBest; // wspolrzedna y punktu na segmencie nablizej lezacego kursora

        var segmentStart; // punkt poczatku segmentu
        var segmentFinish; // punkt koncaa segmentu

        var segmentVLength; // dlugosc wektora segmentu

        var segmentVx; // wspolrzedna x wektora segmentu
        var segmentVy; // wspolrzedna y wektora segmentu

        var xStart; // wspolrzedna x poczatku segmentu
        var yStart; // wspolrzedna y poczatku segmentu
        var xFinish; // wspolrzedna x konca segmentu
        var yFinish; // wspolrzedna y konca segmentu

        var xPointer = latlng.lng(); // wspolrzedna x kursora
        var yPointer = latlng.lat(); // wspolrzedna y kursora

        var pointerVx; // wspolrzedna x wektora majacego poczatek w poczatku segmentu i koniec w punkcie kursora
        var pointerVy; // wspolrzedna y ...

        var pointerVLength; // dlugosc wektora "punktu kursora"

        var cosSP; // cosinus kata wektorow segmentu i punktu

        var scalarResolute; // rzut skalarny wektora punktu na wektor segmentu

        var dist;
        // przeglad segmentow polyline aby okreslic ktorego najblizej znajduje sie kursor

        if (line == null) {
            for (var lineIndex in objLC.array) {

                line = objLC.array[lineIndex];
                var poly = line.polyline;

                if (!line.bounds.containsLatLng(latlng)) // odrzucamy te, w granicach ktorych nie znajduje sie kursor
                    continue;

                for (var i = 0; i < poly.getVertexCount() - 1; i++) {
                    var x;
                    var y;
                    segmentStart = poly.getVertex(i);
                    segmentFinish = poly.getVertex(i + 1);

                    xStart = segmentStart.lng();
                    yStart = segmentStart.lat();

                    xFinish = segmentFinish.lng();
                    yFinish = segmentFinish.lat();

                    segmentVx = xFinish - xStart;
                    segmentVy = yFinish - yStart;

                    pointerVx = xPointer - xStart;
                    pointerVy = yPointer - yStart;

                    var dist2StartFromFinish = Math.pow(segmentVx, 2) + Math.pow(segmentVy, 2);
                    segmentVLength = Math.sqrt(dist2StartFromFinish);

                    var dist2PointerFromStart = Math.pow(pointerVx, 2) + Math.pow(pointerVy, 2);
                    pointerVLength = Math.sqrt(dist2PointerFromStart);

                    cosSP = ((segmentVx * pointerVx) + (segmentVy * pointerVy)) / (segmentVLength * pointerVLength);

                    scalarResolute = pointerVLength * cosSP;

                    x = xStart + segmentVx * (scalarResolute / segmentVLength);
                    y = yStart + segmentVy * (scalarResolute / segmentVLength);

                    //document.getElementById("licznik").innerHTML = "x = " + x + " y = " + y;

                    var dist2PointerFromSegment = Math.pow(x - xPointer, 2) + Math.pow(y - yPointer, 2);
                    var dist2PointerFromFinish = Math.pow(xFinish - xPointer, 2) + Math.pow(yFinish - yPointer, 2);

                    dist = dist2PointerFromSegment;

                    if ((dist2PointerFromStart - dist2PointerFromSegment) + (dist2PointerFromFinish - dist2PointerFromSegment) > dist2StartFromFinish) {
                        if (dist2PointerFromStart < dist2PointerFromFinish) {
                            dist = dist2PointerFromStart;
                            x = xStart;
                            y = yStart;
                        }
                        else {
                            dist = dist2PointerFromFinish;
                            x = xFinish;
                            y = yFinish;
                        }
                    }

                    if (minDist > dist) {
                        minDist = dist;
                        closestLine = line;
                        xBest = x;
                        yBest = y;
                    }
                }
            }
        }
        else {
            var poly = line.polyline;
            for (var i = 0; i < poly.getVertexCount() - 1; i++) {
                var x;
                var y;
                segmentStart = poly.getVertex(i);
                segmentFinish = poly.getVertex(i + 1);

                xStart = segmentStart.lng();
                yStart = segmentStart.lat();

                xFinish = segmentFinish.lng();
                yFinish = segmentFinish.lat();

                segmentVx = xFinish - xStart;
                segmentVy = yFinish - yStart;

                pointerVx = xPointer - xStart;
                pointerVy = yPointer - yStart;

                var dist2StartFromFinish = Math.pow(segmentVx, 2) + Math.pow(segmentVy, 2);
                segmentVLength = Math.sqrt(dist2StartFromFinish);

                var dist2PointerFromStart = Math.pow(pointerVx, 2) + Math.pow(pointerVy, 2);
                pointerVLength = Math.sqrt(dist2PointerFromStart);

                cosSP = ((segmentVx * pointerVx) + (segmentVy * pointerVy)) / (segmentVLength * pointerVLength);

                scalarResolute = pointerVLength * cosSP;

                x = xStart + segmentVx * (scalarResolute / segmentVLength);
                y = yStart + segmentVy * (scalarResolute / segmentVLength);

                //document.getElementById("licznik").innerHTML = "x = " + x + " y = " + y;

                var dist2PointerFromSegment = Math.pow(x - xPointer, 2) + Math.pow(y - yPointer, 2);
                var dist2PointerFromFinish = Math.pow(xFinish - xPointer, 2) + Math.pow(yFinish - yPointer, 2);

                dist = dist2PointerFromSegment;

                if ((dist2PointerFromStart - dist2PointerFromSegment) + (dist2PointerFromFinish - dist2PointerFromSegment) > dist2StartFromFinish) {
                    if (dist2PointerFromStart < dist2PointerFromFinish) {
                        dist = dist2PointerFromStart;
                        x = xStart;
                        y = yStart;
                    }
                    else {
                        dist = dist2PointerFromFinish;
                        x = xFinish;
                        y = yFinish;
                    }
                }
                if (minDist > dist) {
                    minDist = dist;
                    closestLine = line;
                    xBest = x;
                    yBest = y;
                }
            }
        }
        return new GLatLng(yBest, xBest);
    };
    this.isPolylineDragged = function() {
        // zwraca wartosc  true/false czy linia jest przesuwana
        if (selectedLine == null)
            return false;
        if (selectedLine.polyline.getVertexCount() != editedPolylineVertices.length)
            return true;
        else {
            for (var i = 0; i < editedPolylineVertices.length; i++) {
                if (selectedLine.polyline.getVertex(i).toUrlValue() != editedPolylineVertices[i].toUrlValue())
                    return true;
            }
            return false;
        }
    };

    this.nextPolylineSchema = function() {
        // przechodzi do kolejnej polyline z listy
        if (xmlPolyIndex >= xmlPolylines.length) {
            objLC.isLoaded = false;
            return;
        }
        var id = xmlPolylines[xmlPolyIndex].getAttribute("id");
        var name = xmlPolylines[xmlPolyIndex].getAttribute("name");
        var coordinates = xmlPolylines[xmlPolyIndex].getAttribute("coordinates");
        var headlatlng = xmlPolylines[xmlPolyIndex].getAttribute("headlatlng");
        var taillatlng = xmlPolylines[xmlPolyIndex].getAttribute("taillatlng");
        var stateId = xmlPolylines[xmlPolyIndex].getAttribute("id_state");
        if (xmlPolyIndex == 0) {
            map.setCenter(new GLatLng.fromUrlValue(headlatlng), 13);
        }
        xmlPolyIndex++;
        objMap.createPolylineSchema(id, name, coordinates, new GLatLng.fromUrlValue(headlatlng), new GLatLng.fromUrlValue(taillatlng), stateId);
        var progress = "Wyrysowano " + (addedPolylineCounter + 1) + "/" + (lstPolylinesLength) + " połączeń";
        document.getElementById("progress").innerHTML = progress;
        addedPolylineCounter++;
        setTimeout(function() { objMap.nextPolylineSchema() }, 1); // opoznienie przed dodaniem kolejnej polyline zeby nie przywiesic przegladarki
    };
    this.createPolylineSchema = function(id, name, coordinates, headLatLng, tailLatLng, stateId) {
        // wyrysowyuje polyline
        var objLine;

        var isN = false;
        var isE = false;
        if (tailLatLng.lat() - headLatLng.lat() >= 0 )
            isN = true;
        if (tailLatLng.lng() - headLatLng.lng() >= 0 )
            isE = true;        

        var strlatlngs = new Array();
        strlatlngs = coordinates.split(","); // coordinates zawiera wspolrzedne oddzielone przecinkami lat,lng,lat,lng...

        var latlngs = new Array();

        for (var j = 0; j < strlatlngs.length; j = j + 2) {
            latlngs.push(new GLatLng(strlatlngs[j], strlatlngs[j + 1]));
        }

        var isWrong = false;
        var polyline = new GPolyline(latlngs, objColors.normalColor, null, objColors.normalOpacity);
        if (polyline.getLength() > 2*headLatLng.distanceFrom(tailLatLng)/Math.sqrt(2) && stateId != "3") {
            polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
            isWrong = true;
        }        
        map.addOverlay(polyline);
        var nameHeadTail = name.split(",");
        var head;
        var tail;
        var icon = new GIcon();
        icon.iconSize = new GSize(16, 16); //G_DEFAULT_ICON ma szerokosc 16??
        icon.iconAnchor = new GPoint(8, 8);        
        if (!objMC.array[nameHeadTail[0]]) {            
            if (headLatLng.distanceFrom(polyline.getVertex(0)) < 20) {
                icon.image = objImages.normal;
                
            } else {
                icon.image = objImages.wrong;
            }
            var marker = new GMarker(headLatLng, { icon: icon, title: nameHeadTail[0], zIndexProcess: function() {return 100;} });
            map.addOverlay(marker);
            head = new clsMarker(nameHeadTail[0], marker, icon.image);
            //head.lstLineStart.push(objLine);
            objMC.array[nameHeadTail[0]] = head;        
        }
        else {
            head = objMC.array[nameHeadTail[0]];            
            // porowanienie z innymi, ktore maja tu poczatek lub koniec
            for (var k in head.lstLineStart) {
                var lineStart = head.lstLineStart[k];
                // porownanie pierwszej wspolrzednej z pierwsza wspolrzedna
                if (polyline.getVertex(0).distanceFrom(lineStart.polyline.getVertex(0)) > 8) {
                    isWrong = true;
                    polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineStart.polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineStart.defaultColor = objColors.wrongColor;
                    lineStart.defaultOpacity = objColors.wrongOpacity;
                }
            }
            for (var k in head.lstLineEnd) {
                var lineEnd = head.lstLineEnd[k];
                // porownanie pierwszej wspolrzednej z ostatnia wspolrzedna
                if (polyline.getVertex(0).distanceFrom(lineEnd.polyline.getVertex(lineEnd.polyline.getVertexCount()-1)) > 8) {
                    isWrong = true;
                    polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineEnd.polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineEnd.defaultColor = objColors.wrongColor;
                    lineEnd.defaultOpacity = objColors.wrongOpacity;
                }
            }
        }        
        if (!objMC.array[nameHeadTail[1]]) {
            if (tailLatLng.distanceFrom(polyline.getVertex(polyline.getVertexCount() - 1)) < 20) {
                icon.image = objImages.normal;
            } else {
                icon.image = objImages.wrong;
            }
            var marker = new GMarker(tailLatLng, { icon: icon, title: nameHeadTail[1], zIndexProcess: function() {return 100;} });
            map.addOverlay(marker);            
            tail = new clsMarker(nameHeadTail[1], marker, icon.image);
            //tail.lstLineEnd.push(objLine);
            objMC.array[nameHeadTail[1]] = tail;
        }
        else {
            tail = objMC.array[nameHeadTail[1]];            
            // porowanienie z innymi, ktore maja tu poczatek lub koniec
            for (var k in tail.lstLineStart) {
                var lineStart = tail.lstLineStart[k];
                // porownanie ostatniej wspolrzednej z pierwsza wspolrzedna
                if (polyline.getVertex(polyline.getVertexCount()-1).distanceFrom(lineStart.polyline.getVertex(0)) > 8) {
                    isWrong = true;
                    polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineStart.polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineStart.defaultColor = objColors.wrongColor;
                    lineStart.defaultOpacity = objColors.wrongOpacity;
                }
            }
            for (var k in tail.lstLineEnd) {
                var lineEnd = tail.lstLineEnd[k];
                // porownanie ostatniej wspolrzednej z ostatnia wspolrzedna
                if (polyline.getVertex(polyline.getVertexCount()-1).distanceFrom(lineEnd.polyline.getVertex(lineEnd.polyline.getVertexCount()-1)) > 8) {
                    isWrong = true;
                    polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineEnd.polyline.setStrokeStyle({color:objColors.wrongColor, opacity:objColors.wrongOpacity});
                    lineEnd.defaultColor = objColors.wrongColor;
                    lineEnd.defaultOpacity = objColors.wrongOpacity;
                }
            }
        }        
        
        if (isWrong)
            objLine = new clsLine(id, name, stateId, polyline, head, tail, objColors.wrongColor, objColors.wrongOpacity);
        else
            objLine = new clsLine(id, name, stateId, polyline, head, tail, objColors.normalColor, objColors.normalOpacity);
        head.lstLineStart.push(objLine);
        tail.lstLineEnd.push(objLine);
        objLine.insertRow();        
        objLC.array[id] = objLine;        
        if (isN && isE)
            objLC.lstNE.push(objLine);
        else if (isN && !isE)
            objLC.lstNW.push(objLine);
        else if (!isN && !isE)
            objLC.lstSW.push(objLine);
        else
            objLC.lstSE.push(objLine);
    };
    this.drawSchema = function(schema_id) {
        // wyrysowywuje siec

        if (objSC.schemaIsEdited)
            return;
        if (GBrowserIsCompatible()) {

            this.clear();

            var doticon = new GIcon();
            //doticon.image = "http://www.marsrutai.info/node.gif";
            doticon.image = "http://maps.google.com/intl/en_ALL/mapfiles/dd-via.png";
            doticon.iconSize = new GSize(11, 11);
            doticon.iconAnchor = new GPoint(5, 5);

            vMarker = new GMarker(map.getCenter(), { draggable: true, icon: doticon, title: "Przeciągnij aby zmienić drogę" });

            map.addOverlay(vMarker);

            vMarker.show();
            vMarker.hide();

            GEvent.addListener(vMarker, "dragstart", function() {
                isVMarkerDragged = true;
                editedPolylineVertices = new Array();
                for (var j = 0; j < selectedLine.polyline.getVertexCount(); j++) {
                    editedPolylineVertices.push(selectedLine.polyline.getVertex(j));
                }
            });

            GEvent.addListener(vMarker, "dragend", function(middlePoint) {
                var dir = new GDirections(null, info);
                dir.loadFromWaypoints(new Array(selectedLine.polyline.getVertex(0).toUrlValue(), middlePoint.toUrlValue(), selectedLine.polyline.getVertex(selectedLine.polyline.getVertexCount() - 1).toUrlValue()), { getPolyline: true, travelMode: G_TRAVEL_MODE_WALKING, preserveViewport: true });
                // nasluchiwanie czy dostepne sa rezultaty load()
                var eventDirError = GEvent.addListener(dir, "error", function() {
                    // TODO: jezeli nie pieszo to samochodem.. jezeli nie samochodem to zwykla linia
                    //document.getElementById("echo").innerHTML += dir.getStatus().code;
                    dir.loadFromWaypoints(new Array(selectedLine.polyline.getVertex(0).toUrlValue(), middlePoint.toUrlValue(), selectedLine.polyline.getVertex(selectedLine.polyline.getVertexCount() - 1).toUrlValue()), { getPolyline: true, travelMode: G_TRAVEL_MODE_DRIVING, preserveViewport: true });
                    GEvent.removeListener(eventDirError);
                });
                var eventDirLoad = GEvent.addListener(dir, "load", function() {
                    document.getElementById("info").innerHTML = "";
                    lstRecordedActions.push(new Array(selectedLine, editedPolylineVertices, selectedLine.stateId));
                    map.removeOverlay(selectedLine.polyline);
                    selectedLine.polyline = dir.getPolyline();
                    selectedLine.polyline.setStrokeStyle({color: objColors.selectedColor, opacity: objColors.selectedOpacity });
                    map.addOverlay(selectedLine.polyline);
                    if (lstEditedLines[selectedLine.id] == null)
                        lstEditedLines[selectedLine.id] = 1;
                    else
                        lstEditedLines[selectedLine.id] = lstEditedLines[selectedLine.id] + 1;
                    selectedLine.setStateId("2");
                    document.getElementById("btnCofnij").disabled = "";
                    GEvent.removeListener(eventDirLoad);
                });
                isVMarkerDragged = false;
                document.getElementById("btnZapisz").disabled = "";
                document.getElementById("btnZapisz").value = "Zapisz";
            });

            // wczytanie zawartosci dbtoxml.php generujacego xml z bazy danych
            document.getElementById("echo").innerHTML = "";
            var xmlhttp = GetXmlHttpObject();
            if (xmlhttp == null) {
                alert("Your browser does not support AJAX!");
                return;
            }
            var url = "src/schemas.php";
            url += "?f=2";
            url += "&id=" + schema_id;
            xmlhttp.open("GET", url, true);
            //var licznik = 0;
            var requestTimer = setTimeout(function() {
                //licznik++;
                document.getElementById("progress").innerHTML = "i się przywiesiło...";
                //document.getElementById("echo").innerHTML += " " + xmlhttp.statusText;
                xmlhttp.abort();
                //xmlhttp.open("GET", url, true);
                //xmlhttp.send(null);
                // Handle timeout situation, e.g. Retry or inform user.
            }, 10000);
            xmlhttp.onreadystatechange = function() {
                if (xmlhttp.readyState != 4) {
                    document.getElementById("progress").innerHTML = '<img src="img/loader.gif" style="margin-right:4px;">Wczytywanie połączeń...'; //+ licznik;
                    return;
                }
                clearTimeout(requestTimer);
                //document.getElementById("echo").innerHTML = xmlhttp.statusText + " " + new Date();
                //if (xhReq.status != 200)  {
                    // Handle error, e.g. Display error message on page
                    //return;
                //}
                var xmlDoc = xmlhttp.responseXML;                
                xmlPolylines = xmlDoc.getElementsByTagName("polyline");
                lstPolylinesLength = xmlPolylines.length;
                var progress = "Wyrysowano 0/" + (lstPolylinesLength) + " połączeń";
                document.getElementById("progress").innerHTML = progress;
                objMap.nextPolylineSchema();
            };
            xmlhttp.send(null);

            GEvent.addListener(map, "singlerightclick", function(point) {
                var offset = 34;
                if (objSC.schemaIsEdited && pointedLine != null) {                    
                    document.getElementById("cmUsunKrawedz").style.display = "none";
                    if (selectedLine != null && selectedLine.isEdited) {
                        var index = objMap.getPointedVertex(mouseLatLng);
                        if (index != null) {
                            pointedVertexIndex = index;
                            // TODO: visibility = "visible" dla opcji ...
                            document.getElementById("cmUsunKrawedz").style.display = "block";
                            offset = 56;
                        }
                    }                    
                    document.getElementById("context_menu").style.left = point.x;
                    document.getElementById("context_menu").style.top = point.y - offset + document.getElementById("context_menu").offsetHeight;
                    document.getElementById("context_menu").style.visibility = "visible";
                }
            });

            GEvent.addListener(map, "click", function() {
                document.getElementById("context_menu").style.visibility = "hidden";
                if (selectedLine != null && selectedLine != pointedLine) {
                    selectedLine.deselect();
                    selectedLine = null;
                }
                if (pointedLine != null) {
                    //document.getElementById('line_' + pointedLine.id).scrollIntoView(true);
                    document.getElementById("lst_lines").scrollTop = document.getElementById('line_' + pointedLine.id).offsetTop;
                    pointedLine.select();
                    selectedLine = pointedLine;
                }
            });
            GEvent.addListener(map, "dragstart", function() {
                document.getElementById("context_menu").style.visibility = "hidden";
            });

            GEvent.addListener(map, "mouseout", function() {
                if (pointedLine != null)
                    pointedLine.mouseout();
            });
            //var licznik = 0;
            GEvent.addListener(map, "mousemove", function(latlng) {
                mouseLatLng = latlng;

                if (isVMarkerDragged)// || (true && pointedLine != null && pointedLine.isSelected && objMap.isPolylineDragged()))
                    return;
                if ((document.getElementById("optEditStylePoly").selected) && selectedLine != null && selectedLine.isEdited && objMap.isPolylineDragged()) {
                    //document.getElementById("echo").innerHTML = "return " + latlng;
                    return;
                }
                //document.getElementById("echo").innerHTML = latlng;

                var point;
                var dist;

                if (selectedLine != null) {
                    // wybrane polaczenie ma pierwszenstwo
                    point = objMap.getClosestPoint(latlng, selectedLine);
                    dist = latlng.distanceFrom(point);
                }
                else {
                    point = objMap.getClosestPoint(latlng, closestLine);
                    dist = latlng.distanceFrom(point);                    
                }

                if (closestLine == null)
                    return;

                var accuracy = 1;
                if (map.getZoom() <= 13)
                    accuracy = 2;

                if (selectedLine == null) {
                    if (dist > 15*accuracy || (latlng.distanceFrom(closestLine.polyline.getVertex(0)) < 7/accuracy) || (latlng.distanceFrom(closestLine.polyline.getVertex(closestLine.polyline.getVertexCount() - 1)) < 7/accuracy)) {
                        point = objMap.getClosestPoint(latlng); // ustalono nowe pointedPolyline
                        dist = latlng.distanceFrom(point); // odleglosc kursora od polaczenia
                    }
                }
                else {
                    if (dist > 50) {
                        point = objMap.getClosestPoint(latlng); // ustalono nowe pointedPolyline
                        dist = latlng.distanceFrom(point); // odleglosc kursora od polaczenia
                    }
                }
                
                if (closestLine != pointedLine && pointedLine != null)
                    pointedLine.mouseout();
                if (dist < 50) {                    
                    pointedLine = closestLine;                    
                    pointedLine.mouseover();
                    if (pointedLine.isSelected) {
                        // kursor w granicach wybranego polaczenia
                        if (objSC.schemaIsEdited && document.getElementById("optEditStyleDir").selected) {
                            // edycja ulicami
                            vMarker.setPoint(point);
                            vMarker.show();
                        }
                        else if (objSC.schemaIsEdited && document.getElementById("optEditStylePoly").selected) {
                            // edycja swobodna
                            pointedLine.enableEditing();
                            pointedLine.isEdited = true;

                            //if (objMap.isPolylineDragged())

                            editedPolylineVertices = new Array();
                            for (var j = 0; j < selectedLine.polyline.getVertexCount(); j++) {
                                editedPolylineVertices.push(selectedLine.polyline.getVertex(j));
                            }

                            //isPointedPolylineEdited = true;
                            
                            //document.getElementById("echo").innerHTML = latlng;
                            GEvent.clearInstanceListeners(pointedLine.polyline);
                            var eventLineUpdated = GEvent.addListener(pointedLine.polyline, "lineupdated", function() {
                                if (objMap.isPolylineDragged()) {
                                    lstRecordedActions.push(new Array(selectedLine, editedPolylineVertices, selectedLine.stateId));
                                    selectedLine.setStateId("2");
                                    if (lstEditedLines[selectedLine.id] == null)
                                        lstEditedLines[selectedLine.id] = 1;
                                    else
                                        lstEditedLines[selectedLine.id] = lstEditedLines[selectedLine.id] + 1;
                                    document.getElementById("btnCofnij").disabled = "";
                                    document.getElementById("btnZapisz").disabled = "";
                                    document.getElementById("btnZapisz").value = "Zapisz";
                                    editedPolylineVertices = new Array();
                                    for (var j = 0; j < selectedLine.polyline.getVertexCount(); j++) {
                                        editedPolylineVertices.push(selectedLine.polyline.getVertex(j));
                                    }
                                    selectedLine.isEdited = false;
                                    selectedLine.bounds = new GLatLngBounds(new GLatLng(selectedLine.polyline.getBounds().getSouthWest().lat() - 0.002,selectedLine.polyline.getBounds().getSouthWest().lng() - 0.002),
                                                                            new GLatLng(selectedLine.polyline.getBounds().getNorthEast().lat() + 0.002,selectedLine.polyline.getBounds().getNorthEast().lng() +  0.002));
                                    //licznik++;
                                }
                                GEvent.removeListener(eventLineUpdated);
                                pointedLine.isEdited = false;
                                //document.getElementById("echo").innerHTML = licznik;
                            });
                        }
                    }
                    else {
                        // kursor poza wybranym polaczeniem
                        if (objSC.schemaIsEdited && document.getElementById("optEditStyleDir").selected) {
                            // edycja ulicami
                            vMarker.hide();
                        }
                        else if (objSC.schemaIsEdited && document.getElementById("optEditStylePoly").selected) {
                            // edycja swobodna
                            if (selectedLine != null) {
                                selectedLine.polyline.disableEditing();
                                selectedLine.isEdited = false
                            }
                        }
                    }
                }
                else {
                    // kursor poza wskazywanym polaczeniem
                    if (pointedLine != null)
                        pointedLine.mouseout();
                    if (objSC.schemaIsEdited && document.getElementById("optEditStyleDir").selected) {
                        // edycja ulicami
                        vMarker.hide();
                    }
                    else if (objSC.schemaIsEdited && document.getElementById("optEditStylePoly").selected) {
                        // edycja swobodna
                        if (selectedLine != null) {
                            selectedLine.polyline.disableEditing();
                            selectedLine.isEdited = false;
                        }
                        if (pointedLine != null)
                            pointedLine.polyline.disableEditing();
                    }
                    pointedLine = null;
                }                
            });
        }
    };
    this.backwardAction = function() {
        // cofa akcje
        if (lstRecordedActions.length > 0) {
            var recordedAction = lstRecordedActions.pop();
            var line = recordedAction[0];
            var latlngs = recordedAction[1];
            var stateId = recordedAction[2];
            //document.getElementById("echo").innerHTML = id + " - " + latlngs.length;

            map.removeOverlay(line.polyline);
            var polyline = new GPolyline(latlngs, line.currentColor, null, line.currentOpacity);
            line.setPolyline(polyline);
            map.addOverlay(polyline);

            line.setStateId(stateId);

            if (lstSavedLines[line.id] != null && lstSavedLines[line.id] != 0) {
                lstEditedLines[line.id] = lstSavedLines[line.id];
                lstSavedLines[line.id] = 0;
            }
            else
                lstEditedLines[line.id] = lstEditedLines[line.id] - 1;

            document.getElementById("btnZapisz").disabled = "";
            document.getElementById("btnZapisz").value = "Zapisz";

            if (lstRecordedActions.length == 0)
                document.getElementById("btnCofnij").disabled = "disabled";
        }
    };

    var lstCheckedLines = new Array();

    this.createPolylineRD = function(line) {
        //var nameHeadTail = lstPolylinesNames[key].split(",");
        var poly;
        editedPolylineVertices = new Array();
        for (var j = 0; j < line.polyline.getVertexCount(); j++) {
            editedPolylineVertices.push(line.polyline.getVertex(j));
        }
        lstRecordedActions.push(new Array(line, editedPolylineVertices, line.stateId));
        var dirW = new GDirections(null, info);
        GEvent.addListener(dirW, "error", function() {
            var dirD = new GDirections(null, info);
            GEvent.addListener(dirD, "error", function() {
                document.getElementById("echo").innerHTML += "dirW & dirD" + line.name + ", ";
            });
            GEvent.addListener(dirD, "load", function() {
                document.getElementById("info").innerHTML = "";
                map.removeOverlay(line.polyline);
                poly = dirD.getPolyline();
                line.setPolyline(poly);
                map.addOverlay(poly);
                poly.setStrokeStyle({ color: line.currentColor, opacity: line.currentOpacity });
                if (lstEditedLines[line.id] == null)
                    lstEditedLines[line.id] = 1;
                else
                    lstEditedLines[line.id] = lstEditedLines[line.id] + 1;
                line.setStateId("1");
            });
            dirD.loadFromWaypoints(new Array(line.head.marker.getLatLng(), line.tail.marker.getLatLng()), { getPolyline: true, travelMode: G_TRAVEL_MODE_DRIVING, preserveViewport: true });
        });
        GEvent.addListener(dirW, "load", function() {            
            var dirD = new GDirections(null, info);
            GEvent.addListener(dirD, "error", function() {
                document.getElementById("info").innerHTML = "";
                map.removeOverlay(line.polyline);
                poly = dirW.getPolyline();
                line.setPolyline(poly);
                map.addOverlay(poly);
                if (lstEditedLines[line.id] == null)
                    lstEditedLines[line.id] = 1;
                else
                    lstEditedLines[line.id] = lstEditedLines[line.id] + 1;
                line.setStateId("1");
            });
            GEvent.addListener(dirD, "load", function() {
                var distW = dirW.getDistance().meters;
                var distD = dirD.getDistance().meters;
                document.getElementById("info").innerHTML = "";
                map.removeOverlay(line.polyline);
                if (distD < distW)
                    poly = dirD.getPolyline();
                else
                    poly = dirW.getPolyline();
                line.setPolyline(poly);
                map.addOverlay(poly);
                poly.setStrokeStyle({ color: line.currentColor, opacity: line.currentOpacity });
                if (lstEditedLines[line.id] == null)
                    lstEditedLines[line.id] = 1;
                else
                    lstEditedLines[line.id] = lstEditedLines[line.id] + 1;
                line.setStateId("1");
            });
            dirD.loadFromWaypoints(new Array(line.head.marker.getLatLng(), line.tail.marker.getLatLng()), { getPolyline: true, travelMode: G_TRAVEL_MODE_DRIVING, preserveViewport: true });
        });
        dirW.loadFromWaypoints(new Array(line.head.marker.getLatLng(), line.tail.marker.getLatLng()), { getPolyline: true, travelMode: G_TRAVEL_MODE_WALKING, preserveViewport: true });
    };
    this.nextPolylineRD = function(i) {
        if (i > lstCheckedLines.length - 1) {
            document.getElementById("btnZapisz").disabled = "";
            document.getElementById("btnZapisz").value = "Zapisz";
            document.getElementById("btnCofnij").disabled = "";
            return;
        }
        var eventAddOverlay = GEvent.addListener(map, "addoverlay", function() {
            GEvent.removeListener(eventAddOverlay);
            document.getElementById("progress").innerHTML = "Zresetowano " + (i+1) + "/" + lstCheckedLines.length + " połączeń";
            objMap.nextPolylineRD(i+1);
        });
        //document.getElementById("echo").innerHTML = i;
        this.createPolylineRD(lstCheckedLines[i]);
    };
    this.restoreDefault = function(line) {
        // przywraca domyslny ksztalt polaczenia
        lstCheckedLines = new Array();
        if (line == null) {
            for (var key in objLC.array) {
                if (objLC.array[key].isChecked)
                    lstCheckedLines.push(objLC.array[key]);
            }
            //document.getElementById("echo").innerHTML = keys.length;
        }
        else {
            lstCheckedLines.push(line);
        }        
        this.nextPolylineRD(0);
    };

    this.createPolylineMS = function(line) {
        var poly;
        var head = line.polyline.getVertex(0);
        var tail = line.polyline.getVertex(line.polyline.getVertexCount() - 1);
        editedPolylineVertices = new Array();
        for (var j = 0; j < line.polyline.getVertexCount(); j++) {
            editedPolylineVertices.push(line.polyline.getVertex(j));
        }
        lstRecordedActions.push(new Array(line, editedPolylineVertices, line.stateId));
        if (lstEditedLines[line.id] == null)
            lstEditedLines[line.id] = 1;
        else
            lstEditedLines[line.id] = lstEditedLines[line.id] + 1;

        map.removeOverlay(line.polyline);
        poly = new GPolyline(new Array(head, tail), line.currentColor, null, line.currentOpacity);
        line.setPolyline(poly);
        map.addOverlay(poly);
        //lstEditedPolylines[key] = poly;
        line.setStateId("2");
    };
    this.nextPolylineMS = function(i) {
        if (i > lstCheckedLines.length - 1) {
            document.getElementById("btnZapisz").disabled = "";
            document.getElementById("btnZapisz").value = "Zapisz";
            document.getElementById("btnCofnij").disabled = "";
            return;
        }
        var eventAddOverlay = GEvent.addListener(map, "addoverlay", function() {
            GEvent.removeListener(eventAddOverlay);
            document.getElementById("progress").innerHTML = "Wyprostowano " + (i+1) + "/" + lstCheckedLines.length + " połączeń";
            objMap.nextPolylineMS(i+1);
        });
        //document.getElementById("echo").innerHTML = i;
        this.createPolylineMS(lstCheckedLines[i]);
    };
    this.makeStraight = function(line) {
        // przywraca domyslny ksztalt polaczenia
        lstCheckedLines = new Array();
        if (line == null) {
            for (var key in objLC.array) {
                if (objLC.array[key].isChecked)
                    lstCheckedLines.push(objLC.array[key]);
            }
            //document.getElementById("echo").innerHTML = keys.length;
        }
        else {
            lstCheckedLines.push(line);
        }
        this.nextPolylineMS(0);
    };
    this.acceptPolyline = function(prmLine) {
        // zatwierdza ksztalt
        lstCheckedLines = new Array();
        if (prmLine == null) {
            for (var key in objLC.array) {
                if (objLC.array[key].isChecked) {
                    lstCheckedLines.push(objLC.array[key]);
                }
            }
        }
        else {
            lstCheckedLines.push(prmLine);            
        }
        for (var i = 0; i < lstCheckedLines.length; i++) {
            var line = lstCheckedLines[i];
            editedPolylineVertices = new Array();
            for (var j = 0; j < line.polyline.getVertexCount(); j++) {
                editedPolylineVertices.push(line.polyline.getVertex(j));
            }
            lstRecordedActions.push(new Array(line, editedPolylineVertices, line.stateId));
            if (lstEditedLines[line.id] == null)
                lstEditedLines[line.id] = 1;
            else
                lstEditedLines[line.id] = lstEditedLines[line.id] + 1;
            line.defaultColor = objColors.normalColor;
            line.defaultOpacity = objColors.normalOpacity;
            line.setStateId("3");
            document.getElementById("progress").innerHTML = "Zatwierdzono " + (i+1) + "/" + lstCheckedLines.length + " połączeń";
        }

        //this.nextPolylineAc(0);
        document.getElementById("btnZapisz").disabled = "";
        document.getElementById("btnZapisz").value = "Zapisz";
    };

    var savedLinesLength;

    this.savePolyline = function(licznikZapisu) {
        if (!objSC.schemaIsEdited)
            return;
        if (licznikZapisu > lstKeys.length - 1) {
            return;
        }
        var key = lstKeys[licznikZapisu]
        lstSavedLines[key] = lstEditedLines[key];
        if (lstEditedLines[key] == 0) {
            objMap.savePolyline(++licznikZapisu); // TODO
            return;
        }
        lstEditedLines[key] = 0;

        var line = objLC.array[key];
        var coordinates = "";
        for (var i = 0; i < line.polyline.getVertexCount() - 1; i++) {
            var vertex = line.polyline.getVertex(i);
            coordinates += vertex.toUrlValue() + ",";
        }
        coordinates += line.polyline.getVertex(line.polyline.getVertexCount() - 1).toUrlValue();

        var xmlhttp = GetXmlHttpObject();
        if (xmlhttp == null) {
            alert("Your browser does not support AJAX!");
            return;
        }
        var url = "src/schemas.php";
        url += "?f=3";
        url += "&id=" + key;
        url += "&coordinates=" + coordinates;
        url += "&id_state=" + objLC.array[key].stateId;
        url += "&sid=" + Math.random();
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {
                savedLinesLength++;
                licznikZapisu++;
                document.getElementById("progress").innerHTML = "Zapisano " + savedLinesLength + " zmienionych połączeń";
                objMap.savePolyline(licznikZapisu);
            }
        };
        xmlhttp.open("GET", url, true);
        xmlhttp.send(null);
    }
    this.saveSchema = function() {
        // zachowuje schemat w bazie danych
        lstKeys = new Array();
        for (var key in lstEditedLines) {
            lstKeys.push(key);
        }
        //document.getElementById("echo").innerHTML += lstKeys.length + " | ";
        savedLinesLength = 0;
        this.savePolyline(0);
    };

    this.nextPolylinePattern = function() {
        // przechodzi do kolejnej polyline z listy
        if (xmlPolyIndex >= xmlPolylines.length) {
            for (var key in objMC.array) {
                map.addOverlay(objMC.array[key].marker);
            }
            document.getElementById("btnDodajSiec").disabled = "";
            document.getElementById("btnDodajSiec").value = "Dodaj";
            return;
        }        

        var id = xmlPolylines[xmlPolyIndex].getAttribute("id");

        var contains = false;

	for (var k = 0; k<lstKeys.length; k++) {
		if (lstKeys[k] == id) {
			contains = true;
			break;
		}
	}

        if (contains) {
            xmlPolyIndex++;
            lstPolylinesLength--;
            var progress = "Wyrysowano " + (addedPolylineCounter) + "/" + (lstPolylinesLength) + " połączeń";
            document.getElementById("progress").innerHTML = progress;
            //addedPolylineCounter++;
            objMap.nextPolylinePattern();
            return;
        }

        var name = xmlPolylines[xmlPolyIndex].getAttribute("name");
        var headlatlng = xmlPolylines[xmlPolyIndex].getAttribute("head");
        var hll = headlatlng.split(",");
        if (new Number(hll[0]) < 40)
            headlatlng = hll[1] + "," + hll[0];
        var taillatlng = xmlPolylines[xmlPolyIndex].getAttribute("tail");
        var tll = taillatlng.split(",");
        if (new Number(tll[0]) < 40)
            taillatlng = tll[1] + "," + tll[0];
        if (xmlPolyIndex == 0) {
            map.setCenter(new GLatLng.fromUrlValue(headlatlng), 13);
        }
        xmlPolyIndex++;
        /*objMap.createPolylinePattern(id, name, new GLatLng.fromUrlValue(headlatlng), new GLatLng.fromUrlValue(taillatlng));
        var progress = "Wyrysowano " + (addedPolylineCounter + 1) + "/" + (lstPolylinesLength) + " połączeń";
        document.getElementById("progress").innerHTML = progress;
        addedPolylineCounter++;
        setTimeout(function() { objMap.nextPolylinePattern() }, 1); // opoznienie przed dodaniem kolejnej polyline zeby nie przywiesic przegladarki*/
        var eventAddOverlay = GEvent.addListener(map, "addoverlay", function() {
            GEvent.removeListener(eventAddOverlay);
            var progress = "Wyrysowano " + (addedPolylineCounter + 1) + "/" + (lstPolylinesLength) + " połączeń";
            document.getElementById("progress").innerHTML = progress;
            addedPolylineCounter++;
            lstKeys.push(id);
            objMap.nextPolylinePattern();
        });
        objMap.createPolylinePattern(id, name, new GLatLng.fromUrlValue(headlatlng), new GLatLng.fromUrlValue(taillatlng));
    };
    this.createPolylinePattern = function(id, name, headLatLng, tailLatLng) {
        // wyrysowywuje polyline        
        var nameHeadTail = name.split(",");
        var head;
        var tail;
        var icon = new GIcon();
        icon.iconSize = new GSize(16, 16); //G_DEFAULT_ICON ma szerokosc 16??
        icon.iconAnchor = new GPoint(8, 8);
        icon.image = objImages.normal;

        if (!objMC.array[nameHeadTail[0]]) {
            var marker = new GMarker(headLatLng, { icon: icon, title: nameHeadTail[0], zIndexProcess: function() {return 100;} });
            //map.addOverlay(marker);
            head = new clsMarker(nameHeadTail[0], marker, icon.image);
            objMC.array[nameHeadTail[0]] = head;
        }
        else
            head = objMC.array[nameHeadTail[0]];
        if (!objMC.array[nameHeadTail[1]]) {
            var marker = new GMarker(tailLatLng, { icon: icon, title: nameHeadTail[1], zIndexProcess: function() {return 100;} });
            //map.addOverlay(marker);
            tail = new clsMarker(nameHeadTail[1], marker, icon.image);
            objMC.array[nameHeadTail[1]] = tail;
        }
        else
            tail = objMC.array[nameHeadTail[1]];

        var polyline;

        var dirD = new GDirections(null, info);
        GEvent.addListener(dirD, "error", function() {
            var dirW = new GDirections(null, info);
            GEvent.addListener(dirW, "error", function() {
                document.getElementById("echo").innerHTML += "dirW & dirD" + name + ", ";
                var latlngs = new Array(headLatLng, tailLatLng);
                polyline = new GPolyline(latlngs, objColors.normalColor, null, objColors.normalOpacity);
                map.addOverlay(polyline);
                var objLine = new clsLine(id, name, "1", polyline, head, tail)
                objLC.array[id] = objLine;
            });
            GEvent.addListener(dirW, "load", function() {
                document.getElementById("info").innerHTML = "";
                polyline = dirW.getPolyline();
                polyline.setStrokeStyle({color:objColors.normalColor, opacity:objColors.normalOpacity});
                map.addOverlay(polyline);
                var objLine = new clsLine(id, name, "1", polyline, head, tail)
                objLC.array[id] = objLine;
            });
            dirW.loadFromWaypoints(new Array(headLatLng, tailLatLng), { getPolyline: true, travelMode: G_TRAVEL_MODE_WALKING, preserveViewport: true });
        });
        GEvent.addListener(dirD, "load", function() {
            if (document.getElementById("optTram").selected) {
                var dirW = new GDirections(null, info);
                GEvent.addListener(dirW, "error", function() {
                    document.getElementById("info").innerHTML = "";
                    polyline = dirD.getPolyline();
                    polyline.setStrokeStyle({color:objColors.normalColor, opacity:objColors.normalOpacity});
                    map.addOverlay(polyline);
                    var objLine = new clsLine(id, name, "1", polyline, head, tail)
                    objLC.array[id] = objLine;
                });
                GEvent.addListener(dirW, "load", function() {
                    //document.getElementById("echo").innerHTML += "DW |";
                    var distW = dirW.getDistance().meters;
                    var distD = dirD.getDistance().meters;
                    document.getElementById("info").innerHTML = "";
                    if (distD < distW)
                        polyline = dirD.getPolyline();
                    else
                        polyline = dirW.getPolyline();

                    polyline.setStrokeStyle({color:objColors.normalColor, opacity:objColors.normalOpacity});
                    map.addOverlay(polyline);
                    var objLine = new clsLine(id, name, "1", polyline, head, tail)
                    objLC.array[id] = objLine;
                });
                dirW.loadFromWaypoints(new Array(headLatLng, tailLatLng), { getPolyline: true, travelMode: G_TRAVEL_MODE_WALKING, preserveViewport: true });
            }
            else {
                //document.getElementById("echo").innerHTML += "D |";
                document.getElementById("info").innerHTML = "";
                polyline = dirD.getPolyline();
                polyline.setStrokeStyle({color:objColors.normalColor, opacity:objColors.normalOpacity});
                map.addOverlay(polyline);
                var objLine = new clsLine(id, name, "1", polyline, head, tail)
                objLC.array[id] = objLine;
            }
        });
        dirD.loadFromWaypoints(new Array(headLatLng, tailLatLng), { getPolyline: true, travelMode: G_TRAVEL_MODE_DRIVING, preserveViewport: true });
    };
    this.drawPattern = function(source) {
        // wyrysowywuje wzorzec
        document.getElementById("btnDodajSiec").disabled = "disabled";
        document.getElementById("btnDodajSiec").value = "Czekaj...";
        if (GBrowserIsCompatible()) {
            objMap.clear();

            var xmlhttp = GetXmlHttpObject();
            if (xmlhttp == null) {
                alert("Your browser does not support AJAX!");
                return;
            }
            var url;
            var number = new Number(source);
            if (isNaN(number))
                url = source;
            else {
                url = "src/patterns.php";
                url += "?f=2";
                url += "&id_city=" + source;
            }
            xmlhttp.open("GET", url, true);
            var requestTimer = setTimeout(function() {
                document.getElementById("progress").innerHTML = "i się przywiesiło...";
                xmlhttp.abort();
               // Handle timeout situation, e.g. Retry or inform user.
            }, 10000);
            xmlhttp.onreadystatechange = function() {
                if (xmlhttp.readyState != 4) {
                    document.getElementById("progress").innerHTML = "Wczytywanie połączeń...";
                    return;
                }
                clearTimeout(requestTimer);
                var xmlDoc = xmlhttp.responseXML;
                xmlPolylines = xmlDoc.getElementsByTagName("polyline");
                lstPolylinesLength = xmlPolylines.length;
                var progress = "Wyrysowano 0/" + (lstPolylinesLength) + " połączeń";
                document.getElementById("progress").innerHTML = progress;
                lstKeys = new Array();
                objMap.nextPolylinePattern();
            };
            xmlhttp.send(null);
        }
    };

    this.saveNewPolyline = function(schema_id, licznikZapisu) {
        if (licznikZapisu > lstPolylinesLength - 1) {
            objSC.showDefaultNav();
            objMap.clear();
            return;
        }
        var xmlhttp = GetXmlHttpObject();
        var line = objLC.array[lstKeys[licznikZapisu]];
        var coordinates = "";
        for (var i = 0; i < line.polyline.getVertexCount() - 1; i++) {
            var vertex = line.polyline.getVertex(i);
            coordinates += vertex.toUrlValue() + ",";
        }
        coordinates += line.polyline.getVertex(line.polyline.getVertexCount() - 1).toUrlValue();

        //var nameHeadTail = line.name.split(",");
        var url = "src/schemas.php";
        url += "?f=5";
        url += "&id=" + lstKeys[licznikZapisu];
        url += "&name=" + encodeURI(line.name);
        url += "&id_schema=" + schema_id;
        url += "&coordinates=" + coordinates;
        url += "&headlatlng=" + line.head.marker.getLatLng().toUrlValue();
        url += "&taillatlng=" + line.tail.marker.getLatLng().toUrlValue();
        url += "&sid=" + Math.random();
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {
                licznikZapisu++;
                var progress = "Zapisano " + (licznikZapisu) + "/" + (lstPolylinesLength) + " połączeń";
                document.getElementById("progress").innerHTML = progress;
                objMap.saveNewPolyline(schema_id, licznikZapisu);
            }
        };
        xmlhttp.open("GET", url, true);
        xmlhttp.send(null);
    }
    this.savePattern = function(schema_name, hidden) {
        // zachowuje wzorzec jako nowa siec
        var schema_id;
        lstKeys = new Array();
        var xmlhttp = GetXmlHttpObject();

        if (xmlhttp == null) {
            alert("Your browser does not support AJAX!");
            return;
        }
        var url = "src/schemas.php";
        url += "?f=4";
        url += "&name=" + schema_name;
        url += "&hidden=" + hidden;
        url += "&sid=" + Math.random();        
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {                
                var xmlDoc = xmlhttp.responseXML;
                var schemas = xmlDoc.getElementsByTagName("schema");
                schema_id = schemas[0].getAttribute("id");
                //var lstPolylinesLength = 0;
                //for (var key in lstPolylines) {
                //    lstPolylinesLength++;
                //}
                for (var key in objLC.array) {
                    lstKeys.push(key);
                }
                //document.getElementById("echo").innerHTML = lstKeys.length;
                objMap.saveNewPolyline(schema_id, 0);
            }
        };
        xmlhttp.open("GET", url, true);
        xmlhttp.send(null);
    };

    this.cmMouseover = function(cmDiv) {
        // kursor nad menu kontekstowym
        cmDiv.style.background = '#e0edf3';
        cmDiv.style.borderColor = '#a8d8eb';
    };
    this.cmMouseout = function(cmDiv) {
        // kursor opuscil menu kontekstowe
        cmDiv.style.background = 'Transparent';
        cmDiv.style.borderColor = 'Menu';
    };
    this.cmMakeStraight = function() {
        // kliknieto pozycje Resetuj z menu kontekstowego
        objMap.makeStraight(pointedLine);
        document.getElementById("context_menu").style.visibility = "hidden";
    };
    this.cmRestoreDefault = function() {
        // kliknieto pozycje Resetuj z menu kontekstowego
        objMap.restoreDefault(pointedLine);
        document.getElementById("context_menu").style.visibility = "hidden";
    };
    this.cmAcceptPolyline = function() {
        objMap.acceptPolyline(pointedLine);
        document.getElementById("context_menu").style.visibility = "hidden";
    }
    this.cmDeletePointedVertex = function() {
        //if (pointedVertexIndex < selectedLine.polyline.getVertexCount() - 1) {
        //    if (selectedPolyline.getVertex(pointedVertexIndex).distanceFrom(selectedPolyline.getVertex(pointedVertexIndex+1)) < 2)
        //        // w sytuacji gdy wlaczenie edycji utworzylo krawedzie nalozone na siebie usuwamy je obie
        //        selectedPolyline.deleteVertex(pointedVertexIndex+1);
        //}
        selectedLine.polyline.deleteVertex(pointedVertexIndex);
        document.getElementById("context_menu").style.visibility = "hidden";
    };
}
