<?php

/**
 * @file
 * Enables users to save their current exposed filter settings for views.
 */

/**
 * Implements hook_menu().
 */
function easy_history_menu() {
  $items['admin/config/easy_history'] = array(
    'title' => 'Easy History',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('easy_history_settings'),
    'access arguments' => array('administer content')
  );
  $items['views-save/%easy_history'] = array(
    'title' => 'Saved views',
    'access callback' => FALSE,
  );

  return $items;
}

function easy_history_settings_validate($form,  &$form_state) {
  switch ($form_state['values']['warp_history']) {
  case 'anon':
    db_query('delete from {easy_history} where uid=0');
    drupal_set_message('Anonymous statistics deleted');
    break;
  case 'all':
    db_query('delete from {easy_history}');
    drupal_set_message('All search history deleted');
    break;
  }
}
function easy_history_settings($form_id, &$form_state) {
  $views = views_get_all_views();
  $vids = array_map(function($v) { return $v->name; }, $views);
  $form = array(
    'easy_history_track_anonymous' => array(
      '#type' => 'checkbox',
      '#default_value' => variable_get('easy_history_track_anonymous', false),
      '#title' => 'Track searches for anonymous',
    ),
    'easy_history_views_to_track' => array(
      '#type' => 'checkboxes',
      '#title' => t('Views should be tracked'),
      '#default_value' => array_values(variable_get('easy_history_views_to_track', array('diamond_search'))),
      '#options' => array_combine($vids, array_keys($views)), 
      '#description' => 'Only selected views vill be tracked, don`t forget to  revisit this page when you add a new view to the system',
      '#required' => true,
    ),
    'easy_history_text' => array(
      '#type'=>'textfield',
      '#default_value' => variable_get('easy_history_text','no'),
      '#title' => 'text'
    ),
    'warp_history' => array(
      '#type' => 'select',
      '#title' => 'Delete searches history',
      '#empty_value' => 'Select an option',
      '#options' => array('anon'=>'Delete anonymous history', 'all'=>'Delete all history')
    ),
  );
  return system_settings_form($form);
}
/**
 * HERERERERE it shows the view by overriding the GET  Implements hook_url_inbound_alter().
 */
function easy_history_url_inbound_alter(&$path) {
  if (arg(0) == 'views-save') {
    if (is_numeric($id = arg(1)) && (float) $id == (int) $id && count(arg())==2) {
      $id = (int) $id;
      $save = easy_history_load($id);
      if ($save && easy_history_display_access($save)) {
        $path = $save->view_path['path'];
        if (!empty($save->view_path['options']['query'])) {
          $_GET = $save->view_path['options']['query'] + $_GET;
        }
        $_GET['easy_history'] = $id;
      }
    }
  }
}

/**
 * Implements hook_theme().
 */
function easy_history_theme() {
  $theme['easy_history_modal'] = array(
    'variables' => array(),
  );
  $theme[ 'views_view_field__search_history__newsletter_date' ] = array( 
    'arguments' => array('view' => FALSE, 'field' => FALSE, 'row' => FALSE),
    'original hook' => 'views_view_field',
    'template' => 'newsletter-date-field',
    'path' => drupal_get_path('module', 'easy_history') . '/views',
  );
  $theme[ 'views_view_field__search_history__expression' ] = array( 
    'arguments' => array('view' => FALSE, 'field' => FALSE, 'row' => FALSE),
    'original hook' => 'views_view_field',
    'template' => 'updated-products-field',
    'path' => drupal_get_path('module', 'easy_history') . '/views',
  );
  return $theme;
}
/**
 * Implements hook_permission().
 */
function easy_history_permission() {
  $perms = array(
    'administer easy_history' => array(
      'title' => t('Administer Views Save'),
      'description' => t('Administer settings and fields for saved views.'),
    ),
    'create easy_history' => array(
      'title' => t('Use Views Save'),
      'description' => t('Save exposed filter settings for views. Anonymous users have to log in in any case, but without the permission no button will be displayed.'),
    ),
    'access easy_history' => array(
      'title' => t('View published saved views'),
    ),
    'view own unpublished easy_history' => array(
      'title' => t('View own unpublished saved views'),
    ),
  );



  return $perms;
}

/**
 * Implements hook_entity_info().
 */
function easy_history_entity_info() {
  $types['easy_history'] = array(
    'label' => t('Saved view'),
    'controller class' => 'EntityAPIController',
    'views controller class' => 'EntityDefaultViewsController',
    'entity class' => 'Entity',
    'base table' => 'easy_history',
    'uri callback' => 'easy_history_uri',
    'fieldable' => TRUE,
    'entity keys' => array(
      'id' => 'id',
      'label' => 'title',
    ),
    'module' => 'easy_history',
  );
  return $types;
}

/**
 * Implements hook_entity_property_info().
 */
function easy_history_entity_property_info() {
  $info['easy_history']['properties'] = array(
    'id' => array(
      'label' => t('ID'),
      'type' => 'integer',
      'description' => t('The primary identifier for a saved view.'),
      'schema field' => 'id',
      'validation callback' => 'entity_metadata_validate_integer_positive',
    ),
    'title' => array(
      'label' => t('Title'),
      'type' => 'text',
      'description' => t('The title of the saved view.'),
      'schema field' => 'title',
      'required' => TRUE,
    ),
    'status' => array(
      'label' => t('Status'),
      'type' => 'boolean',
      'description' => t('Whether the saved view is published or not.'),
      'schema field' => 'status',
      'options list' => 'easy_history_status_options_list',
    ),
    'user' => array(
      'label' => t('User'),
      'type' => 'user',
      'description' => t('The user who created this saved view.'),
      'schema field' => 'uid',
    ),
    'created' => array(
      'label' => t('Date created'),
      'type' => 'date',
      'description' => t('The date the saved view was created.'),
      'schema field' => 'created',
    ),
    'changed' => array(
      'label' => t('Date changed'),
      'type' => 'date',
      'description' => t('The date the saved view was last changed.'),
      'schema field' => 'changed',
    ),
    'view_path' => array(
      'label' => t('Path'),
      'type' => t('text'),
      'description' => t('The path to the saved view.'),
    ),
    'resultswas' => array(
      'label' => t('Initial resilts'),
      'type' => t('integer'),
      'description' => t('Results saved on history create.'),
      'schema field' => 'initcount'
    ),
    'resultslast' => array(
      'label' => t('Updated resilts'),
      'type' => t('integer'),
      'description' => t('Results saved on last check.'),
      'schema field' => 'currcount'
    ),
    'newsletter_date' => array(
      'label' => t('Newsletter created'),
      'type' => t('integer'),
      'description' => t('Newsletter creation date.'),
      'schema field' => 'newsletter_date'
    ),
    'newsletter_ref' => array(
      'label' => t('Newsletter node'),
      'type' => t('integer'),
      'description' => t('Newsletter node reference.'),
      'schema field' => 'newsletter_ref'
    ),
  );

  return $info;
}


/**
 * Implements hook_cron().
 *
 * Purge views saved by anonymous users that are older than a week.
 */
function easy_history_cron() {
  timer_start('cccc');
  $lastnodeupdate = db_query('select max(created) from {node}')->fetchField();
  $ids = db_query('SELECT id FROM {easy_history} where uid>0 AND changed<:lastnode limit 100', array(':lastnode'=>$lastnodeupdate))->fetchCol();
  $n=0;
  foreach ($ids as $id) {
    $hist = easy_history_load($id);
    $oldnodes = $hist->nodes;
    $q = db_query($hist->query);
    $newnodes = array();
    while ($nn=$q->fetchObject()) {
      $newnodes[] = $nn->nid;
    }
    $hist->changed = REQUEST_TIME;
    $hist->nodes = $newnodes;
    $hist->currcount = count($newnodes);
    $hist->save();
    $n++;
    drupal_set_message('Updated saved view ' . $hist->id . '. Count updated from ' . $hist->initcount . ' to ' . $hist->currcount);
  }
  $time = timer_read('cccc');
  watchdog('performance', 'Checking ' . $n . ' saved views in ' . $time . ' time');
}

/**
 * Implements hook_views_api().
 */
function easy_history_views_api() {
  return array(
    'api' => '3.0',
    'path' => drupal_get_path('module', 'easy_history') . '/views',
    'template_path' => drupal_get_path('module', 'easy_history') . '/views',
  );
}


/**
 * Loads a single saved view.
 *
 * @param int $id
 *   The saved view's ID.
 * @param bool $reset
 *   Whether to reset the internal cache for saved views.
 *
 * @return Entity|null
 *   The loaded saved view, if it exists. NULL otherwise.
 *
 * @see entity_load()
 */
function easy_history_load($id, $reset = FALSE) {
  $save = entity_load('easy_history', array($id), array(), $reset);
  return $save ? reset($save) : NULL;
}

/**
 * Loads multiple saved views at once.
 *
 * @param array|false $ids
 *   The IDs of the saved views to load, or FALSE to load all saved views.
 * @param array $conditions
 *   Conditions to filter the returned saved views by.
 * @param bool $reset
 *   Whether to reset the internal cache for saved views.
 *
 * @return array
 *   An array of saved view objects indexed by their IDs. When no results are
 *   found, an empty array is returned.
 *
 * @see entity_load()
 */
function easy_history_load_multiple($ids = FALSE, array $conditions = array(), $reset = FALSE) {
  return entity_load('easy_history', $ids, $conditions, $reset);
}

/**
 * URI callback for the saved view entity.
 *
 * @param Entity $save
 *   The saved view whose URI should be returned.
 *
 * @return array
 *   The URI of the saved view, as an array containing "path" and "options".
 */
function easy_history_uri(Entity $save) {
  $uri['path'] = 'views-save/' . $save->id;
  $uri['options'] = array();
  return $uri;
}

/**
 * Property callback which retrieves the path to a saved view as a string.
 *
 * @param Entity $save
 *   The saved view.
 *
 * @return string
 *   The path to the saved view, as a string.
 */
function easy_history_path(Entity $save) {
  return 'views-save/' . $save->id;
}

/**
 * Access callback for displaying a saved view.
 *
 * @param Entity $save
 *   The saved view to display.
 * @param object $account
 *   The account for which access should be checked. Defaults to the currently
 *   logged-in user.
 *
 * @return bool
 *   Whether the user should be allowed to access the saved view.
 */
function easy_history_display_access(Entity $save, $account = NULL) {
  global $user;
  if (!isset($account)) {
    $account = $user;
  }

  if (user_access('administer easy_history', $account)) {
    return TRUE;
  }
  if ($save->status && user_access('access easy_history', $account)) {
    return TRUE;
  }
  if ($account->uid && $save->uid == $account->uid && user_access('view own unpublished easy_history', $account)) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Options list callback for the "status" field of saved views.
 *
 * @return array
 *   An array of options, mapped to their labels.
 *
 * @see easy_history_entity_property_info()
 */
function easy_history_status_options_list() {
  return array(
    0 => t('Unpublished'),
    1 => t('Published'),
  );
}

/**
 * Implements hook_query_TAG_alter().
 *
 * This is the hook_query_alter() for queries tagged with 'easy_history_access'.
 * It adds access checks for the user account given by the 'account' meta-data
 * (or global $user if not provided), for an operation given by the 'op'
 * meta-data (or 'view' if not provided; other possible values are 'update' and
 * 'delete').
 */
function easy_history_query_easy_history_access_alter(QueryAlterableInterface $query) {
  _easy_history_query_easy_history_access_alter($query, 'easy_history');
}

/**
 * Implements hook_query_TAG_alter().
 *
 * This function implements the same functionality as
 * easy_history_query_easy_history_access_alter() for the SQL field storage engine.
 * Access conditions are added for field values belonging to saved views only.
 */
function easy_history_query_entity_field_access_alter(QueryAlterableInterface $query) {
  _easy_history_query_easy_history_access_alter($query, 'entity');
}

/**
 * Helper for access functions.
 *
 * @param QueryAlterableInterface $query
 *   The query to add conditions to.
 * @param string $type
 *   Either 'easy_history' or 'entity' depending on what sort of query it is. See
 *   easy_history_query_easy_history_access_alter() and
 *   easy_history_query_entity_field_access_alter() for more information.
 *
 * @throws Exception
 *   If the query doesn't contain the necessary columns.
 */
// Stolen from _node_query_node_access_alter().
function _easy_history_query_easy_history_access_alter(QueryAlterableInterface $query, $type) {
  global $user;

  // Read meta-data from query, if provided.
  if (!($account = $query->getMetaData('account'))) {
    $account = $user;
  }

  if (user_access('administer easy_history', $account)) {
    return;
  }
  if (!user_access('access easy_history', $account)) {
    $query->where('0 = 1');
    return;
  }

  $tables = $query->getTables();
  $base_table = $query->getMetaData('base_table');
  $join_field = '';
  foreach ($tables as $table_info) {
    $table = $table_info['table'];
    if (!($table instanceof SelectQueryInterface)) {
      // If the easy_history table is in the query, it wins immediately.
      if ($table == 'easy_history') {
        $base_table = $table;
        break;
      }
      // Check whether the table has a foreign key to easy_history.id. If it
      // does, do not run this check again as we found a base table and only
      // easy_history can trump that.
      if (!$base_table) {
        // The schema is cached.
        $schema = drupal_get_schema($table);
        if (isset($schema['foreign keys'])) {
          foreach ($schema['foreign keys'] as $relation) {
            if ($relation['table'] === 'easy_history' && count($relation['columns']) == 1 && reset($relation['columns']) == 'id') {
              $base_table = $table;
              $join_field = key($relation['columns']);
            }
          }
        }
      }
    }
  }
  // If we found nothing, fail with an exception.
  if (!$base_table) {
    throw new Exception(t('Query tagged for saved view access but there is no saved view id. Add foreign keys to easy_history.id in schema to fix.'));
  }

  // Find all instances of the base table being joined -- could appear more than
  // once in the query, and could be aliased.

  $filter = ($type == 'entity') ? db_and() : $query;
  foreach ($tables as $alias => $tableinfo) {
    $table = $tableinfo['table'];
    if (!($table instanceof SelectQueryInterface) && $table == $base_table) {
      $sub = $filter;
      if ($type == 'entity') {
        // Set a common alias for entities.
        $base_alias = $alias;
        $join_field = 'entity_id';
      }
      if ($table != 'easy_history') {
        $sub = db_select('easy_history', 'vs')
          ->fields('vs', array('id'))
          ->where("$alias.$join_field = vs.id");
        $alias = 'vs';
      }

      if (!$account->uid || !user_access('view own unpublished easy_history')) {
        $sub->condition("$alias.status", 1);
      }
      else {
        $or = db_or();
        $or->condition("$alias.status", 1);
        $or->condition("$alias.uid", $account->uid);
        $sub->condition($or);
      }

      if ($table != 'easy_history') {
        $filter->exists($sub);
      }
    }
  }

  if ($type == 'entity') {
    // All the access conditions are only for field values belonging to saved
    // views.
    $filter->condition("$base_alias.entity_type", 'easy_history');
    $or = db_or();
    $or->condition($filter);
    // If the field value belongs to a non-node entity type then this function
    // does not do anything with it.
    $or->condition("$base_alias.entity_type", 'easy_history', '<>');
    // Add the compiled set of rules to the query.
    $query->condition($or);
  }
}



/**
 * Implements hook_action_info().
 */
function easy_history_action_info() {
  return array(
    'easy_history_publish' => array(
      'type' => 'easy_history',
      'label' => t('Publish'),
      'configurable' => FALSE,
      'triggers' => array('any'),
      'behavior' => array('changes_property'),
    ),
    'easy_history_unpublish' => array(
      'type' => 'easy_history',
      'label' => t('Unpublish'),
      'configurable' => FALSE,
      'triggers' => array('any'),
      'behavior' => array('changes_property'),
    ),
  );
}

/**
 * Publishes the given saved view.
 *
 * Action callback used in easy_history_action_info().
 *
 * @param $object
 *   The saved view to publish.
 *
 * @see actions_do()
 */
function easy_history_publish($object) {
  $object->status = 1;
}

/**
 * Unpublishes the given saved view.
 *
 * Action callback used in easy_history_action_info().
 *
 * @param $object
 *   The saved view to unpublish.
 *
 * @see actions_do()
 */
function easy_history_unpublish($object) {
  $object->status = 0;
}

function d($what) { var_dump($what); die; }

function getQ($view) {
  $query = $view->build_info['query'];
  $sql = (string) $query;
  $quoted = array();
  $connection = Database::getConnection();
  foreach ((array) $query->arguments() as $key => $val) {
    $quoted[$key] = $connection->quote($val);
  }
  $sql = str_replace("\n" , ' ' ,strtr($sql, $quoted));
  $sql = preg_replace('~(.+) ORDER .*$~i', '$1', $sql);
  return $sql;
}
function easy_history_views_post_execute(&$view) {
  if (preg_match('/views-save/', $_SERVER['REQUEST_URI'])) return;
  global $user;
  if (!variable_get('easy_history_track_anonymous', false) && user_is_anonymous()) return;
  $allowed_views = array_filter(array_values(variable_get('easy_history_views_to_track', array())), function($v) { return !empty($v); });
  if (strpos(current_path(), 'export')) return;
  if (!in_array($view->name, $allowed_views)) return;
  $sid = session_api_get_sid(1);
  $query = drupal_get_query_parameters($_GET, array('q', 'page', 'easy_history'));
  unset($query['mode']);
  if (!$query) return; // no save for views without filter;

  ksort($query);
  $uri['path'] = current_path();
  if ($query) {
    $uri['options']['query'] = $query;
  }
  $title = crc32(json_encode($uri)) . '--' . $sid;
  $q = new EntityFieldQuery;
  $saves = $q
    ->entityCondition('entity_type', 'easy_history')
    ->propertyCondition('title', $title)
    ->execute();
  if (!empty($saves['easy_history'])) {
    $save = current(entity_load('easy_history', array_keys($saves['easy_history'])));
    $save->changed = REQUEST_TIME;
    $save->currcount = $view->total_rows;
    $save->nodes = array_map( function($r) { return $r->nid; }, $view->result);
  }
  
  if (empty($save)) {
    $q = getQ($view);
    $nids = array();
    $nodes = db_query($q);
    while ($node=$nodes->fetchObject()) {
      $nids[] = $node->nid;
    }
    $properties = array(
      'uid' => $user->uid,
      'bundle' => 1,
      'view_path' => $uri,
      'title' => $title,
      'status' => 0,
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
      'initcount'=>$view->total_rows,
      'currcount'=>$view->total_rows,
      'nodes' => $nids,
      'query' => $q,
    );
    $save = entity_create('easy_history', $properties);
  }
  $save->save();
}
function easy_history_views_pre_render(&$view) {
  //die(getQ($view));
  if ($view->name=='search_history') {
    drupal_add_js(drupal_get_path('module','easy_history') . '/easy_history.js', array('scope'=>'footer'));
    drupal_add_css(drupal_get_path('module','easy_history') . '/easy_history.css');
  }
  if (isset($_GET['easy_history'])) {
    $nids = array_map(function($n) { return $n->nid ; },  $view->result);
    $updated_nodes = db_query('select group_concat(nid) as nids from {node} n inner join {easy_history} eh where n.changed>eh.created and eh.id=:ehid and nid in (' . join(',', $nids) . ')', array(':ehid' => $_GET['easy_history']))->fetch();
  }
}

function easy_history_form_simplenews_node_form_alter(&$form, &$form_state, $form_id) {
  if (!preg_match('~\/saved-view\/(\d+)~', $_SERVER['HTTP_REFERER'], $m)) return;

  $form['history_ref'] = array(
    '#type' => 'hidden',
    '#value' => $m[1],
    '#weight' => -10,
  );
}

function easy_history_node_submit($node, $form, &$form_state) {
  if ($node->type!='simplenews' || empty($form_state['input']['history_ref'])) return;

  $save = current(entity_load('easy_history', [(int)$form_state['input']['history_ref']]));
  $save->newsletter_date = REQUEST_TIME;
  $save->save();
}
