RysownikSurface = Class.create(
{
    SVGNS : "http://www.w3.org/2000/svg",
    initialize: function(sx,sy)
    { // sx,sy - surface size
		this.width = 0;
		this.height = 0;
		this.x = 0;
		this.y = 0;
        this.s = document.createElementNS(this.SVGNS, 'svg');
        this.s.style.cursor="pointer";
        this.s.style.position="absolute";
        if (sx == undefined || sy == undefined)
        {
            sx = 0;
            sy = 0;
        }
        this.resize(sx,sy);
    },
    attach: function(node)
    { // pod jaki element podczepiamy nasz svg
        if (node instanceof String)
        {
            node = $(node);
        }
        node.appendChild(this.s);
    },
    add: function(node)
    { // dodawanie do svg kszta�t�w
        this.s.appendChild(node);
    },
    remove: function(node)
    { // usuwanie z svg kszta�t�w
        this.s.removeChild(node);
    },
    resize: function(w,h)
    { //zmiana rozmiaru, przyjmuje tablice.. cho� mo�e te� przyja� x,y
        if (w instanceof Array)
        {
            h = w[1];
            w = w[0]
        }
        this.s.setAttribute('width',w);
        this.s.setAttribute('height',h);
        this.s.style.width = w+"px";
        this.s.style.height = h+"px";
		this.width = w;
		this.height = h;
    },
	moveTo: function(x,y) {
		this.s.style.left = x+"px";
		this.s.style.top = y+"px";
		this.x = x;
		this.y = y;
	},
	show: function() {
		this.s.style.display = 'block';
	},
	hide: function() {
		this.s.style.display = 'none';
	},
    getNode: function()
    {
        return this.s;
    }
});

RysownikPath = Class.create(
{
    SVGNS : "http://www.w3.org/2000/svg",
    defaultOptions:
    {
      'stroke': {'color':'rgb(0,0,0)','width':1,'opacity':'1.0','join':'round','cap':'butt','dasharray':'none','miterlimit':4},
      'fill' : {'opacity':'1.0','fp' : [0,0],'direction':'V','color':'rgb(0,0,0)','arr':[['rgb(0,0,0)','50'],['rgb(255,255,255)','100']]}
    },
    initialize: function(surface)
    { // surface instance of Surface
        this.stroke=$H(this.defaultOptions.stroke);
        this.xfill=$H(this.defaultOptions.fill);
        this.p = document.createElementNS(this.SVGNS,'path');
        this.defs = document.createElementNS(this.SVGNS,'defs');
        surface.add(this.defs);
        surface.add(this.p);
        // gradienty:
        if(!window.RysownikGradientsDefs)
        {
            var gradients = new RysownikSurface()
                gradients.attach(document.body);
            window.RysownikGradientsDefs = document.createElementNS(this.SVGNS,'defs');            
                gradients.add(window.RysownikGradientsDefs);                
        }
    },
    setStroke: function(options)
    { //JSON: {color: rgb(r,g,b), width, opacity, join, cap, dasharray}
        this.stroke = this.stroke.merge($H(options));
        this.p.setAttribute('stroke',this.stroke.get('color'));
        this.p.setAttribute('stroke-opacity',this.stroke.get('opacity'));
        this.p.setAttribute('stroke-width',this.stroke.get('width'));
        this.p.setAttribute('stroke-linecap',this.stroke.get('cap'));
        this.p.setAttribute('stroke-linejoin',this.stroke.get('join'));
        this.p.setAttribute('stroke-dasharray',this.stroke.get('dasharray')); //none lub string z intami dash array
        this.p.setAttribute('stroke-miterlimit',this.stroke.get('miterlimit'));
    },
    setFill: function(type,json)
    { /* type : solid, radial(gradient), linear(gradient)
       * arr  : kolory dla gradientu, dowolna ilo�� tablic dwuelementowych [color,offset w % ale jako int bez '%']   
       *
       * solid :
       *   'solid',json -> {'opacity' : '' , 'color' : 'rgb(r,g,b)'}
       * linear :
       *   'linear',json -> {'opacity' : '', 'direction' : 'X/Y/H/V', 'arr' : []} 
       * radial :
       *   'radial',json -> {'opacity' : '', 'fp' : [x,y], 'arr' : []}        
       */     
      this.xfill = this.xfill.merge($H(json));
      this.p.setAttribute('fill-opacity',this.xfill.get('opacity'));
      if (type == 'solid')
      {
        this.solidFill();
      }        
      else
      {
        if (type == 'linear')
        {
          this.linearFill();
        }
        else if (type == 'radial')   // radial do wyrzucenia nie obs�ugiwane przez VML zbyt dobrze
        {
          this.radialFill();
        }
        var arr = this.xfill.get('arr');
        var id = "";
        for (var i=0; i < arr.length; i++)
        {
          var stop = document.createElementNS(this.SVGNS,'stop');
          stop.setAttribute('stop-color',arr[i][0]);
          stop.setAttribute('offset',arr[i][1]+"%");
          this.gradient.appendChild(stop);
          id += String(arr[i][0]).replace("#","","g").replace(",","","g").replace("(","","g").replace(")","","g");
        }
        
        if (document.getElementById(id))
        {//TODO: po co je wyrzuca�.. mo�na by zostawi� tylko robi� przegl�d...
            window.RysownikGradientsDefs.removeChild(document.getElementById(id));
        }
        window.RysownikGradientsDefs.appendChild(this.gradient);
        this.gradient.setAttribute('id',id);
        //this.defs.appendChild(this.gradient);
        this.p.setAttribute('fill','url(#'+id+')');
      }    
    },  
    solidFill: function()
    {
      this.p.setAttribute('fill',this.xfill.get('color'));
      this.p.setAttribute('fill-rule','nonzero'); //narazie sta�a  // evenodd - nonzero
      
    },
    linearFill: function()
    {
      var a,b,c,d;
      this.gradient = document.createElementNS(this.SVGNS,'linearGradient');
      switch (this.xfill.get('direction'))
      {
        case 'X': // -> \
          a=b='0%';
          c=d='100%';
        break
        case 'Y': // -> /
          a=d='0%';
          b=c='100%';
        break
        case 'H': // horizontal
          a=b=d='0%';
          c='100%';
        break
        case 'V': // vertical
          a=b=c='0%';
          d='100%';
        break
      }
      this.gradient.setAttribute('x1',a);
      this.gradient.setAttribute('y1',b);
      this.gradient.setAttribute('x2',c);
      this.gradient.setAttribute('y2',d);
    },
    radialFill: function()
    {
      this.gradient = document.createElementNS(this.SVGNS,'radialGradient');
      this.gradient.setAttribute('id','g1');
      this.gradient.setAttribute('cx','50%');
      this.gradient.setAttribute('cy','50%');
      this.gradient.setAttribute('r','50%');
      var fp = this.xfill.get('fp');
      this.gradient.setAttribute('fx',fp[0]+"%");
      this.gradient.setAttribute('fy',fp[1]+"%");
    },
    cmd: function (cmd)
    { // bezpo�rednio komenda dodawna do path
      //this.p.hasAttribute('d')
        var v = this.p.hasAttribute('d') ? this.p.getAttribute('d') +' '+cmd : cmd;
        this.setD(v);
    },
    setD: function(d)
    { // pozwala na ustawienie parametru d zgodnie z przekazanym stringiem, aby szybciej wygenerowa� path
      this.p.setAttribute('d',d);
    },
    getNode: function()
    {
      return this.p;
    },
    // gotowe komendy:
    moveTo: function(x,y)
    {
      this.cmd('M'+x+','+y);
    },
    lineTo: function(x,y)
    {
      this.cmd('L'+x+','+y);
    },
    curveTo: function(x1,y1,x2,y2,x,y)
    {
      this.cmd('C'+x1+','+y1+','+x2+','+y2+','+x+','+y);
    },
    circle: function(cx,cy,r)
    {
      this.cmd("M"+(cx+r)+","+cy+" a"+r+","+r+" 0 1,0 0, 1 z");
    },
    end: function()
    {
      this.cmd("z");
    }
});

RysownikLabel = Class.create(
{
    SVGNS : "http://www.w3.org/2000/svg",
    defaultOptions:
    {
      'stroke': {'color':'rgb(0,0,0)','width':0.4,'opacity':'1.0'},
      'fill' : {'opacity':1,'color':'rgb(255,255,255)'}
    },
    initialize: function(surface)
    { // surface instance of Surface
		this.surface = surface;
        this.stroke=$H(this.defaultOptions.stroke);
        this.xfill=$H(this.defaultOptions.fill);
		this.rect = document.createElementNS(this.SVGNS,'rect');
		this.text = document.createElementNS(this.SVGNS,'text');
		this.description = document.createTextNode('');
		this.text.appendChild(this.description);
		this.text.setAttribute('x', 1);
		this.text.setAttribute('y', 10);
		this.text.setAttribute('font-size', 9);
		this.text.setAttribute('fill-opacity', this.xfill.get('opacity'));
		this.text.setAttribute('fill', this.xfill.get('color'));
		this.rect.setAttribute('x', 0);
		this.rect.setAttribute('y', 0);
		this.rect.setAttribute('width', this.surface.width);
		this.rect.setAttribute('height', this.surface.height);
		this.rect.setAttribute('fill-opacity', this.xfill.get('opacity'));
		this.surface.add(this.rect);
		this.surface.add(this.text);
    },
    setStroke: function(options)
    { //JSON: {color: rgb(r,g,b), width, opacity, join, cap, dasharray}
        this.stroke = this.stroke.merge($H(options));
        this.rect.setAttribute('stroke',this.stroke.get('color'));
        this.rect.setAttribute('stroke-opacity',this.stroke.get('opacity'));
        this.rect.setAttribute('stroke-width',this.stroke.get('width'));
    },
    setColor: function(json)
    {
      this.xfill = this.xfill.merge($H(json));
      this.rect.setAttribute('fill', this.xfill.get('color'));
      this.rect.setAttribute('stroke', this.xfill.get('color'));
    },
    getNode: function()
    {
      return this.text;
    },
    setLabel: function(label)
    {
	  this.description.nodeValue = label;
    }
});
