--- /node_embed.module	1970-01-01 10:00:00.000000000 +1000
+++ ../../../../marmaladesoul/Cochlear/www.cochlear.com/sites/all/modules/node_embed/node_embed.module	2010-07-22 23:08:05.000000000 +1000
@@ -0,0 +1,467 @@
+<?php 
+// $Id: $
+/**
+ * This module defines an input filter for taking an embed code syntax ([[nid:###]])
+ * and removing the embed code and replacing with a rendered node view at that position
+ * in the text field. *
+ */
+/**
+ * @file module code to define the input filter for node embedding.
+ */
+
+global $NODE_EMBED_REGEX,$NODE_EMBED_REGEX_TRIMMED;
+$NODE_EMBED_REGEX = "/\[{2}\s*(nid:\d+.*)\]{2}/";
+$NODE_EMBED_REGEX_TRIMMED = "/^nid:(\d+)((\s[\d\w]+:[\d\w]+)*)$/";
+
+/**
+ * Implementation of hook_help().
+ */
+function node_embed_help($path, $arg) {
+  $output = '';
+  switch ($path) {
+    case 'admin/settings/modules#description':
+      $output = t('Node Embed allows the embedding of other nodes in a single node.');
+      break;
+    case 'admin/settings/node_embed':
+      $output = t('<p>Node Embed module enables the embedding of other nodes in a single node.</p>');
+      break;
+  }
+  
+  return $output;
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function node_embed_menu() {
+  $items = array();
+
+  $items['admin/settings/node_embed'] = array(
+    'title' => 'Node Embed',
+    'description' => t('Node Embed allows the embedding of other nodes in a single.<br/>Configure Node Embed Settings.'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_embed_admin_settings_form'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_NORMAL_ITEM,
+  );
+
+  return $items;
+}
+
+/**
+ * Node Embed admin settings form.
+ *
+ * @return
+ * The settings form used by Node Embed.
+ */
+function node_embed_admin_settings_form() {
+  $form['node_embed'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Node Embed Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  
+  $form['node_embed']['node_embed_instructions'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Configuration Instructions'),
+    '#description' => t("<br/>To enable nodes to embed nodes, configure your sites' input filters (<a href='filters/add'>admin/settings/filters/add</a>) to use the 
+   '<i>Insert node</i>' filter."),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  
+  $form['fckeditor'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('FCKEditor Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  
+/*  $form['fckeditor']['node_embed_use_fckeditor'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use FckEditor.'),
+    '#description' => t('Select this option if you want to use FckEditor.'),
+    '#default_value' => variable_get('node_embed_use_fckeditor', 0),
+  );
+*/  
+  $form['fckeditor']['fckeditor_instructions'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('FCKEditor Install Instructions'),
+    '#description' => t("<p>Under the <i>node_embed</i> module directory, there is the '<i>fckeditor/NodeEmbed</i>' directory, 
+          that will provide a tool bar plugin for fckeditor.<br/><br/>
+          
+          To configure the plugin:<br/>
+          <ol>
+          <li>Copy the NodeEmbed directory to <i>sites/all/modules/fckeditor/plugins</i> directory.</li>
+          <li>Add line below to fckeditor.config.js as a plugin:<br/>
+             <code>FCKConfig.Plugins.Add( 'NodeEmbed', 'en' );</code></li>
+          <li>Then add the NodeEmbed plugin to a ToolbarSet for your tool set, e.g.
+             <code>['Link','Unlink','NodeEmbed','Anchor']</code>.<br/>For more information, see
+             <a target='_blank' href='http://docs.cksource.com/FCKeditor_2.x/Developers_Guide/Customization/Plug-ins#Installing_and_adding_plugin'>Installing and adding plugin in FCKeditor</a></li>
+          <li>Select the correct drupal toolbar from the fckeditor settings page.</li>
+          <li>Enable the default view 'fckeditor-node-embed'.  This view provides the content of the 
+             plugin dialog box.  The <i>page-fckeditor-node-embed.tpl.php</i> template under <i>node_embed/theme</i>
+             is used for this page, to override it, copy to your theme directory and tweak what you need.</li>
+          </p>"),
+  	'#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  
+  return system_settings_form($form);
+}
+
+/**
+ * Implementation of hook_enable().
+ */
+function node_embed_enable() {
+  variable_set('node_embed_use_fckeditor', 0);
+}
+
+/**
+ * Implementation of hook_disable().
+ */
+function node_embed_disable() {
+  variable_del('node_embed_use_fckeditor');
+}
+
+/**
+ * Implementation of hook_filter()
+ */
+function node_embed_filter($op, $delta = 0, $format = -1, $text = '') {
+  global $NODE_EMBED_REGEX;
+  
+  switch ($op) {
+  case 'list':
+    return array(0 => t('Insert node'));
+
+  case 'description':
+    return t('By including the syntax <code>[[nid:node_id]]</code> (eg <code>[[nid:345]]</code>), this filter will embed the node with given NID');
+
+  case 'prepare':
+    return $text;
+
+  case 'no cache':
+    return TRUE;
+
+  case "process":
+    // replace on [[nid:###]]
+    // replace on [[nid:### key1:value1 key2:value2 key3:value3 .... ]]
+    // TODO: Do we put checks in for the incorrect format ?
+    //  eg [[ nid<space>:XXXX ]] or [[ nid<space>:<space>XXXX ]] or [[[ nid<space>:<space>XXXX ]] or [[[ nid<space>:<space>XXXX ]]]    
+    return preg_replace_callback($NODE_EMBED_REGEX, '_node_make_replacements',$text);
+  }
+}
+
+/**
+ * Implementation of hook_filter_tips()
+ */
+function node_embed_filter_tips($delta, $format, $long = FALSE) {
+  return t('[[nid:123]] - insert a node content');
+}
+
+/**
+ * Implementation of hook_preprocess_node()
+ */
+function node_embed_preprocess_node(&$vars) {
+  if (!empty($vars['node_embedded'])) { 
+    $vars['template_files'][] = "node-embed--default";
+    $vars['template_files'][] = 'node-embed--' . $vars['type'];
+  }
+}
+  
+/**
+ * Provides the replacement html to be rendered in place of the embed code.
+ * Does not handle nested embeds.
+ *
+ * @param $matches
+ *    numeric node id that has been captured by preg_replace_callback
+ * @return
+ *    The rendered HTML replacing the embed code
+ */ 
+function _node_make_replacements($matches) {
+  $params_array = array();
+
+  $embedded_node_params = node_embed_get_embedded_node($matches[1]);
+  
+  //TODO: Why won't this pick up empty ?
+  if (isset($embedded_node_params)) {
+    if($node = node_load(key($embedded_node_params))) {
+
+      if (!$node->status || !node_access('view', $node)) {
+        return '';
+      }
+      else {
+        $node->node_embedded=current($embedded_node_params);
+      }
+    }
+  }
+  else {
+    return '';
+  }
+
+  $output = node_view($node);
+  return $output;
+}
+
+/**
+ * Implementation of hook_theme_registry_alter
+ * This is where we add our default template for the fckeditor view page template.
+ * We want our path suggestion for the module to be overridden by the theme, so 
+ * some re-ordering is needed.
+ */  
+function node_embed_theme_registry_alter(&$theme_registry) {  
+  $paths = $theme_registry['page']['theme paths'];
+  $theme = $theme_registry['page']['theme path'];
+  
+  $key = array_search($theme, $paths);
+  
+  if ($key === FALSE) {
+    $theme_registry['page']['theme paths'][] = drupal_get_path('module', 'node_embed') ."/theme";
+  }
+  else {
+    unset($theme_registry['page']['theme paths'][$key]);
+    $theme_registry['page']['theme paths'][] = drupal_get_path('module', 'node_embed') ."/theme";
+    $theme_registry['page']['theme paths'][] = $theme_registry['page']['theme path'];
+    // reset the keys
+    $theme_registry['page']['theme paths'] = array_values($theme_registry['page']['theme paths']);
+  }
+}
+
+/**
+ * make compatible with views 2 for default view.
+ */
+function node_embed_views_api() {
+  return array('api' => 2.0);
+}
+  
+/**
+ * Implementation of hook_views_default_views().
+ */
+function node_embed_views_default_views() {
+    $path = drupal_get_path('module', "node_embed") ."/fckeditor/fckeditor_node_embed.view.inc";
+    include_once($path);
+    $views[$view->name] = $view;
+  
+  return $views;
+}
+
+/**
+ * Implement hook_form_alter()
+ * add a validation handler to nodes with node_embed.
+ *
+ */
+function node_embed_form_alter(&$form, $form_state, $form_id) {
+  $form['#validate'][] = 'node_embed_validate';
+}
+
+/**
+ * validation for the node_embed filter.
+ * we do not allow nodes to embed in themselves.
+ * results in segment fault.
+ * 
+ * This checks whether there is an attempt to self embed a node or
+ * if there is an to embed a node when it is all ready embedded in a
+ * chain of nodes.
+ * 
+ * The appropriate error messages are displayed
+ */
+function node_embed_validate($form, &$form_state) {
+  // Body is not the only entry of content and of embedding node
+  // Fields of Content Type
+  $nid = $form['nid']['#value'];
+  if ($nid){
+    // Perform recursive check on embedded node
+    $node_content_fields= node_embed_get_node_field_values($form['#post']);
+    $conflict_fields = _valid_embed_reference($nid, $nid, $form['#post'],true);
+
+     
+    if (count($conflict_fields) > 0) {
+      $msg = t('<strong>Node Embed Module Error</strong><br/>');
+      $msg .= t('<ul>');
+      foreach($conflict_fields as $field_name => $conflict_nodes) {
+        foreach($conflict_nodes as $attempted_embed_node_id=>$embedded_node) {
+          $msg .= t('<li>');
+          $msg .= t('Cannot use node ID "' . $attempted_embed_node_id . '" in Field "' . _get_content_field_label($field_name) . '"<br/>');
+          if ($nid == $attempted_embed_node_id) {
+            $msg .= t('Cannot embed a node into itself!');
+          }
+          else if (is_null($embedded_node)) {
+            $msg .= t('Node ID "<strong>'. $attempted_embed_node_id . '</strong>" DOES NOT EXIST!');
+          }
+          else {
+            // TODO: Is it possible to add an achor reference ?
+            $msg .= t('Node ID "<strong>'. $nid . '</strong>" is all ready embedded in node ID "' . key(current($embedded_node)). '" in Field "' . _get_content_field_label(current(current($embedded_node))) . '"<br/>');
+            if (key(current($embedded_node)) != $attempted_embed_node_id) {
+              $msg .= t('Node ID "'.  key(current($embedded_node)) . '" is embedded in node ID "<strong>' . $attempted_embed_node_id . '</strong>" in Field "' . _get_content_field_label(key($embedded_node)) . '"<br/>');
+            }
+          }
+          $msg .= t('</li>');
+        }
+      }
+      $msg .= t('</ul>');
+      form_set_error('edit-body', $msg);
+    }
+  }
+}
+
+/**
+ * This recursive function performs a check on each node that is to be embedded
+ * that the node is not trying to embed with itself or create a circular reference.
+ *
+ * @param int $nid	- Current Node ID being evaluated
+ * @param int $reference_node - Node ID to compare to
+ * @param array $form	- The node editing form
+ *
+ * @return array
+ * 					returns an array list of fields that have conflicting embedded nodes with references to associated fields
+ *   'field_name' =>
+ *  		array (
+ *   			attempted_embedded_node_id =>
+ *   				array (
+ *     					'attempted_embedded_node_field_name' => array (conflict_node_id => 'conflict_node_field_name',),
+ *   				),
+ * 			),
+ *
+ */
+function _valid_embed_reference($nid, $reference_node,$node_properties, $start_recurse=false) {
+  global $NODE_EMBED_REGEX;
+  global $_node_embed_result_array;
+  global $_node_embed_orig_field;
+  global $_node_embed_attempted_node_embed;
+  global $_node_embed_parent_field;
+   
+  if ($start_recurse) {
+    $_node_embed_parent_field = 'self';
+  }
+
+  $node_embed_field_list = node_embed_get_node_field_values($node_properties);
+
+  $found = FALSE;
+  foreach($node_embed_field_list as $field_name => $node_embed_body) {
+    if ($start_recurse) {
+      $_node_embed_orig_field=$field_name;
+    }
+
+    $match_count = preg_match_all($NODE_EMBED_REGEX,$node_embed_body, $matches);
+    if ($match_count !==FALSE && $match_count != 0) {
+      for ($i=0; $i < $match_count; $i++) {
+        $attempted_embed_node_params = node_embed_get_embedded_node($matches[1][$i]);
+        if (!empty($attempted_embed_node_params)) {
+          if($embedded_node_id = key($attempted_embed_node_params)) {
+            if ($start_recurse) {$_node_embed_attempted_node_embed=$embedded_node_id;}
+            if (node_load($embedded_node_id )) {
+              if($found = (is_numeric($embedded_node_id ) && $embedded_node_id == $reference_node)) {
+                $_node_embed_result_array[$_node_embed_orig_field][$_node_embed_attempted_node_embed]=array($_node_embed_parent_field => array($nid => $field_name));
+              }    // Check for Circular Reference
+              elseif (is_numeric($embedded_node_id)) {
+                $_node_embed_parent_field = $field_name;
+                _valid_embed_reference($embedded_node_id ,$reference_node, get_object_vars(node_load($embedded_node_id)));
+              }
+            }
+            else {
+              $_node_embed_result_array[$_node_embed_orig_field][$_node_embed_attempted_node_embed]=NULL;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return $_node_embed_result_array;
+}
+
+/**
+ * This function returns an array of content fields that
+ * use the node embedded input filter and their corresponding
+ * values in those fields
+ *
+ * @param array $node_properties
+ * @return array $node_embed_field_list
+ */
+function node_embed_get_node_field_values($node_properties) {
+  $node_embed_field_list = array();
+
+  if (array_key_exists('body', $node_properties) && array_key_exists('format', $node_properties)) {
+    if (is_numeric($node_properties['format'])) {
+      $num_rows = db_result(db_query("SELECT count(*) FROM {filters} WHERE format='%d' AND module = 'node_embed'", $node_properties['format']));
+      if ($num_rows >= 1) {
+        $node_embed_field_list['body'] =  $node_properties['body'];
+      }
+    }
+  }
+
+  if (module_exists('content')) {
+    // Loop thru POST fields to see if there are any matches
+    // Look for 'field_XXXXX" and check on filter format
+    foreach($node_properties as $field_name => $value) {
+      if (strpos($field_name, 'field_') !== FALSE) {
+        foreach($value as $key => $field_value) {
+          if (array_key_exists('format', $field_value)) {
+            if (is_numeric($field_value['format'])) {
+              $num_rows = db_result(db_query("SELECT count(*) FROM {filters} WHERE format='%d' AND module = 'node_embed'", $field_value['format']));
+              if ($num_rows >= 1) {
+                $node_embed_field_list[$field_name] =  $field_value['value'];
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return  $node_embed_field_list;
+}
+
+/**
+ * Get the label name of the CCK Field
+ * @param string $field_name
+ * 
+ * @return string
+ */
+function _get_content_field_label($field_name) {
+  if (empty($field_name)) return '';
+  if (strcmp($field_name, 'body')==0) return 'Body';
+
+  if (module_exists('content')) {
+    $info = content_fields($field_name);
+    return $info['widget']['label'];
+  }
+}
+
+/**
+ * The function will parse an attempted embed node token
+ * 		"[[ nid:xxx ..... ]]"
+ * and return an array with node as the key and any associated key:value pairs
+ * 
+ * @param $attempted_embed_token
+ * 
+ * @return an array with the embedded node as key
+ */
+function node_embed_get_embedded_node($attempted_embed_token) {
+  global $NODE_EMBED_REGEX_TRIMMED;
+  
+  $embedded_node_params = NULL;
+  $attempted_token = preg_replace('/\s\s+/', ' ', trim($attempted_embed_token));
+  $match_count = preg_match($NODE_EMBED_REGEX_TRIMMED,$attempted_token, $matches);
+    
+  if ($match_count) {
+    if (is_numeric($matches[1])) {
+      // $matches is of the form "key:value key:value key:value ..."
+      // Use tab and newline as tokenizing characters as well
+      $key_value_array=NULL;
+      $tok = strtok($matches[2], " ");
+
+      //TODO:This assumes that the key valus are unique
+      while ($tok !== false) {
+        list($key, $value) =explode(":", $tok);
+        $key_value_array[$key] =$value;
+        $tok = strtok(" ");
+      }
+
+      $embedded_node_params[$matches[1]]=$key_value_array;
+    }
+  }
+  
+  return $embedded_node_params;
+}
\ No newline at end of file
