<?php
/*
 * icl_content.module
 * 
 * @file ICanLocalize content handling
 */

define ( 'ICL_CONTENT_PERM_COMMENT', 'moderate comments in own language');
define ( 'ICL_CONTENT_PERM_TRANSLATE', 'submit content for translation');

module_load_include('inc', 'icl_core', 'icl_core.wrapper');
module_load_include('inc', 'icl_content', 'icl_content.wrapper');
module_load_include ( 'inc', 'icl_core', 'icl_core.constants' );
module_load_include ( 'inc', 'icl_core', 'icl_core.webservices' );
module_load_include ( 'inc', 'icl_content', 'icl_content.contact_form' );
module_load_include ( 'inc', 'icl_content', 'icl_content.block' );
module_load_include ( 'inc', 'icl_content', 'icl_content.dashboard' );
module_load_include ( 'inc', 'icl_content', 'icl_content.string' );
module_load_include ( 'inc', 'icl_content', 'icl_content.images' );
module_load_include ( 'inc', 'icl_content', 'icl_content.stats' );

define ( 'ICL_CONTENT_SEND_MANUAL', 'manual' );
define ( 'ICL_CONTENT_SEND_PROMPT', 'prompt' );
define ( 'ICL_CONTENT_SEND_AUTOMATIC', 'automatic' );

define ( 'ICL_CONTENT_PUBLISH_TRANSLATIONS', 'publish_translations');
define ( 'ICL_CONTENT_DONT_PUBLISH_TRANSLATIONS', 'dont_publish_translations');

define ( 'ICL_CONTENT_MENU_ORIGINAL', 'menu_original');
define ( 'ICL_CONTENT_MENU_SEPARATE', 'menu_separate');

define ( 'ICL_CONTENT_DELETE_MANUAL', 'manual' );
define ( 'ICL_CONTENT_DELETE_AUTOMATIC', 'automatic' );

define ( 'ICL_CONTENT_TRANSLATE_PUBLISHED', 'published' );
define ( 'ICL_CONTENT_TRANSLATE_NEXT', 'next' );
define ( 'ICL_CONTENT_TRANSLATE_NOT', 'not' );

define ( 'ICL_CONTENT_UPDATE_LINKS', 'update_links' );
define ( 'ICL_CONTENT_DONT_UPDATE_LINKS', 'dont_update_links' );


function icl_perms() {
  return array ();
}

/**
 * Implementation of hook_menu().
 * @see http://api.drupal.org/api/function/hook_menu/6
 *
 * @return array
 */
function icl_content_menu() {
  $items [_icl_wrapper_get_root_menu('translation-management/dashboard')] = array (
      'title' => 'Translation Dashboard', 
      'description' => 'Presents a Dashboard interface to manage translations', 
      'page callback' => 'drupal_get_form', 
      'page arguments' => array (
          'icl_content_dashboard' ), 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'file' => 'icl_content.dashboard.inc',
      'weight' => 1,
      );
  /*
   $items [_icl_wrapper_get_root_menu('translation-management/icl-review')] = array (
      'title' => 'Translation Review', 
      'description' => 'Presents an interface to review received translations', 
      'page callback' => 'drupal_get_form', 
      'page arguments' => array (
          'icl_content_translation_review' ), 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'weight' => -3,
      'file' => 'icl_content.dashboard.inc' );
  */
  $items [_icl_wrapper_get_root_menu('translation-management/reports')] = array (
      'title' => 'Translation Status Reports', 
      'description' => 'Enable translation status reports', 
      'page callback' => 'drupal_get_form', 
      'page arguments' => array (
          'icl_content_status_report' ), 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'file' => 'icl_content.stats.inc',
      'weight' => 8,
      );

  $items [_icl_wrapper_get_root_menu('translation-management/icl-check')] = array (
      'title' => 'Status Check', 
      'description' => 'Checks Drupal\'s multilingual system, reports possible problems and suggests solutions', 
      'page callback' => 'icl_status_check', 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'weight' => 25,
      'file' => 'icl_content.check.inc' );
  $items ['icl_content/word_count'] = array (
      'page callback' => 'icl_content_word_count', 
      'page arguments' => array (),
      'access arguments' => array('access content'),
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.module' );
  $items ['node/%node/icl_publish'] = array (
      'page callback' => 'icl_content_publish_translation', 
      'page arguments' => array(1),
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.module' );
  $items ['icl_content/icl_status/%icl_node'] = array (
      'page callback' => 'icl_content_icl_status', 
      'page arguments' => array (2),
      'access arguments' => array('access content'),
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.module' );
  $items ['icl_content/icl_string_status'] = array (
      'page callback' => 'icl_content_string_status', 
      'page arguments' => array (),
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.string.inc' );
  $items ['icl_content/icl_string_send'] = array (
      'page callback' => 'icl_content_string_send', 
      'page arguments' => array (),
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.string.inc' );
  $items ['icl_content/icl_queued_strings'] = array (
      'page callback' => 'drupal_get_form', 
      'title' => 'Strings queued for translation', 
      'description' => 'Shows strings that have been queued for translation.', 
      'page callback' => 'drupal_get_form', 
      'page arguments' => array (
          'icl_content_send_queued_strings' ), 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.string.inc' );
  $items ['icl_content_type/dismiss_warning'] = array (
      'page callback' => 'icl_content_dismiss_warning', 
      'page arguments' => array (),
      'access arguments' => array('access content'),
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.dashboard.inc' );
  $items [_icl_wrapper_get_root_menu('translation-management/icl-image-translation')] = array (
      'title' => 'Image Translation', 
      'description' => 'Presents an interface for replacing images in translated content', 
      'page callback' => 'drupal_get_form', 
      'page arguments' => array (
          'icl_content_image_translations' ), 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'file' => 'icl_content.images.inc',
      'weight' => 30
  );
  $items ['icl_content/icl_image_replace'] = array (
      'page callback' => 'icl_content_image_replace_callback', 
      'page arguments' => array (),
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.images.inc' );
      
   $items [_icl_wrapper_get_root_menu('translation-management/icl-link-translation')] = array (
      'title' => 'Link Translation', 
      'description' => 'Presents an interface for replacing links in translated content', 
      'page callback' => 'drupal_get_form', 
      'page arguments' => array (
          'icl_content_link_translations' ), 
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'file' => 'icl_content.links.inc',
       'weight' => 35
   );
   $items ['icl_content/icl_link_replace'] = array (
      'page callback' => 'icl_content_link_replace_callback', 
      'page arguments' => array (),
      'access arguments' => array (
          ICL_CONTENT_PERM_TRANSLATE ), 
      'type' => MENU_CALLBACK, 
      'file' => 'icl_content.links.inc' );
  
  return $items;
}

/**
 * Implementation of hook_help().
 */
function icl_content_help($path, $arg) {
  // @todo Review and remove
//  switch ($path) {
//    case 'admin/content/translation-management/icl-image-translation':
//      $output = '<p>'. t('This page allows you to specify alternative images for translated content. The alternative images are selected using an automatic replacement method or you can specify your own path for each image.') .'</p>';
//      $output .= '<p>'. t('Types of elements replaced:') . '<ul><li>' . t('&lt;img src="<b>Local url</b>"&gt;') . '</li><li>' . t('&lt;embed src="<b>Local url</b>"&gt;') . '</li><li>' . t('&lt;object ... &gt; &lt;param name="movie" value="<b>Local url</b>"&gt;') . '</li></ul></p>';
//      $output .= '<p>'. t('An alternative image is only used in translated content if it exists. Otherwise the image in the original content is used. ');
//      $output .= t('<a href="@url">More info</a>', array('@url' => ICL_IMAGE_REPLACEMENT_INFO)) . '</p>';
//      return $output;
//    break;
//  case 'admin/content/translation-management/icl-link-translation':
//      $output = '<p>'. t('This page allows you to specify alternative links for translated content. The alternative links are selected using an automatic replacement method or you can specify your own path for each link.') .'</p>';
//      $output .= '<p>'. t('Types of elements replaced:') . '<ul><li>' . t('&lt;a href="<b>Local url</b>"&gt;') . '</li><li>' . t('&lt;a href="<b>External url</b>"&gt;') . '</li></ul></p>';
//      $output .= '<p>'. t('An alternative link is only used in translated content if it exists. Otherwise the link in the original content is used.') .'</p>';
//      return $output;
//  }

  if ($path == _icl_wrapper_get_root_menu('translation-management/icl-image-translation')) {
      $output = '<p>'. t('This page allows you to specify alternative images for translated content. The alternative images are selected using an automatic replacement method or you can specify your own path for each image.') .'</p>';
      $output .= '<p>'. t('Types of elements replaced:') . '<ul><li>' . t('&lt;img src="<b>Local url</b>"&gt;') . '</li><li>' . t('&lt;embed src="<b>Local url</b>"&gt;') . '</li><li>' . t('&lt;object ... &gt; &lt;param name="movie" value="<b>Local url</b>"&gt;') . '</li></ul></p>';
      $output .= '<p>'. t('An alternative image is only used in translated content if it exists. Otherwise the image in the original content is used. ');
      $output .= t('<a href="@url">More info</a>', array('@url' => ICL_IMAGE_REPLACEMENT_INFO)) . '</p>';
      return $output;
  } else if ($path == _icl_wrapper_get_root_menu('translation-management/icl-link-translation')) {
      $output = '<p>'. t('This page allows you to specify alternative links for translated content. The alternative links are selected using an automatic replacement method or you can specify your own path for each link.') .'</p>';
      $output .= '<p>'. t('Types of elements replaced:') . '<ul><li>' . t('&lt;a href="<b>Local url</b>"&gt;') . '</li><li>' . t('&lt;a href="<b>External url</b>"&gt;') . '</li></ul></p>';
      $output .= '<p>'. t('An alternative link is only used in translated content if it exists. Otherwise the link in the original content is used.') .'</p>';
      return $output;
  }
}


/**
 * Implementation of hook_init().
 */
function icl_content_init() {
  global $conf, $language;
  
  if (user_access('use on-page translation')) {
    
    if (module_exists('l10n_client') && user_access(ICL_CONTENT_PERM_TRANSLATE)) {
      // add string to l10n_client
      drupal_add_js(array('send_button' => t('Queue for translation')), 'setting');
      drupal_add_js(array('send_link' => t('Send now')), 'setting');
      drupal_add_js(array('queued_message' => t('There are strings queued for translation: ')), 'setting');
      drupal_add_js(array('checking_status' => t('Checking status...')), 'setting');
      $ican_string_status_url = _icl_wrapper_url('icl_content/icl_string_status');
      $ican_string_send_url = _icl_wrapper_url('icl_content/icl_string_send');
      $ican_string_que_url = _icl_wrapper_url(_icl_wrapper_get_root_menu('translation-management/dashboard'), array('query' => 'string=queued'));
      drupal_add_js(
                    array('ican_url' =>
                          array('ican_string_status_url' => $ican_string_status_url,
                                'ican_string_send_url' => $ican_string_send_url,
                                'ican_string_que_url' => $ican_string_que_url)),
                          'setting');
      
  
      drupal_add_js(drupal_get_path('module', 'icl_content') . '/js/icl_string.js');
    }    
  }
  
  if(user_access(ICL_CONTENT_PERM_TRANSLATE)) {
    icl_content_set_string_queue_message();
  }
}

function icl_content_get_rids($nid, $type){
  
  switch($type){
    case 'node':
      $table = 'icl_content_status';
      $id_type = 'nid';
      break;
    
    case 'block':
      $table = 'icl_block_status';
      $id_type = 'bid';
      break;

    case 'contact_form':    
      $rids = variable_get('icl_contact_form_rids', array());
      foreach ($rids as $lang => $rid) {
        $rids[$lang] = max($rid);
      }
      return $rids;
    
  }
  $rids = FALSE;
  $query = _icl_wrapper_db_query("SELECT cn.rid, cs.target
                      FROM
                        {" . $table . "} cn
                      JOIN
                        {icl_core_status} cs
                      ON
                        cs.rid = cn.rid
                      WHERE
                        " . $id_type . " = %d
                      ORDER BY cn.rid", (int)$nid);
  while ( $request = db_fetch_array ( $query ) ) {
    $rids[$request['target']] = $request['rid'];
  }
  
  return $rids;
  
}

function icl_content_icl_status($item) {

  $source = null;
  
  if (substr($item, 0, 6) == "block-") {
    $bid = substr($item, strlen("block-"));
    $rids = icl_content_get_rids($bid, 'block');
    $time = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT timestamp FROM {icl_block_status} WHERE bid = %d", $bid));

    $block = _icl_wrapper_block_box_get($bid);

    $word_count = icl_content_get_words_in_data(_icl_content_extract_block($block));
    $type = 'block';

    // we have to calculate the block md5 each time as we don't know it has changed.
    $current_md5 = icl_content_calculate_block_md5($block);

  } else if (substr($item, 0, 8) == "contact-") {
    
    $rids = icl_content_get_rids($bid, 'contact_form');
    $time = variable_get('icl_contact_form_timestamp', 0);
    $word_count = icl_content_get_words_in_data(_icl_content_extract_standard_contact_form());
    $type = 'contact form';
    
    $current_md5 = icl_content_calculate_stardard_contact_form_md5();
    
  } else {
    
    // a node
    $node = node_load($item);
    $rids = icl_content_get_rids($node->nid, 'node');
    $word_count = icl_content_get_words_in_node($node);
    $type = 'node';
    
    $current_md5 = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT md5 FROM {icl_node} WHERE nid = %d", $node->nid));
    if ($rids === FALSE) {
      if (isset($node->tnid) && $node->tnid != $node->nid && $node->tnid != 0) {
        $node = node_load($node->tnid);
        $source = array(
                        'nid' => $node->nid,
                        'title' => $node->title,
                      );
      }
    }
    
    
  }
  
  if ($rids === FALSE) {
    
    if ($source) {
      $data .= t('This is a translation of ') . '<a href="'. _icl_wrapper_url('node/'.$source['nid']) .'">'.$source['title'].'</a><br>';
    } else {
      $data .= t('This @type has not been sent for translation.', array('@type' => $type)) . '<br>';
    }
  } else {
    // source node

    $data = '';
    
    $data .= '<table><thead><tr><th>Language</th><th>Status</th><th>Translator</th></tr></thead><tbody>';
    $class = "odd";
  
    foreach($rids as $lang => $rid){
    
      $query = _icl_wrapper_db_query("SELECT * FROM {icl_core_status} WHERE rid = %d", $rid);
      
      $translators = icl_core_fetch_translators_and_word_count($rid);
        
      
      
      while($result = db_fetch_object($query)) {
        if ($result->target == $lang){
          $word_count = $translators[$lang]['word_count'];
          $status = $translators[$lang]['status'];
          if ($status == CMS_TARGET_LANGUAGE_DONE) {
            $request_md5 = _icl_content_get_md5_for_rid($type, $rid);
            if ($current_md5 == $request_md5) {
              $status = t('Complete');
            } else {
              $status = t('Complete - Translation needs update');
            }
          } else if ($status == ICL_STATUS_FAILED) {
            $status = t('Failed');
          } else if ($status == CMS_TARGET_LANGUAGE_TRANSLATED) {
            $status = t('Translation ready');
          } else {
            $status = t('In progress');
          }
    
          $chat_link = '/websites/' . variable_get('icl_core_website_id', '') . '/cms_requests/' . $rid . '/chat?lang='. icl_core_get_language_name($result->target) . '&no_refresh=1';
          if (isset($translators[$result->target]['translator']) && strlen($translators[$result->target]['translator']) > 0) {
            $chat = icl_create_icl_popup_link($chat_link) . $translators[$result->target]['translator'] . '</a>';
          } else {
            $chat = 'None assigned';
          }
    
          $data .= '<tr class="' . $class . '"><td>' . icl_core_get_drupal_language_name($result->target) . '</td><td>' . $status . '</td><td>' . $chat . '</td></tr>';
          if ($class == "odd") {
            $class = "even";
          } else {
            $class = "odd";
          }
        }  
      }
  
      $data .= '<tr class="' . $class . '"><td colspan="3">';
      $project_link = '/websites/' . variable_get('icl_core_website_id', '') . '/cms_requests/' . $rid . '?no_refresh=1';
      $data .= icl_create_icl_popup_link($project_link) . t('Project page ') . '</a>' . t('on ICanLocalize.com') . '<br>';

      $time = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT timestamp FROM {icl_content_status} WHERE rid = %d", $rid));

      if ($time != 0) {
        $data .= t('Sent for translation: ') . format_date($time, 'small') . '<br>';
      }
    
      $data .= t('Job size: !words words', array('!words' => $word_count));    

      $data .= '</td></tr>';
    
      if ($class == "odd") {
        $class = "even";
      } else {
        $class = "odd";
      }
    }
    $data .= '</tbody></table>';
  }
  
  _icl_wrapper_drupal_json(array('status' => TRUE, 'data' => $data));
  
  
}
function icl_content_publish_translation($node) {
  $node->status = 1;
  node_save($node);
  
  $link = '<a href="' . _icl_wrapper_url(_icl_wrapper_get_drupal_menu('admin/content/icl-review')) . '">';
  drupal_set_message($node->title. t(' has been published. Return to !linkTranslation Review</a>', array('!link' => $link)));
  _icl_wrapper_drupal_goto('node/'.$node->nid);
  
}




function icl_content_get_words_in_data($data, $lang_code = '') {
  $asian_languages = array('ja', 'ko', 'zh-hans', 'zh-hant', 'mn', 'ne', 'hi', 'pa', 'ta', 'th');
  
  $words_in_data = 0;

  // Get rid of all PHP code.       
  $search = array('/<\?((?!\?>).)*\?>/s');
  
  foreach($data as $content) {
    if ($content['translate']) {
      if(in_array($lang_code, $asian_languages)){
        if ($content['format'] == 'csv') {
          $text_all = "";
          foreach($content['text'] as $text) {
            $text_all = $text_all . ' ' . $text;
          }
          $text_all = preg_replace($search, '', $text_all); 
          $words_in_data += strlen(strip_tags(trim($text_all))) / 6;
        } else {
          $words_in_data += strlen(strip_tags(trim(preg_replace($search, '', $content['text'])))) / 6;
        }
      } else {
        
        if ($content['format'] == 'csv') {
          $text_all = "";
          foreach($content['text'] as $text) {
            $text_all = $text_all . ' ' . $text;
          }
          $text_all = preg_replace($search, '', $text_all); 
          $words = explode(" ", strip_tags(trim($text_all)));
          
        } else {
          $words = explode(" ", strip_tags(trim(preg_replace($search, '', $content['text']))));
        }
        foreach($words as $word) {
          if (strlen($word) > 0)  {
            $words_in_data += 1;
          }
        }
      }      
    }
  }
  
  return (int)$words_in_data;
}
function icl_content_get_words_in_node($node) {
  $data = _icl_content_extract_node($node);
  
  return icl_content_get_words_in_data($data, $node->language);
}


function icl_content_word_count()
{
  $word_count = 0;
  $node_count = 0;
  $details = array();
  $node_details = array();
  
  $lang = $_REQUEST['language'];
  if ($lang == "0") {
    $lang = "";
  }

  global $icl_content_dashboard_filter;
  
  $icl_content_dashboard_filter = array(
    'language' => $_REQUEST['language'],
    'translation' => $_REQUEST['translation'],
    'status_enabled' => $_REQUEST['status_enabled'] == 1,
    'status' => $_REQUEST['status_status'],
    'type_enabled' => $_REQUEST['type_enabled'] == 1,
    'type' => $_REQUEST['type_type'],
  );
  if ($icl_content_dashboard_filter['language'] == '0') {
    // handle language neutral setting
    $icl_content_dashboard_filter['language'] = '';
  }

  $query = icl_content_dashboard_build_filter_query($page_mode = false);
  
  while ( $result = db_fetch_array ( $query ) ) {
    
    if ($result['tnid'] == 0) {
      $node_count += 1;
      
      if ($result['type'] == 'icl_block_marker') {
        
        $result['type'] = 'Block';

        $block = _icl_wrapper_block_box_get($result['nid']);
    
        $block_data = _icl_content_extract_block($block);
        
        $words_in_item = icl_content_get_words_in_data($block_data);

        $node_details['block-'.$result['nid']] = array('Block - '._icl_content_get_block_title($block_data), $words_in_item);
    
      } else if ($result['type'] == 'icl_contact_form_marker') {
        
        $result['type'] = 'Contact Form';
        $words_in_item = icl_content_get_words_in_data(_icl_content_extract_standard_contact_form());
        $node_details['contact_form'] = array('Contact Form', $words_in_item);
        
      } else {
      
        $node = node_load($result['nid']);
        
        $words_in_item = icl_content_get_words_in_node($node);
        $node_details[$node->nid] = array($node->title, $words_in_item);
      }
      
      
      $word_count += $words_in_item;
      
      if (!isset($details[$result['type']])) {
        $details[$result['type']] = $words_in_item;
      } else {
        $details[$result['type']] += $words_in_item;
      }
    }
  }

  $data = '<br>' . t('There are approximately !words words in !nodes nodes. <br>The cost estimate to translate to any language is $!cost.<br>The details for each node type are:',
                                                  array(
                                                        '!words' => $word_count,
                                                        '!nodes' => $node_count,
                                                        '!cost' => $word_count * 0.07
                                                        ));
  $data .= '<table><thead><tr><th>Node type</th><th>Words</th><th>Cost estimate</th></tr></thead><tbody>';
  
  $details['Total'] = $word_count;
  
  $class = "odd";
  foreach($details as $type => $words) {
    if ($type == 'Total') {
      $data .= '<tr class="' . $class . '"><td><b>' . $type . '</b></td><td><b>' . $words . '</b></td><td><b>$' . $words * 0.07 . '</b></td></tr>';
    } else {
      $data .= '<tr class="' . $class . '"><td>' . $type . '</td><td>' . $words . '</td><td>$' . $words * 0.07 . '</td></tr>';
    }
    if ($class == "odd") {
      $class = "even";
    } else {
      $class = "odd";
    }
  }
  
  $data .= '</tbody></table>';

  $data .= 'Details for each node:';
  $data .= '<table><thead><tr><th>Node</th><th>Words</th><th>Cost estimate</th></tr></thead><tbody>';
  
  $class = "odd";
  foreach($node_details as $nid => $node_data) {
    $data .= '<tr class="' . $class . '"><td>' . $node_data[0] . '</td><td>' . $node_data[1] . '</td><td>$' . $node_data[1] * 0.07 . '</td></tr>';
    if ($class == "odd") {
      $class = "even";
    } else {
      $class = "odd";
    }
  }
  
  $data .= '</tbody></table>';
  
  _icl_wrapper_drupal_json(array('status' => TRUE, 'data' => $data));
}
/**
 * Implementation of hook_xmlrpc()
 * @see http://api.drupal.org/api/function/hook_xmlrpc/6
 *
 * @return array() The XML-RPC method definitions
 */
function icl_content_xmlrpc() {
  return array ( // Translation status method
      array (
          'icanlocalize.notify_comment_translation', 
          'icl_content_xmlrpc_callback', 
          array (
              'int',  // Return value, see handler function head comment
              'string',  // Signature
              'int',  // Website ID
              'int',  // request ID
              'string' ),  // body
          t ( 'Handles comment translation status postbacks from ICanLocalize.com' ) )
      );
}

/*
 * The XML-RPC method to notify about comment translations
 *
 * 0 – Unknown error
 * 1 – success
 * 2 – Signature failed
 * 3 – website_id incorrect
 * 4 – request_id not found
 */

function icl_content_xmlrpc_callback($signature, $website_id, $request_id, $translation) {
  $accesskey = variable_get ( 'icl_core_accesskey', 0 );
  $checksum = $accesskey . $website_id . $request_id;
  if (md5 ( $checksum ) == $signature) {
    $wid = variable_get ( 'icl_core_website_id', 0 );
    if ($website_id == $wid) {
      $cid = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT cid FROM {icl_comment_translation} WHERE rid = %d", $request_id));
      if ($cid == FALSE) {
        return 4;
      } else {

        set_comment_to_database($cid, $translation);

        _icl_wrapper_db_query("DELETE FROM {icl_comment_translation} WHERE rid = %d", $request_id);  
        return 1;
      }
    } else {
      return 3;
    }
  } else {
    return 2;
  }
}

function set_comment_to_database($cid, $comment) {
  $parts = explode("\n{{T:1}}\n", $comment);
    
  $table_name = _icl_wrapper_table_name('comments');
    
  if (sizeof($parts) == 2) {
    _icl_wrapper_db_query("UPDATE {" . $table_name . "} SET subject = '%s', comment = '%s' WHERE cid = %d", $parts[0], $parts[1], $cid);
  } else {
    $format = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT format FROM {" . $table_name . "} WHERE cid = %d", $cid));
    $subject_from_text = trim(truncate_utf8(decode_entities(strip_tags(check_markup($comment, $format))), 29, TRUE));
    
    _icl_wrapper_db_query("UPDATE {" . $table_name . "} SET subject = '%s', comment = '%s' WHERE cid = %d", $subject_from_text, $comment, $cid);
  }

}
/**
 * process the comments that have been translated.
 */
    
function icl_content_process_comments($comments) {

  foreach($comments as $id => $comment) {
    $cid = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT cid FROM {icl_comment_translation} WHERE rid = %d", $id));
    if ($cid != FALSE) {
      
      set_comment_to_database($cid, $comment);
      
      _icl_wrapper_db_query("DELETE FROM {icl_comment_translation} WHERE rid = %d", $id);  
      
    }
    
  }
  
}

/**
 * calculate the md5 value of a node using title and body and other data.
 *
 */

function icl_content_calculate_node_md5($node) {

    $data = _icl_content_extract_node($node);
    
    return icl_content_calculate_md5_from_data($data);
}

/**
 * calculate the md5 value from extracted data.
 *
 */

function icl_content_calculate_md5_from_data($data) {

    $content_text = "";
    
    foreach($data as $content) {
      if ($content['translate']) {
        if (isset($content['format']) && $content['format'] == 'csv') {
          $text_all = "";
          foreach($content['text'] as $text) {
            $text_all = $text_all . ' ' . $text;
          }
          $content_text .= $text_all;
          
        } else {
          $content_text .= $content['text'];
        }
        
      }
    }
    
 
  return md5($content_text);
  
}

/**
 * save the md5 for a node into the icl_node table
 */

function icl_content_save_node_md5($node, $md5) {
  
  $nid = $node->nid;

  // Affected rows change
  $exists = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT nid FROM {icl_node} WHERE nid = %d", $nid));
  
  if ($exists) {
    _icl_wrapper_db_query( "UPDATE {icl_node} SET md5 = '%s' WHERE nid = %d", $md5, $nid );
  } else {
    // data not in table so we need to insert it.
  
    $sql = "INSERT INTO {icl_node} (nid, md5, links_fixed) VALUES (%d, '%s', 0)";
    _icl_wrapper_db_query( $sql, $nid, $md5);
  }
    
}

/**
 * See if the node has changed since it was last sent for translation.
 * Note: it will return TRUE for nodes that have never been translated by icanlocalize
 */
  
function icl_content_has_changed_since_last_translation($nid) {
  return FALSE;
}

/**
 * Implementation of hook_perm().
 */

function icl_content_perm() {
  return array(ICL_CONTENT_PERM_COMMENT, ICL_CONTENT_PERM_TRANSLATE);
}

/*function icl_content_comment(&$comment, $op) {
  if ($op == 'insert' or $op == 'update') {
    if (isset($comment->icl_translate_comment)) {
      $nid = $comment['nid'];
      $original_nid = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT tnid FROM node where nid = %d', $nid));
      $original_lang = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM node where nid = %d', $original_nid));;
      
      if ($comment['icl_translate_comment']) {
        $target_language = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM node where nid = %d', $nid));
        
        $rid = icl_core_send_comment_for_translation($comment['subject'], $comment['comment'], $comment['format'], $original_lang, $target_language);
        
        if ($rid == 0) {
          drupal_set_message ( t ( 'error: Failed to send the comment for translation to the ICanLocalize server. Could not connect.'), 'error');
        } else {
          _icl_wrapper_db_query( "UPDATE {icl_comment_translation} SET rid = %d WHERE cid = %d", $rid, $comment['cid'] );
          
          if (_icl_wrapper_db_affected_rows () == 0) {
            _icl_wrapper_db_query( "INSERT INTO {icl_comment_translation} VALUES(%d, %d, %d)", $rid, $comment['cid'], time ());
          }
            
        }
        
      }
    }
  }
  
  if ($op == 'view' && user_access(ICL_CONTENT_PERM_COMMENT)) {
    $rid = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT rid FROM {icl_comment_translation} WHERE cid = %d", $comment->cid));
    if ($rid != FALSE) {
      $target_language = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM node where nid = %d', $comment->nid));
      $languages = language_list();
      $comment->comment .= '<div class="message status"><div class="comment_sent">' . t ('This comment has been sent for translation to !language.', array('!language' => $languages[$target_language]->native)) . '</div></div>';
    } else {
      if (isset($comment->nid)) {
        $node = node_load($comment->nid);
        icl_content_show_translated_comments($node);
      }
    }
    
  }
  
}*/

/**
 * Implementation of hook_nodeapi().
 * @see http://api.drupal.org/api/function/hook_nodeapi/6
 *
 * @param object $node
 * @param string $op
 * @param bool $a3
 * @param bool $a4
 */
function icl_content_nodeapi(&$node, $op) {
  if (! translation_supported_type ( $node->type )) {
    return;
  }
  
  if ($op == 'insert' || $op == 'update') {
    
    $node_md5 = icl_content_calculate_node_md5($node);
    icl_content_save_node_md5($node, $node_md5);
  } else if ($op == 'presave' && !isset($node->icanlocalize_link_fix)) {
    
    _icl_content_fix_image_paths($node);
    _icl_content_fix_relative_link_paths($node);
    
    if(variable_get ( 'icl_content_update_links_options', ICL_CONTENT_UPDATE_LINKS ) == ICL_CONTENT_UPDATE_LINKS) {
    
      // the node is about to be saved
      
      _icl_content_fix_links($node);
      
      if (!isset($node->icanlocalize_creating_translation)) {
        icl_content_fix_links_in_all_dirty_nodes();
      }
    }
  }
  
  if (!user_access(ICL_CONTENT_PERM_TRANSLATE)) {
    return;
  }
  
  // We need to preprocess if the automatic sending is selected
  if ($op == 'insert' || $op == 'update') {
    
    if (isset($node->minor_edit)) {
      if($node->minor_edit) {
        _icl_wrapper_db_query("UPDATE {icl_content_status} SET md5 = '%s' where nid=%d", $node_md5, $node->nid);
        // exit now - we have nothing else to do.
        return;
      }
    }
    
    if (variable_get ( 'icl_content_send_options', ICL_CONTENT_SEND_MANUAL ) == ICL_CONTENT_SEND_AUTOMATIC) {
      $langs = icl_core_available_languages ();
      $langs_targets = _icl_core_available_targets_for_origin ( $node->language );
      if (isset($node->icanlocalize)) {
        $langs_diff = array_diff ( array_keys ( $langs_targets ), $node->icanlocalize );
      } else {
        $langs_diff = array_keys( $langs_targets );
      }
      $node->icanlocalize = $op == 'insert' ? array_keys ( $langs_targets ) : $langs_diff;
    }
    
    if (isset ( $node->icl_content_skip )) {
      $settings = variable_get ( 'icl_content_skip_per_node', array () );
      $settings [$node->nid] = $node->icl_content_skip;
      variable_set ( 'icl_content_skip_per_node', $settings );
      
      if ($node->icl_content_skip == ICL_CONTENT_TRANSLATE_NOT) {
        return;
      } else if ($node->icl_content_skip == ICL_CONTENT_TRANSLATE_PUBLISHED && $node->status != 1) {
        return;
      }
    }
  }
  
  // Do the actual translation request processing
  if ($op == 'insert' && isset ( $node->icanlocalize ) && ! empty ( $node->language )) {
    $site_languages = language_list('language', TRUE);
    
    $targets = array ();
    $translators = $node->translators;
    foreach ( $node->icanlocalize as $code ) {
      if ($code && isset ( $site_languages [$code] )) {
        $targets [] = $site_languages [$code];
      }
    }
    if (count ( $targets )) {
      $origin = $site_languages [$node->language];
      $data = _icl_content_extract_node ( _icl_wrapper_drupal_clone($node) , $targets);
      
      $previous_rids = NULL;
      $rids_sent = icl_core_send_content_for_translation('icl_content',
                                            $data,
                                            $origin,
                                            $targets,
                                            $previous_rids,
                                            url ( 'node/' . $node->nid, array ( 'absolute' => TRUE ) ),
                                            $node->title,
                                            $translators
                                            );
      
      
      foreach ($rids_sent as $rid) {
        if ($rid != 0) {
          _icl_wrapper_db_query( "INSERT INTO {icl_content_status} VALUES(%d, %d, %d, '%s')", $rid, $node->nid, time (), $node_md5 );

          // Notify the status.
          // We need to do this here because we have now saved the rid and nid to the icl_content_status table.
          $status = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT status FROM {icl_core_status} WHERE rid=%d", $rid));
          $lang = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT target FROM {icl_core_status} WHERE rid=%d", $rid));
          icl_core_notify_translation_status($rid, $lang, $status);
        }
      }      
    }
    
  } else if ($op == 'update' && isset ( $node->icanlocalize ) && (sizeof( $node->icanlocalize ) > 0) && ! empty ( $node->language )) {
    if (_icl_content_translation_in_progress_for_langs ( $node->nid, $node->icanlocalize )) {
      return;
    }
    
    $site_languages = language_list('language', TRUE);
    
    $previous_rids = icl_content_get_rids($node->nid, 'node');

    $translators = $node->translators;
    $targets = _icl_content_get_langs_needing_update($node->icanlocalize, $previous_rids, 'node', $node_md5, $translators);

    if (count ( $targets )) {
      $origin = $site_languages [$node->language];
      
      // create a separate cms_request for each language if possible
      // if the languages have previously been sent as a combined cms_request
      // we need to do the same this time.
      
      $grouped_targets = _icl_group_targets_by_rid($node->nid, 'node', $node->language, $targets, $previous_rids);

      $data = _icl_content_extract_node ( $node , $grouped_targets);
      
      
      $translators = $node->translators;
      $rids_sent = icl_core_send_content_for_translation('icl_content',
                                            $data,
                                            $origin,
                                            $grouped_targets,
                                            $previous_rids,
                                            url ( 'node/' . $node->nid, array ( 'absolute' => TRUE ) ),
                                            $node->title,
                                            $translators
                                            );
      
      
      foreach ($rids_sent as $rid) {
        if ($rid != 0) {
          _icl_wrapper_db_query( "INSERT INTO {icl_content_status} VALUES(%d, %d, %d, '%s')", $rid, $node->nid, time (), $node_md5 );
          
          // Notify the status.
          // We need to do this here because we have now saved the rid and nid to the icl_content_status table.
          $status = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT status FROM {icl_core_status} WHERE rid=%d", $rid));
          $lang = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT target FROM {icl_core_status} WHERE rid=%d", $rid));
          icl_core_notify_translation_status($rid, $lang, $status);
        }
      }      
    }
    
  } else if ($op == 'prepare' && ! isset ( $node->icanlocalize ) && $node->nid) {
    $node->icanlocalize = array ();
    foreach ( array_keys ( _icl_content_statuses ( $node->nid, 'node' ) ) as $code ) {
      $node->icanlocalize [] = $code;
    }
  } else if ($op == 'delete' && isset ( $node->icanlocalize )) {
    // TODO Implement deletion logic
  } else if ($op == 'view') {
    icl_content_show_translated_comments($node);
    
   if (isset($_GET['review']) && $_GET['review'] == "1") {
    icl_core_add_thickbox();
    drupal_add_js ( drupal_get_path ( 'module', 'icl_core' ) . '/js/icl_reminders.js' );
    
    $button_text = t('Translation is OK - Publish');
    $link_text = t('Translation needs fixing - chat with translator');
    $original_node = $node->tnid;
    $cms_request_id = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT rid FROM {icl_content_status} WHERE nid = %d", $original_node));
    
    $link = icl_create_icl_popup_link('/websites/' . variable_get('icl_core_website_id', '') . '/cms_requests/' . $cms_request_id . '/chat?lang='. icl_core_get_language_name($node->language));
    
    $back_to_link = '<a href="' . _icl_wrapper_url(_icl_wrapper_get_drupal_menu('admin/content/icl-review')) . '">&laquo; Back to Translation Review</a>';
    
    $form = '<form id="icl_publish" action="/node/' . $node->nid . '/icl_publish" method="post"><div class="icl_publish"><input type="submit" value="'.$button_text.'" /> &nbsp; | &nbsp; ' . $link . $link_text.'</a><br />'.$back_to_link.'</div></form>';
    $node->content['body']['#value'] = $form . $node->content['body']['#value'];
   }
  }

  
}

function _icl_content_get_md5_for_rid($type, $rid){
  switch($type){
    case 'node':
      $md5 = _icl_wrapper_db_result( _icl_wrapper_db_query( "SELECT md5 FROM {icl_content_status} WHERE rid = %d", $rid));
      break;
    
      case 'block':
      $md5 = _icl_wrapper_db_result( _icl_wrapper_db_query( "SELECT md5 FROM {icl_block_status} WHERE rid = %d", $rid));
      break;

    case 'contact_form':
    case 'contact form':
      $md5s = variable_get('icl_contact_form_md5s', array());
      $md5 = $md5s[$rid];
      break;
  }
  
  return $md5;
  
}

function _icl_content_get_langs_needing_update($languages, $previous_rids, $type, $current_md5, $translators){
  $site_languages = language_list('language', TRUE);

  $targets = array ();
  foreach ( $languages as $code ) {
    if ($code) {
      if(isset($previous_rids[$code])){
        $previous_rid = $previous_rids[$code];
        $previous_md5 = _icl_content_get_md5_for_rid($type, $previous_rid);
      } else {
        $previous_rid = FALSE;
        $previous_md5 = '';
      }
      if ($previous_md5 != $current_md5) {
        $targets [] = $site_languages[$code];
      } else {
        // The node hasn't changed since the last transaltion
        // Check to see if we haven't translated this language
        if (_icl_wrapper_db_result(_icl_wrapper_db_query("SELECT status FROM {icl_core_status} WHERE rid = %d AND target = '%s'", $previous_rid, $code)) === FALSE) {
          $targets [] = $site_languages[$code];
        }
        
      }
    }
  }
  
  return $targets;
}

function _icl_group_targets_by_rid($id, $type, $source_lang, $targets, &$previous_rids){
  
  foreach($targets as $lang_target){
    if (isset($previous_rids[$lang_target->language])) {
      $previous_rid = $previous_rids[$lang_target->language];
    } else {
      $previous_rid = NULL;
    }
    $languages = icl_get_all_languages_associated($id, $type, $source_lang, $previous_rid);
    foreach($languages as $lang) {
      if($lang != $lang_target->language) {
        if ($previous_rids[$lang] < $previous_rid) {
          $previous_rids[$lang] = $previous_rid;
        }
      }
    }
  }
  
  $grouped_targets = array();
  foreach($targets as $lang_target){
    if (isset($previous_rids[$lang_target->language])) {
      $previous_rid = $previous_rids[$lang_target->language];
    } else {
      $previous_rid = NULL;
    }
    if ($previous_rid != null) {
      if(!isset($grouped_targets[$previous_rid])){
        $grouped_targets[$previous_rid] = array();
      }
      $grouped_targets[$previous_rid][] = $lang_target;
      
    } else {
      $grouped_targets[] = array($lang_target);
    }
  }
  
  return $grouped_targets;
}

function icl_content_show_translated_comments($node) {
  if (variable_get ('icl_content_comment_view', 1)) {
    if ($node->nid != $node->tnid && $node->tnid != 0) {
      // A translated page
      
      global $user;
      
      if ($user->uid) {
        
        if (user_access(ICL_CONTENT_PERM_COMMENT)) {
          $table_name = _icl_wrapper_table_name('comments');

          if ($node->comment_count > 0 || _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT COUNT(*) FROM {" . $table_name . "} WHERE nid = %d", $node->nid)) > 0) {
      
            $js = drupal_get_js();
            if (strpos($js, 'icl_comments.js') === FALSE) {
            
              $source_lang = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM {node} WHERE tnid = %d and nid = %d', $node->tnid, $node->tnid));
            
              _icl_wrapper_drupal_set_html_head('<script type="text/javascript" src="http://www.google.com/jsapi"></script>');
              drupal_add_js('google.load("language", "1");', 'inline');
        
              $languages = language_list();
        
              $js_lang = 'var languages = [ { code:"' . $source_lang . '",name:"' . $languages[$source_lang]->native . '"}, {code:"' . $node->language . '",name:"' . $languages[$node->language]->native . '"}];';
              
              drupal_add_js($js_lang, 'inline');
              
              $js_source_lang = 'var source_language_message = "<div class=\'icanlocalize_comment_note\'>' . t ('This comment was auto translated from !language. See !note_link.', array(
                                                                                                                                                                                          "!language" => $languages[$node->language]->native,
                                                                                                                                                                                          "!note_link" => ICL_COMMENT_NOTE)) . '</div>"';
              
              drupal_add_js($js_source_lang, 'inline');
              
              $js_failed_message = 'var failed_translation_message = "<div class=\'status\'>' . t ('Google AJAX Language translation failed') .  '</div>"';
              
              drupal_add_js($js_failed_message, 'inline');
              
              drupal_add_js(drupal_get_path('module', 'icl_content') . '/js/icl_comments.js');
            }
          }
        }
      }
    }
  }
}


/**
 * fix any images paths in the body of the node for translated content
 * also fix paths to js, css and embedded objects.
 *
 */

function _icl_content_fix_image_paths(&$node) {
  // see if this is a translation
  if(isset($node->nid) && isset($node->tnid) && $node->tnid != 0) {
  
    if($node->nid != $node->tnid) {
      // this is a translation.
    
      $source_lang = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM {node} WHERE tnid = %d and nid = %d', $node->tnid, $node->tnid));
      
      $source_path = "node/" . $node->tnid;
      $source_path = drupal_get_path_alias($source_path);
    
      $node->body = _icl_content_fix_image_paths_in_body($node->body, $source_lang, $node->language, $source_path);

      if (isset($node->teaser) && $node->teaser != "") {
        $node->teaser = node_teaser($node->body);
      }

    }
    
    return FALSE;
  }
}

function _icl_content_fix_image_paths_in_body($body, $source_lang, $target_lang, $source_path) {
  $image_paths = _icl_content_get_image_paths($body);
  
  foreach($image_paths as $path) {
    
    $src_path = resolve_url($source_path, $path[2]);
    if ($src_path != $path[2]) {
      $search = $path[1] . $path[2] . $path[1];
      $replace = $path[1] . $src_path . $path[1];
      $new_link = str_replace($search, $replace, $path[0]);
      
      $body = str_replace($path[0], $new_link, $body);
      
      
    }
    
  }
  return $body;
}



/**
 * fix any relative paths in the body of the node for translated content
 *
 */

function _icl_content_fix_relative_link_paths(&$node) {
  // see if this is a translation
  if(isset($node->nid) && isset($node->tnid) && $node->tnid != 0) {
  
    if($node->nid != $node->tnid) {
      // this is a translation.
    
      $source_lang = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM {node} WHERE tnid = %d and nid = %d', $node->tnid, $node->tnid));
      
      $source_path = "node/" . $node->tnid;
      $source_path = drupal_get_path_alias($source_path);
    
      $node->body = _icl_content_fix_relative_link_paths_in_body($node->body, $source_lang, $node->language, $source_path);

      if (isset($node->teaser) && $node->teaser != "") {
        $node->teaser = node_teaser($node->body);
      }

    }
    
    return FALSE;
  }
}

function _icl_content_fix_relative_link_paths_in_body($body, $source_lang, $target_lang, $source_path) {
  $link_paths = _icl_content_get_link_paths($body);
  
  foreach($link_paths as $path) {
    
    $src_path = resolve_url($source_path, $path[2]);
    if ($src_path != $path[2]) {
      $search = $path[1] . $path[2] . $path[1];
      $replace = $path[1] . $src_path . $path[1];
      $new_link = str_replace($search, $replace, $path[0]);
      
      $body = str_replace($path[0], $new_link, $body);
      
      
    }
    
  }
  return $body;
}

/**
 * get the paths to images in the body of the content
 */

function _icl_content_get_link_paths($body) {
  
  $regexp_links = array(
                      "/<a\shref\s*=\s*([\"\']??)([^\"]*)[\"']>(.*)<\/a>/siU",
                      );

  $links = array();
  
  foreach($regexp_links as $regexp) {
    if (preg_match_all($regexp, $body, $matches, PREG_SET_ORDER)) {
      foreach ($matches as $match) {
        $links[] = $match;
      }
    }
  }
  
  return $links;
}

function icl_content_fix_links_in_all_dirty_nodes() {
  $query = _icl_wrapper_db_query("SELECT nid FROM {icl_node} WHERE links_fixed = 0 OR links_fixed is NULL");

  $nid = _icl_wrapper_db_result( $query );
  
  while ( $nid !== null && $nid !== FALSE) {
    $node = node_load($nid, NULL, TRUE); // make sure it's not loaded from the cache otherwise the domain access setting can be lost.
    if ($node == FALSE) {
      _icl_wrapper_db_query("UPDATE {icl_node} SET links_fixed = 1 WHERE nid = %s", $nid);
    } else {
      if($node->nid == $node->tnid || $node->tnid == 0) {
        // this is the original source
        _icl_wrapper_db_query("UPDATE {icl_node} SET links_fixed = 1 WHERE nid = %s", $nid);
      } else {
        // A translation, fix the links and save the node
        _icl_content_fix_links($node);
        $node->icanlocalize_link_fix = TRUE;
        
        $node->pathauto_perform_alias = FALSE;
        
        node_save($node);
      }      
    }
    
    
    $nid = _icl_wrapper_db_result( $query );
  }
}

/**
 * NOTE: This is a duplicate of the function in translation module
 * NOTE: The db_rewrite_sql has been removed to stop the domain access module
 * NOTE: filtering the results. This is required as the xmlrpc might not be
 * NOTE: the same domain as the original node.
 *
 * Get all nodes in a translation set, represented by $tnid.
 *
 * @param $tnid
 *   The translation source nid of the translation set, the identifier
 *   of the node used to derive all translations in the set.
 * @return
 *   Array of partial node objects (nid, title, language) representing
 *   all nodes in the translation set, in effect all translations
 *   of node $tnid, including node $tnid itself. Because these are
 *   partial nodes, you need to node_load() the full node, if you
 *   need more properties. The array is indexed by language code.
 */
function icl_content_translation_node_get_translations($tnid) {
  static $translations = array();

  if (is_numeric($tnid) && $tnid) {
    if (!isset($translations[$tnid])) {
      $translations[$tnid] = array();
      $result = _icl_wrapper_db_query('SELECT n.nid, n.title, n.language FROM {node} n WHERE n.tnid = %d', $tnid);
      while ($node = db_fetch_object($result)) {
        $translations[$tnid][$node->language] = $node;
      }
    }
    return $translations[$tnid];
  }
}


function _icl_content_fix_links_in_text($text, $source_lang, $language, &$all_links_fixed) {

  $referenced_nodes = _icl_content_get_local_links($text, $source_lang);
  
  // do any of these referenced nodes have translations.
  
  $all_links_fixed = TRUE;
  
  foreach ($referenced_nodes as $ref_node) {
    $translations = icl_content_translation_node_get_translations($ref_node["node"]);
    if ($translations != null) {
      if (array_key_exists($language, $translations)) {
        $translated_nid = $translations[$language]->nid;
        $search = "href=" . $ref_node["match"][1] . $ref_node["match"][2] . $ref_node["match"][1];
        $replace = "href=\"/" . $language . "/node/" . $translated_nid . "\"";
        $new_link = str_replace($search, $replace, $ref_node["match"][0]);
        
        $text = str_replace($ref_node["match"][0], $new_link, $text);
      } else {
        $all_links_fixed = FALSE;
      }
    }
  }

  if (is_string($text)) {
    if (module_exists('contact')) {
      // check links to contact page.
      
      $regexp_links = "/<a\shref\s*=\s*([\"\']??)([^\"]*)[\"']>(.*)<\/a>/siU";
    
      if (preg_match_all($regexp_links, $text, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
          if ($match[2] == '/contact') {
            $new_link = str_replace($match[2], '/' . $language . $match[2], $match[0]);
            $text = str_replace($match[0], $new_link, $text);
            
          }
        }
      }
    }  
  }
  
  return $text;
}

/**
 * fix any links in the body of the node for translated content
 *
 */

function _icl_content_fix_links(&$node) {
  // see if this is a translation
  if(isset($node->nid) && isset($node->tnid) && $node->tnid != 0) {
  
    if($node->nid != $node->tnid) {
      // this is a translation.
    
      // we need to fixup any links to translated pages.

      $source_lang = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM {node} WHERE tnid = %d and nid = %d', $node->tnid, $node->tnid));
    
      $all_links_fixed = FALSE;
      
      $node->body = _icl_content_fix_links_in_text($node->body, $source_lang, $node->language, $all_links_fixed);

      if (isset($node->teaser) && $node->teaser != "") {
        $node->teaser = node_teaser($node->body);
      }

      if (module_exists('content')) {
        $type = content_types($node->type);
        if (isset($type['fields'])) {
          foreach ($type['fields'] as $field) {
            $field_name = $field['field_name'];
            $cck_data = $node->$field_name;
            
            if (!empty($cck_data)) {
              foreach ($cck_data as $index => $data) {
                
                if (isset($data['value'])) {
                  $cck_links_fixed = FALSE;
                  $data['value'] = _icl_content_fix_links_in_text($data['value'], $source_lang, $node->language, $cck_links_fixed);
                  $cck_data[$index] = $data;
                  
                  $all_links_fixed = $all_links_fixed && $cck_links_fixed;
                }
                
              }
              $node->$field_name = $cck_data;
            }
          }
        }
      }

      if ($all_links_fixed) {
        _icl_wrapper_db_query("UPDATE {icl_node} SET links_fixed = 1 WHERE nid = %s", $node->nid);
      } else {
        _icl_wrapper_db_query("UPDATE {icl_node} SET links_fixed = 0 WHERE nid = %s", $node->nid);
      }
    }
    
    return FALSE;
  }
}

/**
 * get the links in the body of the content
 */

function _icl_content_get_local_links($body, $language) {
  
  global $base_url;
  global $base_path;
  global $base_root;
  
  //$regexp_links = "/<a\shref\s*=\s*([\"\']??)([^\"]*)[\"']>(.*)<\/a>/siU";
  $regexp_links = "/<\s*a\s+[^>]*href\s*=\s*([\"']?)([^\"' >]+)[\"' >]/siU";

  $links = array();
  
  if (is_string($body)) {
    if (preg_match_all($regexp_links, $body, $matches, PREG_SET_ORDER)) {
      foreach ($matches as $match) {
        $link = $match[2];
  
        if (stripos($link, $base_root) == 0) {
          // remove the base path
          $link = substr($link, strlen($base_root));
        }
        if ($link[0] == "/") {
          $normal_path = drupal_get_normal_path(substr($link, 1), $language);
          if ($normal_path != substr($link, 1)) {
            $link = "/" . $normal_path;
          }
        } else {
          $link = drupal_get_normal_path($link);
        }  
        $link = resolve_url($base_root . "/node/", $link);
          
        
        if (stripos($link, $base_root . "/node/") === 0) {
          $node = substr($link, strlen($base_root . "/node/"));
          $links[] = array(
                          "node" => $node,
                          "match" => $match
                          );
        }
      }
    }
  }
  
  return $links;
}

/**
 * Resolve a URL relative to a base path. This happens to work with POSIX
 * filenames as well. This is based on RFC 2396 section 5.2.
 */
function resolve_url($base, $url) {
        if (!strlen($base)) return $url;
        // Step 2
        if (!strlen($url)) return $base;
        // Step 3
        if (preg_match('!^[a-z]+:!i', $url)) return $url;
        $base = parse_url($base);
        if ($url{0} == "#") {
                // Step 2 (fragment)
                $base['fragment'] = substr($url, 1);
                return unparse_url($base);
        }
        unset($base['fragment']);
        unset($base['query']);
        if (substr($url, 0, 2) == "//") {
                // Step 4
                return unparse_url(array(
                        'scheme'=>$base['scheme'],
                        'path'=>$url,
                ));
        } else if ($url{0} == "/") {
                // Step 5
                $base['path'] = $url;
        } else {
                // Step 6
                $path = explode('/', $base['path']);
                $url_path = explode('/', $url);
                // Step 6a: drop file from base
                array_pop($path);
                // Step 6b, 6c, 6e: append url while removing "." and ".." from
                // the directory portion
                $end = array_pop($url_path);
                foreach ($url_path as $segment) {
                        if ($segment == '.') {
                                // skip
                        } else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') {
                                array_pop($path);
                        } else {
                                $path[] = $segment;
                        }
                }
                // Step 6d, 6f: remove "." and ".." from file portion
                if ($end == '.') {
                        $path[] = '';
                } else if ($end == '..' && $path && $path[sizeof($path)-1] != '..') {
                        $path[sizeof($path)-1] = '';
                } else {
                        $path[] = $end;
                }
                // Step 6h
                $base['path'] = join('/', $path);

        }
        // Step 7
        return unparse_url($base);
}

function unparse_url($parsed)
    {
    if (! is_array($parsed)) return false;
    $uri = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '':'//'): '';
    $uri .= isset($parsed['user']) ? $parsed['user'].($parsed['pass']? ':'.$parsed['pass']:'').'@':'';
    $uri .= isset($parsed['host']) ? $parsed['host'] : '';
    $uri .= isset($parsed['port']) ? ':'.$parsed['port'] : '';
    if(isset($parsed['path']))
        {
        $uri .= (substr($parsed['path'],0,1) == '/')?$parsed['path']:'/'.$parsed['path'];
        }
    $uri .= isset($parsed['query']) ? '?'.$parsed['query'] : '';
    $uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
    return $uri;
    }
    
/**
 * Implementation of hook_form_alter().
 * @see http://api.drupal.org/api/function/hook_form_alter/6
 *
 * @param array $form
 * @param array $form_state
 * @param string $form_id
 */
function icl_content_form_alter(&$form, $form_state, $form_id) {
  
  static $level = array();
  if (isset($level[$form_id]) && $level[$form_id] > 0) {
    // stop altering any additional forms
    // This happens for the node-type form because we
    // call the node-add form to get the data types.
    return;
  }
  if (!isset($level[$form_id])) {
    $level[$form_id] = 0;
  }
  $level[$form_id] += 1;
  
  if (user_access(ICL_CONTENT_PERM_TRANSLATE)) {
  
    //$send_setting = variable_get ( 'icl_content_send_options', ICL_CONTENT_SEND_MANUAL );
    
    if ($form ['#id'] == 'node-form' && isset ( $form ['#node']->type ) && translation_supported_type ( $form ['#node']->type )) {
      icl_content_alter_node_add_form ( $form, $form_state );
    } else if ($form_id == 'node_type_form') {
      icl_content_alter_node_type_form ( $form, $form_state );
    } else if ($form_id == 'comment_form' && user_access(ICL_CONTENT_PERM_COMMENT)) {
      //icl_content_alter_comment_form ( $form, $form_state );
    } else if ($form_id == 'menu_overview_form') {
      module_load_include ( 'inc', 'icl_content', 'icl_content.menus' );
      icl_content_menu_overview_form_alter ( $form, $form_state );
    }
  }
  
  if ($form_id == 'contact_mail_page') {
    icl_content_alter_standard_contact_form($form, $form_state );
  }
  
  if ($form_id == 'locale_translate_seek_form') {
    icl_content_alter_locale_translate_seek_form($form, $form_state);
  }
  
}

/**
 * Implementation of hook_theme().
 * @see http://api.drupal.org/api/function/hook_theme/6
 *
 * @return array
 */
  function icl_content_theme() {
    return  _icl_wrapper_hook_theme(array (
      'icl_content_fancy_status' => array (
          'arguments' => array (
              'node' => NULL ),
              'short' => FALSE), 
      'icl_content_translated_status' => array (
          'arguments' => array (
              'node' => NULL ) ), 
      'icl_content_admin_nodes' => array (
          'arguments' => array (
              'form' => NULL ) ),
      'icl_content_dashboard_translation_selection' => array (
          'arguments' => array (
              'form' => NULL ) ),
      'icl_content_queued_strings' => array (
          'arguments' => array (
              'form' => NULL ) ),
      'icl_content_images' => array (
          'arguments' => array (
              'form' => NULL ) ),
    'icl_content_links' => array (
          'arguments' => array (
              'form' => NULL ) ),
      'icl_content_dashboard_nodes' => array(
          'arguments' => array(
              'form' => NULL )
      ) ));
  }

/**
 * find the translated term if by name and langauge
 * returns the last match.
 */

function _icl_content_find_translated_term_tid($name, $language) {
  // check ones with a translation first.
  $table_name = _icl_wrapper_table_name('term_data');
  $db_result = _icl_wrapper_db_query("SELECT t.tid, t.* FROM {" . $table_name . "} t WHERE LOWER(t.name) = LOWER('%s') AND t.language = '%s' AND t.trid <> 0", trim($name), $language);
  $result = array();
  while ($term = db_fetch_object($db_result)) {
    $result[] = $term;
  }

  if (count($result) == 0) {
    // no results that have a translation so try others.    
    $db_result = _icl_wrapper_db_query("SELECT t.tid, t.* FROM {" . $table_name . "} t WHERE LOWER(t.name) = LOWER('%s') AND t.language = '%s'", trim($name), $language);
    $result = array();
    while ($term = db_fetch_object($db_result)) {
      $result[] = $term;
    }
  }
  
  return end($result)->tid;
}

/**
 * find all the translated terms by name and langauge
 * returns the last match.
 */

function _icl_content_find_all_translated_term_tids($name, $language) {
  $table_name = _icl_wrapper_table_name('term_data');
  $db_result = _icl_wrapper_db_query("SELECT t.tid, t.* FROM {" . $table_name . "} t WHERE LOWER(t.name) = LOWER('%s') AND t.language = '%s'", trim($name), $language);
  $result = array();
  while ($term = db_fetch_object($db_result)) {
    $result[] = $term->tid;
  }

  return $result;
}

/**
 * make sure that the translation terms for the node are in the langauge of the node.
 */

function _icl_content_ensure_all_taxonomy_is_in_node_language( $node, $data ) {
  
  $changed = false;
  
  foreach ( $node->taxonomy as $taxonomy ) {
    if ( $taxonomy->language != $node->language) {
      
      // only set the language if we are translating it and
      // the vocabulary is set to "Per language terms"
      $taxonomy_found = false;
      foreach ( $data as $item ) {
        $format = isset ( $item ['format'] ) ? $item ['format'] : 'plain';
        $type = $item ['type'];
        switch ($format) {
          case 'csv' :
            if (substr ( $type, 0, strlen ( 'taxonomy' ) ) == 'taxonomy') {
              $matches = array ();
              preg_match ( '/taxonomy\[(\d+)\]/i', $type, $matches );
              $vid = $matches [1];
              if ($vid == $taxonomy->vid) {
                if (i18ntaxonomy_vocabulary ( $vid ) == I18N_TAXONOMY_TRANSLATE) { // Per language terms
                  if (in_array($taxonomy->name, $item['original_data'])) {
                    $taxonomy_found = true;
                  }
                }
              }
            }
            break;
        }
      }
      
      if ($taxonomy_found) {
        $table_name = _icl_wrapper_table_name('term_data');
        _icl_wrapper_db_query("UPDATE {" . $table_name . "} SET language = '%s' WHERE tid = %s AND vid = %s", $node->language, $taxonomy->tid, $taxonomy->vid );
        $changed = true;
      }
    }
  }
  if ($changed) {
    return node_load( $node->nid );
  } else {
    return $node;
  }
}

/**
 * get all the translation term ids for the given term_id
 * return an array of term ids index by language.
 */

function _icl_content_get_translations_for_term( $tid ) {
  
  $i18n_languages = i18n_supported_languages();

  $translated_term_tids = array();
  foreach ($i18n_languages as $lang => $lang_name) {                        
    $translated_term_tid = i18ntaxonomy_translation_term_tid( $tid , $lang );
    if ($translated_term_tid != null) {
      $translated_term_tids[$lang] = $translated_term_tid;
    }
  }

  // add the original term
  $term = _icl_wrapper_taxonomy_get_term( $tid );
  
  $translated_term_tids[$term->language] = $tid;
  return $translated_term_tids;

}

/**
 * save the translation set
 * tids is an array of term ids that are ids of the original and translations
 * trid is the id of the translation set
 */
 
function _icl_content_save_translation_term_set( $tids, $trid ) {
  $save_terms = array();
  
  foreach ( $tids as $tid ) {
    $term = _icl_wrapper_taxonomy_get_term( $tid );
    
    $save_terms[$term->language] = $term;
  }
    
  i18ntaxonomy_translation_save( $save_terms, $trid);
  
  
}

function icl_content_sync_blocks() {
  $table_name = _icl_wrapper_table_name('blocks');
  $query = _icl_wrapper_db_query("SELECT * FROM {" . $table_name . "} WHERE module='block' and pages <> '' ");
  while ( $block = db_fetch_array ( $query ) ) {
    
    $bid = $block['bid'];
    
    $pages = explode("\r\n", $block['pages']);
    
    $translated_pages = array();
    
    foreach($pages as $page) {
      if (strpos($page, 'node/') === 0) {
        $nid = substr($page, 5);
        
        $translations = icl_content_translation_node_get_translations($nid);
        
        foreach($translations as $translation) {
          $translation = "node/" . $translation->nid;
          
          if (!in_array($translation, $pages)) {
            $translated_pages[] = $translation;
          }
        }
        
      }
    }
    
    foreach ($translated_pages as $translation) {
      if (!in_array($translation, $pages)) {
        $pages[] = $translation;
      }
      
    }
    $new_pages = implode("\r\n", $pages);
    
    if ($pages != $new_pages) {
      $table_name = _icl_wrapper_table_name('blocks');
      _icl_wrapper_db_query("UPDATE {" . $table_name . "} SET pages = '%s' WHERE bid = %d", $new_pages, $bid);
      
    }

  }
  
}

function icl_content_update_links_in_blocks() {

  $languages = language_list('enabled');
  $languages = $languages[1];

  $query = _icl_wrapper_db_query("SELECT bid FROM {icl_block} WHERE links_fixed <> 1");

  while ( $bid = db_fetch_object ( $query ) ) {
    $bid = $bid->bid;
    $table_name = _icl_wrapper_table_name('blocks');
    $block_title_original = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT title FROM {" . $table_name . "} WHERE delta = %d", $bid));
    $block_original = _icl_wrapper_block_box_get($bid);

    $all_languages_fixed = TRUE;
    if ($block_original['body'] != "") {
      $lid = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT lid FROM {locales_source} WHERE source = '%s' and textgroup = 'blocks'", $block_original['body']));

      foreach($languages as $code => $language) {
        $translation = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $code));
        if (!empty($translation)) {
          $all_links_fixed = FALSE;
          $fixed_translation = _icl_content_fix_links_in_text($translation, "en", $code, $all_links_fixed);
          if ($fixed_translation != $translation) {
            _icl_wrapper_db_query("UPDATE {locales_target} SET translation = '%s' WHERE lid = %d AND language = '%s'", $fixed_translation, $lid, $code);
            
            cache_clear_all('locale:', 'cache', TRUE);
            
          }
          if(!$all_links_fixed) {
            $all_languages_fixed = FALSE;
          }
        }
      }
    }    
    if($all_languages_fixed) {
      _icl_wrapper_db_query("UPDATE {icl_block} SET links_fixed = 1 WHERE bid = %d", $bid);
    }
  }
  
}

function icl_content_update_locale_translation($lid, $language, $value) {
  $translation = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $language));
  if (!empty($translation)) {
    _icl_wrapper_db_query("UPDATE {locales_target} SET translation = '%s' WHERE lid = %d AND language = '%s'", $value, $lid, $language);
  }
  else {
    _icl_wrapper_db_query("INSERT INTO {locales_target} (lid, translation, language) VALUES (%d, '%s', '%s')", $lid, $value, $language);
  }
}

/**
 * Implementation of hook_icanlocalize().
 *
 * @param string $op
 * @param mixed $data
 */
function icl_content_icanlocalize($op, $content, $request_id = 0) {
  global $user;
  
  $original_parent_fields = array();
  
  switch ($op) {
    case 'translation' :
      
      foreach ( $content as $code => $data ) {
        $nid = null;
        $vid = null;
        $bid = null;  // block id
        $sid = null; // Strings group id
        foreach ( $data as $key => $item ) {
          if ($item ['type'] == 'nid') {
            $nid = $item ['data'];
            unset ( $data [$key] );
          }
          if ($item ['type'] == 'vid') {
            $vid = $item ['data'];
            unset ( $data [$key] );
          }
          if ($item ['type'] == 'bid') {
            $bid = $item ['data'];
            unset ( $data [$key] );
          }
          if ($item['type'] == 'sid') {
            return icl_content_string_translation($content, $request_id);
          }
        }
        if ($nid == null || $vid == null) {
          if($bid != null) {
            
            if (!icl_content_save_block_translation($bid, $code, $data)) {
              return FALSE;
            }
            continue;
          } else {
            if (!icl_content_save_contact_form_translation($bid, $code, $data)) {
              watchdog ( 'icl_content', 'No nid or vid in the returned translation: @data', array (
                  '@data' => var_export ( $data, TRUE ) ), WATCHDOG_ERROR );
              return FALSE;
            }
            continue;
          }
        }
  
        if ($bid == null) {        
          $translation = node_load ( array (
              'tnid' => $nid, 
              'language' => $code ), $vid );
          if ($translation) {
            // It is an update
            $node = node_load ( $translation->nid );
            if (! is_object ( $node )) {
              watchdog ( 'icl_content', 'Nonexistent translation node with nid %nid', array (
                  '%nid' => $translation->nid ), WATCHDOG_ERROR );
              return FALSE;
            }
          } else {
            // It is a new translation or the translator has updated a new version.

            $tnid = db_fetch_array(_icl_wrapper_db_query("SELECT tnid FROM {node} where nid=" . $nid));            
            $translations = icl_content_translation_node_get_translations($tnid['tnid']);
            if ( isset($translations[$code]) )  {
              $node = node_load ( $translations[$code]->nid );
              
            }
            else {
              
              $original = node_load ( $nid, $vid );
              if (! is_object ( $original )) {
                watchdog ( 'icl_content', 'Nonexistent originating node with nid %nid', array (
                    '%nid' => $nid ), WATCHDOG_ERROR );
                return FALSE;
              }
              $node = drupal_clone ( $original );
              
              // set the tnid if required.
              if(!isset($original->tnid) || $original->tnid == 0){
                $original->tnid = $original->nid;
                _icl_wrapper_db_query("UPDATE {node} SET tnid = %d WHERE nid = %d", $original->tnid, $original->nid);
              }
              
              $node->tnid = $original->tnid;

              unset ( $original );
              unset ( $node->nid );
              unset ( $node->vid );
              $node->language = $code;
              
              // remove any work flow settings. We don't want to copy those
              if (isset($node->workflow)) {
                unset($node->workflow);
              }

              if ($node->type == "book" and isset($node->book)) {  // $node->book wont be set if this page is not part of a book.
                
                $books_to_update = variable_get('icl_content_books_to_update', array());
                $books_to_update[$node->book['bid']] = TRUE;
                variable_set('icl_content_books_to_update', $books_to_update);
                if ($node->book['bid'] == $nid) {
                  // this is the root of the book so create a new book for the translation.
                  $node->book['bid'] = "new";
                } else {
                  // this is a child page.
                  // find the book id for the translation by checking for translations of this bid node.
                  $book_translations = icl_content_translation_node_get_translations($node->book['bid']);
                  if (isset($book_translations[$code])) {
                    $node->book['bid'] = $book_translations[$code]->nid;
                  } else {
                    watchdog ( 'icl_content', 'book root not translated yet, bid %bid', array (
                        '%bid' => $node->book['bid'] ), WATCHDOG_ERROR );
                    return FALSE;
                  }
                  // now set the parent page.
                  $book_plid = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT nid FROM {book} where mlid = %d", $node->book['plid']));
                  $book_translations = icl_content_translation_node_get_translations($book_plid);
                  if (isset($book_translations[$code])) {
                    $book_plid = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT mlid FROM {book} where nid = %d", $book_translations[$code]->nid));
                    $node->book['plid'] = $book_plid;
                  } else {
                    watchdog ( 'icl_content', 'book root not translated yet, bid %bid', array (
                        '%bid' => $node->book['bid'] ), WATCHDOG_ERROR );
                    return FALSE;
                  }
                  
                  
                }
              }
            }
          }
          
          // Clear the existing teaser.
          $node->teaser = "";
          
          // Clear the existing taxonomy.
          $node->taxonomy = array();
  
          $original = node_load ( $nid );
          $original = _icl_content_ensure_all_taxonomy_is_in_node_language( $original, $data );
          
          $existing_taxonomy = $original->taxonomy;
          
          if (count($existing_taxonomy) > 0) {
          
            // See if we have any taxonomy in the $data. If not we need to add
            // a dummy term so that any previously translated taxonomy gets used.
            
            $taxonomy_found = false;
            foreach ( $data as $item ) {
              $format = isset ( $item ['format'] ) ? $item ['format'] : 'plain';
              $type = $item ['type'];
              switch ($format) {
                case 'csv' :
                  if (substr ( $type, 0, strlen ( 'taxonomy' ) ) == 'taxonomy') {
                    $taxonomy_found = true;
                  }
                  break;
              }
            }
            
            if ( ! $taxonomy_found ) {
              $keys = array_keys($existing_taxonomy);
              $dummy_taxonomy = array (
                'format' => 'csv',
                'type' => 'taxonomy[' . $existing_taxonomy[$keys[0]]->vid. ']',
                'data' => array(),
                'original_data' => array()
                );
              $data[] = $dummy_taxonomy;
            }
            
          }        

          $translated_url_alias = "";
          
          $taxonomy_translated = array();
          
          foreach ( $data as $item ) {
            $format = (isset ( $item ['format'] )  && $item ['format'] != "" ) ? $item ['format'] : 'plain';
            $type = $item ['type'];
            switch ($format) {
              case 'plain' :
                $text = $item ['data'];
                if ($type == 'link_title') {
                  // A menu
                  // see if we already have a menu
                  
                  $existing_mlid = _icl_wrapper_db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE link_path = 'node/%d' AND module = 'menu' ORDER BY mlid ASC", $node->nid, 0, 1));
                  
                  // Find the menu for the original node
                  
                  $mlid = _icl_wrapper_db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE link_path = 'node/%d' AND module = 'menu' ORDER BY mlid ASC", $nid, 0, 1));
                  if ($mlid) {
                    $item = menu_link_load($mlid);
                  
                    // copy the settings but change the text and set language to the translation language.
                    $menu = array('link_title' => $text, 'mlid' => 0, 'plid' => 0, 'menu_name' => $item['menu_name'], 'weight' => $item['weight'], 'options' => $item['options'], 'module' => 'menu', 'expanded' => $item['expanded'], 'hidden' => $item['hidden'], 'has_children' => 0, 'customized' => $item['customized'], 'localized_options' => $item['localized_options']);
                    $menu['localized_options']['langcode'] = $node->language;
                    
                    // do we have a link description in the data.
                    foreach ($data as $test) {
                      if ($test['type'] == 'link_description') {
                        $menu['options']['attributes']['title'] = $test['data'];
                      }
                    }
                    
                    $menu['plid'] = icl_content_get_translated_menu($item['plid'], $node->language);
                    
                    if ($existing_mlid){
                      $menu['mlid'] = $existing_mlid;
                    }
                    
                    if (variable_get ( 'icl_content_menu_options', ICL_CONTENT_MENU_ORIGINAL ) == ICL_CONTENT_MENU_SEPARATE) {
                      // Using a separate menu for translations.
                      $variables = variable_get('i18n_variables', array());
                      
                      $i18n_v_orig = _i18n_variable_init($original->language);
                      $i18n_v_target = _i18n_variable_init($code);
                      foreach ($variables as $v_name) {
                        if ($i18n_v_orig[$v_name] == $menu['menu_name']) {
                          if (isset($i18n_v_target[$v_name])) {
                            // Set the menu name to the menu used for the target language
                            $menu['menu_name'] = $i18n_v_target[$v_name];
                          } else {
                            // No target menu, so we need to create one.
                            $menu['menu_name'] .= '-' . $code;

                            $new_menu = array();
                            $new_menu['menu_name'] = $menu['menu_name'];

                            // remove "menu-" from the front of the menu name
                            // it will be added when we create the new menu.
                            if (strpos($new_menu['menu_name'], 'menu-') === 0) {
                              $new_menu['menu_name'] = substr($new_menu['menu_name'], 5);
                            }

                            $new_menu['title'] = $new_menu['menu_name'];
                            $new_menu['description'] = '';
                            
                            module_load_include ( 'inc', 'menu', 'menu.admin' );
                            $form = array();
                            $form['#insert'] = TRUE;
                            
                            $form_state = array();
                            $form_state['values'] = $new_menu;
                            
                            menu_edit_menu_submit($form, $form_state);
                            
                            i18n_variable_set($v_name, $menu['menu_name'], $code);
                          }
                          
                          // record that we need to sync these menus.
                          $icl_menus_to_sync = variable_get('icl_menus_to_sync', array());
                          $icl_menus_to_sync[$original->language . $code] = array($i18n_v_orig[$v_name],
                                                       $menu['menu_name'],
                                                       $original->language,
                                                       $code);
                          variable_set('icl_menus_to_sync', $icl_menus_to_sync);
                                                       
                        }
                      }
                      
                    }
                    $node->menu = $menu;
                  }
                } else if ( $type == 'url_alias' ) {
                  $translated_url_alias = $text;
                } else if (preg_match('/^nodewords-(.*?)- \(SEO\)/', $type, $matches)) {
                  if (!isset($node->nodewords)) {
                    $node->nodewords = $original->nodewords;
                  }
                  if (isset($node->nodewords)) {
                    $node->nodewords[$matches[1]] = array('value' => $text);
                  }
                } else {
                  $node->$type = $text;
                }
                break;
              case 'csv' :
                if (substr ( $type, 0, strlen ( 'taxonomy' ) ) == 'taxonomy' && module_exists ( 'i18ntaxonomy' )) {
                  $matches = array ();
                  preg_match ( '/taxonomy\[(\d+)\]/i', $type, $matches );
                  $vid = $matches [1];
                  $terms = $item ['data'];
                  $original_terms = $item ['original_data'];
                  
                  switch (i18ntaxonomy_vocabulary ( $vid )) {
                    case I18N_TAXONOMY_NONE :
                      // None -  Do nothing except let the cloned taxonomies in place                                        
                      break;
                    case I18N_TAXONOMY_LOCALIZE :
                      // Localize terms
                      $table_name = _icl_wrapper_table_name('term_data');
                      foreach ( $original_terms as $index => $name ) {
                        $term = _icl_wrapper_fetch_term($table_name, trim ( $name ), $vid );
                        $context = 'taxonomy:term:' . $term->tid . ':name';
                        if (is_object ( $term )) {
                          if (! is_string ( i18nstrings_get_string ( 'taxonomy:term:' . $term->tid . ':name', $node->language ) )) {
                            i18nstrings_add_string($context, $name);
                          }

                          if ($source = i18nstrings_get_source($context, $terms[$index])) {
                            $langcode = $node->language;
                            $exists = (bool) _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT lid FROM {locales_target} WHERE lid = %d AND language = '%s'", $source->lid, $langcode));
                            if (!$exists) {
                              // No translation in this language.
                              _icl_wrapper_db_query("INSERT INTO {locales_target} (lid, language, translation) VALUES (%d, '%s', '%s')", $source->lid, $langcode, $terms[$index]);
                            }
                            else {
                              // Translation exists, overwrite
                              _icl_wrapper_db_query("UPDATE {locales_target} SET translation = '%s' WHERE language = '%s' AND lid = %d", $terms[$index], $langcode, $source->lid);
                            }
                          }
                        }
                        
                      }
                      break;
                    case I18N_TAXONOMY_LANGUAGE :
                      // Set language to vocabulary - not supported
                      // In order to support this configuration we need some kind of mapping between same vocabs with different language
                      break;
                    case I18N_TAXONOMY_TRANSLATE :
                      // Per language terms
                      
                      module_load_include ( 'inc', 'i18ntaxonomy', 'i18ntaxonomy.admin' );
  
                      foreach ( $existing_taxonomy as $tax_id => $term ) {
                        if ($term->vid == $vid) {
                          
                          $i = array_search($term->name, $original_terms);
                          
                          // get the translation set
                          $trid = $term->trid;
                          if ($trid == "0") {
                            // create a translation set
                            $create_terms = array(
                              $term->language => $term);
                            
                            i18ntaxonomy_translation_save( $create_terms);
                            
                            $term = _icl_wrapper_taxonomy_get_term( $term->tid );
                            $trid = $term->trid;
                          
                            
                          }
                          
                          $translated_term_tids = _icl_content_get_translations_for_term($term->tid);
                          
                          // The original term may have a translation.
                          // see if it has one for our language
                          $translated_term_tid = $translated_term_tids[$node->language];
                          if ($translated_term_tid != null) {
                            // see if it is the same
                            
                            if ($i !== false) {
                              $translated_term = _icl_wrapper_taxonomy_get_term( $translated_term_tid );
                              
                              if ( $translated_term->name != $terms [$i] ) {
                                
                                // the term text is different.
                                
                                $form_values = array (
                                    'name' => $terms [$i], 
                                    'language' => $node->language, 
                                    'vid' => $translated_term->vid );
                                _icl_wrapper_taxonomy_save_term ( $form_values );
                                
                                $translated_term_tid = _icl_content_find_translated_term_tid($terms[$i], $node->language);
                                $translated_term_tids[$node->language] = $translated_term_tid;
                                _icl_content_save_translation_term_set($translated_term_tids, $trid);
                              }                            
                            }
                            
                            
                          }
                          else {
                            
                            if ($i !== false) {
                              
                              // we need to create a translated term.
                              $form_values = array (
                                  'name' => $terms [$i], 
                                  'language' => $node->language, 
                                  'vid' => $term->vid );
                              _icl_wrapper_taxonomy_save_term ( $form_values );
                              
                              $translated_term_tid = _icl_content_find_translated_term_tid($terms[$i], $node->language);
                              $translated_term_tids[$node->language] = $translated_term_tid;
                              _icl_content_save_translation_term_set($translated_term_tids, $trid);
                            }                          
                          }
                        
                          if ($translated_term_tid) {
                            $node->taxonomy [$translated_term_tid] = _icl_wrapper_taxonomy_get_term($translated_term_tid);
                            $taxonomy_translated[] = $tax_id;
                          }
  
                        }
                      }
                      break;
                  }
                }
                else if (substr ( $type, 0, strlen ( 'CCK' ) ) == 'CCK') {
                  $matches = array ();
                  preg_match ( '/^CCK\[(.+)\]$/i', $type, $matches );
                  $field = $matches[1];
                  if (strpos($field, '[') === FALSE) {
                    $i = 0;
                    $cck_fields = array();
                    $original_field = $original->$field;
                    if (!empty($item['data'])) {
                      foreach ($item['data'] as $element) {
                        $cck_fields [] = array(
                          'value' => $element,
                          'format' => $original_field[$i]['format'],
                        );
                        $node->$field = $cck_fields;
                        $i++;
                      }
                    }
                  } else {
                    // this is a flexifield.
                    $cck_fields = array();
                    $pos = strpos($field, '[');
                    $parent_field = substr($field, 0, $pos);
                    $sub_field = substr($field, $pos + 1, -1);
                    
                    if (isset($original_parent_fields[$parent_field])) {
                      $original_parent_field = $original_parent_fields[$parent_field];
                    } else {
                      $original_parent_field = $original->$parent_field;
                    }
                    foreach($original_parent_field as $f_index => $f_data) {
                      if (is_array($f_data['value'])) {
                        foreach($f_data['value'] as $f_key => $f_sub_data) {
                          if ($f_key == $sub_field) {
                            
                            $f_data['value'][$sub_field] = array();
                            foreach ($item['data'] as $element) {
                              $f_data['value'][$sub_field][] = array(
                                  'value' => $element);
                            }
                          }
                      
                        }
                      
                        $original_parent_field[$f_index] = $f_data;  
                      }
                      
                    $original_parent_fields[$parent_field] = $original_parent_field;
                    $node->$parent_field = $original_parent_field;
                    }
                    
                  }
                }
                break;
            }
          }
          
          // Add any existing taxonomy that doesn't have a translation.
          foreach($existing_taxonomy as $tax_id => $tax_term) {
            if (!in_array($tax_id, $taxonomy_translated)) {
              $node->taxonomy [$tax_id] = $tax_term;
            }
          }
          
          $node->teaser = node_teaser($node->body);
          $node->icanlocalize_creating_translation = TRUE;
          if ( !isset($translations[$code]) ) {
            if (variable_get('icl_content_publish_options', ICL_CONTENT_PUBLISH_TRANSLATIONS) != ICL_CONTENT_PUBLISH_TRANSLATIONS) {
              // unpulish node
              $node->status = 0;
            }
          }
          
          if (module_exists ( 'pathauto' )) {
            // See if the original node is using an auto alias
            module_load_include('inc', 'pathauto');
            
            $placeholders = pathauto_get_placeholders('node', $original);
            $src = "node/$original->nid";
            $alias = pathauto_create_alias('node', 'return', $placeholders, $src, $original->nid, $original->type, $original->language);
            
            if ($alias == $original->path) {
              $node->path = ""; // Allow path auto to create a new one.
            } else {
              // otherwise copy the url alias
              $node->pathauto_perform_alias = FALSE;
              //$node->path = $original->path;
            }
          }
          
          if ($translated_url_alias != "") {
            // Use the translate alias if we have one.
            
            $node->pathauto_perform_alias = FALSE;
            
            $node->path = $translated_url_alias;
            
          }
          
          $new_node = !isset($node->nid);
          
          module_invoke_all('presave_translation', $node, $nid, $vid, $code);          
          node_save ( $node );
          
          if (module_exists('path') && isset($node->path) && isset($node->pathauto_perform_alias) && $node->pathauto_perform_alias == FALSE) {
            // We may need to manually set the path alias as the user may not have permission to do so.
            path_set_alias('node/'. $node->nid, $node->path, NULL, $language);
          }
          
          
          if ($new_node && module_exists ( 'workflow' )) {
            // Initialize the work flow
            $wid = workflow_get_workflow_for_type($node->type);
            if ($wid) {
              // there is a workflow defined for this node type.
              // set the workflow to the creation state.
              $sid = _workflow_creation_state($wid);
              workflow_execute_transition($node, $sid, t('Translation from Translation Management module'), TRUE);
            }
          }
          
          if (module_exists ( 'domain' )) {
            
            // There is a problem that the domain can be lost.
            // We save it here so that we can do a final check and
            // fix up any problems as the last part of the cron job.
            
            global $_icl_domain;
            if (!isset($_icl_domain)) {
              $_icl_domain = array();
            }
          
            $_icl_domain[$node->nid] = $node;
          }

          // Use an alternative images in translation.
          $images_in_original_node = _icl_content_get_image_paths_for_node($nid);

          if (sizeof($images_in_original_node) > 0) {
            $node_changed = FALSE;
            $file_status = array();
            icl_content_apply_image_replacement('node/' . $node->nid,  
                                                $images_in_original_node,
                                                $node,
                                                $node_changed,
                                                $file_status);
            if ($node_changed) {
              node_save($node);
            }
          }
          
          icl_core_update_translation_link($request_id, $code, $node->nid);
        }
      }
      return TRUE;
      break;
  }
  
  return false;
}

/**
 * update the weight of translated pages in books so they are the same as
 * the original book. This will keep the book pages in order.
 */
  
function icl_content_update_books() {
  
  $books_to_update = variable_get('icl_content_books_to_update', array());

  $changed = FALSE;
  
  foreach ($books_to_update as $bid => $state) {
    $book_toc = _icl_wrapper_book_toc($bid, array(), 10);
    
    foreach($book_toc as $mlid => $title) {
      $menu = db_fetch_array(_icl_wrapper_db_query("SELECT * FROM {menu_links} WHERE mlid=%d", $mlid));
      $nid = substr($menu['link_path'], 5);
      $translations = icl_content_translation_node_get_translations($nid);
      
      foreach ($translations as $lang => $trans) {
        if ($trans->nid != $nid) {
          // get the menu for the translated page
          $trans_menu = db_fetch_array(_icl_wrapper_db_query("SELECT * FROM {menu_links} WHERE link_path='%s'", "node/" . $trans->nid));
          
          // set the weight to be the same as the original
          if ($menu['weight'] != $trans_menu['weight']) {
            _icl_wrapper_db_query("UPDATE {menu_links} SET weight=%d WHERE mlid=%d", $menu['weight'], $trans_menu['mlid']);
            $changed = TRUE;
          }
          
        }
        
      }
      
    }
  }

  if ($changed) {
    menu_cache_clear_all();
  }
  
  // clear the books.
  variable_set('icl_content_books_to_update', array());
}

function icl_content_get_translated_menu($mlid, $language) {
  // find the node this menu points to.
  $node = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT link_path FROM {menu_links} where mlid = %d", $mlid));
  if (strpos($node, "node/") === 0) {
    $nid = (int)substr($node, 5);
    $translations = icl_content_translation_node_get_translations($nid);
    if ( isset($translations[$language]) )  {
      $mlid_trans = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT mlid FROM {menu_links} where link_path = 'node/%d'", $translations[$language]->nid));
      
      return $mlid_trans;
    }
   
    return 0; 
  } else {
    return 0;
  }
}
/* ============== [ Callbacks & Handlers ] ============== */

/**
 * This is a handler for icl_content_form_alter().
 * It sets up the content type editing administration page for icanlocalize module.
 *
 * @param array $form The form to alter
 * @param array $form_state The form state
 * @param string $form_id The form ID
 */
function icl_content_alter_node_type_form(&$form, $form_state) {
  $node_type = $form ['#node_type']->type;
  
  if ($node_type == '') {
    return;
  }
  
  if (empty ( $form_state ['post'] )) {
    module_load_include ( 'inc', 'icl_content', 'icl_content.contentype' );
    $fields = icl_content_get_node_type_fields ( $node_type );
    $node_type_fields = variable_get ( 'icl_content_node_type_fields', array (
        $node_type => array (
            'title', 
            'body' ) ) );
    $defaults = isset ( $node_type_fields [$node_type] ) ? $node_type_fields [$node_type] : array (
        'title', 
        'body' );
    
    $form ['icl_content_node_type_settings'] = array (
        '#type' => 'fieldset', 
        '#title' => t ( 'Content Translation' ), 
        '#collapsible' => TRUE, 
        '#collapsed' => TRUE, 
        '#description' => t ( 'You can set which fields should be sent to translation for this node type.' ) );
    $form ['icl_content_node_type_settings'] ['icl_content_node_type_fields'] = array (
        '#type' => 'checkboxes', 
        '#title' => t ( '@type fields to translate', array (
            '@type' => ucfirst ( $node_type ) ) ), 
        '#options' => $fields, 
        '#default_value' => $defaults );
  } else {
    if (! isset ( $form_state ['post'] ['icl_content_node_type_fields'] )) {
      $form_state ['post'] ['icl_content_node_type_fields'] = array ();
    }
    
    $fields = variable_get ( 'icl_content_node_type_fields', array () );
    $fields [$node_type] = $form_state ['post'] ['icl_content_node_type_fields'];
    variable_set ( 'icl_content_node_type_fields', $fields );
  }
}

/**
 * This is a handler for icanlocalize_form_alter().
 * This handler adds the ICanTranslate option to the node add form if the setup
 * is Prompt on submit.
 *
 * @param array $form The form to alter
 * @param array $form_state The form state
 * @param string $form_id The form ID
 */
function icl_content_alter_node_add_form(&$form, $form_state) {
  
  icl_core_add_thickbox();
  drupal_add_js ( drupal_get_path ( 'module', 'icl_core' ) . '/js/icl_reminders.js' );

  $node = isset ( $form ['#node'] ) ? $form ['#node'] : FALSE;
  $langs = icl_core_available_languages ();  
  $targets = _icl_core_available_targets ();
  $form ['icl_content'] = array (
      '#type' => 'fieldset', 
      '#title' => t ( 'Translation management options' ), 
      '#collapsible' => TRUE, 
      '#collapsed' => FALSE, 
      '#attributes' => _icl_wrapper_form_create_attributes(array('id' => 'icl-content' )));
  
  $disabled = false;
  if (isset ( $node->nid )) {
    $disabled = _icl_content_translation_in_progress ( $node->nid );
  }
  
  if ($node && $node->tnid != $node->nid && $node->tnid != 0) {
    // This is a translation of a source node
    $source_node = node_load ( $node->tnid );
  } else {
    // This is a possible source node
    $input = isset ( $form_state ['values'] ['icanlocalize'] ) ? $form_state ['values'] ['icanlocalize'] : array ();
    
    $skip_default = variable_get ( 'icl_content_skip_per_node', array (
        $node->nid => ICL_CONTENT_TRANSLATE_PUBLISHED ) );
    if ($disabled) {
      $form ['icl_content'] ['icl_content_disabled'] = _icl_wrapper_form_create_markup(array (
          '#type' => 'markup', 
          '#value' => '<div class="box">' . t ( 'Translation is currently in progress and cannot be updated.' ) . '</div>' ));
      $form ['icl_content'] ['minor_edit'] = array (
        '#type' => 'checkbox', 
        '#title' => t ("Minor edit - don't update translation"),
        '#default_value' => FALSE,
        '#description' => t("Select this option if you are only making a minor edit and you don't require the translations of this content updated."),
        );
    } else {
      $form ['icl_content'] ['icl_content_error'] = _icl_wrapper_form_create_markup(array (
        '#type' => 'markup', 
        '#value' => '<div class="messages error" id="no_language_error">' . t ( 'There is no language selected for this content. Please select a language above if you want this content translated.' ) . '</div>' 
      ));

      if (isset($node->tnid) && $node->tnid == $node->nid) {
        $form ['icl_content'] ['minor_edit'] = array (
          '#type' => 'checkbox', 
          '#title' => t ("Minor edit - don't update translation"),
          '#default_value' => FALSE,
          '#description' => t("Select this option if you are only making a minor edit and you don't require the translations of this content updated."),
          );
      }
      
    }    
    // A small hack to include the CSS and JS
    $form ['#validate'] [] = 'icl_content_node_add_form_add_css_and_js';
    icl_content_node_add_form_add_css_and_js ();
  }
  
  
  $form ['icl_content'] ['icl_content_inprogress'] = _icl_wrapper_form_create_markup(array (
      '#type' => 'markup', 
      '#value' => isset ( $source_node ) ? '<div>' . theme ( 'icl_content_translated_status', $node ) . '</div>' : theme ( 'icl_content_fancy_status', $node, FALSE ) ));

  if (isset($form['translation'])) {
    // hide the "Translation options" - we have our own in ICanLocalize
    $form['translation']['#access'] = FALSE;
  }
  
  if (isset($form['#node']->type) && variable_get('language_content_type_' . $form['#node']->type, 0)) {
    if (isset($form['language']) && $form['language']['#default_value'] == '') {
      $default = language_default();
      $form['language']['#default_value'] = (isset($form['#node']->nid) ? $form['#node']->language : $default->language);
    }
  }
  
}

/**
 * This is a handler for icl_content_form_alter().
 * It sets up the send for translation on a comment form.
 *
 * @param array $form The form to alter
 * @param array $form_state The form state
 * @param string $form_id The form ID
 */
/*function icl_content_alter_comment_form(&$form, $form_state) {
  
  // is this a translated node.

  $nid = $form['nid']['#value'];
  $tnid = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT tnid FROM {node} WHERE nid=%d', $nid));
  if ($tnid != 0 && $tnid != $nid) {
    
    $language = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM node where nid = %d', $nid));
    $original_language = _icl_wrapper_db_result(_icl_wrapper_db_query('SELECT language FROM node where nid = %d', $tnid));
    
    $targets = _icl_core_available_targets_for_origin($original_language);
    
    if (in_array($language, array_keys($targets))) {
      
      $language = icl_core_get_language_name($language);
      $original_language = icl_core_get_language_name($original_language);
      $form ['icl_comment_translate_option'] = array (
          '#type' => 'fieldset', 
          '#title' => t ( 'ICanLocalize Comment Translation' ), 
          '#collapsible' => TRUE, 
          '#collapsed' => FALSE, 
          '#description' => 'Do you want your comment professionally translated?' );
      
      $set_check = variable_get ('icl_content_comment_translate_replies', 1);
      if ($form['cid']['#value'] != NULL) {
        // this is an existing comment.
        
        global $user;
        if ($form['uid']['#value'] != $user->uid) {
          // a different user so do set the translate check.
          $set_check = FALSE;
        }
      }
      
      $form ['icl_comment_translate_option'] ['icl_translate_comment'] = array (
          '#type' => 'checkbox', 
          '#title' => t ('Translate from !original_lang to !language', array('!language' => $language, '!original_lang' => $original_language)),
          '#default_value' => $set_check,
          );
    }
  }  
}*/

/**
 * Translates the given nids.
 *
 * @param array $nids
 * @param string $langcode 
 */
function icl_content_translate_posts($nids, $langcodes, $translators) {
  foreach ($nids as $nid) {
    $revision = module_invoke_all('override_revision_to_translate', $nid);
    
    if (sizeof($revision) > 0) {
      $node = node_load($nid, $revision[0]);
    } else {
      $node = node_load($nid);
    }
    if (in_array($node->language, $langcodes)) {
      drupal_set_message(t('You cannot translate %title to its source language', array('%title' => $node->title)));
      continue;
    }
    
    $targets = _icl_get_langs_not_in_progress($nid, 'node', $node, $node->language, $langcodes);
    
    if (sizeof($targets) == 0) {
      continue;
    }
    
    $node->icl_content_skip = -1;
    $node->icanlocalize = (array)$targets;
    $node->translators = $translators;
    
    
    $sql = "
        SELECT DISTINCT s.nid 
        FROM {icl_content_status} s 
            INNER JOIN {icl_node} n ON n.nid = s.nid 
            INNER JOIN {icl_core_status} c ON c.rid = s.rid
        WHERE s.nid = " . $node->nid;
            
    $res = _icl_wrapper_db_query($sql);
    $row = db_fetch_object($res);
    if ($row !== FALSE) {
      $op =  $row->nid > 0 ? 'update':'insert';
    } else {
      $op = 'insert';
    }
    
    icl_content_nodeapi($node, $op);
  }
}

/* ============ [ Helpers ] ============ */

/**
 * Checks wether a translation is in progress for a node.
 *
 * @param int $nid
 */
function _icl_content_translation_in_progress($nid) {
  if (isset ( $nid )) {
    $statuses = _icl_content_statuses ( $nid, 'node' );
    foreach ( $statuses as $status ) {
      if ($status < 5) {
        return true;
      }
    }
  }
  
  return false;
}

/**
 * Checks wether a translation is in progress for a node.
 *
 * @param int $nid
 */
function _icl_content_translation_in_progress_for_langs($nid, $langs) {
  if (isset ( $nid )) {
    $statuses = _icl_content_statuses ( $nid, 'node' );
    foreach($langs as $lang){
      if(isset($statuses[$lang])){
        if($statuses[$lang] < 5){
          return true;
        }
      }
    }
  }
  
  return false;
}

/**
 * This is the #validate callback for node form add/edit.
 * This has a twofold purpose:
 *   1) Add the JS file for the preview state as well
 *   2) Gather the translate-* field data into icanlocalize
 *
 * @param array $form
 * @param array $form_state
 */
function icl_content_node_add_form_add_css_and_js($form = null, &$form_state = null) {
  // Add the JS for Preview pages as well
  drupal_add_js ( drupal_get_path ( 'module', 'icl_content' ) . '/js/icl_content.js' );
  
  // Collect the various translate- values into icanlocalize
  if ($form_state != null) {
    $icanlocalize = array ();
    foreach ( $form_state ['values'] as $key => $item ) {
      if (substr ( $key, 0, strlen ( 'translate-' ) ) == 'translate-') {
        $icanlocalize = array_merge ( $icanlocalize, $item ['icanlocalize'] );
        unset ( $form_state ['values'] [$key] );
      }
    }
    $form_state ['values'] ['icanlocalize'] = $icanlocalize;
  }
}

/*
 * Returns the statuses of the translation requests for this node
 *
 * @param int $nid
 * @return array
 */
function _icl_content_statuses($id, $type) {
  $rids = icl_content_get_rids($id, $type);
  $status = array();
  if($rids !== FALSE){
    foreach($rids as $lang => $rid){
        $status[$lang] = _icl_wrapper_db_result(_icl_wrapper_db_query( "SELECT status FROM {icl_core_status} WHERE rid = %d and target = '%s'", $rid, $lang ));
    }
  }
  return $status;
}

function _icl_content_does_need_update($id, $type) {
  $rids = icl_content_get_rids($id, $type);
  
  return true;
}


/**
 * returns true if translations exist for the target langauges
 */

function _icl_content_do_translations_exist($name, $original_language, $target_languages) {
  $tid = _icl_content_find_translated_term_tid($name, $original_language);
  if ($tid) {
    $translated_terms = _icl_content_get_translations_for_term($tid);
    
    $keys = array_keys($translated_terms);
    if (isset($target_languages)) {
      foreach ($target_languages as $target) {
        if ( array_search($target, $keys) === false) {
          return false;
        }
      }      
    }
    
    // we have all the languages
    return true;
  }
  
  return false;
}

function icl_get_latest_request_id($id, $type, $source_language, $target_code){
  switch($type) {
    case 'node':
      $table = '{icl_content_status}';
      $id_type = 'content.nid';
      break;
    
    case 'block':
      $table = '{icl_block_status}';
      $id_type = 'content.bid';
      break;
    
  }
  
  $sql = "SELECT content.rid FROM
              {$table} content
          JOIN 
             {icl_core_status} core
          ON
             content.rid = core.rid
          WHERE
             {$id_type} = {$id} AND
             core.origin = '{$source_language}' AND
             core.target = '{$target_code}'
          ORDER BY rid DESC
          LIMIT 1
          ";
          
  return _icl_wrapper_db_result(_icl_wrapper_db_query($sql));
}

function icl_get_all_languages_associated($id, $type, $source_language, $rid) {

    if (!isset( $rid )) {
      // no $rid so no languages
      return array();
    }
    $languages = array();
    $query = _icl_wrapper_db_query("SELECT target FROM {icl_core_status} WHERE rid={$rid}");
    while($lang = db_fetch_array($query)){
      $languages[] = $lang['target'];
    }

    if($type == 'contact_form') {
      // Contact forms are only one language per cms_request
      $lang = _icl_wrapper_db_result(_icl_wrapper_db_query("SELECT target FROM {icl_core_status} WHERE rid={$rid}"));
      return array($lang);
    }
    
    switch($type) {
      case 'node':
        $table = '{icl_content_status}';
        $id_type = 'content.nid';
        break;
      
      case 'block':
        $table = '{icl_block_status}';
        $id_type = 'content.bid';
        break;
      
    }
    // check other request_ids that include these languages.

    $other_rids = array();    
    foreach($languages as $target_code) {
        $sql = "SELECT content.rid FROM
                    {$table} content
                JOIN 
                   {icl_core_status} core
                ON
                   content.rid = core.rid
                WHERE
                   {$id_type} = {$id} AND
                   core.origin = '{$source_language}' AND
                   core.target = '{$target_code}'";
                
        $query = _icl_wrapper_db_query($sql);
        while($rid = db_fetch_array($query)){
            if (!in_array($rid['rid'], $other_rids)){
                $other_rids[] = $rid['rid'];
            }
        }
    }
    foreach($other_rids as $id){
      $query = _icl_wrapper_db_query("SELECT target FROM {icl_core_status} WHERE rid={$id}");
      while($other_lang = db_fetch_array($query)){
            if (!in_array($other_lang['target'], $languages)){
                $languages[] = $other_lang['target'];
            }
        }
        
    }
    
    return $languages;
    
}

function _icl_get_langs_not_in_progress($id, $type, $data, $source_lang, $langcodes){
  
  $previous_rids = icl_content_get_rids($id, $type);
  
  $targets = array();
  $rid_status = _icl_content_statuses($id, $type);
  foreach($langcodes as $lang){
    if(!isset($rid_status[$lang])){
      // haven't translated to this language before.
      $targets[] = $lang;
    } else {
      if ($type != 'contact_form') {
        $langs = icl_get_all_languages_associated($id, $type, $source_lang, $previous_rids[$lang]);
        $all_available = true;
        foreach($langs as $temp_lang){
          $test_rid = icl_get_latest_request_id($id,
                                                $type,
                                                $source_lang,
                                                $temp_lang);
          $query = _icl_wrapper_db_query("SELECT status FROM {icl_core_status} WHERE rid={$test_rid}");
          while($state = db_fetch_array($query)){
            if($state['status'] != CMS_TARGET_LANGUAGE_DONE and $state['status'] != ICL_STATUS_SUCCESSFUL){
              // translation is still in progress for one or more languages.
              $all_available = false;
            }
          }
        }
        
        if(!$all_available) {
          continue;
        }
      }
      
      if($rid_status[$lang] == ICL_STATUS_SUCCESSFUL){
        // translation is complete to this language.
        $targets[] = $lang;
      } else {
      
        switch($type){
          case 'node':
            drupal_set_message(t('A translation is in progress for %title to %lang', array('%title' => $data->title, '%lang' => icl_core_get_language_name($lang))));
            break;
          
          case 'block':
            drupal_set_message(t('A translation is in progress for %block to %lang', array('%block' => $data['info'], '%lang' => icl_core_get_language_name($lang))));
            break;

          case 'contact_form':
            drupal_set_message(t('A translation is in progress for the contact form to %lang', array('%lang' => icl_core_get_language_name($lang))));
            break;
        }
      }
    }
  }

  return $targets;
}


function _icl_content_parse_flat_taxonomy_type($type, $values) {
  $data = array ();
  $pointer = &$data;
  $key = strtok ( $type, '[]' );
  while ( $key != false ) {
    $pointer [$key] = array ();
    $pointer = &$pointer [$key];
    $key = strtok ( '[]' );
  }
  $pointer = $values;
  
  return $data;
}

/**
 * get the best translation status for the node
 * -1 = no status ie. not translated.
 */

function _icl_content_get_best_translation_status($nid, $type_of_node = 'node') {
  
  $statuses = _icl_content_statuses ( $nid , $type_of_node);

  $best_code = -1;
  foreach ( $statuses as $target => $code ) {
    if ($code == ICL_STATUS_FAILED) {
      $best_code = $code;
      break;
    }
    if ($best_code == -1) {
      $best_code = $code;
    } else {
      $best_code = min($best_code, $code);
    }
  }
  
  return $best_code;
}


/* ========== [ Themes ] ========== */
/**
 * Theming node add status field
 *
 * @param boolean|object $node
 */
function theme_icl_content_fancy_status($node, $short) {
  $targets = _icl_core_available_targets (FALSE, $node->language);
  $status = "";

  // first check if we have a request id asscoiated with the node
  // This is to check for the case that we are sending a node that is a translation
  // to be translated in a new language
  // eg Dutch -> English -> Chinese.
  if(isset($node->nid)){
    $request = db_fetch_array(_icl_wrapper_db_query("SELECT rid FROM {icl_content_status} WHERE nid =" . $node->nid));
  }
  
  if(!isset($request['rid']) && $node->tnid != $node->nid && $node->tnid != 0){
    
      // this is a translation.
      
      $targets = _icl_core_available_targets ();
      $status =  t ( '@origin translation', array (
      '@origin' => icl_core_get_language_name($node->language)));
  }
  else  
  if (! empty ( $node ) & ! empty ( $node->nid )) {
    if ($node->type == 'icl_block_marker') {
      $best_code = _icl_content_get_best_translation_status($node->nid, 'block');
    } else if ($node->type == 'icl_contact_form_marker') {
      $best_code = _icl_content_get_best_translation_status($node->nid, 'contact_form');
    } else {
      $best_code = _icl_content_get_best_translation_status($node->nid);
    }
      
    switch ($best_code) {
      case ICL_STATUS_INQUEUE :
      case ICL_STATUS_REQUESTED :
      case ICL_STATUS_UNKNOWN_2 :
      case ICL_STATUS_UNKNOWN_3 :
      case ICL_STATUS_UNKNOWN_4 :
      case ICL_STATUS_READY :
        $status = t ( 'Translation in progress' );
        break;
      case ICL_STATUS_SUCCESSFUL :
        $status = t ( 'Translation complete' );
        if ($node->type == 'icl_block_marker') {

          // We don't know if a block has changed from the core status as we don't hook any saving of blocks.
          // We need to calculate each time.
          $block = _icl_wrapper_block_box_get($node->nid);
          $block_md5 = icl_content_calculate_block_md5($block);

          $rids = icl_content_get_rids($node->nid, 'block');
          $rids = "(" . implode(',', $rids) . ")";

          $sql = "
            SELECT DISTINCT s.bid 
            FROM {icl_block_status} s 
                INNER JOIN {icl_block} b ON b.bid = s.bid 
                INNER JOIN {icl_core_status} c ON c.rid = s.rid
            WHERE s.bid = {$node->nid} AND '{$block_md5}' <> s.md5 AND c.status = " . ICL_STATUS_SUCCESSFUL . " AND c.rid IN " . $rids;
          $res = _icl_wrapper_db_query($sql);
          $row = db_fetch_object($res);
          if ($row->bid > 0) {
            $status = t ( 'Translation needs update' );
            
          }
        } else if ($node->type == 'icl_contact_form_marker') {
          $rids = variable_get('icl_contact_form_rids', array());
          $current_md5 = icl_content_calculate_stardard_contact_form_md5();

          $previous_md5s = variable_get('icl_contact_form_md5s', '');
          foreach ($rids as $rid) {
            if ($previous_md5s[$rid] != $current_md5) {
              $status = t ( 'Translation needs update' );
              break;
            }
          }
        } else {
 
          $rids = icl_content_get_rids($node->nid, 'node');
          $rids = "(" . implode(',', $rids) . ")";
         
          $sql = "
            SELECT DISTINCT s.nid 
            FROM {icl_content_status} s 
                INNER JOIN {icl_node} n ON n.nid = s.nid 
                INNER JOIN {icl_core_status} c ON c.rid = s.rid
            WHERE s.nid = {$node->nid} AND n.md5 <> s.md5 AND c.status = " . ICL_STATUS_SUCCESSFUL . " AND c.rid IN " . $rids;
          $res = _icl_wrapper_db_query($sql);
          $row = db_fetch_object($res);
          if ($row && $row->nid > 0) {
            $status = t ( 'Translation needs update' );
          }
        }
        break;
      case ICL_STATUS_FAILED :
        $status = t ( 'Translation failed' );
        break;
      default:
        $status = t ( 'Not translated yet' );
        break;
    }
  } else {
    $status = t ( 'Not translated yet' );
  }
  if( $status == "" ){
    $status = t ( 'Not translated yet' );
  }
  
  if ( $short ) {
    return '<div>' . $status . '</div>';
  } else {
    return '<div>' . t ( 'Translation status: ') . $status . '</div>';
  }
}

/**
 * Themes the translated pages' response.
 *
 * @param object $node
 * @return string               
 */
function theme_icl_content_translated_status($node) {
  $targets = _icl_core_available_targets ();
  return t ( '@origin translation', array (
      '@origin' => $targets [$node->language]->name ) );
}

/**
 * Implements hook_nodewords_tags_alter.
 */
function icl_content_nodewords_tags_alter(&$data) {
  
  foreach($data as $key => $value) {
    $data[$key] = t($value);
  }
}

/**
 * Implementation of hook_cron()
 * @see http://api.drupal.org/api/function/hook_cron/6
 *
 */
function icl_content_cron() {
  
  if (variable_get('icl_translate_reports_enabled', FALSE) && variable_get('icl_report_use_crop', FALSE)) {
    icl_content_do_translation_status_report();
  }
  
}
