<?php
// $Id: convert.inc,v 1.8 2008/05/19 16:09:48 merlinofchaos Exp $
/**
 * @file convert.inc
 *
 * Contains forms and routines to convert older views to newer views.
 */

/**
 * Page callback for the tools - Views 1 convert page
 */
function views_ui_admin_convert() {
  if (!db_table_exists('view_view')) {
    return t('There are no Views 1 views stored in the database to convert.');
  }
  $items = array();
  $sorts = array();

  $header = array(
    array('data' => t('View name'), 'field' => 'name', 'sort' => 'asc'),
    array('data' => t('Description')),
    array('data' => t('Operations')),
  );
  $current_views = views_get_all_views();

  $result = db_query("SELECT v.* FROM {view_view} v");
  while ($view = db_fetch_object($result)) {
    $ops = array();
    if (!isset($current_views[$view->name])) {
      $ops[] = l(t('Convert'), "admin/build/views1/convert/$view->name");
    }
    else {
      $ops[] = t('Converted');
    }
    $ops[] = l(t('Delete'), "admin/build/views1/delete/$view->name");

    $item = array();
    $item[] = check_plain($view->name);
    $item[] = check_plain($view->description);
    $item[] = implode(' | ', $ops);
    $items[] = $item;

    $ts = tablesort_init($header);
    switch ($ts['sql']) {
      case 'name':
      default:
        $sorts[] = $item[0];
        break;
      case 'title':
        $sorts[] = $item[1];
        break;
    }
  }

  if (!empty($ts)) {
    if (strtolower($ts['sort']) == 'desc') {
      arsort($sorts);
    }
    else {
      asort($sorts);
    }
  }

  $i = array();
  foreach ($sorts as $id => $title) {
    $i[] = $items[$id];
  }
  $output = t('The table below lists Views version 1 views that are stored in the database. You can either convert them to work in Views version 2, or delete them. The views are convertible only if there is no Views 2 view with the same name.');
  $output .= theme('table', $header, $i);
  return $output;
}

/**
 * Page callback for the tools - Views 1 convert page
 */
function views_ui_convert1($name) {
  $old = views1_load($name);
  if (!$old) {
    return t('Unable to find view.');
  }

  $view = views1_import($old);

  if ($view) {
    views_ui_cache_set($view);
    drupal_goto('admin/build/views/edit/' . $view->name);
  }
  else {
    return t('Unable to convert view.');
  }
}

/**
 * Page to delete a Views 1 view.
 */
function views_ui_delete1_confirm(&$form_state, $vid) {
  $form_state['vid'] = $vid;
  $form = array();

  $cancel = 'admin/build/views/tools/convert';
  if (!empty($_REQUEST['cancel'])) {
    $cancel = $_REQUEST['cancel'];
  }
  return confirm_form($form,
                  t('Are you sure you want to delete the view %name?',
                  array('%name' => $view->name)),
                  $cancel,
                  t('This action cannot be undone.'),
                  t('Delete'),
                  t('Cancel'));
}

/**
 * Submit handler to delete a view.
 */
function views_ui_delete1_confirm_submit(&$form, &$form_state) {
  views1_delete($form_state['vid']);
  drupal_set_message(t('The view has been deleted'));
  $form_state['redirect'] = 'admin/build/views/tools/convert';
}

/**
 * Convert a Views 1 view to a Views 2 view.
 */
function views1_import($imported) {
  views_module_include('views_convert.inc');

  $view = views_new_view();

  $view->name = $imported->name;
  $view->description = $imported->description;

  if (!empty($imported->page)) {
    $view->add_display('page');
  }
  if (!empty($imported->block)) {
    $view->add_display('block');
  }
  $view->init_display();

  $handler = &$view->display['default']->handler;
  $handler->set_option('title', $imported->page_title);
  $handler->set_option('header', $imported->page_header);
  $handler->set_option('header_format', $imported->page_header_format);
  $handler->set_option('footer', $imported->page_footer);
  $handler->set_option('footer_format', $imported->page_footer_format);
  $handler->set_option('empty', $imported->page_empty);
  $handler->set_option('empty_format', $imported->page_empty_format);

  $handler->set_option('use_pager', $imported->use_pager);
  $handler->set_option('items_per_page', $imported->nodes_per_page);
  $handler->set_option('pager_element', 0);
  $handler->set_option('offset', 0);

  $access = array('type' => 'none', 'role' => array(), 'perm' => '');
  if ($imported->access) {
    $access['type'] = 'role';
    $access['role'] = drupal_map_assoc($imported->access);
  }

  $handler->set_option('access', $access);

  if (!empty($imported->page)) {
    $handler = &$view->display['page']->handler;
    $url = str_replace('$arg', '%', $imported->url);
    $handler->set_option('path', $url);
    if ($imported->menu) {
      $menu = array('type' => 'normal');
      if ($imported->menu_tab) {
        $menu['type'] = 'tab';
      }
      if ($imported->menu_tab_default) {
        $menu['type'] = 'default tab';
      }
      $menu['title'] = $imported->menu_title;
      $handler->set_option('menu', $menu);

      if ($menu['type'] == 'default tab') {
        $tab_options = array('type' => 'none');
        switch ($imported->menu_tab_default_parent_type) {
          case 'tab':
          case 'normal':
            $tab_options['type'] = $imported->menu_tab_default_parent_type;
            break;
        }
      }
      $tab_options['title'] = $imported->menu_parent_title;
      $tab_options['weight'] = $imported->menu_parent_tab_weight;
      $handler->set_option('tab_options', $tab_options);
    }

    views1_convert_style($view, $handler, $imported->page_type);
  }

  if (!empty($imported->block)) {
    $handler = &$view->display['block']->handler;

    if ($imported->block_title) {
      $handler->set_override('title');
      $handler->set_option('title', $imported->block_title);
    }

    if ($imported->nodes_per_block != $imported->nodes_per_page) {
      $handler->set_override('items_per_page');
      $handler->set_option('items_per_page', $imported->nodes_per_block);
      $handler->set_option('offset', 0);
    }

    if (empty($imported->block_use_page_header)) {
      $handler->set_override('header');
      $handler->set_option('header', $imported->block_header);
      $handler->set_option('header_format', $imported->block_header_format);
    }
    if (empty($imported->block_use_page_footer)) {
      $handler->set_override('footer');
      $handler->set_option('footer', $imported->block_footer);
      $handler->set_option('footer_format', $imported->block_footer_format);
    }
    if (empty($imported->block_use_page_empty)) {
      $handler->set_override('empty');
      $handler->set_option('empty', $imported->block_empty);
      $handler->set_option('empty_format', $imported->block_empty_format);
    }

    $handler->set_option('more', $imported->block_more);

    $handler->set_override('style_plugin');
    views1_convert_style($view, $handler, $imported->block_type);
  }

  // For each of the fields, arguments, filters, and sorts in the old view,
  // check if a handler for this item exists in Views 2 and add it,
  // then see if any other modules want to adapt it using hook_views_convert().

  foreach ($imported->field as $field) {
    $id = NULL;
    if (views_get_handler($field['tablename'], $field['field'], 'field')) {
      $id = $view->add_item('default', 'field', $field['tablename'], $field['field']);
    }
    if ($view->display_handler->get_option('style_plugin') == 'table') {
      $options = $view->display_handler->get_option('style_options');
      if (!empty($field['defaultsort'])) {
        $options['default'] = $id;
      }
      if (!empty($field['sortable'])) {
        $options['info'][$id]['sortable'] = TRUE;
      }
      $view->display_handler->set_option('style_options', $options);
    }

    if (!empty($field['label'])) {
    $item = $view->get_item('default', 'field', $id);
      $item['label'] = $field['label'];
      $view->set_item('default', 'field', $id, $item);
    }
    foreach (module_implements('views_convert') as $module) {
      module_invoke($module, 'views_convert', 'default', 'field', $view, $field, $id);
    }
  }
  foreach ($imported->sort as $field) {
    $id = NULL;
    if (views_get_handler($field['tablename'], $field['field'], 'sort')) {
      $id = $view->add_item('default', 'sort', $field['tablename'], $field['field']);
    }
    foreach (module_implements('views_convert') as $module) {
      module_invoke($module, 'views_convert', 'default', 'sort', $view, $field, $id);
    }
  }
  foreach ($imported->argument as $field) {
    // Arguments didn't used to be identified by table.name so we just have to
    // leave that out.
    foreach (module_implements('views_convert') as $module) {
      module_invoke($module, 'views_convert', 'default', 'argument', $view, $field, NULL);
    }
  }
  foreach ($imported->filter as $field) {
    $id = NULL;
    if (views_get_handler($field['tablename'], $field['field'], 'filter')) {
      $id = $view->add_item('default', 'filter', $field['tablename'], $field['field']);
    }
    foreach (module_implements('views_convert') as $module) {
      module_invoke($module, 'views_convert', 'default', 'filter', $view, $field, $id);
    }
  }
  // Exposed filters now get added to the filter array, not as a separate array.
  $count = 0;
  foreach ($imported->exposed_filter as $field) {
    if (views_get_handler($field['tablename'], $field['field'], 'filter')) {
      $view->display['default']->display_options['filters'][$field['field']]['exposed'] = 1;

      // Use the count to emulate the old, hardcoded filter naming.
      $view->display['default']->display_options['filters'][$field['field']]['expose']['identifier'] = 'filter' . $count;
      $view->display['default']->display_options['filters'][$field['field']]['expose']['label'] = $field['label'];
      $view->display['default']->display_options['filters'][$field['field']]['expose']['operator'] = $field['operator'] ? 'op' . $count : '';
      $view->display['default']->display_options['filters'][$field['field']]['expose']['optional'] = $field['optional'];
      $view->display['default']->display_options['filters'][$field['field']]['expose']['single'] = $field['single'];
    }
    $count++;
    foreach (module_implements('views_convert') as $module) {
      module_invoke($module, 'views_convert', 'default', 'exposed_filter', $view, $field, $field['field']);
    }
  }

  return $view;
}

function views1_convert_style(&$view, &$handler, $type) {
  switch ($type) {
    case 'list':
      $handler->set_option('style_plugin', 'list');
      $handler->set_option('style_options', array('type' => 'ul'));
      $handler->set_option('row_plugin', 'fields');
      break;
    case 'node':
      $handler->set_option('row_plugin', 'node');
      $handler->set_option('row_options', array('teaser' => FALSE, 'links' => TRUE));
      break;
    case 'teaser':
      $handler->set_option('row_plugin', 'node');
      $handler->set_option('row_options', array('teaser' => TRUE, 'links' => TRUE));
      break;
    case 'table':
      $options = array();
      $options['columns'] = array();
      $options['default'] = '';
      $options['info'] = array();
      $options['override'] = FALSE;
      $options['order'] = 'asc';

      $handler->set_option('style_plugin', 'table');
      $handler->set_option('style_options', $options);
      break;
    default:
      // Ask around if anybody else knows.
      foreach (module_implements('views_convert') as $module) {
        module_invoke($module, 'views_convert', $handler->id, 'style', $view, $type);
      }
  }
}
/**
 * Load a version 1 view from the database.
 *
 */
function views1_load($arg) {
  static $cache = array();
  $which = is_numeric($arg) ? 'vid' : 'name';
  if (isset($cache[$which][$arg])) {
    return $cache[$which][$arg];
  }

  $where = (is_numeric($arg) ? "v.vid =  %d" : "v.name = '%s'");
  $view = db_fetch_object(db_query("SELECT v.* FROM {view_view} v WHERE $where", $arg));

  if (!$view->name) {
    return NULL;
  }

  $view->access = ($view->access ? explode(', ', $view->access) : array());

  // load the sorting criteria too.
  $result = db_query("SELECT * FROM {view_sort} vs WHERE vid = $view->vid ORDER BY position ASC");

  $view->sort = array();
  while ($sort = db_fetch_array($result)) {
    if (substr($sort['field'], 0, 2) == 'n.') {
      $sort['field'] = 'node' . substr($sort['field'], 1);
    }
    $sort['id'] = $sort['field'];
    $view->sort[] = $sort;
  }

  $result = db_query("SELECT * FROM {view_argument} WHERE vid = $view->vid ORDER BY position ASC");

  $view->argument = array();
  while ($arg = db_fetch_array($result)) {
    $arg['id'] = $arg['type'];
    $view->argument[] = $arg;
  }

  $result = db_query("SELECT * FROM {view_tablefield} WHERE vid = $view->vid ORDER BY position ASC");

  $view->field = array();
  while ($arg = db_fetch_array($result)) {
    if ($arg['tablename'] == 'n') {
      $arg['tablename'] = 'node';
    }
    $arg['id'] = $arg['fullname'] = "$arg[tablename].$arg[field]";
    $arg['queryname'] = "$arg[tablename]_$arg[field]";
    $view->field[] = $arg;
  }

  $result = db_query("SELECT * FROM {view_filter} WHERE vid = $view->vid ORDER BY position ASC");

  // TODO - Is it safe to ignore this $filters variable? This function depends
  // on lots of additional code needed to call hook_implements and construct
  // all the views tables, so using it will add a lot of code to this file.
  //$filters = _views_get_filters();
  $view->filter = array();
  while ($filter = db_fetch_array($result)) {
    if (substr($filter['field'], 0, 2) == 'n.') {
      $filter['field'] = 'node' . substr($filter['field'], 1);
    }

    if ($filter['operator'] == 'AND' ||
        $filter['operator'] == 'OR' ||
        $filter['operator'] == 'NOR' ||
        $filters[$filter['field']]['value-type'] == 'array' ) {
      if ($filter['value'] !== NULL && $filter['value'] !== '') {
        $filter['value'] = explode(',', $filter['value']);
      }
      else {
        $filter['value'] = array();
      }
    }
    $filter['id'] = $filter['field'];
    $view->filter[] = $filter;
  }

  $result = db_query("SELECT * FROM {view_exposed_filter} WHERE vid = $view->vid ORDER BY position ASC");

  $view->exposed_filter = array();
  while ($arg = db_fetch_array($result)) {
    $arg['id'] = $arg['field'];
    $view->exposed_filter[] = $arg;
  }

  $cache['vid'][$view->vid] = $view;
  $cache['name'][$view->name] = $view;

  return $view;
}

/**
 * Delete a version 1 view from the database.
 *
 */
function views1_delete($arg) {
  static $cache = array();
  $where = (is_numeric($arg) ? "v.vid =  %d" : "v.name = '%s'");
  $view = db_fetch_object(db_query("SELECT v.* FROM {view_view} v WHERE $where", $arg));

  if (!$view->name) {
    return NULL;
  }

  $result = db_query("DELETE * FROM {view_sort} vs WHERE vid = $view->vid");
  $result = db_query("DELETE * FROM {view_argument} WHERE vid = $view->vid");
  $result = db_query("DELETE * FROM {view_tablefield} WHERE vid = $view->vid");
  $result = db_query("DELETE * FROM {view_filter} WHERE vid = $view->vid");
  $result = db_query("DELETE * FROM {view_exposed_filter} WHERE vid = $view->vid");
  $result = db_query("DELETE * FROM {view_view} WHERE vid = $view->vid");
}

