var CANVAS = {
    drawEllipse : function (context, x, y, w, h) {
      var kappa = .5522848;
          ox = (w / 2) * kappa, // control point offset horizontal
          oy = (h / 2) * kappa, // control point offset vertical
          xe = x + w,           // x-end
          ye = y + h,           // y-end
          xm = x + w / 2,       // x-middle
          ym = y + h / 2;       // y-middle

      context.beginPath();
      context.moveTo(x, ym);
      context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
      context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
      context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
      context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
      context.closePath();
    },
    drawRoundRect : function (context, x, y, w, h, r) {
      context.beginPath();
      context.moveTo(x + r, y);
      context.lineTo(x + w - r, y);
      context.quadraticCurveTo(x + w, y, x + w, y + r);
      context.lineTo(x + w, y + h - r);
      context.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
      context.lineTo(x + r, y + h);
      context.quadraticCurveTo(x, y + h, x, y + h - r);
      context.lineTo(x, y + r);
      context.quadraticCurveTo(x, y, x + r, y);
/*
      context.arcTo(x + w, y, x + w, y + h, r);
      context.arcTo(x + w, y + h, x, y + w, r);
      context.arcTo(x, y + h, x, y, r);
      context.arcTo(x, y, x + w, y, r);
*/
      context.closePath();
    },
    drawArrow : function (context, x, y, w, h, dir) {
        context.beginPath();
        switch(dir) {
            case 'down':
                context.moveTo(x, y);
                context.lineTo(x + w, y);
                context.lineTo(x + w / 2, y + h);
                context.lineTo(x, y);
                break;
            case 'up':
                context.moveTo(x, y + h);
                context.lineTo(x + w / 2, y);
                context.lineTo(x + w, y + h);
                context.lineTo(x, y + h);
                break;
            case 'left':
                context.moveTo(x + w, y);
                context.lineTo(x + w, y + h);
                context.lineTo(x, y + h / 2);
                context.lineTo(x + w, y);
                break;
            case 'right':
                context.moveTo(x, y);
                context.lineTo(x + w, y + h / 2);
                context.lineTo(x, y + h);
                context.lineTo(x, y);
                break;
        }
        context.closePath();
    }
}

function getElements(parent, ns, nsPrefix, tagName) {
  if(!parent.getElementsByTagNameNS) {
    return parent.getElementsByTagName(nsPrefix + ':' + tagName);
  } else {
    return parent.getElementsByTagNameNS(ns, tagName);
  }
}
  
function getElementText(parent, ns, nsPrefix, tagName, defaultValue) {
  var elements = getElements(parent, ns, nsPrefix, tagName);
  if(elements.length == 0) {
	  return defaultValue;
  }

  var child = elements[0].firstChild;
  if(child == null) {
	  return defaultValue;
  }
  
  return child.nodeValue;
}
  
function getAttribute(parent, ns, nsPrefix, attrName) {
  if(!parent.getAttributeNS) {
    return parent.getAttribute(nsPrefix + ':' + attrName);
  } else {
    return parent.getAttributeNS(ns, attrName);
  }
}

/* ************************************************************************
   License for the following two methods (rgb2hsb, hsb2rgb):
   
   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2004-2007 1&1 Internet AG, Germany, http://www.1and1.org

   License:
     LGPL: http://www.gnu.org/licenses/lgpl.html
     EPL: http://www.eclipse.org/org/documents/epl-v10.php
     See the LICENSE file in the project's top-level directory for details.

   Authors:
     * Sebastian Werner (wpbasti)
     * Andreas Ecker (ecker)

************************************************************************ */
function rgb2hsb(vRed, vGreen, vBlue) {
  var vHue, vSaturation, vBrightness;

  vRed = parseFloat(vRed);
  vGreen = parseFloat(vGreen);
  vBlue = parseFloat(vBlue);

  var cmax = (vRed > vGreen) ? vRed : vGreen;

  if (vBlue > cmax) {
    cmax = vBlue;
  }

  var cmin = (vRed < vGreen) ? vRed : vGreen;

  if (vBlue < cmin) {
    cmin = vBlue;
  }

  vBrightness = cmax / 255.0;

  if (cmax != 0) {
    vSaturation = (cmax - cmin) / cmax;
  } else {
    vSaturation = 0;
  }

  if (vSaturation == 0) {
    vHue = 0;
  }
  else
  {
    var redc = (cmax - vRed) / (cmax - cmin);
    var greenc = (cmax - vGreen) / (cmax - cmin);
    var bluec = (cmax - vBlue) / (cmax - cmin);

    if (vRed == cmax) {
      vHue = bluec - greenc;
    } else if (vGreen == cmax) {
      vHue = 2.0 + redc - bluec;
    } else {
      vHue = 4.0 + greenc - redc;
    }

    vHue = vHue / 6.0;
    if (vHue < 0) vHue = vHue + 1.0;
  }

  return {
    hue        : Math.round(vHue * 360),
    saturation : Math.round(vSaturation * 100),
    brightness : Math.round(vBrightness * 100)
  };
}

function hsb2rgb(vHue, vSaturation, vBrightness) {
  var i, f, p, q, t, vReturn;

  vHue = parseFloat(vHue / 360);
  vSaturation = parseFloat(vSaturation / 100);
  vBrightness = parseFloat(vBrightness / 100);

  if (vHue >= 1.0) vHue %= 1.0;
  if (vSaturation > 1.0) vSaturation = 1.0;
  if (vBrightness > 1.0) vBrightness = 1.0;

  var tov = Math.floor(255 * vBrightness);

  var vReturn = {};

  if (vSaturation == 0.0) {
    vReturn.red = vReturn.green = vReturn.blue = tov;
  }
  else
  {
    vHue *= 6.0;

    i = Math.floor(vHue);

    f = vHue - i;

    p = Math.floor(tov * (1.0 - vSaturation));
    q = Math.floor(tov * (1.0 - (vSaturation * f)));
    t = Math.floor(tov * (1.0 - (vSaturation * (1.0 - f))));

    switch(i)
    {
      case 0:
        vReturn.red = tov;
        vReturn.green = t;
        vReturn.blue = p;
        break;

      case 1:
        vReturn.red = q;
        vReturn.green = tov;
        vReturn.blue = p;
        break;

      case 2:
        vReturn.red = p;
        vReturn.green = tov;
        vReturn.blue = t;
        break;

      case 3:
        vReturn.red = p;
        vReturn.green = q;
        vReturn.blue = tov;
        break;

      case 4:
        vReturn.red = t;
        vReturn.green = p;
        vReturn.blue = tov;
        break;

      case 5:
        vReturn.red = tov;
        vReturn.green = p;
        vReturn.blue = q;
        break;
    }
  }

  return vReturn;
}

function intToHexRGB(value) {
	var num = Number(value);
	if(num < 0) {
		num = 0xffffff + num + 1;
	}
	var ret = num.toString(16);
	return "#" + "000000".substr(0, 6 - ret.length) + ret;
}

function hexToRGB(hex) {
    var rgb = new Array();
    if(hex.indexOf('#') == 0) {
        hex = hex.substr(1);
    }
    if(hex.length == 3) {
        rgb[0] = parseInt(hex.charAt(0) + hex.charAt(0), 16);
        rgb[1] = parseInt(hex.charAt(1) + hex.charAt(1), 16);
        rgb[2] = parseInt(hex.charAt(2) + hex.charAt(2), 16);
    }
    if(hex.length == 6) {
        rgb[0] = parseInt(hex.substr(0, 2), 16);
        rgb[1] = parseInt(hex.substr(2, 2), 16);
        rgb[2] = parseInt(hex.substr(4, 2), 16);
    }
    return rgb;
}

function toRadians(deg) {
    return deg / 180.0 * Math.PI;
}

function toDegrees(rad) {
    return rad * 180.0 / Math.PI;
}

function getBorderColor(color) {
	var col = parseInt(color.substr(1), 16);
  var red   = col & 0xff0000 >> 16;
  var green = col & 0xff00 >> 8;
  var blue  = col & 0xff;
	
	col = (red * 0.5) << 16 |
	      (green * 0.5) << 8 |
				(blue * 0.5);
	
	return intToHexRGB(col);
}

function toMilliseconds(vbTimestamp) {
  var result = 0;
  var vbZeroTime = -2209165200000; //30.12.1899 00:00:00 in milliseconds
  var oneDay = 86400000; //1 day in milliseconds (24 * 60 * 60 * 1000)

  var dayCount = Math.floor(vbTimestamp);
  var frac = vbTimestamp - dayCount;
   
  var date = vbZeroTime + (dayCount * oneDay); //compute java date

  // avoid problems with dst offset
  var retTime = new Date(date);
  retTime.setHours(0);
  retTime.setMinutes(0);
  retTime.setSeconds(0);
  retTime.setMilliseconds(0);
  date = retTime.getTime();
  
  var time = oneDay * frac;
  
  return date + time;
}

var LONG_DAY_NAMES = [
    LANG.day_sunday,
    LANG.day_monday,
    LANG.day_tuesday,
    LANG.day_wednesday,
    LANG.day_thursday,
    LANG.day_friday,
    LANG.day_saturday
];
var LONG_MONTH_NAMES = [
    LANG.month_january,
    LANG.month_february,
    LANG.month_march,
    LANG.month_april,
    LANG.month_may,
    LANG.month_june,
    LANG.month_july,
    LANG.month_august,
    LANG.month_september,
    LANG.month_october,
    LANG.month_november,
    LANG.month_december,
];

function simpleDateFormat(date, format){
  var ret = format;
    
  var year = date.getFullYear();
  var month = date.getMonth() + 1;
  var dom = date.getDate();
  var hour = date.getHours();
  var h12 = hour % 12;
  var minute = date.getMinutes();
  var second = date.getSeconds();
  
  ret = ret.replace('yyyy', year);
  year = year % 100;
  ret = ret.replace('yy', year < 10 ? "0" + year : year);
    
  ret = ret.replace('HH', hour < 10 ? "0" + hour : hour);
  ret = ret.replace('H', hour);
  ret = ret.replace('hh', h12 < 10 ? "0" + h12 : h12);
  ret = ret.replace('h', h12);
  ret = ret.replace('a', hour < 12 ? "AM" : "PM");
    
  ret = ret.replace('mm', minute < 10 ? "0" + minute : minute);
    
  ret = ret.replace('ss', second < 10 ? "0" + second : second);

  ret = ret.replace('MMMM', LONG_MONTH_NAMES[month - 1]);
  ret = ret.replace('MM', month < 10 ? "0" + month : month);

  ret = ret.replace('EEEE', LONG_DAY_NAMES[date.getDay()]);
  ret = ret.replace('dd', dom < 10 ? "0" + dom : dom);
    
  return ret;
}

function char2hex(s){
  for(var k, i = s.length, r = ""; i; r = ((k = s.charCodeAt(--i).toString(16 )).length - 1 ? k : "0" + k) + r);
  return r;
}

function hex2bin(s){
  for(var i = 0, l = s.length, r = ""; i < l; r += String.fromCharCode(parseInt(s.substr(i, 2), 16)), i += 2);
  return r;
}
/*
Raphael.el.moveTo = function(x, y){
	switch (this.type) {
    case "path":
      var path = pathToRelative(this.attrs.path),
            dim = pathDimensions(path),
            dx = (path[0][1] - dim.x) + x,
            dy = (path[0][2] - dim.y) + y;
      path[0][1] = dx;
      path[0][2] = dy;
      return this.attr({path: path});
      break;
    default:
      return this.attr({x: x, y: y});
    break;
	}
  return this;
};
*/

function cancelBubble( event ) {
  if(event.stopPropagation) {
    event.stopPropagation();
  }
  event.cancelBubble = true;
};

function cancelBubblePreventDefault( event ) {
  if(event.stopPropagation) {
    event.stopPropagation();
  }
  event.cancelBubble = true;
  event.preventDefault();
};

var touchMoved = false;
function touchHandler(event) {
    var touches = event.changedTouches,
        first = touches[0],
        type = "";
        
    switch(event.type) {
        case "touchstart":
            type = "mousedown";
            if(navigator.userAgent.indexOf("Android") != -1) {
                event.preventDefault();
            }
            break;
            
        case "touchmove":
            type="mousemove";        
            touchMoved = true;
            event.preventDefault();
            break;        
            
        case "touchend":
            type="mouseup";
            touchMoved = false;
            if(touchMoved && navigator.userAgent.indexOf("Android") != -1) {
                event.preventDefault();
            }
            break;
            
        default:
            return;
    }

    var simulatedEvent = document.createEvent("MouseEvent");
    
    simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,
                                  false, false, false, false, 0/*left*/, null);
                                                                            
    first.target.dispatchEvent(simulatedEvent);
}

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/
 
var Base64 = {
  // private property
  _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
 
  // public method for encoding
  encode : function (input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;
 
    input = Base64._utf8_encode(input);
 
    while (i < input.length) {
 
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);
 
      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;
 
      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }
 
      output = output +
      this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
      this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
 
    }
 
    return output;
  },
 
  // public method for decoding
  decode : function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;
 
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
    while (i < input.length) {
 
      enc1 = this._keyStr.indexOf(input.charAt(i++));
      enc2 = this._keyStr.indexOf(input.charAt(i++));
      enc3 = this._keyStr.indexOf(input.charAt(i++));
      enc4 = this._keyStr.indexOf(input.charAt(i++));
 
      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;
 
      output = output + String.fromCharCode(chr1);
 
      if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
      }
 
    }
 
    output = Base64._utf8_decode(output);
 
    return output;
 
  },
 
  // private method for UTF-8 encoding
  _utf8_encode : function (string) {
    string = string.replace(/\r\n/g,"\n");
    var utftext = "";
 
    for (var n = 0; n < string.length; n++) {
 
      var c = string.charCodeAt(n);
 
      if (c < 128) {
        utftext += String.fromCharCode(c);
      }
      else if((c > 127) && (c < 2048)) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      }
      else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }
 
    }
 
    return utftext;
  },
 
  // private method for UTF-8 decoding
  _utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;
 
    while ( i < utftext.length ) {
 
      c = utftext.charCodeAt(i);
 
      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      }
      else if((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i+1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      }
      else {
        c2 = utftext.charCodeAt(i+1);
        c3 = utftext.charCodeAt(i+2);
        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
        i += 3;
      }
 
    }
 
    return string;
  }
};

