/**
 * @copyright 2007 "Rambler Internet Holding"
 * @author Alexey Golubchik
 */

typeof GA == 'undefined' && (GA = {})
GA.ranges = {};

/**
 * Возвращает_выделенный_текст_как_объект_Range.
 * @return {Range}
 */
GA.ranges.getSelectedRange = typeof window.getSelection != 'undefined'?
  function() {
    //return oDocument.defaultView.getSelection().getRangeAt(0)
    return window.getSelection().getRangeAt(0)
  }:
  function() {
    return document.selection.createRange()
  };

/**
 * возвращает_текст_выделенной_области, внутри_контейнера.
 * @param {Object} oContainer
 */
GA.ranges.getSelectedString = typeof window.getSelection != 'undefined'?
  function(oContainer) {
    return oContainer.value.substring(
      oContainer.selectionStart, oContainer.selectionEnd
    )
  }:
  function(oContainer) {
    oContainer.document.parentWindow.focus()
    oContainer.focus();
    var selectedRange = document.selection.createRange(),
    retunRange = selectedRange.duplicate();
    retunRange.moveToElementText(oContainer);
    if ( retunRange.parentElement().contains(selectedRange.parentElement()) ) {
      selectedRange.text
    }
  };

/**
 * Вставляет_в_выделенную_область, внутри_контейнера, строку.
 * @param {Object} str
 * @param {Object} oContainer
 */
GA.ranges.setSelectedString = typeof window.getSelection != 'undefined'?
  function(str, oContainer) {
    var st = oContainer.scrollTop,
    sl = oContainer.scrollLeft,
    b = Number(oContainer.selectionStart <= oContainer.selectionEnd),
    indxs = [oContainer.selectionStart, oContainer.selectionEnd],
    ln = str.length,
    v = oContainer.value;
    str += v.substring(indxs[b]);
    oContainer.value = v.substring(0, indxs[b ^ 1]) + str;
    oContainer.focus();
    indxs[b] = ln + indxs[b ^ 1];
    oContainer.setSelectionRange(indxs[0], indxs[1]);
    oContainer.scrollTop = st;
    oContainer.scrollLeft = sl
  }:
  function(str, oContainer) {
    oContainer.document.parentWindow.focus()
    oContainer.focus();
    var selectedRange = document.selection.createRange(),
    retunRange = selectedRange.duplicate();
    retunRange.moveToElementText(oContainer);
    if ( retunRange.parentElement().contains(selectedRange.parentElement()) ) {
      retunRange = selectedRange.duplicate();
      selectedRange.text = str;
      retunRange.setEndPoint('EndToEnd', selectedRange);
      retunRange.select()
    }
  };

/**
 * Возвращаяет_строку_от_начала_и_до_выделенной_области, внутри_контейнера.
 * @param {input, textarea} oContainer
 * @return {String}
 */
GA.ranges.getStringBeforeSelected = typeof window.getSelection != 'undefined'?
  function(oContainer) {
    return oContainer.value.substring(
      0,
      oContainer.selectionStart < oContainer.selectionEnd?
        oContainer.selectionStart:
        oContainer.selectionEnd
    )
  }:
  function(oContainer) {
    oContainer.document.parentWindow.focus()
    oContainer.focus();
    var selectedRange = document.selection.createRange(),
    retunRange = selectedRange.duplicate();
    retunRange.moveToElementText(oContainer);
    if ( retunRange.parentElement().contains(selectedRange.parentElement()) ) {
      retunRange.setEndPoint('EndToStart', selectedRange);
      return retunRange.text
    }
  }

/**
 * Возвращаяет_строку_от_завершения_выделенной_обласи_и_доконца, внутри_контейнера.
 * @param {input, textarea} oContainer
 * @return {String}
 */
GA.ranges.getStringAfterSelected = typeof window.getSelection != 'undefined'?
  function(oContainer) {
    return oContainer.value.substring(
      oContainer.selectionStart > oContainer.selectionEnd?
        oContainer.selectionStart:
        oContainer.selectionEnd
    )
  }:
  function(oContainer) {
    oContainer.document.parentWindow.focus()
    oContainer.focus();
    var selectedRange = document.selection.createRange(),
    retunRange = selectedRange.duplicate();
    retunRange.moveToElementText(oContainer);
    if ( retunRange.parentElement().contains(selectedRange.parentElement()) ) {
      retunRange.setEndPoint('StartToEnd', selectedRange);
      return retunRange.text
    }
  }

/**
 * Сворачивает_выделенную_область.
 * @param {Object} oContainer
 * @param {Boolean} [toBegin] по_умолчанию_true_и_сворачивает_в_начальной_точке,
 * если_false_сворачивает_в_конечной_точке.
 */
GA.ranges.collapse = typeof document.selection != 'undefined'? //window.getSelection == 'undefined'?
  function(oContainer, toBegin) {
    (arguments.length == 1 || toBegin) && (toBegin = true);
    oContainer.document.parentWindow.focus()
    oContainer.focus();
    var selectedRange = document.selection.createRange(),
    containerRange = selectedRange.duplicate();
    selectedRange.collapse(toBegin);
    selectedRange.select()
  }:
  function(oContainer, toBegin) {
    var b = Number(oContainer.selectionStart <= oContainer.selectionEnd),
    indxs = [oContainer.selectionStart, oContainer.selectionEnd];
    (arguments.length == 1 || toBegin) && (b ^= 1);
    oContainer.focus();
    oContainer.setSelectionRange(indxs[b], indxs[b])
  };

/**
 * Расширяет_длину_выделенной_области, так_чтобы_ее_край_лежал_
 * (перед, после)_указанной_строкой.
 * @param {String} searchedText
 * @param {Object} oContainer
 * @param {String} sWhere endBefore, endAfter
 */
GA.ranges.extendSelect = typeof window.getSelection != 'undefined'?
  function(searchedText, oContainer, sWhere) {
    var b = Number(oContainer.selectionStart <= oContainer.selectionEnd),
    indxs = [oContainer.selectionStart, oContainer.selectionEnd],
    i = oContainer.value.indexOf(searchedText, indxs[b]);
    oContainer.focus();
    indxs[b] = i == -1? oContainer.value.length: i + (sWhere == 'endAfter'? searchedText.length: 0);
    oContainer.setSelectionRange(indxs[0], indxs[1]);
    return oContainer.value.substring(indxs[b ^ 1], indxs[b])
  }:
  function(searchedText, oContainer, sWhere) {
    oContainer.document.parentWindow.focus()
    oContainer.focus();
    var selectedRange = document.selection.createRange(),
    retunRange = selectedRange.duplicate(),
    containerRange = selectedRange.duplicate();
    containerRange.moveToElementText(oContainer);
    if ( !containerRange.parentElement().contains(selectedRange.parentElement()) ) {
      return
    }
    if ( selectedRange.findText(searchedText) &&
      containerRange.parentElement().contains(selectedRange.parentElement())
    ) {
      retunRange.setEndPoint(sWhere == 'endAfter'? 'EndToEnd': 'EndToStart', selectedRange);
      retunRange.select();
      return retunRange.text
    }
    retunRange.setEndPoint('EndToEnd', containerRange);
    retunRange.select();
    return retunRange.text
  }
/**
 * Хранилище, сохранений_выделенных_областей.
 */
GA.ranges.aStore = [];
/**
 * Сохраняет_позицию_и_размер_выделенной_области_объекта.
 * @param {Object} oNode
 */
GA.ranges.storeSelection = typeof window.getSelection != 'undefined'?
  function(oNode) {
    var i=0, l = GA.ranges.aStore.length;
    while (i < l && GA.ranges.aStore[i].oNode != oNode) {
      i++
    }
    GA.ranges.aStore[i] = {
      'oNode': oNode,
      'selectionStart': oNode.selectionStart,
      'selectionEnd': oNode.selectionEnd
    }
  }:
  function(oNode) {
    var i=0, l = GA.ranges.aStore.length,
    selectedRange = document.selection.createRange(),
    retunRange = selectedRange.duplicate();
    retunRange.moveToElementText(oContainer);
    if ( retunRange.parentElement().contains(selectedRange.parentElement()) ) {
      while (i < l && GA.ranges.aStore[i].oNode != oNode) {
        i++
      }
      GA.ranges.aStore[i] = {
        'oNode': oNode,
        'textRange': selectedRange
      }
    }
  }
/**
 * Восстанавливает_позицию_и_размер_выделенной_области_в_объекте.
 * @param {Object} oNode
 */
GA.ranges.restoreSelection = typeof window.getSelection != 'undefined'?
  function(oNode) {
    for (var i = GA.ranges.aStore.length; i--;) {
      if (GA.ranges.aStore[i].oNode == oNode) {
        oNode.setSelectionRange(
          GA.ranges.aStore[i].selectionStart,
          GA.ranges.aStore[i].selectionEnd
        );
        return
      }
    }
  }:
  function(oNode) {
    for (var i = GA.ranges.aStore.length; i--;) {
      if (GA.ranges.aStore[i].oNode == oNode) {
        GA.ranges.aStore[i].textRange.select();
        return
      }
    }
  }
