      // Copyright 2005 Edvardas Scerbavicius, <edvardas@gmail.com>

      var osportns = "http://www.example.org/osportNS";
      var svgNS = "http://www.w3.org/2000/svg";
      var xlinkNS = "http://www.w3.org/1999/xlink";

      //var root = svg_document.getElementById("root");
	  var svg_document;// = document.getElementById("mapframe").contentDocument;
	  var root;// = svg_document.getElementById("root");
      var width;// = parseInt(root.getAttributeNS(null, "width"));
      var height;// = parseInt(root.getAttributeNS(null, "height"));

      //var toolbar = svg_document.getElementById("ToolBarBorder");
      var toolbar_width;// = parseInt(toolbar.getAttributeNS(null, "width"));
      var toolbar_height;// = parseInt(toolbar.getAttributeNS(null, "height"));
      var working_layer; // "run" or "course" // manau kad reikia shito atsikratyti... dabar yra "Layer" argumentas ant Toolsu
     
      function EventCtrl() {}
      EventCtrl.listeners = {mousedown:null, mousemove:null, mouseup:null};  

      EventCtrl.set = function(action, listener) {
            if (!listener) return;     

            EventCtrl.remove(action);
            EventCtrl.listeners[action] = listener;
            svg_document.addEventListener(action, listener, true);
      }

      EventCtrl.get = function(action) {
           return EventCtrl.listeners[action];
      }
	  
	  EventCtrl.fire = function(action) {
           listener = EventCtrl.listeners[action];
           if (listener) {
		        var evt = svg_document.createEvent("MouseEvents");
                evt.initMouseEvent(action, true, true, window, 0, -1, -1, -1, -1, false, false, false, false, 0, null);
                listener(evt);
			//	svg_document.dispatchEvent(evt);
		   }
      }
	  
      EventCtrl.remove = function(action) {
            listener = EventCtrl.listeners[action];
            if (listener) {
                svg_document.removeEventListener(action, listener, true);
                EventCtrl.listeners[action] = null;
            }
      }

       // -----------------------TOOLBAR-------START----------------
     function ToolBox() {}
     ToolBox.tool = null;
     ToolBox.overToolbar_listener = function(evt) {
              ToolBox.tool = EventCtrl.get("mousedown");
              EventCtrl.set("mousedown", MoveTool.pickobject_listener);
      }
      ToolBox.outToolbar_listener = function(evt) {
              EventCtrl.set("mousedown", ToolBox.tool);
      }
      // -----------------------TOOLBAR-----END------------------
      
      
      //======================OBJECT=FACTORY================START=============
      function Factory() {}
      Factory.id = 0;

      Factory.createSVGRect = function(x, y, w, h, color) {
          var rec = svg_document.createElementNS(svgNS, "rect");
          rec.setAttributeNS(null, "y", y);
          rec.setAttributeNS(null, "x", x);
          rec.setAttributeNS(null, "width", w);
          rec.setAttributeNS(null, "height", h);
          rec.setAttributeNS(null, "fill", color);
          return rec;
      }
      
      Factory.createSVGCircle = function(type, x, y, r, color) {
          var circle = svg_document.createElementNS(svgNS,"circle");
          circle.setAttributeNS(osportns,"type", type);
          circle.setAttributeNS(null,"r", r);
          circle.setAttributeNS(null,"cx", x);
          circle.setAttributeNS(null,"cy", y);
          circle.setAttributeNS(null,"stroke", color);
          circle.setAttributeNS(null,"stroke-width", "0.06cm");
          circle.setAttributeNS(null,"stroke-opacity", "0.9");
          circle.setAttributeNS(null,"fill-opacity", "0");
          circle.setAttributeNS(null,"id", "id" + Factory.id);
          Factory.id += 1;
          //svg_document.getElementById(layer).appendChild(circle);
          return circle;
      }
      
      Factory.createSVGTriangle = function(type, x, y, r, edge, color) {
          var newStart = svg_document.createElementNS(svgNS,"polygon");
          newStart.setAttributeNS(osportns,"type", type);
          newStart.setAttributeNS(osportns,"type", type);
          newStart.setAttributeNS(osportns,"r", r);
          newStart.setAttributeNS(osportns,"edge", edge);
          newStart.setAttributeNS(null,"stroke-width", "0.06cm");
          newStart.setAttributeNS(null,"stroke-opacity", "0.9");
          newStart.setAttributeNS(null,"fill-opacity", "0");
          newStart.setAttributeNS(null,"id", "id" + Factory.id);
          newStart.setAttributeNS(null,"stroke", color);
          
          var vertices = Geometry.calculateVertices({x:x, y:y}, r, {x:x, y:(y-r)}, edge);
          newStart.setAttributeNS(null, "points", "" + vertices.a.x + "," + vertices.a.y + " " +
                                               vertices.b.x + "," + vertices.b.y + " " +
                                               vertices.c.x + "," + vertices.c.y);

          var incenter = Geometry.calculateIncenterPosition(vertices.a, vertices.b, vertices.c);
          newStart.setAttributeNS(osportns, "incenterX", incenter.x);
          newStart.setAttributeNS(osportns, "incenterY", incenter.y);

          Factory.id += 1;
          //svg_document.getElementById(layer).appendChild(newStart);
          return newStart;
      }
      
      Factory.createSVGUse = function(layer, type, x, y, color) {
          var classname = "OsFinish";
          var newUseEl = svg_document.createElementNS(svgNS,"use");
          newUseEl.setAttributeNS(osportns,"type", type);
          newUseEl.setAttributeNS(null,"x", x);		
          newUseEl.setAttributeNS(null,"y", y);	
          newUseEl.setAttributeNS(null,"stroke", color); 
          newUseEl.setAttributeNS(null,"stroke-opacity", "0.9"); 
          newUseEl.setAttributeNS(null,"fill-opacity", "0"); 
          newUseEl.setAttributeNS(null,"stroke-width", "0.06cm");
          newUseEl.setAttributeNS(null,"id", "id" + Factory.id);
          Factory.id += 1;
          newUseEl.setAttributeNS(xlinkNS,"href","#" + classname);	
          //svg_document.getElementById(layer).appendChild(newUseEl);
          return newUseEl;
      }
      
      Factory.createSVGLine = function(type, point1, point2, style, idprefix) {
          var newLine = svg_document.createElementNS(svgNS,"polyline");
          newLine.setAttributeNS(osportns,"type", type);
          newLine.setAttributeNS(null, "points", point1.x + "," + point1.y + " " + point2.x + "," + point2.y);
          newLine.setAttributeNS(null,"id", idprefix + Factory.id);
          newLine.setAttributeNS(null, "stroke-opacity", "0.9");

          for (var i in style) {
                  newLine.setAttributeNS(null, style[i][0], style[i][1]); 
          }

          Factory.id += 1;
          //svg_document.getElementById(layer).appendChild(newLine);
          return newLine;
      }
                                                            //("course", "number", this.target.id.substring(2), "5", center.x, center.y);
      Factory.createSVGText = function(layer, type, id, txt, x, y) {
          var text = svg_document.createTextNode(txt);
          //alert(text.nodeValue);
          var newText = svg_document.createElementNS(svgNS,"text");
          newText.setAttributeNS(osportns,"type", type);
          newText.setAttributeNS(null,"id", id);
          newText.setAttributeNS(null,"x", x);
          newText.setAttributeNS(null,"y", y);
          newText.setAttributeNS(null,"font-family", "arial");
          newText.setAttributeNS(null,"font-weight", "bold");
          newText.setAttributeNS(null,"font-size", "16");
          newText.setAttributeNS(null,"fill-opacity", "0.9");
          newText.setAttributeNS(null,"fill", "#FF1493");
          //introspection(newText);
          newText.appendChild(text);
          return newText;
      }

      
      Factory.createGraphicObj = function(target) {
           //alert(target);
		   if (!target)
		       return null;
		   if (target.nodeName == "#document")
   		       return null;
		   
           if ("correspondingUseElement" in target) { // Opera
                 target = target.correspondingUseElement
           }
          
		  //console.log(target);
          var type = target.getAttributeNS(osportns,"type");

          if (!type) 
              return null;
          
          if ("toolbox" == type) {
              return new OsToolBar(target);
          }
          else if ("finish" == type) {
              return new OsFinish(target);
          }
          else if ("start" == type) {
              return  new OsStart(target);
          }
          else if ("line" == type) {
              return new OsLine(target);
          }
          else if ("controlpoint" == type) {
              return new OsControlPoint(target);
          }
          else if ("number" == type) {
              return new OsNumber(target);
          }
          else {
              //alert("implement it: " + type);
              return null;
          }
      }

      //======================OBJECT=FACTORY================END=================

	  
      //==============================TOOLS==============START================

      //==============================COURSE TOOL==============START=====================
      function Tool()  {}
      Tool.run = function() {
   		  EventCtrl.fire("mousedown"); // kadangi ToolBaras dabar jau ne SVG tai reikia imituoti mousedown,
      }
      
      function CourseTool()
      {   
           CourseTool.coursepoint = null; // first point of course line segment
      }

	  CourseTool.Command1 = function(first_point) {
	      function CourseToolCommand1(first_point) {
		      this.previous_point = CourseTool.coursepoint;
		      this.first_point = first_point;
			  //this.layer = layer;
		  }
		  CourseToolCommand1.prototype.execute = function() {
	           CourseTool.coursepoint = this.first_point;
               if (EventCtrl.get("mousedown") == CourseTool.firstpoint_listener) {// selektintas toolsas jau gali buti visai kitas!
                    EventCtrl.set("mousedown", CourseTool.secondpoint_listener); 
               }
			   return true;
		  }
		  CourseToolCommand1.prototype.undo = function() {
		      CourseTool.coursepoint = this.previous_point;
             // if (EventCtrl.get("mousedown") == CourseTool.secondpoint_listener) {
            //      EventCtrl.set("mousedown", CourseTool.firstpoint_listener);
            //  }
		  }
		  return new CourseToolCommand1(first_point);
	  }

      CourseTool.run = function(layer) {
          Tool.run();
          CourseTool.layer = layer; // possibly reikes atsratineti ir anksciau buvusi laeri.... (ant demo) nors vargu...
          EventCtrl.set("mousedown", CourseTool.firstpoint_listener);
      }

      CourseTool.firstpoint_listener = function(evt) {
   	       //if (!evt.isTrusted) return; // sugeneruotas klikas
           if(evt.clientX == -1) return;
	  	   Invoker.execute(CourseTool.Command1({x:evt.pageX, y:evt.pageY}));
      }

  	  CourseTool.Command2 = function(second_point) {
	      function CourseToolCommand2(second_point) {
		      this.previous_point = CourseTool.coursepoint;
		      this.second_point = second_point;
			  this.layer = CourseTool.layer;
		  }
		  CourseToolCommand2.prototype.execute = function() {
              if (!this.line) {
                  this.line = Factory.createSVGLine("line", CourseTool.coursepoint,  this.second_point, [["stroke","blue"], ["stroke-width","2px"], ["stroke-dasharray","2,2,2,2"]], "r");
              }
              svg_document.getElementById(this.layer).appendChild(this.line);
	          CourseTool.coursepoint = this.second_point;
		      return true;
		  }
		  CourseToolCommand2.prototype.undo = function() {
		      CourseTool.coursepoint = this.previous_point;
              svg_document.getElementById(this.layer).removeChild(this.line);
		  }
		  return new CourseToolCommand2(second_point);
	  }

      CourseTool.secondpoint_listener = function(evt) {   
         var obj = Factory.createGraphicObj(evt.target);
 	     //if (obj && (obj.id == "toolbox")) {console.log("XXX2"); return;}
	  
         var x = evt.pageX;
         var y = evt.pageY;

      	  if (((x < 0) || (y < 0)) || ((x > width) || (y > height))) {
		      //console.log("XXXX");
              return;
          }
          else {
	  	  	  Invoker.execute(CourseTool.Command2({x:evt.pageX, y:evt.pageY}));
          }
      }
      //==============================COURSE TOOL==============END=====================

       //==============================REMOVE TOOL==============START=====================
      function RemoveTool()  {}

      RemoveTool.run = function() {
           Tool.run();
           EventCtrl.set("mousedown", RemoveTool.removetool_listener);
      }

	  RemoveTool.Command = function(obj) {
	      function RemoveToolCommand(obj) {
		      this.obj = obj;
		  }
		  RemoveToolCommand.prototype.execute = function() {
			  this.obj.remove();
			  return true;
		  }
		  RemoveToolCommand.prototype.undo = function() {
			  this.obj.restore();
		  }
		  return new RemoveToolCommand(obj);
	  }

      RemoveTool.removetool_listener = function(evt) {
  	     //if (!evt.isTrusted) return; // sugeneruotas klikas
         if(evt.clientX == -1) return;

         var obj = Factory.createGraphicObj(evt.target);
 	     if (obj && (obj.id == "toolbox")) return;

         if (obj) {// Startas, KP ar Finishas, linija
		    Invoker.execute(RemoveTool.Command(obj));
  	     }
      }
	  //==============================REMOVE TOOL==============END=====================

	  //==============================COMMENT TOOL==============START=====================
	  
	  function CommentTool() {}
          CommentTool.comments = new Object;  

	  CommentTool.run = function() {
              Tool.run();
              EventCtrl.set("mousedown", CommentTool.commentobject_listener);
	  }
	  CommentTool.commentobject_listener = function(evt) {
              //console.log(evt.pageX, evt.pageY);
              //console.log("<div style='z-index:110; position:absolute; left:" + evt.pageX + "px; top:" + evt.pageY +"px;'>" + evt.pageX + "</div>");
             
			 /*
              $("html").append("<div style='z-index:110; position:absolute; left:" + (evt.pageX-1) + "px; top:" + (evt.pageY-16) +"px;'><a href=\"#extensions\" onclick=\"TagToTip('T2TBalloon', BALLOON, true, FADEIN, 400, FADEOUT, 400, ABOVE, true, WIDTH, 200, PADDING, 8, TEXTALIGN, 'justify', OFFSETX, -17)\" xonmouseout=\"UnTip()\"><img src='../images/icons/comment_big2.gif' border=\"0\"/></a></div>");*/
			  
			  $("html").append("<div style='z-index:110; position:absolute; left:" + (evt.pageX-1) + "px; top:" + (evt.pageY-16) +"px;'><img src='../images/icons/comment_big2.gif' border=\"0\" style=\"cursor:pointer\" onclick=\"showComment(this, event);\"/></div>");
			  
			  
              //console.log(document);
              /*
              var obj = Factory.createGraphicObj(evt.target);
              if (obj && obj.isCommentable) {
                      var hasnumber = obj.getNumber();
                      var number = '';
                      if (hasnumber) {
                            if (obj.id in CommentTool.comments) { 
                                 hasnumber = hasnumber.slice(0,-1); // pashaliname *
                            }
                            number = '&number='+hasnumber;
                      } 
                      else return;
                      var comment = (obj.id in CommentTool.comments) ? ('&comment='+CommentTool.comments[obj.id]) : '';

                      window.open('comment.html?demo&id=' + obj.id + number + comment, 'blank', 'width=400,height=90,status=yes');
              }
              */
	  }

	  CommentTool.comments_json = function() {
                var jsonstr = '';
                for (var property in CommentTool.comments) {
                      jsonstr += (property + ":\"" + CommentTool.comments[property] + "\",");
                }
                jsonstr = '{' + jsonstr.slice(0,-1) + '}';
                return jsonstr;  
          }

	  CommentTool.comment = function(objectid, comment) {
               var cp = Factory.createGraphicObj(svg_document.getElementById(objectid));
               if (!(objectid in CommentTool.comments) && comment) {
                    cp.setNumber(cp.getNumber()+'*');
               }
               if ((objectid in CommentTool.comments) && !comment) {
                    cp.setNumber(cp.getNumber().slice(0,-1));
                    delete CommentTool.comments[objectid];
               }
               if (comment) {
                     CommentTool.comments[objectid] = encodeURIComponent(comment);
               }
          }


	  //==============================COMMENT TOOL==============END=====================
	  
	  //==============================JOIN TOOL==============START=====================
	  function JoinTool() {
               JoinTool.selectedObj = null; // join this object with ->
               JoinTool.arrow = null; // show this arrow around selected oject
               JoinTool.newline = null;     // use this line
          }

	  JoinTool.run = function() {
              Tool.run();
              EventCtrl.set("mousedown", JoinTool.firstobject_listener);
	  }
	  
	  JoinTool.Command = function(obj) {
	      function JoinToolCommand(obj) {
		      this.first_obj = JoinTool.selectedObj;
		      this.second_obj = obj;
			  this.line = null;
			  this._undo_startlines = [];
			  //this.line = JoinTool.newline;
		  }
		  JoinToolCommand.prototype.execute = function() {
			  // reikia pashalinti/atstatyti tas linijas kurios junge starta su ansktesniu objektu
			  if(this.first_obj.isChangeable && (start_line = this.first_obj.getLine())) { // startai
		          this._undo_startlines.push(start_line.remove());
			  }
			  if(this.second_obj.isChangeable && (start_line = this.second_obj.getLine())) {
			      this._undo_startlines.push(start_line.remove());
		      }

              // jeigu KP jungiamas su startu jo numeris 1   // ish esme tai turetu buti realizuota join(connect) metode!
              if (this.first_obj instanceof OsStart && this.second_obj instanceof OsControlPoint) {
                 this.second_obj._undo_number = (this.second_obj.getNumber() || 0);
                 this.second_obj.updateNumber(1);
              }
              // jungiami du KP
              else if (this.first_obj instanceof OsControlPoint && this.second_obj instanceof OsControlPoint) {
                 if (hasnumber = this.first_obj.getNumber()) {
                    this.second_obj._undo_number = (this.second_obj.getNumber() || 0);
                    this.second_obj.updateNumber(parseInt(hasnumber.split(',').pop())+1);
                 }
              }
		
              if (!this.line) {
			      this.line = new OsLine(Factory.createSVGLine("line", {x:-1, y:-1}, {x:-1, y:-1}, [["stroke", "#FF1493"], ["stroke-width", "0.06cm"]], "ln"));
			      this.line.appendTo("course").join(this.first_obj, this.second_obj);
                 
			  }
			  else {
			       this.line.restore();
			  }
              return true;
		  }
		  JoinToolCommand.prototype.undo = function() {
			  this.line.remove(); // to neuzhtenka - dar reikia atstatyti sena jungtis su STARTU !
			  var len = this._undo_startlines.length;
			  for(var i=0; i<len; i++) {
			      this._undo_startlines.pop().restore().show(); // ji dar buvo paslepta kazhkur!
			  }
              
              if (this.second_obj._undo_number) {
                   this.second_obj.setNumber(this.second_obj._undo_number); 
              }
              else if(this.second_obj._undo_number == 0)  { // anksciau neturejo numerio - bet naujas numeris suteiktas
                   this.second_obj.removeNumber(); 
              }
		  }
		  return new JoinToolCommand(obj);
	 }


          /* Ishskiriam pazhymeta objekta ir ieshkom ka prie jo prijungti */
	 JoinTool.firstobject_listener = function(evt) {
             //if (!evt.isTrusted) return; // sugeneruotas klikas
             if(evt.clientX == -1) return;

             var obj = Factory.createGraphicObj(evt.target);

             if (obj && obj.isJoinable) // Startas, KP ar Finishas
             {
                  if (obj instanceof OsControlPoint) { //jei be numerio jungti negalime
                       var hasnumber = obj.getNumber();
                       if (!hasnumber) { return;}
                  }
                  JoinTool.selectedObj = obj;
               
                  //<arrow> code
                  if (JoinTool.arrow) {
                       JoinTool.arrow.hide().appendTo("course");
				  }
				  else {
				       JoinTool.arrow = new OsStart(Factory.createSVGTriangle("arrow", 0, 0, 3, 5, "#FF1493"));
                       JoinTool.arrow.hide().appendTo("course");
                       JoinTool.arrow.isJoinable = false; // gal kiek ugly?:)
				  }
                  // </arrow> code
               
                  if (JoinTool.newline) {
                      JoinTool.newline.hide().appendTo("course");
				  }
				  else {
				      JoinTool.newline = new OsLine(Factory.createSVGLine("line", {x:-1, y:-1}, {x:-1, y:-1}, [["stroke", "#FF1493"], ["stroke-width", "0.06cm"]], "ln"));
                      JoinTool.newline.hide().appendTo("course");
			      }
				  //svg_document.getElementById("course").appendChild(join_line);

                  EventCtrl.set("mousemove", JoinTool.move_listener);
                  EventCtrl.set("mousedown", JoinTool.secondobject_listener);
             }
       }
	      
      JoinTool.move_listener = function(evt) {
      	  var obj = Factory.createGraphicObj(evt.target);
          if (obj && obj.isJoinable && !obj.equal(JoinTool.selectedObj)) // Startas, KP ar Finishas
          {   
              JoinTool.arrow.hide();
              JoinTool.newline.connect(JoinTool.selectedObj, obj).show(); // connect line to objects and show it
          }
          else {

              //if (arrow) arrow.show(); // neefektyvu pastovei keisti atributa, nors butu galima uzhfiksuoti, kad jis ir taip yra matomas
              if(JoinTool.newline.isConnected)
                   JoinTool.newline.disconnect().hide(); // hide line // neefektyvu nes jau gali buti atjungt
              
              // <arrow> code
              var objCenter = JoinTool.selectedObj.getCenter();
              var p1 = Geometry.intersection(objCenter, JoinTool.selectedObj.radius+6, {x:evt.pageX, y:evt.pageY});
              var p2 = Geometry.intersection(objCenter, JoinTool.selectedObj.radius+9, {x:evt.pageX, y:evt.pageY});
              var vertices = Geometry.calculateVertices(p1, 3, p2, 5);
              JoinTool.arrow.setVertices(vertices);
              JoinTool.arrow.show(); 
              // </arrow> code
          }
      }
      
      
      JoinTool.secondobject_listener = function(evt) {
          JoinTool.arrow.remove();
          JoinTool.newline.remove();
      
          var obj = Factory.createGraphicObj(evt.target);
	      if (obj && obj.isJoinable && !obj.equal(JoinTool.selectedObj)) { // Startas, KP ar Finishas
  		      Invoker.execute(JoinTool.Command(obj));
		  }

          EventCtrl.remove("mousemove");
          EventCtrl.set("mousedown", JoinTool.firstobject_listener);
		  //console.log("WTF");
      }
      //==============================JOIN TOOL==============END===================


      //==============================NEW OBJECT TOOL==============START==============
	  function CreateTool() {
               CreateTool.objectClass = null;
          }
	  
	  CreateTool.run = function(name, layer) {
          Tool.run();
	      CreateTool.objectClass = name;
		  CreateTool.layer = layer;
          EventCtrl.set("mousedown", CreateTool.createobject_listener);
	  }
	  
	  CreateTool.Command = function(new_obj) {
	      function CreateToolCommand(new_obj) {
		      this.obj = new_obj;
			  this.layer = CreateTool.layer;
		  }
		  CreateToolCommand.prototype.execute = function() {
		      this.obj.appendTo(this.layer);
			  return true;
		  }
		  CreateToolCommand.prototype.undo = function() {
		      //svg_document.getElementById(layer).removeChild(this.target);
		      //this.obj.removeFrom(this.layer);
		      this.obj.target.parentNode.removeChild(this.obj.target);
		  }
		  return new CreateToolCommand(new_obj);
	  }
	
      CreateTool.createobject_listener = function(evt) {
          //alert(evt.clientX);
          if(evt.clientX == -1) return;
		 
		  var new_obj = CreateTool.objectClass.newInstance(evt.pageX, evt.pageY);
		  Invoker.execute(CreateTool.Command(new_obj));

          // Google MAPS window kodas:
		 /*
		  var mp = fromXYtoLatLng({x: evt.pageX, y:evt.pageY}); 
		  console.log("Shekit: x:%i y:%i", mp.lat, mp.lng);
                    map.setCenter(new GLatLng(mp.lng, mp.lat),15, G_SATELLITE_MAP);
		  addPointer(new GLatLng(mp.lng, mp.lat),18, 32, "#FF1493");
		  */
	  }
      //==============================NEW OBJECT TOOL==============END===============

      function fromXYtoLatLng(point) {
	      //var angles = {a:{lat:5, lng:1}, b:{lat:10, lng:6}}; 
		  var angles = {sw:{lat:54.67308197438369, lng:25.22134780883789}, ne:{lat:54.693465808838155, lng:25.25186061859131}};
	  
	      var new_width = angles.ne.lng - angles.sw.lng;
          var new_height = angles.ne.lat - angles.sw.lat;  
		  
		  var map_point = {lat:null, lng:null};
		  map_point.lat = angles.sw.lng + point.x * new_width/width;
		  map_point.lng = angles.sw.lat + (height-point.y) * new_height/height;
		  
		  return map_point;
	  }
	  
      function addPointer(g_point, r, edge, color) {
	      var x = map.fromLatLngToDivPixel(g_point).x;
	      var y = map.fromLatLngToDivPixel(g_point).y;
      
          var vertices = Geometry.calculateVertices({x:x, y:y}, r, {x:x, y:(y-r)}, edge);
          
       	  var newStart = new GPolygon([
            map.fromDivPixelToLatLng(new GPoint(vertices.a.x, vertices.a.y)),
            map.fromDivPixelToLatLng(new GPoint(vertices.b.x, vertices.b.y)),
            map.fromDivPixelToLatLng(new GPoint(vertices.c.x, vertices.c.y)),
            map.fromDivPixelToLatLng(new GPoint(vertices.a.x, vertices.a.y))
		  ], color, 2, 1, "#ff0000", 0);
		  
  	      map.clearOverlays(); // !!! ishtryneme visus markerius
          map.addOverlay(newStart);
          
          //return newStart;
          
      }

   
  
      //======MOVE TOOL=======================START=================================
        function MoveTool() {
              MoveTool.selectedObj = null;
        }
 
        MoveTool.run = function()  {
              Tool.run();
              EventCtrl.set("mousedown", MoveTool.pickobject_listener);
        }

		MoveTool.Command = function(point) {
	      function MoveToolCommand(point) {
		      this.obj = MoveTool.selectedObj;
		      this.point = point;
			  this._undo_point = this.obj._undo_point;
		  }
		  MoveToolCommand.prototype.execute = function() {
			  this.obj.move(this.point.x, this.point.y);
			  return true;
		  }
		  MoveToolCommand.prototype.undo = function() {
			  this.obj.move(this._undo_point.x, this._undo_point.y);
		  }
		  return new MoveToolCommand(point);
	    }
      	  
        MoveTool.pickobject_listener = function(evt) {
  	          //if (!evt.isTrusted) return; // sugeneruotas klikas
              if(evt.clientX == -1) return;


              MoveTool.selectedObj = Factory.createGraphicObj(evt.target);
              if (!MoveTool.selectedObj) return; // tokio objekto sukurti negalime
              if (!MoveTool.selectedObj.isMovable) return; // negalime judinti

              MoveTool.selectedObj._undo_point = {x:evt.pageX, y:evt.pageY};
			  MoveTool.selectedObj.setMovePoint(evt.pageX, evt.pageY);
              EventCtrl.set("mousemove", MoveTool.moveobject_listener);
              EventCtrl.set("mouseup", MoveTool.putobject_listener);
        }

        MoveTool.moveobject_listener = function(evt) {
   	      //var id = MoveTool.selectedObj.target.ownerSVGElement.suspendRedraw(1000);
   	      MoveTool.selectedObj.move(evt.pageX, evt.pageY);
          //MoveTool.selectedObj.target.ownerSVGElement.unsuspendRedraw(id);
        }

       MoveTool.putobject_listener = function(evt) {
	       var point = {x:evt.pageX, y:evt.pageY};
	          if((point.x != MoveTool.selectedObj._undo_point.x)||(point.y != MoveTool.selectedObj._undo_point.y)){
	      		  Invoker.execute(MoveTool.Command(point));
			  }
              EventCtrl.remove("mousemove");
              EventCtrl.remove("mouseup");
       }
      //======MOVE TOOL=======================END==============================


      function domTool()
     {  //http://kb.mozillazine.org/Parsing_and_serializing_XML
         var serializer = new XMLSerializer();
         var doc = svg_document.getElementById("course");
         var xml = serializer.serializeToString(doc);
         alert(xml);
           //       Factory.createSVGCircle("course", "test",500, 100, 5, "red");
      }

	  //==============================TOOLS==============END===================

	  
      // COMMON OBJECT METHODS --------------- START -----------------
	  appendTo = function(layer) {
	       svg_document.getElementById(layer).appendChild(this.target);
		   return this;
	  }
	  //removeFrom = function(layer) {
	   //    svg_document.getElementById(layer).removeChild(this.target);
	  //     //intro(svg_document.getElementById(layer));
	//	   //console.log(svg_document.getElementById(layer));
	 // }
      OsFinish.prototype.appendTo = appendTo;
      OsStart.prototype.appendTo = appendTo;
      OsControlPoint.prototype.appendTo = appendTo;
      OsLine.prototype.appendTo = appendTo;
      //OsLine.prototype.equal = equal;
      //OsFinish.prototype.removeFrom = removeFrom;
      //OsStart.prototype.removeFrom = removeFrom;
      //OsControlPoint.prototype.removeFrom = removeFrom;
      //OsLine.prototype.removeFrom = removeFrom;
      //OsLine.prototype.equal = equal;
	  

      function equal(obj) {
          if (!obj) return false;
          return (this.target == obj.target);
      }
      OsFinish.prototype.equal = equal;
      OsStart.prototype.equal = equal;
      OsControlPoint.prototype.equal = equal;
      OsLine.prototype.equal = equal;

      function addLineId(id) {
          var linestr = this.target.getAttributeNS(osportns, "lines");
          var lines = new Array;
          
          if (linestr)
              lines = IdArray.createFromString(linestr);
              
          lines.push(id);
          this.target.setAttributeNS(osportns, "lines", lines.join());
      }
      OsFinish.prototype.addLineId = addLineId;
      OsControlPoint.prototype.addLineId = addLineId;
      
      function getLines() {
	      var idString = this.target.getAttributeNS(osportns, "lines");
	      var lines = new Array;

              // alert("lines", idString);

	      if (idString) { // attributas egzistuoja
 	          var ids = IdArray.createFromString(idString);// => ["id1", "id2", "id3"];
	      
	          for (var i in ids) {
                  var target = svg_document.getElementById(ids[i]);
      	          var obj = Factory.createGraphicObj(target);
      	          lines.push(obj);
	          }
	      }
	      return lines; 
      }       
      OsFinish.prototype.getLines = getLines;
      OsControlPoint.prototype.getLines = getLines;
      
      function updateLines() {
          if (!this.lines)
               this.lines = this.getLines(); // <circle osport:lines="id1, id2, id3"/>
          
	      for (var i in this.lines) {
	          this.lines[i].update(); // perpaishome visas linijas
	      }
      }
      OsFinish.prototype.updateLines = updateLines;
      OsControlPoint.prototype.updateLines = updateLines;
     
      function removeLine(id) {
          var linestr = this.target.getAttributeNS(osportns, "lines");
          var lines = new Array;
          
          if (linestr)
              lines = IdArray.createFromString(linestr);
          
          for(var i in lines) {
              if(lines[i] == id) {
                  lines.splice(i, 1);
              }
          }
          this.target.setAttributeNS(osportns, "lines", lines.join());
      }
      OsFinish.prototype.removeLine = removeLine;
      OsControlPoint.prototype.removeLine = removeLine;

      function remove() {
          if (working_layer != "course") return; 
          
          this._undo_lines = this.getLines();
          for(var i in this._undo_lines) {
              this._undo_lines[i].remove(); // pashaliname visas prijungtas linijas
          }
          // jei tai controlpointas, tai jeigu jis turi numeri reikia pashalinti ir numeri.
          var hasnumber = this.target.getAttributeNS(osportns, "number");
          if (hasnumber) {
		         this._undo_number = svg_document.getElementById("nb" + this.id.substring(2));
                 this.target.parentNode.removeChild(this._undo_number);
                 //introspection(document); //.getElementById("nb" + this.target.id.substring(2)));
          }

          this._undo_parentNode = this.target.parentNode;
          this._undo_parentNode.removeChild(this.target);
          // ir tik tada pashaliname save
		  return this;

      }
      OsFinish.prototype.remove = remove;
      OsControlPoint.prototype.remove = remove;
	  
	  function restore() {
          this._undo_parentNode.appendChild(this.target);
          if (this._undo_number) this._undo_parentNode.appendChild(this._undo_number);
          for(var i in this._undo_lines) {
              this._undo_lines[i].restore(); // pashaliname visas prijungtas linijas
          }
		  return this;
	  }
      OsFinish.prototype.restore = restore;
      OsControlPoint.prototype.restore = restore;

      // COMMON OBJECT METHODS --------------- END -------------------


      // == ToolBar object ======================START========================
      function OsToolBar(target)
      {   
          this.target = target;
          this.isJoinable = false;
          this.isMovable = true;
          this.id = this.target.getAttributeNS(null,"id");

      }
      OsToolBar.prototype.setMovePoint = function(x, y) {
          this.dx = this.target.x.baseVal.value - x;
          this.dy = this.target.y.baseVal.value - y;
      }
      OsToolBar.prototype.move = function(x, y) {
          //var width = parseInt(svg_document.firstChild.getAttribute("width"));
      	  //var height = parseInt(svg_document.firstChild.getAttribute("height"));
      	  
      	  xposition = x + this.dx;
      	  yposition = y + this.dy;
      	  
      	  if ((xposition < 0) || (yposition < 0)) return;
      	  if ((xposition > (width - toolbar_width)) || (yposition > (height-toolbar_height))) return;
      	  
      	  this.target.x.baseVal.value = xposition; //x + this.dx;
	      this.target.y.baseVal.value = yposition; //y + this.dy;
      }

      // == ToolBar object ======================END=========================

      // == OsNumber object ======================START=========================
      function OsNumber(target)
      {   
          this.target = target;
          this.isJoinable = false;
          this.isMovable = true;
          this.id = this.target.getAttributeNS(null,"id");
          this.dx = 0;
          this.dy = 0;
      }
      OsNumber.prototype.setMovePoint = function(x, y) {
          this.dx = this.target.getAttributeNS(null,"x") - x;
          this.dy = this.target.getAttributeNS(null,"y") - y;
      	  //intro(this.target.x.baseVal);
      }
      OsNumber.prototype.move = function(x, y) {
      	  xposition = x + this.dx;
    	  yposition = y + this.dy;
          this.target.setAttributeNS(null,"x", xposition);
          this.target.setAttributeNS(null,"y", yposition);
      }
      OsNumber.prototype.getPosition = function() {
           return {x:this.target.getAttributeNS(null,"x"), y:this.target.getAttributeNS(null,"y")};
      }
      OsNumber.prototype.getValue = function() {
           return this.target.firstChild.nodeValue;
      }
      OsNumber.prototype.setValue = function(value) {
           this.target.firstChild.nodeValue = value;
      }
      OsNumber.prototype.remove = function() {
           this._undo_cp = svg_document.getElementById("id" + this.id.substring(2));
		   this._undo_cp_number = this._undo_cp.getAttributeNS(osportns, "number");
           this._undo_cp.removeAttributeNS(osportns, "number");
           this._undo_parentNode = this.target.parentNode;
		   this._undo_parentNode.removeChild(this.target);
		   return this;
      }

      OsNumber.prototype.restore = function() {
	      this._undo_parentNode.appendChild(this.target);
		  this._undo_cp.setAttributeNS(osportns, "number", this._undo_cp_number);
		  return this;
	  }

      // == OsNumber object ======================END=========================

      // == OsFinish object ======================START========================
      function OsFinish(target)
      {   
          this.target = target;
          this.isJoinable = true;
          this.isMovable = true;
          
          this.id = this.target.getAttributeNS(null,"id");
          var element = svg_document.getElementById("OsOuterCircle");
          this.stepX = element.cx.baseVal.value;
          this.stepY = element.cy.baseVal.value; 

          this.radius = element.r.baseVal.value;                
          this.dx = 0;
          this.dy = 0;
          
          this.lines = null;
      }
      
      OsFinish.prototype.move = function(x, y) {
          var newx = x + this.dx;
          var newy = y + this.dy;

      	  if ((newx < (- this.radius)) || (newy < (- this.radius))) return;
      	  if ((newx > (width - this.radius)) || (newy > (height - this.radius))) return;

       	  this.target.x.baseVal.value = newx;
	  this.target.y.baseVal.value = newy;
	  this.updateLines();
      }
      
      OsFinish.prototype.getCenter = function() {
          return {x:this.target.x.baseVal.value + this.stepX, y:this.target.y.baseVal.value + this.stepY};
      }

      OsFinish.prototype.setMovePoint = function(x, y) {
          this.dx = this.target.x.baseVal.value - x;
          this.dy = this.target.y.baseVal.value - y;
      }
           
      OsFinish.newInstance = function(x, y) {
          var radius = svg_document.getElementById("OsOuterCircle").r.baseVal.value;
         // alert(radius);
          return new OsFinish(Factory.createSVGUse("course", "finish", x - radius, y - radius, "#FF1493"));
      }

      // == OsFinish object ======================END========================
      
      
      // == OsStart object ======================START========================
      function OsStart(target)
      {   
          this.target = target;
          this.isJoinable = true;
          this.isChangeable = true;
          this.isMovable = true;
          this.id = this.target.getAttributeNS(null,"id");

          this.radius = parseInt(target.getAttributeNS(osportns, "r"));//24;                
          this.edge = parseInt(target.getAttributeNS(osportns, "edge"));//42;                
          this.dx = 0;
          this.dy = 0;
          this.line = null;
      }
      
      OsStart.prototype.hide = function() {
           this.target.setAttributeNS(null,"visibility", "hidden");
		   return this;
     }
      OsStart.prototype.show = function() {
           this.target.setAttributeNS(null,"visibility", "visible");
		   return this;
     }


      OsStart.prototype.move = function(x, y) {
          var newx = x + this.dx;
          var newy = y + this.dy;

      	  if ((newx < 0) || (newy < 0)) return;
      	  if ((newx > width) || (newy > height)) return;

          this.target.setAttributeNS(osportns, "incenterX", newx);
          this.target.setAttributeNS(osportns, "incenterY", newy);

          this.updateLine();

          if (!this.line) { // nepajungtas
              var vertices = Geometry.calculateVertices(
              {x:newx, y:newy}, this.radius, {x:newx, y:(newy-this.radius)}, this.edge);
              this.setVertices(vertices);
          }
      }
      
      OsStart.prototype.getCenter = function() {
          var x = this.target.getAttributeNS(osportns, "incenterX");
          var y = this.target.getAttributeNS(osportns, "incenterY");
          
          return {x:parseInt(x), y:parseInt(y)};
      }
      
      OsStart.prototype.updateLine = function() {
         var id = this.target.getAttributeNS(osportns, "line");
         if (id) {
             var target = svg_document.getElementById(id);
             this.line = Factory.createGraphicObj(target);
             this.line.update();
         }
         else { // liko be liniju
           //this.defaultVertices();
         }
      }
      
      OsStart.prototype.defaultVertices = function() {
          var center = this.getCenter();
          var vertices = Geometry.calculateVertices(center, this.radius, {x:center.x, y:(center.y-this.radius)}, this.edge);
          this.setVertices(vertices);
      }
      
      // uzhrashome tashka uzh kurio paememe objekta, kad uzh jo galetume ji tempti
      OsStart.prototype.setMovePoint = function(x, y) {
          var center = this.getCenter();
          this.dx = center.x - x;
          this.dy = center.y - y;
      }
      
      OsStart.prototype.getLine = function() {
          var id = this.target.getAttributeNS(osportns, "line");
          var line = null;
          if (id) {
  	          var target = svg_document.getElementById(id);
              line = Factory.createGraphicObj(target);
          }
          return line;
      }

      OsStart.prototype.remove = function() {
          if (working_layer != "course") return; 

          this._undo_line = this.getLine();
          if (this._undo_line) this._undo_line.remove(); // pashaliname prijungta linija
          this._undo_parentNode = this.target.parentNode;
          this._undo_parentNode.removeChild(this.target);
          // ir tik tada pashaliname save
		  return this;
      }
	  
      OsStart.prototype.restore = function() {
	      this._undo_parentNode.appendChild(this.target);
		  if (this._undo_line) this._undo_line.restore();
		  return this;
	  }
	  
      OsStart.prototype.update = function(obj) {
          var center = this.getCenter();
          var point = obj.getCenter();
          // 2. galima pasinaudojus intersection(), parinkti jungties tashka
          var p1 = Geometry.intersection({x:point.x, y:point.y}, this.radius, {x:center.x, y:center.y});
          var p2 = Geometry.intersection({x:center.x, y:center.y}, this.radius, {x:point.x, y:point.y});
          // 3. surasti du likusius tashkus
          var vertices = Geometry.calculateVertices(center, this.radius, p2, this.edge);
          this.setVertices(vertices);
      }

     
      OsStart.prototype.setVertices = function(vertices) {
          //var id = this.target.ownerSVGElement.suspendRedraw(1000);
          this.target.setAttributeNS(null, "points", "" + vertices.a.x + "," + vertices.a.y + " " +
                                                   vertices.b.x + "," + vertices.b.y + " " +
                                                   vertices.c.x + "," + vertices.c.y);
          //this.target.ownerSVGElement.unsuspendRedraw(id);
      }

      
      OsStart.prototype.addLineId = function(id) {
          //var line = this.getLine();
          //if(line)
          //    line.remove(); // chia sena linija pashalinama
               
          this.target.setAttributeNS(osportns, "line", id);
      }
      
      OsStart.prototype.removeLine = function(id) {
          var lineid = this.target.getAttributeNS(osportns, "line");
          if (lineid == id) {
              this.target.setAttributeNS(osportns, "line", "");
              //this.defaultVertices();
          }
      }
 
      OsStart.newInstance = function(x, y) { //24,42
          return new OsStart(Factory.createSVGTriangle("start", x, y, 18, 32, "#FF1493"));
      }
      // == OsStart object ======================END========================
      
      

      // == OsControlPoint object =====================START====================
      function OsControlPoint(target)
      {   
          this.target = target;
          this.isJoinable = true;
          this.isMovable = true;
          this.isCommentable = true;
          this.id = this.target.getAttributeNS(null,"id");

          this.dx = 0;
          this.dy = 0;
          
          this.radius = this.target.r.baseVal.value;                
          this.lines = null;
      }


      OsControlPoint.prototype.move = function(x, y) {
          oldCenter = this.getCenter(); // reikia numerio stumdymui
          var newx = x + this.dx;
          var newy = y + this.dy;

      	  if ((newx < 0) || (newy < 0)) return;
      	  if ((newx > width) || (newy > height)) return;

      	  this.target.cx.baseVal.value = newx; //x + this.dx; // perkelem apskritima
          this.target.cy.baseVal.value = newy; //y + this.dy;

	  this.updateLines();
          var hasnumber = this.getNumber();
          if(hasnumber) {
                var number = new OsNumber(svg_document.getElementById("nb" + this.id.substring(2)));
                var number_pos = number.getPosition();
                number.move(newx-(oldCenter.x - number_pos.x), newy-(oldCenter.y - number_pos.y));
          }
      }
	  
	  
      OsControlPoint.prototype.getCenter = function() {
          return {x:this.target.cx.baseVal.value, y:this.target.cy.baseVal.value};
      }
	  
      
      OsControlPoint.prototype.setMovePoint = function(x, y) {
          this.dx = this.target.cx.baseVal.value - x;
          this.dy = this.target.cy.baseVal.value - y;
      }

      OsControlPoint.prototype.getNumber = function() {
           return this.target.getAttributeNS(osportns, "number");
      }
      
      OsControlPoint.prototype.removeNumber = function() {
           var number = new OsNumber(svg_document.getElementById("nb" + this.id.substring(2)));
           number.remove();
           this.target.removeAttributeNS(osportns, "number");
      }

      OsControlPoint.prototype.setNumber = function(value) {
              var number = new OsNumber(svg_document.getElementById("nb" + this.id.substring(2)));
              number.setValue(value);
              this.target.setAttributeNS(osportns, "number", value);
      }
      
      OsControlPoint.prototype.updateNumber = function(value) {
         var center = this.getCenter();
         var number = this.getNumber();
         if (!number) {
              this.target.setAttributeNS(osportns, "number", value);
              var newText = Factory.createSVGText("course", "number", "nb" + this.id.substring(2), value, center.x-5, center.y-18);
              svg_document.getElementById("course").appendChild(newText);

         }
         else if(number){
              //var number = new OsNumber(svg_document.getElementById("nb" + this.id.substring(2)));
              //console.log(hasnumber, number.getValue());
              var old_number = number.split(',').map(function(x) {return parseInt(x)});
              if (old_number.indexOf(value) == -1) {
                   //console.log(value, old_number);
                   old_number.push(value);
                   old_number.sort(function(a,b){return a-b});
                   //numbers = number + ',' + value;
                   this.setNumber(old_number.join(","));
              }
              //this.target.setAttributeNS(osportns, "number", numbers);
         }
      }
	  
      OsControlPoint.newInstance = function(x, y) {
          return new OsControlPoint(Factory.createSVGCircle("controlpoint", x, y, 14, "#FF1493"));
      }
      // == OsControlPoint object =====================END=====================
  
  
      // == OsLine object =====================START=========================
      function OsLine(target)
      {   
          this.target = target;
          this.isJoinable = false;
          this.isMovable = false;
          this.id = this.target.getAttributeNS(null,"id");
          
          this.obj1 = null;
          this.obj2 = null;
      }
	  
      OsLine.prototype.hide = function() {
           this.target.setAttributeNS(null,"visibility", "hidden");
		   return this;
      }
      OsLine.prototype.show = function() {
           this.target.setAttributeNS(null,"visibility", "visible");
		   return this;
      }

	  // bandymas atsikratyti .coonect ir .save
      OsLine.prototype.join = function(obj1, obj2) {
	      this.connect(obj1, obj2);
          this.target.setAttributeNS(osportns, "objects", [this.obj1.id, this.obj2.id].join());
          this.obj1.addLineId(this.id);
          this.obj2.addLineId(this.id);

/*          
          // jeigu KP jungiamas su startu jo numeris 1   // ish esme tai turetu buti realizuota join(connect) metode!
          if (this.obj1 instanceof OsStart) {
              if (this.obj2 instanceof OsControlPoint) {
                  this.obj2.updateNumber(1);
              }
          }
          // jungiami du KP
          else if (this.obj1 instanceof OsControlPoint) {
              var hasnumber = this.obj1.getNumber();
              if (hasnumber && this.obj2 instanceof OsControlPoint) {
                  this.obj2.updateNumber(parseInt(hasnumber.split(',').pop())+1);
              }
          }
          */

		  return this;
      }
      
      // Shito metodo pagalba line objektas suzhino kokius objektus jis jungs
      OsLine.prototype.connect = function(obj1, obj2) {
          this.obj1 = obj1;
          this.obj2 = obj2;

          if (this.obj1.isChangeable) { // paslepiame sena(fiksuota) starto jungti!
              if (line = this.obj1.getLine()) // laikinai paslepsime sena jungti
                   line.hide();
          }
          if (this.obj2.isChangeable) {
              if (line = this.obj2.getLine())
                   line.hide();
          }
         
          this.update(); // kadangi nustatyti nauji this.obj1 ir this.obj2, tai Startai bus automatishaki orientuoti vienas i kita!
          this.isConnected = true;
	      return this;
      }
      
      OsLine.prototype.disconnect = function() {
          if (this.obj1.isChangeable) {
               if (line = this.obj1.getLine()) { // atstatome sena startu jungti
                   line.show();
                   this.obj1.updateLine();
               }
          }
          if (this.obj2.isChangeable) {
               if (line = this.obj2.getLine()) {
                   line.show();
                   this.obj2.updateLine();
               }
          }
          this.obj1 = this.obj2 = null;
          this.isConnected = false;
		  return this;
      }

      
      // perpaishoma linija ir jos jungiami objektai (jei reikia)
      OsLine.prototype.update = function() {
          //var id = this.target.ownerSVGElement.suspendRedraw(1000);
        
          if (!(this.obj1 && this.obj2)) {
              var objs = this.getObjects();
			  if (!objs) return this;
              this.obj1 = objs[0];
              this.obj2 = objs[1];
          }
          
          if (this.obj1.isChangeable)      // jei tai startas, tai reikia ji perpieshti
              this.obj1.update(this.obj2); 
          if (this.obj2.isChangeable)
              this.obj2.update(this.obj1); // ---||---
      
          var center1 = this.obj1.getCenter();
          var center2 = this.obj2.getCenter();
 
          var p1 = Geometry.intersection(center1, this.obj1.radius, center2);
          var p2 = Geometry.intersection(center2, this.obj2.radius, center1);
           
          this.target.setAttributeNS(null, "points", p1.x + "," + p1.y + " " + p2.x + "," + p2.y);

          //alert(p1.x + "," + p1.y + " " + p2.x + "," + p2.y);
          //this.target.ownerSVGElement.unsuspendRedraw(id);
		  return this;
      }
     
      OsLine.prototype.getObjects = function() {
          var objstr = this.target.getAttributeNS(osportns, "objects");
          if(!objstr) return null;
          
          var idarr = IdArray.createFromString(objstr);       
          var objarr = new Array;
          for (i in idarr) {
               objarr.push(Factory.createGraphicObj(svg_document.getElementById(idarr[i])));
          }
          return objarr; //idarr.map(function (id) {return Factory.createGraphicObj(svg_document.getElementById(id));});
      }
     
      OsLine.prototype.remove = function() {
	      //console.log("removing line: ", this.id);
          this._undo_objs = this.getObjects();
          if (this._undo_objs) {
              for (var i=0; i<this._undo_objs.length; i++) {
			      if (!this._undo_objs[i]) continue; // chia Operoje kazkodel kartais jie buna null
                  this._undo_objs[i].removeLine(this.id);
              }
          }
          //svg_document.getElementById(working_layer).removeChild(this.target);
		  this._undo_parentNode = this.target.parentNode;
          this._undo_parentNode.removeChild(this.target);
		  return this;
      }
	  
      OsLine.prototype.restore = function() {
	      //console.log("line restore: ", this.id);
		  this._undo_parentNode.appendChild(this.target);
          //var objs = this.getObjects();
          if (this._undo_objs) {
              for (var i in this._undo_objs) {
                  this._undo_objs[i].addLineId(this.id);
              }
          }
		  this.update();
		  return this;
	  }
	  
      
//      OsLine.newInstance = function(lpoint, rpoint) {
//          return new OsLine(Factory.createSVGLine("linecontrolpoint", x, y, 18, "#FF1493"));
//      }

      // == OsLine object =====================END=========================



      // == Geometry object ======================START======================
      function Geometry()  {}
      
      /* 
      paskaichiuoja dvieju apskritimu susikirtimu tashkus
      taip gauname trikampio virshuniu koordinates 
      */
      Geometry.calculateVertices = function(centerA, radiusA, centerB, radiusB) {
         // http://mathforum.org/library/drmath/view/51836.html

         var v1 = new Object();
         var v2 = new Object();
      
         var e = centerB.x - centerA.x;
         var f = centerB.y - centerA.y;
         var p = Math.sqrt(Math.pow(e, 2) + Math.pow(f, 2));
         var k = (Math.pow(p, 2) + Math.pow(radiusA, 2) - Math.pow(radiusB, 2)) / (2 * p); 
         var b = Math.sqrt(Math.pow(radiusA, 2) - Math.pow(k, 2));                             
         v1.x = centerA.x + e * k/p + (f/p) * b;
         v1.y = centerA.y + f * k/p - (e/p) * b;
         //OR
         v2.x = centerA.x + e * k/p - (f/p) * b;
         v2.y = centerA.y + f * k/p + (e/p) * b;

         return {a: {x: Math.round(centerB.x), y: Math.round(centerB.y)}, 
                  b: {x: Math.round(v1.x), y: Math.round(v1.y)}, 
                  c: {x: Math.round(v2.x), y: Math.round(v2.y)}};
          
      }
    
      /*
      paskaichiuoja apskritimo ir tieses (einanchios per apskritimo centra ir a2) susikirtimo tashka
      */
      Geometry.intersection = function(c, r, a2) {
      // http://www.kevlindev.com/gui/math/intersection/
      
          var a  = Math.pow((a2.x - c.x), 2) + Math.pow((a2.y - c.y), 2);
          var deter = 4*a*Math.pow(r,2);

          if ( deter == 0 ) {
              return {x:c.x, y:c.y}; // VIENAS tashkas
          } else {
              var e  = Math.sqrt(deter);
              var u1 = e / ( 2*a );
           //   var u2 = (-e) / ( 2*a ); // tolimesnis tashkas
        
              var x1 = c.x + (a2.x - c.x) * u1;
              var y1 = c.y + (a2.y - c.y) * u1;

              return {x:x1, y:y1};
          }
      }
      
      /*
      paskaichiuoja lygiakraschio trikampio centro tashka
      */      
      Geometry.calculateIncenterPosition = function(a,b,c) {
          // http://poppy.macromedia.com/~thiggins/articles/incenter/
          var sideA = Math.sqrt(Math.pow(a.x - b.x,2) + Math.pow(a.y - b.y,2));
          var icx = (a.x + b.x + c.x) / 3;
          var icy = (a.y + b.y + c.y) / 3;
        
          return {x:Math.round(icx), y:Math.round(icy)};
      }


	        /*
      paskaichiuoja trumpiausia atstuma nuo tasko iki atkarpos (arba iki linijos, jei toline==true)
      a,b - tieses taskai, c - nutoles taskas
	  */      
	Geometry.calculateDistanceFromLine = function(a,b,c, toline) {
	
	  //http://www.codeguru.com/forum/printthread.php?t=194400
		var r_numerator = (c.x-a.x)*(b.x-a.x) + (c.y-a.y)*(b.y-a.y);
        var r_denomenator = (b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y);
        var r = r_numerator / r_denomenator;

		var px = a.x + r*(b.x-a.x);
		var py = a.y + r*(b.y-a.y);
    
		var s = ((a.y-c.y)*(b.x-a.x)-(a.x-c.x)*(b.y-a.y) ) / r_denomenator;

        var distanceLine = Math.abs(s)*Math.sqrt(r_denomenator);
		if(toline) return distanceLine;

		// (xx,yy) is the point on the lineSegment closest to (cx,cy)
        var xx = px;
        var yy = py;

        if ((r >= 0) && (r <= 1)) {
            return distanceLine;
			//distanceSegment = distanceLine;
        }
        else {
			var dist1 = (c.x-a.x)*(c.x-a.x) + (c.y-a.y)*(c.y-a.y);
            var dist2 = (c.x-b.x)*(c.x-b.x) + (c.y-b.y)*(c.y-b.y);
           
			if (dist1 < dist2) {
                xx = a.x;
                yy = a.y;
                return Math.sqrt(dist1);
            }
            else {
                xx = b.x;
                yy = b.y;
                return Math.sqrt(dist2);
            }
        }
	}

    // == Geometry object ======================END========================
      
      
      
      //======================IdArray====================START=============
      function IdArray() {}
      IdArray.createFromString = function(idString) {
         var ids = idString.split(',');
        // var iids = new Array;
        // for (i in ids) {
        //      iids.push(ids[i].replace(/^\s+|\s+$/gm,''));
        // }           
        //  return iids; 
          
		  return ids;
		  //return idString.split(',').map(function(str) {return str.replace(/^\s+|\s+$/gm,'');});
      }
      //======================IdArray====================END===============
      
      //======================SVGTip====================START==============
      function Tip() {}
      Tip.elements = null;

      Tip.Create = function() {
          var x = 0;
          var y = 0;
         
          var rec = Factory.createSVGRect(x, y, 0, 14, "#edefc2");
          var border = Factory.createSVGRect(x-1, y-1, 0, 16, "black");
          var str = svg_document.createTextNode("Control Point Tool");

          var txt = svg_document.createElementNS(svgNS, "text");
          //this.txt.setAttribute("style", "font-family:arial; font-size:10px; fill:black;");
          txt.setAttributeNS(null, "font-family", "arial");
          txt.setAttributeNS(null, "font-size", "10px");
          txt.setAttributeNS(null, "fill", "black");
          txt.setAttributeNS(null, "y", y + 10);
          txt.setAttributeNS(null, "x", x + 1);
          txt.appendChild(str);
         
          var grp = svg_document.createElementNS(svgNS, "g");
          grp.setAttributeNS(null, "transform", "translate(0,0)");
          grp.setAttributeNS(null, "visibility", "hidden");
          grp.appendChild(border);
          grp.appendChild(rec);
          grp.appendChild(txt);
 
          svg_document.documentElement.appendChild(grp);

          Tip.elements = {str: str, grp:grp, txt:txt, rec:rec, border:border};
      }
      Tip.showTip = function(x, y, text) {
          Tip.elements.str.nodeValue = decodeURIComponent(unescape(text));
          Tip.elements.grp.setAttributeNS(null, "visibility", "visible");
          var textwidth = Tip.elements.txt.getComputedTextLength() + 0.5*10;
          Tip.elements.rec.setAttributeNS(null, "width", textwidth);
          Tip.elements.border.setAttributeNS(null, "width", textwidth+2);

           var root = svg_document.getElementById("root");
           var width = parseInt(root.getAttributeNS(null, "width"));
           var height = parseInt(root.getAttributeNS(null, "height"));

           if ((x+textwidth) > width) {
                 x = width - textwidth - 10;
           }
           if ((y+20) > height) {
                 y = y - 40;
           }

          Tip.elements.grp.setAttributeNS(null, "transform", "translate(" + x + "," + y + ")");
      }
      Tip.show = function(text, delay, event) {
          if (Tip.elements == null) { Tip.Create(); }
          var x = event.pageX;
          var y = event.pageY+20;
          Tip.tip_timeout = setTimeout("Tip.showTip(" + x + "," + y +",'" + text + "');", delay);
      }

      Tip.hide = function() {
          clearTimeout(Tip.tip_timeout);
          Tip.elements.grp.setAttributeNS(null, "visibility", "hidden");
      }

      //======================SVGTip====================END==============

      //======================Button====================START==============
/*  
  function Button(buttons) {
          Button.buttons = buttons;
      }
      
      Button.prototype.over = function(id, text, event) {
          Tip.show(text, 500, event);
          var state = svg_document.getElementById(id).getAttributeNS(osportns,"state");
          if (state == "off") 
              svg_document.getElementById(id).setAttributeNS(null, "fill", "WhiteSmoke");
      }

      Button.prototype.out = function(id) {
          Tip.hide();          
          var state = svg_document.getElementById(id).getAttributeNS(osportns,"state");
          if (state == "off")
               svg_document.getElementById(id).setAttributeNS(null, "fill", "#E0E6EC");
      }
      Button.down = function(id) {
          svg_document.getElementById(id).setAttributeNS(null, "fill", "Wheat");
          svg_document.getElementById(id).setAttributeNS(osportns,"state", "on");

          var buttons = Button.buttons; //['button_start', 'button_move', 'button_cp', 'button_finish', 'button_bin', 'button_join', 'button_dom', 'button_course'];
          for (var i in buttons) {
              if (buttons[i] == id) continue;
              svg_document.getElementById(buttons[i]).setAttributeNS(osportns,"state", "off");
              svg_document.getElementById(buttons[i]).setAttributeNS(null, "fill", "#E0E6EC");
          }
      }
      Button.changeMap = function(map) {
          var status = map.getAttributeNS(null, "visibility");
          if (status == "visible")
              map.setAttributeNS(null, "visibility", "hidden");
          else
              map.setAttributeNS(null, "visibility", "visible");
      }
*/
      //======================Button====================END=================

      //DEBUG introspection
      function intro(obj) {
         property_list = "";
            for (prop in obj) {
	            property_list += prop + " - ";
            }
         alert(property_list);
      }
	  
	  	  	  // IE has no Array.map
if (typeof Array.prototype.map == "undefined") {
    Array.prototype.map = function(fn, thisObj) {
        var scope = thisObj || window;
        var a = [];
        for ( var i=0, j=this.length; i < j; ++i ) {
            a.push(fn.call(scope, this[i], i, this));
        }
        return a;
    };
}

if (typeof Array.prototype.indexOf == "undefined") {
    Array.prototype.indexOf = function(el, start) {
        var start = start || 0;
        for ( var i=0; i < this.length; ++i ) {
            if ( this[i] === el ) {
                return i;
            }
        }
        return -1;
    };
}
