// ==UserScript==
// @author   Franck Depierre
// @name   add_englishinparis_translations.user.js
// @description	Insert buttons for each blog's POST, if translations are found. When user clicks on a button, open the article he pointed out and add the collected translations.
// @namespace     
// @include          http://englishinparis.blogspirit.com*

// @version       0.91

///////////////////////////////////

// This is a Greasemonkey user script.

// To install the script, 
// 1 . Install FireFox  http://www.mozilla.org/firefox
// 2. Install the firefox extension called Greasemonkey: http://greasemonkey.mozdev.org/
// then restart Firefox
// 3. Open this script in firefox and click on the install button.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "add_englishinparis_translations", and click Uninstall.

///////////////////////////////////
/*
 Changelog:
 ==========
 v0.1 :  Alpha. Release
 v02  :  backgroud color yellow for test. More accurate search pattern.
 v03 : test remove all script
 v04: test remove only domain script
 v05:  add configuration menu command
 v06: sort founded translations in an Array
 v07: try to make style sheet import absolute
 v08 : force body tet style arial
 v0.9 : correct regexp construction
*/

// ==/UserScript==

// Wait the full page to loaded previous to run the parsing actions
window.addEventListener(
    'load',function(){initialization()},
    true);

/*--- Initialise global data values. ---*/

var _debug = 0;
    
/* base64 encoded icon for insertion on the blog 
This icon is a blue pensil. Common Creative Licence opencliarts.org  */ 
  var _button_img ='iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+g'+
    'vaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1ggEEzgPLuE1RwAAAf5J'+
    'REFUeNqt1E9Ik3EYwPGv79xGKdFL851jsYnjRdCEMdxAdgoPhYcIOlSQl4bQP4i5'+
    'DhEVIUkTgi5FdUnK8KBJBUEFkZdKHEkmbUq50Uw7CFFaTZvsfbp4ik3Y257jj9/z'+
    '4fc8v4cHKhdVFVHc7sPBpqb7Azbb42Xo6DANqeoen98/NOrzTRcslpTA9SfgsJqg'+
    'bBZd74u1tSV+qeqswKQBvXHYXl02VVOzy9naOvQiEEiL3T4jkChANGKqRE3rCgSD'+
    'Y4stLXOiKCmBKQPO9pjCPJ7o3vb2xHJz85xUVaUEkgJXbpjCvN5oZzj87k8gkNl4'+
    'WVJg8AO4txa7v2kjGxtPhl2uI8OKotpSqVUMA+CrAaMRWMwVy1FKYQ5HSHM6D45Y'+
    'rTtq5ufXWVsTYAV4OwCPJkrlKaVLjd2x2z2ufF5YWFgHfgKfv8O9c5tVVRTU9VO7'+
    'a2v9nQCZTJ5CIQf8BsYvwczSZqDl34MD+/313V3O4bamZ3XpT6tMTrs2sMRTuHy6'+
    'vB9127ad6elOTr0MicwiK88V0dT+H9B3E3bWlj0i/b37BnNpXSSLyEfEeIXcitFp'+
    'at6OR0KHviV9hmQRySJfXrM6Eiduai01ehTH2IOGpew4+TcPmbh7jQt6A07Tq+jE'+
    'Ud/tq+erL9ZrqP+9IHXflrrYMe09lQyvG61S1l/tN66SkGSxcAAAAABJRU5ErkJg'+
    'gg==';

/* Variable use to parse the blog POST */  
  /* Regular expression related to POST content */
  var _re_post_begin=/Read.*(article|lyric)/i; /* Start of POST */
  var _re_post_end=/Permalink/i; /* End of Post */
  /* Data  not to be considered while parsing */
  var _re_usefull_vocabulary=/Useful Vocabulary/i; 
  
  /* Content parsing status */
  var _deep_parsing = 6; /* how deep script should try to find POST content from POST root */
  var _parsing_status = 0; /* 0 :nothing,  1: anchor found, 2: Read the article found, 3: word found */
  var _strong_content; /* strong tag content  stored while seeking for its translation */
  var _anchor_id;
  var _insertion_location_node = null; /* Node where button has to be inserted */

  /* All xml structure found and storage in memory */
  var _xml_data_storage = new Array(); /* Array where all xml data are parsed */
  
/* Variable use when user fires "get article with translation" */
  var _article_content; /* article content from a GM_xmlhttpRequest to the target article url */
  //var _xml_parser = new DOMParser(); /* xml dom parser use to parse data to insert in the article page */
  //var _xml_data_doc; /* current xml data parsed */
  var _xml_http_get_status = 1; /* status set to failed if no article content is available 0 ok, 1 failed, 2 alert message has been displayed */

  /* variable to record the opened windows and wait for the content to be parsed by the DOM parser*/ 
  var _new_window;
  var _wait_for_body_intervalID;
  
  /* Do a HTTP request when the url of the pointed articles are found to have them in cache */
  var _prefetch_url = 1;
  
  /* Time out value */
  var _extra_timeout = 200; /* Delay to let the DOM parser to finish to build the tree when body has been found */
  var _looping_interval = 100; /* lnterval where to check if the body has been found by the DOM parser */
  var _http_request_timeout = 4000; /* Maximum delay to get the article using GM_xmlhttpRequest */
  var _button_reset_timeout = 3000; /* Time out to reset the button in the not fired postion */

  /* static Colors */
  var _warning_background_color = '#acf400'; /* Background color for the warning to the top the article */
	var _warning_text_size =  "8pt";
  
/*--- End of global data values initialisation ---*/  

/* user string message function */
function user_message(msg_name) {

  switch (msg_name) {
    case 'popup_not_allowed':
      message = 'Sorry, if you want to get the article with translation, \n';
      message += 'you need first to allow this web site to open pop up windows.\n\n';
      message += 'Go in the firefox toolbar, click on tools->option and select the content tab,\n';
      message += 'Click on the button named "authorised sites,"\n';
      message += 'Then, enter "englishinparis.blogspirit.com" and click on the "Authorize" button.'
    break;
    case 'error_occurs':
    message = 'Sorry, the process to fill the article with translation failed.\n';
    message += 'Try the normal link to read the article';
    break;
    case 'article_not_available':
    message = "You have requested to get the article with translation,";
    message += " but the article is not available.\n";
    message += "Sorry, try to click on the other link to display the article without translation."
    break;
    case 'icon_get_article_title':
      message = "Click here to display the article with translation";
    break;
    case 'get_article_with_translation':
      message = " with translation by clicking this button ";
    break;
    case 'article_warning':
        /*HTML content */
       message = "WARNING: On your request, translations have been inserted to this article by the Grease Monkey script. " ;
       message += "Also, page links and behaviours may have been corrupted. ";
       message += "Move the mouse over the highlighted words to display the translations."
    break;
    case 'default_backgroud_color':
       message = "English In Paris : Set translations background to yellow";
    break;
    case 'gray_backgroud_color':
       message = "English In Paris : Set translations background to gray";
    break;
    
    default:
  }
  
  return message;
}


/* Set the button style to display a clicked effect */
function set_button_img_style(img,status) {  

  if(!img) return;
  
  style_dark = "2px solid #444";
  style_ligth = "1px solid #bbb";
  
  if (status) {
    img.style.borderTop = img.style.borderLeft = style_dark;
    img.style.borderRight = img.style.borderBottom = style_ligth;  
  } else {  
    img.style.borderTop = img.style.borderLeft = style_ligth;
    img.style.borderRight = img.style.borderBottom = style_dark;  
  }
}

/* Function called on page loaded */ 
function initialization() {

  /* Set menu to configure the word  backgroud  color */ 
  GM_registerMenuCommand(user_message('default_backgroud_color') , set_highligth_background_style_default); /*  default is yellow */
  GM_registerMenuCommand(user_message('gray_backgroud_color') , set_highligth_background_style_ligth_gray);
  
  /* Call the procedure to parse the POSTs */
  tags_detection();

}

/* Get the post part class = content in the document where POST's  are located */
function tags_detection() {

  var blog_content = document.evaluate(
  "//div[@class='content']",
  document,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);
 
  for (var i = 0; i < blog_content.snapshotLength; i++) {

    thisContent = blog_content.snapshotItem(i);
    
    if (thisContent.hasChildNodes) {
      get_post_content(thisContent, 0);
    }
  }
}

/* Find the translation content and the url regarding the blog's format */
function get_post_content(thisContent, deep) {
  
  /* This function should not occurs in a too deep location */
  if ((!thisContent) || (_deep_parsing < deep)) {
    return;
  }
    
  for (var j = 0; j < thisContent.childNodes.length; j++) {

  if (_debug) {
    GM_log('status: ' +
            _parsing_status +
            ' deep: '+ 
            deep +
            ' content length : ' + 
            thisContent.childNodes.length + 
            ' node name: '+
            thisContent.childNodes[j].nodeName +
            ' node content: ' + 
            thisContent.childNodes[j].nodeValue
            );
   }
    
    switch (thisContent.childNodes[j].nodeName) {
      case '#text':
        /* Check if the content has POST tag and set the related status */
        find_re_in_text(thisContent.childNodes[j]);
        
        /* we are after a strong tag so this is a translation. Add the last found word and its content to the storage */
        if ((_parsing_status == 4) && 
            (valid_content_text(thisContent.childNodes[j])) && 
            (_strong_content != thisContent.childNodes[j].nodeValue)) {
            
          add_translation_content_to_storage(_strong_content , thisContent.childNodes[j].nodeValue, _anchor_id);
          _strong_content = "";
          _parsing_status = 3;
        }
      break;
      /*@todo when EM is found something to do*/
      
      case 'A':
        /* If this is an anchor we are at the beginning of a new POST.  Record as POST reference ID*/
        anchor_id_name = thisContent.childNodes[j].id;
        if (anchor_id_name) {
          _parsing_status = 1;
          _anchor_id = anchor_id_name;
        }
        /* If Read article has been found the next <a> child is the URL*/
        if (_parsing_status == 2) {
          decoded_url = add_url_element_to_storage(thisContent.childNodes[j], _anchor_id);
          _parsing_status = 3;
          /* Prefetch the url to have it in the cache */
          if (_prefetch_url) {
              get_related_article_content(decoded_url, 0);
          }
        }
      break;
      case 'STRONG':
        /* Store strong content to record it with the translation later. Set related _parsing_status */
        strong_data  = thisContent.childNodes[j].firstChild.nodeValue;
        if ( (_parsing_status == 3) && 
             (valid_content_text(thisContent.childNodes[j].firstChild))) {
          _parsing_status = 4;
          _strong_content = strong_data;
        }
      break;
      
      default:
    }
    
    /* Also loop in its childs  */
    get_post_content(thisContent.childNodes[j], deep + 1);
  }
}

/*  Valid node text against several constraints. Return 0 if not valid  */
function valid_content_text(current_node) {

  if(!current_node) return 0;
  
  text_content = current_node.nodeValue;
  if( (!text_content) ||
      (text_content.length <= 3) ||
      (_re_usefull_vocabulary.test(text_content))) {
      return 0;
  }
  return 1;
}

/* Seek starting and ending tag in the current node. 
For starting tag initialize the storage structure 
For ending tag create a button and store the storage in the memory */
function find_re_in_text(current_node) {
  
  if(!current_node) return;
  
  text_content = current_node.nodeValue;

  /*  Find text Posted in. Create the button after the previous anchor  if somthing has been found */
  this_is_end = _re_post_end.test(text_content)

  if ((1 < _parsing_status) && this_is_end) {
    create_clickable_icon(_insertion_location_node, _anchor_id);
  }
  
  if(this_is_end) {
    _parsing_status = 0;
  }
  
  /* Detect POST data starting tag */
  if ((_parsing_status == 1) && (_re_post_begin.test(text_content))) {
    _parsing_status = 2;
    /* Record the insertion location node to add button later on */
    _insertion_location_node = current_node;
  }
}

/* Find data correponding to id in the global xml storage */
function get_xml_storage(id) {

  for (var j = 0; j < _xml_data_storage.length; j++) {
    if (_xml_data_storage[j][0] == id) {
      return _xml_data_storage[j];
    }
  }
  return null;
}

/* Add an array to the global storage one */
function add_xml_storage(id) {

  new_array = new Array(1);
  new_array[0] = id;
  _xml_data_storage.push(new_array);
  
  return new_array;
}

/* Get an array where parsed data are stored regarding the id */
function get_add_xml_storage(id) {
  array_id = get_xml_storage(id);
  if (!array_id) {
    array_id = add_xml_storage(id);
  }
  return array_id;
}

/* Get the url element of the article found in englishinparis */
function add_url_element_to_storage(url, id) {

  decoded_url = decodeURIComponent(url);
  new_url_array = new Array('location', decoded_url);
  
  array_id = get_add_xml_storage(id);
  array_id.push(new_url_array);
  
  return decoded_url;
}

/* Gete the article url from xml storage */
function get_article_url(id) {
 
  array_id = get_xml_storage(id);
  
  for (var j = 0; j < array_id.length; j++) {
    if (array_id[j][0] == 'location') {
      return array_id[j][1];
    }
  }
  
  return null;
}

/* Build regexp finding a whole word  */
function build_regex(search_text) {

	if((search_text == null) || (search_text.length <= 0)) {
		return null;
	}

   /* Remove parenthesised content */
  par_regexp = new RegExp("\\W?\\(.*\\)\\W?", 'ig');
  par_result = par_regexp.exec(search_text);
  
  if(par_result) {
    search_text = RegExp.leftContext;
    if((RegExp.rightContext) && (0 < RegExp.rightContext)) {
      search_text += " " + RegExp.rightContext;
    }
  }
    
  first_search = "";
  end_search = "";
      
  do {
    /*  Case verb start with "to"*/
    verb_regexp = new RegExp("^to ", 'ig');
    verb_result = verb_regexp.exec(search_text);
  
    if(verb_result) {
      /* Verb may be composed */
      first_search = search_text.substring(verb_result[0].length);

      vcomp_regexp = new RegExp("^(\\w*)\\W.*", 'ig');
      vcomp_result = vcomp_regexp.exec(first_search);
      
      if (vcomp_result) {
          end_search = first_search.substring(vcomp_result[1].length+1);
          first_search = vcomp_result[1];
          search_pattern = "("+first_search+"{0,2}(s|e|ing|ed)?\\W"+end_search+")";
      } else {
          search_pattern = "("+first_search+"{0,2}(s|e|ing|ed)?)";
      }
      break;
    }
  
    /* Case name */
    name_regexp = new RegExp("^(a |an )", 'ig');
    name_result = name_regexp.exec(search_text);
    if(name_result) {
      first_search = search_text.substring(name_result[0].length);
      search_pattern = "("+first_search+"?(s|es)?)";
      break;
    }
    
    /* Other cases */
    first_search = search_text;
		if(first_search.length <= 0) {
			GM_log("Strange case in regexp building. Content is empty");
		} else {
			search_pattern = "("+first_search+"?(s|es)?)";
		}
    
  } while(0);

	
  new_regexp = new RegExp("\\W" + search_pattern + "\\W", 'ig');

  return new_regexp;
}

/* Add the word and its translation respectively in expression and translation tag. both embedded in a content tag */
function add_translation_content_to_storage(expression, translation, id) {

	real_express = expression.substring(0, expression.indexOf(":"));

  new_regexp = build_regex(real_express);
	
	if (new_regexp != null) {
		new_content_array = new Array('content', real_express, translation, new_regexp);
  
		array_id = get_add_xml_storage(id);
		array_id.push(new_content_array);
		
	}
  
}

/* Create a button and add it before the appended_node with the appeneded node text + with translation */
function create_clickable_icon(appended_node, id) {

  var new_loader_icon = document.createElement('loading_icon_element');
  var new_button = create_button(
            prepare_article_context,
            user_message("icon_get_article_title"),
            20,
            20,
            'data:image/gif;base64,'+
            _button_img,
            id);
  
  new_loader_icon.appendChild(new_button);
  
  var br_node = document.createElement('br');
  new_loader_icon.appendChild(br_node);
  
  var text_node = document.createElement('p');
  text_node.innerHTML = appended_node.nodeValue + user_message("get_article_with_translation");
  text_node.appendChild(new_loader_icon);
  
  appended_node.parentNode.insertBefore(text_node, appended_node);
}

/* Create a button with a mouse event and one img. the img id is set for the event treatment later.
code has been taken from dive into greasemonkey. Thanks Mark Pilgrim  */
function create_button(func, title, width, height, src, img_id) {

    var img, button;
    img = document.createElement('img');
    img.width = width;
    img.height = height;
    /* Set the button style to not pushed */
    set_button_img_style(img,0);
    img.style.marginLeft = "2px";
    img.style.marginRight = "2px";
    img.src = src;
    img.id = img_id;
    button = document.createElement('a');
    button.title = title;
    
    button.addEventListener('click',
                            func, 
                            true);
    button.appendChild(img);
    
    return button;
}
 
/* Function called when user click on the inserted image 
Get content from article and store it in _article_content */
function prepare_article_context(event)
{
  /* init global variable */
  _article_content = null;
  
  /* Store the id tageted by the event */
  _anchor_id = event.target.id;
  
  /* Set button style to pushed */ 
  set_button_img_style(event.target,1);
  /* Set a time out to reset the button pusshed effect later on */
  setTimeout(set_button_img_style, _button_reset_timeout, event.target, 0);
  
  var article_url = get_article_url(event.target.id);
 
  if (article_url) {
    /* Reset global _parsing_status */
    _xml_http_get_status = 1;
    /* Try to get content from the article url */
    get_related_article_content(article_url, 1);
    /* Set a time out to few seconds to disply an error message box to user if nothing has been found */ 
    setTimeout(time_out_after_getting_article_content, _http_request_timeout);
  }
}

/*  Get the article_content using  GM_xmlhttpRequest function 
that seems to be threaded. Set a time out to finish the job in
one another function */
function get_related_article_content(article_url, process_content) {
  
  GM_xmlhttpRequest({
    method: 'GET',
    url: article_url,
    
    onload: function(responseDetails) {
      /* Set a time out (just a event) to process the content and record it only if requested */
      if (process_content) {
        _article_content = new String(responseDetails.responseText);
        setTimeout(process_article_content,1);
      }
    }
  });
}

/*Function called on timeout from prepare_article_context*/
function time_out_after_getting_article_content() {
  /* set http request to the article content status to failure */
  if (_xml_http_get_status == 1) {
    _xml_http_get_status = 0;
    GM_log('IN time_out_after_getting_article_content. Getting the article failed');
    alert(user_message("article_not_available"));
  }
}

/* Function called when the article has been loaded */
function process_article_content() {

  if ((_article_content) && (_article_content != "") && (_xml_http_get_status == 1)) {
    /*  In case some document.* are still somewhere replace then */
    replace_document_attributs();
    /* Remove the script tags from _article_content */
    remove_script_tag_from_content();  
    
    /* Open content in a new windows */
    _new_window = open_new_windows_and_write_in();
    /* Run on Interva to wait for the DOM to fully parse the content */
    _wait_for_body_intervalID = setInterval(ensure_body_has_been_found, _looping_interval);
  } else {
     GM_log('IN process_article_content. No content available or time out already occured');
  }
}

/* Replace domain. attributes with the current on a dummy variable to avoid redirection */
function replace_document_attributs() {
  init_content = _article_content;
  
  my_domain = "document.domain = '" + document.domain + "';"
  search_text = "document.domain\\W?=\\W?'\\w{1,20}.?\\w{1,20}.?\\w{1,20}.?\\w{1,20}.?\\w{1,20}';";
  
  re_function = new RegExp(search_text,'gi');
  init_content  = init_content.replace(re_function, my_domain);
  
  domain_regexp = new RegExp("(document.location|document.cookie)(\\.\\w)?", 'ig');
  init_content  = init_content.replace(domain_regexp, "has_been_replaced");
  
  _article_content = init_content;
}


/* Remove java scripts where a redirection may occur */
function remove_script_tag_from_content () {

  var new_content = "";
  var i = 0;
  var j = 0;
  
  init_content = _article_content;
  
  while (0 < init_content.length) {
    lc_init_content = init_content.toLowerCase();
    i = lc_init_content.indexOf("<scrip");
    j = lc_init_content.indexOf("</script>") + 9;
    
    if ((i < 0) || (j <= 0) || (j < i)) {
      new_content += init_content;
      init_content = "";
    } else {
        new_content += init_content.substring(0, i);
        i = j;
        init_content = init_content.substring(j);
    }
  }
  _article_content = new_content;
}

/* open a new windows and insert the article contents in*/
function open_new_windows_and_write_in() {

  try {  
	
    _new_window = window.open("text/html");
    _new_window.document.write(_article_content);
    _new_window.document.close();
		
  } catch(e) {
  /* @todo check event property */
    /* reset the getting article process status and show on alert message box */ 
    _xml_http_get_status = 0;
    alert(user_message("popup_not_allowed"));
  }
  return _new_window;
}

/* Function called by the avent Interval call after the article content insertion into the new wondows
 Wait to have the body parsed correctly by the dom parser */
function ensure_body_has_been_found() {

  if (_new_window) {
    if(_new_window.document.body) {
      clearInterval(_wait_for_body_intervalID);
      _xml_http_get_status = 0;
      /* Set an extra timeout to make sure DOM has finished its job */
      setTimeout(finalize_article_translation_insertion, _extra_timeout);
    }
  } else if (_xml_http_get_status == 1) {
    alert(user_message("error_occurs"));
    GM_log('IN ensure_body_has_been_found _new_window not available and status 1');
    clearInterval(_wait_for_body_intervalID);
  } else {
    clearInterval(_wait_for_body_intervalID);
    GM_log('IN ensure_body_has_been_found _new_window not available');
  }
}

/* Add the translation to the article and rewrite url to absolute ones */
function finalize_article_translation_insertion() {
  
  article_url = get_article_url(_anchor_id);
	
  /* Add a worning to the top the article */
  add_warning_on_content(_new_window.document, article_url);
  /* add translation to the article */
  add_content_to_article(_new_window.document.body);  
  /* Change url to relative path */
  make_img_url_absolute(_new_window.document, article_url, window.location.href);
  make_link_url_absolute(_new_window.document, article_url, window.location.href);
  /* Make style sheet import relative to the article */
  make_style_sheet_url_absolute(_new_window.document, article_url, window.location.href);
	/*  Sometime body style is corrupted. Force it to Arial or Helvetica */
	forceBodyStyle(_new_window.document);
  
}

/* Add a warning to the top the article telling user content has been change  */
function add_warning_on_content(this_document) {

  if(!this_document) return;
  
  new_node = document.createElement('p'); 
  new_node.innerHTML = user_message('article_warning');
  new_node.style.backgroundColor = _warning_background_color;
	new_node.style.fontSize = _warning_text_size;
  
  this_document.body.insertBefore(new_node, this_document.body.firstChild);
}

/* Parse all link nodes and try to rewrite the url as an absolut one */
function make_link_url_absolute(doc_node, article_location, current_url) {

  if(!doc_node) {
    GM_log("make_link_url_absolute no document available");
    return;
  }

  /* Find all script nodes */
  link_nodes = document.evaluate(
  '//link',
  doc_node,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);
  
  current_location = String(document.location);
  
  for (var i = 0; i < link_nodes.snapshotLength; i++) {
    current_node = link_nodes.snapshotItem(i);
    node_location = String(current_node.href);
    current_node.href = build_absolute_url(current_location, node_location, article_location);
  }
}

/* Parse all image nodes and try to rewrite the url as an absolut one */
function make_img_url_absolute(doc_node, article_location, current_url) {

  if(!doc_node) {
    GM_log("make_url_absolute no document available");
    return;
  }

  /* Find all script nodes */
  link_nodes = document.evaluate(
  '//img',
  doc_node,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);
  
  current_location = String(document.location);
  
  for (var i = 0; i < link_nodes.snapshotLength; i++) {
    current_node = link_nodes.snapshotItem(i);
    node_location = String(current_node.src);
    
    current_node.src = build_absolute_url(current_location, node_location, article_location);
  }
}

/* Built a absolute url regarding the */
function build_absolute_url(current_location, node_location, article_location) {

  if((!current_location) || (!node_location) || (!article_location)) {
    return;
  }

  if (current_location == node_location.substring(0, current_location.length)) {
  
    new_url = article_location.substring(0, article_location.lastIndexOf("/") +1);
    new_url += node_location.substring(current_location.length);
    return new_url;  
  } else {
    return node_location;
  }
}

/* Make imported style sheet url */
function make_style_sheet_url_absolute(doc_node, article_location, current_url) {

  if(!doc_node) {
    GM_log("make_style_sheet_url_absolute no document available");
    return;
  }

  /* Find all script nodes */
  nodes = document.evaluate(
  '//style',
  doc_node,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);
  
  current_location = String(document.location);
  
  for (var i = 0; i < nodes.snapshotLength; i++) {
    current_node = nodes.snapshotItem(i);
    build_import_style_url(current_node, article_location);
  }
}
/* Get domain to the url */
function get_http_domain(url) {

  end_protocole = url.indexOf("http://") + 7;
  current_domain = "http://" + url.substring(end_protocole, url.substring(end_protocole).indexOf("/") + end_protocole);

  return current_domain;
}

/*  Make inmported style sheets path absolute */
function build_import_style_url(current_node, article_location) {

  if((!current_location) || (!node_location) || (!article_location)) {
    return;
  }
	
  /* Find @import url */
  import_regexp = new RegExp("@import url\\((.*)\\);", 'ig');
  import_result = import_regexp.exec(current_node.innerHTML);
  
  if(import_result) {
    current_domain = get_http_domain(article_location);
    if(import_result[1][0] == "/") {
      /* Absolute URL */
      current_node.innerHTML = current_node.innerHTML.replace(import_result[1], current_domain + import_result[1]);
    } else {
      /* */
      current_node.innerHTML = current_node.innerHTML.replace(import_result[1], current_domain + "/" + import_result[1]);
    }
  }
}

/* Usual add style style from Grease monkey */
function addGlobalStyle(doc, css) {
	var head, style;
	head = doc.getElementsByTagName('head')[0];
	if (!head) { return; }
	style = doc.createElement('style');
	style.type = 'text/css';
	style.innerHTML = css;
	head.appendChild(style);
}
/* Sometime style are corrupted by the script.  Force body style to Arial.*/
function forceBodyStyle(doc) {
	addGlobalStyle(doc, 'body { font-family: Arial, Helvetica; }');
}

/* Add the regexp result to the storage array sorting by their position */
function add_regex_result_to_array(my_array, re_result, word, translation) {

  var this_index = re_result.index;
  var this_length = re_result[1].length;
  var this_matched = re_result[1];
  var j = 0;
  
  /* Iterate in each regexp result while they are located before the current one in the text */  
  for (j = 0; j < my_array.length; j++) {
      if(this_index <= my_array[j][0]) break;
  }
      
  new_founded = new Array(this_index, this_length, this_matched, word + ": " + translation);
  my_array.splice(j, 0, new_founded);
}


/*Add the translations found in english in paris page to the article. Only add a title to the word */
function add_content_to_article(new_windows_content) {

  /* Find all nodes with a text nodes */
  text_nodes = document.evaluate(
  "//text()",
  new_windows_content,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);
    
  /*Loop in each text node */
  for (var i = 0; i < text_nodes.snapshotLength; i++) {
    node = text_nodes.snapshotItem(i);
    this_data = node.data;
    attach_node = null;
    begin_content = 0;
        
    array_id = get_xml_storage(_anchor_id);
    sorted_array = new Array();
    
    /* try to find each translated word  in this node content */
    for (var j = 0; j < array_id.length; j++) {
      if ((array_id[j][0] == "content") && (this_founded = array_id[j][3].exec(this_data))) {
        add_regex_result_to_array(sorted_array, this_founded, array_id[j][1], array_id[j][2]);
      }
    }
    
    for (var j = 0; j < sorted_array.length; j++) {
   
      // Make the current tex empty and buid a tree appended to the attach_node 
      str_start = sorted_array[j][0] + 1;
      str_end = str_start + sorted_array[j][1];
  
      // Create two new nodes 
      first_node = document.createElement('font');
      second_text = document.createElement('font');
			
      // Set a darker back ground (from configuration attribut)  to the found text and set the translation to its title 
      second_text.style.backgroundColor = get_highligth_background_style();
      second_text.title = sorted_array[j][3];
      
      first_node.innerHTML = this_data.substr(begin_content, str_start - begin_content);
      second_text.innerHTML = sorted_array[j][2];
      
      node.data = "";
      begin_content = str_end;
       
      if(!attach_node) {
        attach_node = document.createElement('font');
      }
                  
      attach_node.appendChild(first_node);
      attach_node.appendChild(second_text);
        
    }
    
    /* If a tree has been built append it to its parent node */
    if(attach_node) {
      if (begin_content < this_data.length) {
        last_node = document.createElement('font');
        last_node.innerHTML = this_data.substr(str_end);
        attach_node.appendChild(last_node);
      }
      node.parentNode.insertBefore(attach_node, node);
    }
  }
}

/* Configuration parameters functions using GM get_set_value. 
Functions are called from GM menu command */
/*  get translation backgroud color  config  parameterv*/
function get_highligth_background_style() {
  return GM_getValue("gm_englishinparis_backgroud_style", 'yellow');    
}

/*  set config parameter for translation backgroud color to yellow */
function set_highligth_background_style_default() {
 GM_setValue("gm_englishinparis_backgroud_style", 'yellow');
}

/*  set config parameter for translation backgroud color to gray */
function set_highligth_background_style_ligth_gray() {
 GM_setValue("gm_englishinparis_backgroud_style", '#eeeeee');
}







