 class_media_mover_file.inc           | 75 +++++++++++++++++++++---------------
 class_media_mover_step.inc           | 13 +++++++
 media_mover_api.install              | 74 +++++++++++++++++++++++++++++++++--
 media_mover_api.module               |  6 ++-
 media_mover_ui/media_mover_ui.module | 56 +++++++++++++++++++--------
 modules/mm_token/mm_token.module     |  3 +-
 modules/mm_views/mm_views.module     |  2 +
 7 files changed, 175 insertions(+), 54 deletions(-)

diff --git a/class_media_mover_file.inc b/class_media_mover_file.inc
index 9e1d29e..d58478e 100644
--- a/class_media_mover_file.inc
+++ b/class_media_mover_file.inc
@@ -41,28 +41,32 @@ class media_mover_file {
   /**
    * Get media mover file data for the requested id.
    *
-   * @param $mmfid
+   * @param int $mmfid
    *   Media Mover file id
+   * @param array $data
+   *   Media mover file data (if already loaded)
    * @return
    *   Boolean, did the file load or not?
    *
    */
-  function load($mmfid) {
+  function load($mmfid, $data = NULL) {
     // Load the file
     // @TODO how much integration should there be between managed drupal files?
 
-    $query = db_select('media_mover_files', 'mmf')
-      ->condition('mmf.mmfid', $mmfid, '=')
-      ->fields('mmf');
-    $result = $query->execute()->fetchAssoc();
+    if ($mmfid && !$data) {
+      $query = db_select('media_mover_files', 'mmf')
+        ->condition('mmf.mmfid', $mmfid, '=')
+        ->fields('mmf');
+      $data = $query->execute()->fetchAssoc();
 
-    // No file data was found
-    if (! $result) {
-      return FALSE;
+      // No file data was found
+      if (! $data) {
+        return FALSE;
+      }
     }
 
     // Load the data onto the file
-    $this->load_data($result);
+    $this->load_data((array) $data);
 
     // Allow the file to be altered
     drupal_alter('media_mover_file_load', $this);
@@ -201,17 +205,9 @@ class media_mover_file {
    * @return Entity link or FALSE if file entity is unknown.
    */
   function get_entity_link($op = NULL) {
-    $entity_type = $this->data_get('entity_type');
-    $entity_id = $this->data_get('entity_id');
-    if (!$entity_type && !$entity_id && isset($this->nid)) {
-      $entity_type = 'node';
-      $entity_id = $this->nid;
-    }
-    elseif (isset($this->data['node'])) {
-      $entity_type = 'node';
-      $entity_id = $this->data['node']->nid;
-    }
-    else {
+    $entity_type = $this->entity_type;
+    $entity_id = $this->entity_id;
+    if (!$entity_type && !$entity_id) {
       return FALSE;
     }
     // @todo Is there a way to avoid loading $entity?
@@ -376,6 +372,7 @@ class media_mover_file {
       'step_order' => $step->step_order,
       'sid' => $step->sid,
       'result_uri' => $uri,
+      'fid' => isset($this->fid) ? $this->fid : FALSE,
     ));
 
     // Update the current uri
@@ -437,20 +434,38 @@ class media_mover_file {
   }
 
   /**
-   * Return a node or nid from a file if it exists
+   * Set file source entity type/id
    *
-   * @return object
+   * @param string $entity_type
+   *   Entity type
+   * @param int $entity_id
+   *   Entity id
    */
-  function node_get($load = TRUE) {
-    if (! $nid = $this->nid) {
-      if (! $nid = $this->data['node']->nid) {
-        return FALSE;
-      }
+  function entity_set($entity_type, $entity_id) {
+    $this->entity_type = $entity_type;
+    $this->entity_id = $entity_id;
+  }
+
+  /**
+   * Return source entity type/id from a file
+   *
+   * @param boolean $load
+   *   Select return type
+   * @return array or object
+   *   Array keys: 'entity_type', 'entity_id' or object if $load = TRUE if entity has been set, or FALSE
+   */
+  function entity_get($load = TRUE) {
+    if (empty($this->entity_type) && empty($this->entity_id)) {
+      return FALSE;
     }
     if ($load) {
-      return node_load($nid);
+      $entities = entity_load($this->entity_type, array($this->entity_id));
+      $entity = reset($entities);
+      return $entity;
+    }
+    else {
+      return array('entity_type' => $this->entity_type, 'entity_id' => $this->entity_id);
     }
-    return $nid;
   }
 
 
diff --git a/class_media_mover_step.inc b/class_media_mover_step.inc
index 05f0606..180fb47 100644
--- a/class_media_mover_step.inc
+++ b/class_media_mover_step.inc
@@ -224,7 +224,20 @@ class media_mover_step {
         foreach ($files as $id => $selected_file) {
           // Create the media mover file
           $mmfile = new media_mover_file($this);
+          $mmfile->fid = isset($selected_file['fid']) ? $selected_file['fid'] : FALSE;
           $mmfile->update_uri($selected_file['uri'], $this);
+
+          // Pass Entity data from the harvest/select step to the subsequent steps
+          if (isset($selected_file['entity_type']) && isset($selected_file['entity_id'])) {
+            $mmfile->entity_type = $selected_file['entity_type'];
+            $mmfile->entity_id = $selected_file['entity_id'];
+//@todo: add uid here as well...
+          }
+
+          // Generalized way to pass arbitrary data from the harvest/select step to the subsequent steps
+          if (isset($selected_file['meta'])) {
+            $mmfile->data_set('meta', $selected_file['meta']);
+          }
           $mmfile->save(TRUE);
           $files[$id] = $mmfile;
         }
diff --git a/media_mover_api.install b/media_mover_api.install
index 40afcb1..ddc0673 100644
--- a/media_mover_api.install
+++ b/media_mover_api.install
@@ -30,10 +30,23 @@ function media_mover_api_schema() {
     'description' => 'Holds file data for a specific  Media Mover file.',
     'fields' => array(
       'mmfid' => array('type' => 'serial'),
-      'nid' => array('type' => 'int', 'unsigned' => TRUE),
       'fid' => array('type' => 'int', 'unsigned' => TRUE, 'description' => 'Drupal file id'),
       'cid' => array('type' => 'varchar', 'length' => 255, 'default' => '', 'description' => 'Configuration machine name ID'),
       'step_order' => array('type' => 'int', 'unsigned' => TRUE, 'description' => 'Step order that this file is currently in'),
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The name of the source entity type for this file, NULL if not connected to any entity.',
+      ),
+      'entity_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => FALSE,
+        'default' => NULL,
+        'description' => 'The source entity id for this file.',
+      ),
       'source_uri' => array(
         'type' => 'text',
         'size' => 'medium',
@@ -72,10 +85,11 @@ function media_mover_api_schema() {
     ),
     'indexes' => array(
       'mmfid' => array('mmfid'),
-      'nid' => array('nid'),
       'cid' => array('cid'),
       'fid' => array('fid'),
       'cid, fid' => array('cid', 'fid'),
+      'entity_type' => array('entity_type'),
+      'entity_id' => array('entity_id'),
     ),
     'primary key' => array('mmfid')
   );
@@ -210,7 +224,7 @@ function media_mover_api_schema() {
 
   // cache schema
   $schema['cache_media_mover'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_media_mover']['description'] = 'Cache table for the Media Mover module to store configuration and node data';
+  $schema['cache_media_mover']['description'] = 'Cache table for the Media Mover module to store configuration and entity data';
 
   return $schema;
 }
@@ -234,4 +248,56 @@ function media_mover_api_7101() {
   Update media_mover_files - move all files into a serialized files col
 
    */
-}
\ No newline at end of file
+}
+
+/**
+ * Update Schema for Entity API.
+ *
+ */
+function media_mover_api_update_7102() {
+  // Add entity_type field & add index
+  if (!db_field_exists('media_mover_files', 'entity_type')) {
+    db_add_field('media_mover_files', 'entity_type', array(
+      'type' => 'varchar',
+      'length' => 32,
+      'not null' => TRUE,
+      'default' => '',
+      'description' => 'The name of the source entity type for this file, NULL if not connected to any entity.',
+    ));
+    db_add_index('media_mover_files', 'entity_type', array('entity_type'));
+
+  }
+
+  // Add entity_id field and copy nid into it & add index
+  if (!db_field_exists('media_mover_files', 'entity_id')) {
+    db_add_field('media_mover_files', 'entity_id', array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => FALSE,
+      'default' => NULL,
+      'description' => 'The source entity id for this file.',
+    ));
+    db_add_index('media_mover_files', 'entity_id', array('entity_id'));
+  }
+
+  // Populate entity_id = nid, entity_type = 'node' for set nid fields
+  if (db_field_exists('media_mover_files', 'nid')) {
+    switch (Database::getConnection()->databaseType()) {
+      case 'mysql':
+      case 'mysqli':
+      case 'pqsql':
+        db_query('UPDATE {media_mover_files} SET entity_id = nid, entity_type = \'node\' WHERE nid <> 0')->execute();
+        break;
+    }
+  }
+}
+
+/**
+ * Remove Schema for legacy nodes.
+ *
+ */
+function media_mover_api_update_7103() {
+  // Drop 'nid' field
+  db_drop_field('media_mover_files', 'nid');
+}
+
diff --git a/media_mover_api.module b/media_mover_api.module
index 8cf7533..c57dd5a 100644
--- a/media_mover_api.module
+++ b/media_mover_api.module
@@ -1075,7 +1075,8 @@ function media_mover_api_token_list($type = 'all') {
     $tokens['media_mover_file'] = array(
       'uri' => t('The uri of the current media mover file.'),
       'filename' => t('Sanitized name of the file.'),
-      'nid' => t('The node id this file is related to if it exists.'),
+      'entity_type' => t('The entity type this file is related to if it exists.'),
+      'entity_id' => t('The entity id this file is related to if it exists.'),
       'fid' => t('Drupal file id if it exists'),
       'cid' => t('Media Mover configuration id (sanitized).'),
       'cid-raw' => t('Media Mover configuration id.'),
@@ -1103,7 +1104,8 @@ function media_mover_api_token_values($type, $object = NULL, $options = array())
     $tokens = array(
       'uri' => $object->uri,
       'filename' => check_plain(basename($object->uri)),
-      'nid' => $object->nid,
+      'entity_type' => $object->entity_type,
+      'entity_id' => $object->entity_id,
       'fid' => $object->fid,
       'cid' => check_plain($object->cid),
       'cid-raw' => $object->cid,
diff --git a/media_mover_ui/media_mover_ui.module b/media_mover_ui/media_mover_ui.module
index 1d21a13..84ebc2f 100644
--- a/media_mover_ui/media_mover_ui.module
+++ b/media_mover_ui/media_mover_ui.module
@@ -1197,27 +1197,29 @@ function media_mover_ui_files_list($configuration = FALSE, $status = FALSE) {
   $results = $query->execute();
 
   foreach ($results as $result) {
+    $file = new media_mover_file();
+    $file->load(FALSE, $result);
     if ($configuration) {
       $conf = $configuration;
     }
     else {
-      $conf = media_mover_api_configuration_load($result->cid);
+      $conf = media_mover_api_configuration_load($file->cid);
     }
     $rows[] = array(
-      l($result->mmfid, MMA_MENU_PATH . '/file/' . $result->mmfid . '/edit'),
-      $result->nid ? l(t('node @id', array('@id' => $result->nid)), 'node/' . $result->nid) : t('NA'),
-      $result->source_uri,
-      $result->uri,
-      isset($conf->steps[$result->step_order]) ? $conf->steps[$result->step_order]->build['description'] : t('NA'),
-      $result->status,
+      l($file->mmfid, MMA_MENU_PATH . '/file/' . $file->mmfid . '/edit'),
+      $file->get_entity_link(),
+      $file->source_uri,
+      $file->uri,
+      isset($conf->steps[$file->step_order]) ? $conf->steps[$file->step_order]->build['description'] : t('NA'),
+      $file->status,
       l($conf->name, MMA_MENU_PATH . '/configuration/' . $conf->cid),
-      format_date($result->date),
+      format_date($file->date),
     );
   }
 
   $header = array(
     array('data' => t('ID')),
-    array('data' => t('Node')),
+    array('data' => t('Entity')),
     array('data' => t('Selected file')),
     array('data' => t('Current file')),
     array('data' => t('Current Step')),
@@ -1272,11 +1274,12 @@ function media_mover_ui_edit_file_form($form, &$form_state, $file) {
   $configuration = media_mover_api_configuration_load($file->cid);
 
   // Get each of the actions for this configuration
-  if (! empty($file->steps)) {
-    foreach ($file->steps as $id => $step) {
+  if (! empty($configuration->steps)) {
+    foreach ($configuration->steps as $step_order => $step) {
+      $file_link = $file->get_link($step_order);
       $rows[] = array(
         t('Step: %name', array('%name' => $step->name)),
-        t('File: !file', array('!file' => l($file->data['files'][$id], $file->data['files'][$id])))
+        t('File: !file', array('!file' => $file_link))
       );
     }
     // build the header
@@ -1297,11 +1300,28 @@ function media_mover_ui_edit_file_form($form, &$form_state, $file) {
     '#rows' => 10,
   );
 
-  $form['file']['nid'] = array(
-    '#title' => "Node ID",
+  // Entity API
+  $entity_type_options = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    $entity_type_options[$entity_type] = $entity_info['label'];
+  }
+  $form['file']['entity'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Entity'),
+  );
+  $form['file']['entity']['entity_type'] = array(
+    '#title' => t('Entity type'),
+    '#type' => 'select',
+    '#options' => $entity_type_options,
+    '#default_value' => ! empty($file->entity_type) ? $file->entity_type : NULL,
+    '#description' => t('File is associated with this Entity type. You can assocate a Media Mover file with one Entity type/ID.'),
+  );
+  // @todo: Add javascript to switch entity id <-> entity name and autofill JS popup
+  $form['file']['entity']['entity_id'] = array(
+    '#title' => t('Entity ID'),
     '#type' => 'textfield',
-    '#default_value' => ! empty($file->nid) ? $file->nid : NULL,
-    '#description' => t('File is associated with this Node ID. You can assocate a Media Mover file with one NID'),
+    '#default_value' => ! empty($file->entity_id) ? $file->entity_id : NULL,
+    '#description' => t('File is associated with this Entity ID. You can assocate a Media Mover file with one Entity type/ID'),
   );
 
   $options = media_mover_api_file_status();
@@ -1337,7 +1357,9 @@ function media_mover_ui_edit_file_form($form, &$form_state, $file) {
 function media_mover_ui_edit_file_form_submit($form, &$form_state) {
 
   $file = new media_mover_file($form_state['values']['mmfid']);
-  $file->nid = $form_state['values']['nid'];
+// @todo: implement Validation that entity type/id exist
+  $file->entity_type = $form_state['values']['entity_type'];
+  $file->entity_id = $form_state['values']['entity_id'];
   if ($file->status != $form_state['values']['status']) {
     $file->status_set('*', $form_state['values']['status']);
     $file->status = $form_state['values']['status'];
diff --git a/modules/mm_token/mm_token.module b/modules/mm_token/mm_token.module
index a1ba696..7c74e8d 100644
--- a/modules/mm_token/mm_token.module
+++ b/modules/mm_token/mm_token.module
@@ -88,7 +88,8 @@ function mm_token_token_list($type = 'all') {
   if ($type == 'mm_file' || $type == 'all') {
     $tokens['Media Mover File'] = array(
 	    'mmfid' => t('Media Mover File Id'),
-	    'nid' => t('Node Id of assocaited node (if any)'),
+	    'entity_type' => t('Entity type of associated entity (if any)'),
+	    'entity_id' => t('Entity Id of associated entity (if any)'),
 	    'fid' => t('File Id of associated file type entry (if any)'),
 	    'cid' => t('Media Mover configuration from whence this file came'),
 	    'harvest_file' => t('Path to harvested file'),
diff --git a/modules/mm_views/mm_views.module b/modules/mm_views/mm_views.module
index 88d9b27..9de9802 100644
--- a/modules/mm_views/mm_views.module
+++ b/modules/mm_views/mm_views.module
@@ -154,6 +154,7 @@ function mm_views_select($step) {
  * @return array of tables
  */
 function mm_views_views_tables() {
+// @todo: Entity API, update
   $table = views_new_table('media_mover_files', 'internal', 'node', 'nid', 'nid');
   views_table_add_filter($table, 'cid', 'Media Mover: Configuration files', t('This will filter a view to nodes that have files with files generated by this Media Mover configuration.'),
     array(
@@ -195,6 +196,7 @@ function views_handler_filter_media_mover_api_list() {
 function views_handler_filter_media_mover_api_custom($op, $filter, $filterinfo, &$query) {
 
   $tablename = $query->get_table_name('media_mover_files', $num);
+// @todo: Entity API, update
   $query->add_table($tablename, FALSE, 1, array('left' => array('table' => 'node', 'field' => 'nid'), 'right' => array('field' => 'nid')));
 
   // build the where clause
