 ultimate_cron.admin.inc |    8 +--
 ultimate_cron.drush.inc |    4 +-
 ultimate_cron.info      |    1 +
 ultimate_cron.install   |   98 +++++++++++++++++++++++++++--------
 ultimate_cron.module    |  128 ++++++++++++++++-------------------------------
 5 files changed, 125 insertions(+), 114 deletions(-)

diff --git a/ultimate_cron.admin.inc b/ultimate_cron.admin.inc
index b18ecb9..fe5c714 100755
--- a/ultimate_cron.admin.inc
+++ b/ultimate_cron.admin.inc
@@ -117,7 +117,6 @@ function ultimate_cron_function_settings_form($form, &$form_state, $function) {
   // Load settings
   $hooks = ultimate_cron_get_hooks();
   $hook = $hooks[$function];
-  $fid = $hook['fid'];
   $conf = ultimate_cron_get_settings($function);
   $conf += _ultimate_cron_default_settings();
 
@@ -245,7 +244,7 @@ function ultimate_cron_view_page($module = NULL) {
       $hook['settings'] = $data[$function]['settings'] + $hook['settings'];
       $hook['settings'] += _ultimate_cron_default_settings();
       $hook['background_process'] = $data[$function]['background_process'];
-      $hook['log'] = ultimate_cron_get_log($hook['fid']);
+      $hook['log'] = ultimate_cron_get_log($function);
       $modules[$hook['module']][$function] = $hook;
     }
   }
@@ -382,14 +381,13 @@ function ultimate_cron_function_log_page($function) {
 
   drupal_set_title(check_plain($function));
 
-  $fid = ultimate_cron_get_function_id($function);
   $query = db_select('ultimate_cron_log', 'l');
-  $query = $query->condition('l.fid', $fid)
+  $query = $query->condition('l.function', $function)
              ->extend('PagerDefault')
                ->limit(10)
              ->extend('TableSort')
                ->orderByHeader($header)
-             ->fields('l', array('lid', 'fid', 'start', 'end', 'status', 'msg'))
+             ->fields('l', array('lid', 'function', 'start', 'end', 'status', 'msg'))
              ->orderBy('l.start', 'DESC');
   $logs = $query->execute()->fetchAll();
 
diff --git a/ultimate_cron.drush.inc b/ultimate_cron.drush.inc
index dcee2b8..c19c3f4 100644
--- a/ultimate_cron.drush.inc
+++ b/ultimate_cron.drush.inc
@@ -118,7 +118,7 @@ function drush_ultimate_cron_cron_list($type = 'all') {
     $hook['settings'] = $data[$function]['settings'] + $hook['settings'];
     $hook['settings'] += _ultimate_cron_default_settings();
     $hook['background_process'] = $data[$function]['background_process'];
-    $hook['log'] = ultimate_cron_get_log($hook['fid']);
+    $hook['log'] = ultimate_cron_get_log($function);
 
     switch ($type) {
       case 'enabled':
@@ -247,7 +247,7 @@ function drush_ultimate_cron_cron_unlock($function) {
     return drush_set_error(dt('"!function" not found', array('!function' => $function)));
   }
 
-  $handle = 'ultimate_cron:' . $hooks[$function]['fid'];
+  $handle = 'ultimate_cron:' . $function;
   if ($process = background_process_get_process($handle)) {
     // Unlock the process
     if (background_process_remove_process($process->handle, $process->start)) {
diff --git a/ultimate_cron.info b/ultimate_cron.info
index c1d139d..637a4b3 100644
--- a/ultimate_cron.info
+++ b/ultimate_cron.info
@@ -4,5 +4,6 @@ core = 7.x
 
 dependencies[] = background_process
 dependencies[] = progress
+dependencies[] = ctools
 
 configure = admin/config/system/cron/settings
diff --git a/ultimate_cron.install b/ultimate_cron.install
index 29652f8..98e41ad 100755
--- a/ultimate_cron.install
+++ b/ultimate_cron.install
@@ -11,14 +11,28 @@
 function ultimate_cron_schema() {
   $schema = array();
 
-  $schema['ultimate_cron_function'] = array(
+  $schema['ultimate_cron'] = array(
     'description' => 'Cron job function list',
+    'export' => array(
+      'key' => 'function',
+      'key name' => 'Function name',
+      'primary key' => 'fid',
+      'identifier' => 'function',
+      'default hook' => 'default_ultimate_cron_function',
+      'api' => array(
+        'owner' => 'ultimate_cron',
+        'api' => 'default_ultimate_cron_functions',
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
     'fields' => array(
       'fid' => array(
         'description' => 'Function ID',
         'type' => 'serial',
         'size' => 'normal',
         'not null' => TRUE,
+        'no export' => TRUE,
       ),
       'function' => array(
         'description' => 'Function name',
@@ -26,27 +40,15 @@ function ultimate_cron_schema() {
         'length' => 127,
         'not null' => TRUE,
       ),
-    ),
-    'primary key' => array('fid'),
-    'unique key' => array('function'),
-  );
-
-  $schema['ultimate_cron_configuration'] = array(
-    'description' => 'Cron job configuration',
-    'fields' => array(
-      'fid' => array(
-        'description' => 'Function ID',
-        'type' => 'int',
-        'size' => 'normal',
-        'not null' => TRUE,
-      ),
-      'configuration' => array(
-        'description' => 'Configuration',
+      'settings' => array(
+        'description' => 'Settings',
         'type' => 'text',
+        'serialize' => TRUE,
         'not null' => FALSE,
       ),
     ),
     'primary key' => array('fid'),
+    'unique key' => array('function'),
   );
 
   $schema['ultimate_cron_log'] = array(
@@ -58,10 +60,10 @@ function ultimate_cron_schema() {
         'size' => 'normal',
         'not null' => TRUE,
       ),
-      'fid' => array(
-        'description' => 'Function ID',
-        'type' => 'int',
-        'size' => 'normal',
+      'function' => array(
+        'description' => 'Function name',
+        'type' => 'varchar',
+        'length' => 127,
         'not null' => TRUE,
       ),
       'start' => array(
@@ -93,8 +95,8 @@ function ultimate_cron_schema() {
     ),
     'primary key' => array('lid'),
     'indexes' => array(
-       'idx_last' => array('fid', 'start'),
-       'idx_count' => array('fid', 'end'),
+       'idx_last' => array('function', 'start'),
+       'idx_count' => array('function', 'end'),
     ),
   );
 
@@ -137,3 +139,53 @@ function ultimate_cron_update_7001() {
     variable_set('ultimate_cron_queue_polling_latency', $polling_latency);
   }
 }
+
+/**
+ * Merge ultimate_cron_function and ultimate_cron_configuration into ultimate_cron
+ */
+function ultimate_cron_update_7002() {
+  $schema = ultimate_cron_schema();
+  db_create_table('ultimate_cron', $schema['ultimate_cron']);
+  db_query("INSERT INTO {ultimate_cron} SELECT f.fid, f.function, c.configuration AS settings FROM ultimate_cron_function f LEFT JOIN ultimate_cron_configuration c ON f.fid = c.fid");
+  db_drop_table('ultimate_cron_function');
+  db_drop_table('ultimate_cron_configuration');
+}
+
+/**
+ * Switch from fid to function name in ultimate_cron_log, background_process, and progress
+ */
+function ultimate_cron_update_7003() {
+  $processes = db_select('background_process', 'b')->fields('b', array('handle'))->condition('handle', 'ultimate_cron:%', 'LIKE')->execute();
+  while ($process = $processes->fetchObject()) {
+    $old_handle = $process->handle;
+    $fid = str_replace('ultimate_cron:', '', $old_handle);
+    if (is_numeric($fid)) {
+      $function = db_select('ultimate_cron', 'u')->fields('u', array('function'))->condition('fid', $fid, '=')->execute()->fetchObject();
+      $new_handle = 'ultimate_cron:' . $function->function;
+      db_update('background_process')->fields(array('handle' => $new_handle))->condition('handle', $old_handle, '=')->execute();
+    }
+  }
+  $progresses = db_select('progress', 'p')->fields('p', array('name'))->condition('name', 'ultimate_cron:%', 'LIKE')->execute();
+  while ($progress = $progresses->fetchObject()) {
+    $old_name = $progress->name;
+    $fid = str_replace('ultimate_cron:', '', $old_name);
+    if (is_numeric($fid)) {
+      $function = db_select('ultimate_cron', 'u')->fields('u', array('function'))->condition('fid', $fid, '=')->execute()->fetchObject();
+      $new_name = 'ultimate_cron:' . $function->function;
+      db_update('progress')->fields(array('name' => $new_name))->condition('name', $old_name, '=')->execute();
+    }
+  }
+  db_add_field('ultimate_cron_log', 'function', array(
+        'description' => 'Function name',
+        'type' => 'varchar',
+        'length' => 127,
+        'not null' => TRUE,
+        'initial' => 'function',
+      ));
+  $fids = db_select('ultimate_cron_log', 'u')->fields('u', array('fid'))->execute();
+  while ($fid = $fids->fetchObject()) {
+    $function = db_select('ultimate_cron', 'u')->fields('u', array('function'))->condition('fid', $fid->fid, '=')->execute()->fetchObject();
+    db_update('ultimate_cron_log')->fields(array('function' => $function->function))->condition('fid', $fid->fid, '=')->execute();
+  }
+  db_drop_field('ultimate_cron_log', 'fid');
+}
diff --git a/ultimate_cron.module b/ultimate_cron.module
index ab2f6f4..3d0a6eb 100755
--- a/ultimate_cron.module
+++ b/ultimate_cron.module
@@ -5,7 +5,6 @@
  * @todo Add filter on overview page.
  * @todo Add log view (with graph).
  * @todo Make proper markup for overview page.
- * @fixme settings is called configuration in DB ... urk!
  *
  * hook_cron_alter(&$hooks)
  * hook_cron_schedule_alter(&$hooks)
@@ -239,7 +238,7 @@ function ultimate_cron_cron($return = FALSE) {
 
       // Handle errors.
       if ($result) {
-        $handle = 'ultimate_cron:' . $hook['fid'];
+        $handle = 'ultimate_cron:' . $function;
         $running[$handle] = $result;
         unset($schedule[$function]);
         $launched++;
@@ -452,13 +451,13 @@ function ultimate_cron_exit($destination = NULL) {
  */
 function ultimate_cron_background_process_shutdown($process, $shutdown_msg = NULL) {
   $args = func_get_args();
-  $fid = str_replace('ultimate_cron:', '', $process->handle);
-  if (is_numeric($fid)) {
+  $function = str_replace('ultimate_cron:', '', $process->handle);
+  if (!empty($function)) {
     static $has_run = array();
-    if (!empty($has_run[$fid])) {
+    if (!empty($has_run[$function])) {
       return;
     }
-    $has_run[$fid] = TRUE;
+    $has_run[$function] = TRUE;
 
     // Record end time
     $end = microtime(TRUE);
@@ -497,7 +496,7 @@ function ultimate_cron_background_process_shutdown($process, $shutdown_msg = NUL
 
     // log results here ...
     $object = (object)array(
-      'fid' => $fid,
+      'function' => $function,
       'start' => $process->start,
       'end' => $end,
       'status' => $result,
@@ -649,7 +648,7 @@ function ultimate_cron_function_settings_form_access($function) {
 function ultimate_cron_run_hook($function, $hook) {
   // Run the job in background
   $result = NULL;
-  $handle = "ultimate_cron:" . $hook['fid'];
+  $handle = "ultimate_cron:" . $function;
   $process = new BackgroundProcess($handle);
 
   // Always run cron job as anonymous user
@@ -689,7 +688,7 @@ function _ultimate_cron_run_hook($function, $hook) {
 
   // Load log if not present
   if (!isset($hook['log'])) {
-    $hook['log'] = ultimate_cron_get_log($hook['fid']);
+    $hook['log'] = ultimate_cron_get_log($function);
   }
 
   $time = time();
@@ -772,7 +771,7 @@ function ultimate_cron_load_hook_data(&$hook) {
   $hook['settings'] = ultimate_cron_get_settings($hook['function']) + $hook['settings'];
 
   // Get log, used for checking last start time
-  $hook['log'] = ultimate_cron_get_log($hook['fid']);
+  $hook['log'] = ultimate_cron_get_log($function);
 }
 
 /**
@@ -847,7 +846,6 @@ function ultimate_cron_get_hooks() {
 
   foreach ($hooks as $function => &$hook) {
     $hook['callback'] = $hook['function'] = $function;
-    $hook['fid'] = ultimate_cron_get_function_id($function);
   }
 
   // Remove ourselves from the list
@@ -916,46 +914,39 @@ function ultimate_cron_unsafe_hooks() {
 /**
  * Get settings for a function.
  *
- * @param $function
+ * @param $function_name
  * @return array
  *   Settings for function
  */
-function ultimate_cron_get_settings($function) {
-  $fid = ultimate_cron_get_function_id($function);
-  if (!$fid) {
-    return NULL;
+function ultimate_cron_get_settings($function_name) {
+  ctools_include('export');
+  $function = ctools_export_crud_load('ultimate_cron', $function_name);
+  if (!isset($function->settings)) {
+    $function->settings = '';
   }
-
-  $conf = db_query("SELECT fid, configuration FROM {ultimate_cron_configuration} WHERE fid = :fid", array(':fid' => $fid))->fetchObject();
-  $conf = $conf && $conf->configuration ? unserialize($conf->configuration) : array();
-  if (empty($conf['catch_up'])) {
-    unset($conf['catch_up']);
+  $settings = (array)$function->settings;
+  if (empty($settings['catch_up'])) {
+    unset($settings['catch_up']);
   }
-  return $conf;
+  return $settings;
 }
 
 /**
  * Set settings for a function.
  *
- * @param $function
+ * @param $function_name
  *   Function to set settings for.
- * @param $conf
+ * @param $settings
  *   Settings data
  * @return boolean
  *   TRUE on success, FALSE on failure.
  */
-function ultimate_cron_set_settings($function, $conf) {
-  $fid = ultimate_cron_get_function_id($function);
-  if (!$fid) {
-    return NULL;
-  }
-
-  return db_merge('ultimate_cron_configuration')
-    ->key(array('fid' => $fid))
-    ->fields(array(
-      'configuration' => serialize($conf),
-    ))
-    ->execute();
+function ultimate_cron_set_settings($function_name, $settings) {
+  ctools_include('export');
+  $function = ctools_export_crud_new('ultimate_cron');
+  $function->function = $function_name;
+  $function->settings = $settings;
+  ctools_export_crud_save('ultimate_cron', $function);
 }
 
 /**
@@ -966,12 +957,12 @@ function ultimate_cron_set_settings($function, $conf) {
  * @return object
  *   Log line.
  */
-function ultimate_cron_get_log($fid) {
+function ultimate_cron_get_log($function) {
   $log = db_query_range("
     SELECT l.* FROM {ultimate_cron_log} l
-    WHERE l.fid = :fid
+    WHERE l.function = :function
     ORDER BY l.start DESC",
-    0, 1, array(':fid' => $fid))
+    0, 1, array(':function' => $function))
       ->fetchAssoc();
   return $log;
 }
@@ -1082,37 +1073,6 @@ function ultimate_cron_easy_hooks_rule($hook = NULL) {
 }
 
 /**
- * Get function ID based on function name. Will create the function in the
- * ultimate_cron_function table, if it doesn't exist.
- *
- * @param $function
- *   Function name
- * @return integer
- *   Function ID.
- */
-function ultimate_cron_get_function_id($function) {
-  static $ids = array();
-  if (isset($ids[$function])) {
-    return $ids[$function];
-  }
-  $fid = db_query("SELECT fid FROM {ultimate_cron_function} WHERE `function` = :function ", array(':function' => $function))->fetchField();
-  if (!$fid) {
-    try {
-      $fid = db_insert('ultimate_cron_function')
-        ->fields(array(
-          'function' => $function
-        ))
-        ->execute();
-    }
-    catch (Exception $e) {
-      $fid = db_query("SELECT fid FROM {ultimate_cron_function} WHERE `function` = :function ", array(':function' => $function))->fetchField();
-    }
-  }
-  $ids[$function] = $fid;
-  return $fid;
-}
-
-/**
  * Reclaims position as the first module in the module list.
  */
 function ultimate_cron_reclaim() {
@@ -1146,21 +1106,21 @@ function ultimate_cron_module_name($module) {
  *   Array of cronjobs and their data.
  */
 function _ultimate_cron_preload_cron_data() {
-  $result = db_query("
-SELECT f.fid, f.function, c.configuration, p.handle, p.service_host, p.start
-FROM {ultimate_cron_function} f
-LEFT JOIN {ultimate_cron_configuration} c ON f.fid = c.fid
-LEFT JOIN {background_process} p ON p.handle = CONCAT('ultimate_cron:', f.fid)
-");
-
+  ctools_include('export');
+  $functions = ctools_export_crud_load_all('ultimate_cron');
   $data = array();
-  while ($row = $result->fetchObject()) {
-    $data[$row->function] = array(
-      'settings' => $row->configuration ? unserialize($row->configuration) : array(),
-      'background_process' => empty($row->handle) ? NULL : (object)array(
-        'handle' => $row->handle,
-        'service_host' => $row->service_host,
-        'start' => $row->start,
+  foreach ($functions as $function_name => $function) {
+    if (!isset($function->settings)) {
+      $function->settings = '';
+    }
+    $handle = 'ultimate_cron:' . $function_name;
+    $process = db_select('background_process', 'b')->fields('b', array('handle', 'service_host', 'start'))->condition('handle', $handle, '=')->execute()->fetchObject();
+    $data[$function_name] = array(
+      'settings' => (array)$function->settings,
+      'background_process' => empty($process->handle) ? NULL : (object)array(
+        'handle' => $process->handle,
+        'service_host' => $process->service_host,
+        'start' => $process->start,
       ),
     );
   }
