//
// Extensions
//

function el_trim(str)
{
  return str.replace(/(^\s+)|(\s+$)/g, "");
}

function el_isspace(chr)
{
  return chr == " " || chr == "\t" || chr == "\n" || chr == "\r";
}

function el_isdigit(chr)
{
  return chr.charCodeAt(0) >= String("0").charCodeAt(0) &&
         chr.charCodeAt(0) <= String("9").charCodeAt(0);
}

function el_int_error(str, minval, maxval)
{
  var len = str.length;
  var i = 0;
 
  for(; i < len && el_isspace(str.charAt(i)); i++);

  if(i == len)
  {
    return 0;
  }

  var begin = i;
  var chr;

  for(; i < len && (el_isdigit(chr = str.charAt(i)) || 
      i == begin && (chr == "+" || chr == "-")); i++);

  var end = i;
  for(; i < len && el_isspace(str.charAt(i)); i++);

  if(i != len)
  {
    return i;
  }

  if(minval !== undefined)
  {
    var intval = parseInt(str.substring(begin, end));

    if(intval < minval)
    {
      return begin;
    }

    if(maxval !== undefined && intval > maxval)
    {
      return begin;
    }
  }

  return -1;
}

//
// Simple stream
//

El_InputStringStream.prototype = 
{ 
  string : "",
  position : 0,
  eof : false,
  fail : false,

  dump : function() 
  { 
    with(this)
    {
      return "El_InputStringStream: " + position + " " + eof + " " + fail + 
             " '" + string + "'";
    }
  },

  get_char : function() 
  { 
    with(this)
    {
      if(position >= string.length)
      {
        eof = fail = true;
      }

      return eof ? null : string.charAt(position++); 
    }
  },

  putback : function() 
  { 
    with(this)
    {
      if(!eof && position > 0)
      {
        position--;
      }
    }
  }

};

function El_InputStringStream(string)
{
  this.string = string;
  this.position = 0;
  this.eof = false;
  this.fail = false;
}

//
// Range
//

El_Range.prototype = 
{
  start : 0,
  end : 0,

  dump : function()
  {
    return this.start + ":" + this.end;
  }
};

function El_Range(start, end)
{
  this.start = start === undefined ? 0 : start;
  this.end = end === undefined ? start : end;
}

//
// Selection
//

function el_set_selection_(range, focus)
{
  if(focus != false)
  {
    this.focus();
  }

  if(this.selectionStart !== undefined)
  {
    this.selectionStart = range.start;
    this.selectionEnd = range.end;
  }
  else
  {
    var text_range = this.createTextRange();
    text_range.collapse(true);
    text_range.moveStart("character", range.start);
    text_range.moveEnd("character", range.end - range.start);
    text_range.select();     
  }
}

function el_get_selection_()
{    
  var result = new El_Range();
    
  with(this)
  {
    if(this.selectionStart !== undefined)
    {
      result.start = this.selectionStart;
      result.end = this.selectionEnd;
    }
    else
    {
      result.begin = -1;
      result.end = -1;
  
      var caretPos = document.selection.createRange();
  
      if(caretPos)
      {
        var bookmark = "~~@NG!~~";
        var orig = this.value.replace(/\r/g, "");
 
        caretPos.text = bookmark;
        var str = this.value.replace(/\r/g, "");
  
        result.start = str.search(bookmark);

        result.end = 
          result.start + orig.length - str.length + bookmark.length;
  
        this.value = orig;
  
        var range = this.createTextRange();
        range.collapse(true);
        range.moveStart("character", result.start);
        range.moveEnd("character", result.end - result.start);
        range.select();
      }
    }
  }
  
  return result;
}
  
function el_insert_(text, range)
{
  with(this)
  {
    if(range !== undefined)
    {
      el_set_selection(range);
    }

    var sel = el_get_selection();

    if(this.selectionStart !== undefined)
    {
      var top = scrollTop;
      var left = scrollLeft;

      var val = value;      
      value = val.substr(0, sel.start) + text + val.substr(sel.end);
      
      scrollTop = top;
      scrollLeft = left;
    }
    else
    {
      var caretPos = document.selection.createRange();
 
      if(caretPos)
      {
        caretPos.text = text;
      }
    }
    var new_sel = new El_Range(sel.start + text.length);
    el_set_selection(new_sel);
  }
}

//
// Enrich objects
//

function el_enrich(object)
{
  if(object !== null)
  {
    if(object.nodeName == "TEXTAREA" || 
       object.nodeName == "INPUT" && object.type == "text")
    {
      el_enrich_edit(object);
    }
  }
  
  return object;
}

function el_enrich_edit(object)
{
  object.el_set_selection = el_set_selection_;
  object.el_get_selection = el_get_selection_;
  object.el_insert = el_insert_;
}

function el_mime_url_encode(text)
{
  return encodeURIComponent(text).replace(/\+/g, "%2B").replace(/\//g, "%2F").
         replace(/'/g, "%27");
}

var js_spec_chars = "\b\f\n\r\t\'\"\\";

var js_spec_chars_escape = 
[
  "\\b",
  "\\f",
  "\\n",
  "\\r",
  "\\t",
  "\\'",
  "\\\"",
  "\\\\"
];

function el_js_escape(text)
{
  var result = "";

  for(var i = 0; i < text.length; i++)
  {
    var chr = text.charAt(i);
    var pos = js_spec_chars.indexOf(chr);

    if(pos < 0)
    {
      result += chr;
    }
    else
    {
      result += js_spec_chars_escape[pos];
    }
  }


  return result;
}

function el_mime_url_decode(text)
{
  return decodeURIComponent(text.replace(/\+/g, "%20"));
}

function el_xml_encode(text)
{
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").
         replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}

function el_get_selection()
{
  if(window.getSelection)
  {
    return window.getSelection();
  }
  else if(document.getSelection)
  {
    return document.getSelection();
  }
  else if(document.selection)
  {
    return document.selection.createRange().text;
  }

  return "";
}

function el_attach_event(obj, event, handler) 
{
  if(obj.addEventListener) 
  {
    obj.addEventListener(event, handler, false);
  } 
  else 
  {
    if(obj.attachEvent) 
    {
      obj.attachEvent('on' + event, handler);
    }
  }
}

function el_detach_event(obj, event, handler) 
{
  if(obj.removeEventListener) 
  {
    obj.removeEventListener(event, handler, false);
  } 
  else 
  {
    if(obj.detachEvent) 
    {
      obj.detachEvent('on' + event, handler);
    }
  }
}

function el_target(e)
{
  return e.target ? e.target : 
    (e.srcElement ? e.srcElement : window.event.srcElement);
}

function el_child_node(parent, child_name)
{
  var childs = parent.childNodes;

  for(var i = 0; i < childs.length; i++)
  {
    var child = childs[i];

    if(child.nodeName == child_name)
    {
      return child;
    }
  }

  return null;
}

function el_child_text(parent, child_name)
{
  try
  {
    return el_child_node(parent, child_name).firstChild.data;
  }
  catch(e)
  {
    return "";
  }
}

