<?php
/**
 * @file
 * Code for the DIY Newsletter feature.
 */

use \DrewM\MailChimp\MailChimp;

include_once 'diy_newsletter.features.inc';

/**
 * Implementation of hook_theme()
 */
function diy_newsletter_theme() {
  return array(
    'diy_newsletter' => array(
      'template' => 'diy-newsletter',
      'variables' => array(
        'intro' => NULL,
        'news' => array(),
        'articles' => array(),
        'more_articles' => array()
      )
    ),
    'diy_newsletter_teaser' => array(
      'template' => 'diy-newsletter-teaser',
      'variables' => array(
        'image' => NULL,
        'headline' => NULL,
        'teaser' => NULL,
        'more_link' => NULL
      )
    )
  );
}

/**
 * Test callback
 */
function diy_newsletter_preview($newsletter_id) {
  $variables = array();

  if($newsletter = entity_load_single('newsletter', $newsletter_id)) {

    if($field_newsletter_intro = field_get_items('newsletter', $newsletter, 'field_newsletter_intro')) {
      $variables['intro'] = nl2br($field_newsletter_intro[0]['value']);
    }

    $teaser_config = array(
      'news' => 'field_newsletter_news',
      'articles' => 'field_newsletter_articles',
      'more_articles' => 'field_newsletter_more_articles',
    );

    foreach($teaser_config as $theme_section => $field) {

      if($current_field = field_get_items('newsletter', $newsletter, $field)) {
        $teasers = array();

        foreach($current_field as $current_field_value) {
          $teasers[] = diy_newsletter_extract_teaser($current_field_value['nid']);
        }

        $variables[$theme_section] = array_chunk($teasers, 2);
      }
    }
  }

  $body = theme('diy_newsletter', $variables);

  return theme('mimemail_message', array(
    'body' => $body
  ));
}

function diy_newsletter_extract_teaser($target_id) {

  $fields = array(
    'article' => array(
      'teaser' => 'field_article_abstract',
      'image' => 'field_article_teaser_upload'
    ),
    'news' => array(
      'teaser' => 'field_teaser',
      'image' => 'field_header_image'
    )

  );

  if($node = node_load($target_id)) {

    $teaser = NULL;
    $image = NULL;

    if($field_teaser = field_get_items('node', $node, $fields[$node->type]['teaser'])) {
      $teaser = $field_teaser[0]['value'];
    }

    if($field_image = field_get_items('node', $node, $fields[$node->type]['image'])) {
      $image = image_style_url('newsletter_thumb', $field_image[0]['uri']);
    }

    return theme('diy_newsletter_teaser', array(
      'image' => $image,
      'headline' => $node->title,
      'teaser' => $teaser,
      'more_link' => url('node/' . $node->nid, array('absolute' => true))
    ));
  }

  return false;


}

/**
 * @file
 * Code for the DIY Newsletter feature.
 */

/**
 * Implements hook_cron().
 */
function diy_newsletter_cron() {
  $current_day = date('l');

  // check if we should autogenerate a newsletter
  if($current_day == 'Monday' && variable_get('diy_newsletter_autogenerate', false)) {
    $today = new DateTime();
    $today->setTime(0,0);

    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'newsletter')
      ->propertyCondition('created', $today->getTimestamp(), '>=')
      ->addMetaData('account', user_load(1));
    $result = $query->execute();

    if (!isset($result['newsletter'])) {
      diy_newsletter_autogenerate();
    }
  }

  // check if we should autosend a newsletter
  if($current_day == 'Sunday' && variable_get('diy_newsletter_autosend', false)) {

    // autosend after 8:30
    $hour = date('H');
    $minute = date('i');

    if((int)$hour >= 8 && (int)$minute >= 30) {
      diy_newsletter_autosend();
    }
  }
}

/**
 * Generates a newsletter
 */
function diy_newsletter_autogenerate() {
  $news = diy_newsletter_get_node_type_content('news');
  $articles = diy_newsletter_get_node_type_content('article');
  $more_articles = diy_newsletter_get_more_articles($news);

  // there could be more_articles, that are the same as in articles
  $more_articles = array_diff($more_articles, $articles);

  $newsletter_id = diy_newsletter_create_newsletter($news, $articles, $more_articles);

  foreach(array_merge($news, $articles, $more_articles) as $node_id) {
    diy_newsletter_add_used_node($node_id, $newsletter_id);
  }
}

/**
 * Extracts similiar articles
 */
function diy_newsletter_get_more_articles($news_entries) {
  // field_article_similar
  $articles = array();

  if($news_entities = node_load_multiple($news_entries)) {
    foreach($news_entities as $news) {
      if($field_article_similar = field_get_items('node', $news, 'field_article_similar')) {

        foreach($field_article_similar as $field_article_similar_value) {
          array_push($articles, $field_article_similar_value['target_id']);
        }
      }
    }
  }

  return $articles;
}

/**
 * Helper to get stuff to send
 *
 * @param $type
 * @return array
 */
function diy_newsletter_get_node_type_content($type) {
  $query = db_select('diy_newsletter_used', 'nu');
  $query->fields('nu' ,array('node_id'));

  if($result = $query->execute()) {
    $all = $result->fetchAll();
    $exclude_nids = array_map(function($item) { return $item->node_id; }, $all);

    // get all nodes for the newsletter
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', $type, '=')
      ->propertyCondition('nid', $exclude_nids ,'NOT IN')
      ->addMetaData('account', user_load(1))
      ->propertyOrderBy('created', 'DESC')
      ->range(0, 20); // something is wrong, if there are more than 20 nodes

    $result = $query->execute();

    if (isset($result['node'])) {
      $nids = array_keys($result['node']);
      return $nids;
    }
  }

  return array();
}

/**
 * Sends all approved newsletters
 */
function diy_newsletter_autosend() {

  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'newsletter')
    ->propertyCondition('status', 1)
    ->addMetaData('account', user_load(1));
  $result = $query->execute();

  if (isset($result['newsletter'])) {
    foreach($result['newsletter'] as $nl) {
      diy_news_send_newsletter($nl->id);
    }
  }
}

/**
 * Sends newsletter with id
 */
function diy_news_send_newsletter($newsletter_id) {

  watchdog('diy_newsletter', 'Start sending newsletter with id: ' . $newsletter_id);

  require(drupal_get_path('module', 'diy_newsletter') .'/mailchimp/vendor/autoload.php');

  $api_key = variable_get('diy_newsletter_mailchimp_key', false);
  if(!$api_key) {
    return false;
  }

  $list_id = variable_get('diy_newsletter_mailchimp_list', false);
  if(!$list_id) {
    return false;
  }

  $newsletter = entity_load_single('newsletter', $newsletter_id);
  if(!$newsletter) {
    return false;
  }

  $MailChimp = new MailChimp($api_key);


  $result = $MailChimp->post("campaigns", [
    'type' => 'regular',
    'settings' => array(
      'subject_line' => $newsletter->subject,
      'from_name' => variable_get('site_name'),
      'reply_to' => 'kundendienst@diybook.at'
    ),
    'recipients' => array(
      'list_id' => $list_id
    )
  ]);

  if ($MailChimp->success()) {
    // campaign has been created
    // get id

    $campaign_id = $result['id'];
    watchdog('diy_newsletter', 'Newsletter campaign has been created: ' . $campaign_id);

    $html = file_get_contents(url('/newsletter/view/'. $newsletter_id, array('absolute' => true)));

    $result = $MailChimp->put("campaigns/". $campaign_id ."/content", [
      'type' => 'regular',
      'html' => $html
    ]);

    if ($MailChimp->success()) {
      watchdog('diy_newsletter', 'Newsletter campaign content has been set: ' . $campaign_id);

      $result = $MailChimp->get("campaigns/". $campaign_id ."/send-checklist");

      if($result['is_ready']) {

        $hold_back = variable_get('diy_newsletter_hold_back', false);

        if(!$hold_back) {
          $result = $MailChimp->post("campaigns/". $campaign_id ."/actions/send");

          $last_response = $MailChimp->getLastResponse();
          if(isset($last_response['headers']['http_code']) && in_array($last_response['headers']['http_code'], array(200, 204))) {
            watchdog('diy_newsletter', 'Newsletter has been sent: ' . $campaign_id);

            $newsletter->status = 2;
            $newsletter->save();
          } else {
            watchdog('diy_newsletter', 'Newsletter send error: ' . $campaign_id, array(), WATCHDOG_CRITICAL);
          }
        }


      } else {

        $errors = array();

        foreach($result['items'] as $item) {
          if($item['type'] == 'error') {
            array_push($errors, $item['details']);
          }
        }

        watchdog('diy_newsletter', 'Newsletter is not ready: ' . implode(' / ', $errors), array(), WATCHDOG_CRITICAL);
      }
    }
  }

  return false;
}

/**
 * Implements hook_menu().
 */
function diy_newsletter_menu() {
  $items = array();

  $items['newsletter/view/%'] = array(
    'title' => 'Newsletter',
    'page callback' => 'diy_newsletter_preview',
    'page arguments' => array(2),
    'access arguments' => array('access content')
  );

  $items['admin/diy/newsletter/settings'] = array(
    'title' => 'Settings',
    'description' => 'Newsletter settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('diy_newsletter_settings_form'),
    'access arguments' => array('administer diy newsletter settings'),
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

/**
 * Implementation of HOOK_permission().
 */
function diy_newsletter_permission() {
  return array(
    'administer diy newsletter settings' => array(
      'title' => t('Administer diy newsletter settings')
    ),
    'administer diy newsletter entites' => array(
      'title' => t('Administer diy newsletter entites')
    )
  );
}

/**
 * Page callback: DIY settings
 */
function diy_newsletter_settings_form($form, &$form_state) {

  $form['diy_newsletter_autogenerate'] = array(
    '#type' => 'checkbox',
    '#title' => t('Autogenerate newsletter'),
    '#default_value' => variable_get('diy_newsletter_autogenerate', false),
    '#description' => t('If set, a newsletter will be generated on cron run each Friday morning.'),
    '#required' => FALSE,
  );

  $form['diy_newsletter_autosend'] = array(
    '#type' => 'checkbox',
    '#title' => t('Autosend newsletter'),
    '#default_value' => variable_get('diy_newsletter_autosend', false),
    '#description' => t('If set, a released newsletter will be sent on cron run Sunday morning.'),
    '#required' => FALSE,
  );

  $form['diy_newsletter_hold_back'] = array(
    '#type' => 'checkbox',
    '#title' => t('Transfer newsletter to Mailchimp without sending it.'),
    '#default_value' => variable_get('diy_newsletter_hold_back', false),
    '#description' => t('If set, a released newsletter will be transfered to mailchimp; then the script will NOT trigger mailchimp send-process (for testing).'),
    '#required' => FALSE,
  );

  $form['diy_newsletter_mailchimp_key'] = array(
    '#type' => 'textfield',
    '#title' => t('Mailchimp API Key'),
    '#default_value' => variable_get('diy_newsletter_mailchimp_key', false),
    '#required' => FALSE
  );

  $form['diy_newsletter_mailchimp_list'] = array(
    '#type' => 'textfield',
    '#title' => t('Mailchimp List ID'),
    '#default_value' => variable_get('diy_newsletter_mailchimp_list', false),
    '#required' => FALSE
  );

  $form['diy_newsletter_send_released'] = array(
    '#type' => 'submit',
    '#value' => 'Send approved newsletters',
    '#submit' => array('diy_newsletter_manual_send')
  );


  $form['diy_newsletter_actions'] = array(
    '#type' => 'fieldset',
    '#title' => t('Helper actions'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE
  );

  $form['diy_newsletter_actions']['diy_newsletter_clear_list'] = array(
    '#type' => 'submit',
    '#value' => 'Clears list of used nodes',
    '#submit' => array('diy_newsletter_clear_used_list')
  );

  $form['diy_newsletter_actions']['diy_newsletter_init_used_list'] = array(
    '#type' => 'submit',
    '#value' => 'Initialize used list',
    '#submit' => array('diy_newsletter_initialize_used_list')
  );

  return system_settings_form($form);
}

/**
 * Sends out all approved newsletters
 */
function diy_newsletter_manual_send() {
  diy_newsletter_autosend();
}

/**
 * Truncates table with used news / articles
 */
function diy_newsletter_clear_used_list() {
  $result = db_truncate('diy_newsletter_used')->execute();

  drupal_set_message(t('Truncated diy_newsletter_used'));
}

/**
 * Puts all news and articles on used list
 */
function diy_newsletter_initialize_used_list() {
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', array('news', 'article'), 'IN')
    ->addMetaData('account', user_load(1));
  $result = $query->execute();

  if (isset($result['node'])) {
    $nids = array_keys($result['node']);

    $query = db_insert('diy_newsletter_used')->fields(array('node_id', 'newsletter_id'));
    foreach ($nids as $nid) {
      $query->values(array(
        'node_id' => $nid,
        'newsletter_id' => 0
      ));
    }

    $query->execute();
  }
}

/**
 * Ads $nid and $newsletter_id to diy_newsletter_used
 *
 * @param $nid
 * @param $newsletter_id
 */
function diy_newsletter_add_used_node($nid, $newsletter_id) {
  $result = db_select('diy_newsletter_used', 'nu')
    ->fields('nu')
    ->condition('node_id', $nid)
    ->condition('newsletter_id', $newsletter_id)
    ->execute();

  if(!$result->rowCount()) {
    // check if it is already on that list
    db_insert('diy_newsletter_used')
      ->fields(array(
        'node_id' => $nid,
        'newsletter_id' => $newsletter_id
      ))
      ->execute();
  }
}

/**
 * Checks if $nid is used in newsletter
 *
 * @param $nid
 */
function diy_newsletter_node_is_used($nid) {
  $result = db_select('diy_newsletter_used', 'nu')
    ->fields('nu')
    ->condition('node_id', $nid)
    ->execute();

  if($result->rowCount()) {
    return true;
  }

  return false;
}

/**
 * Creates a newsletter with the given nodes set as references
 */
function diy_newsletter_create_newsletter($news, $articles, $more_articles) {
  $entity = entity_create('newsletter', array(
    'subject' => 'Neues von DIYBook'
  ));

  $wrapper = entity_metadata_wrapper('newsletter', $entity);

  $wrapper->field_newsletter_news->set($news);
  $wrapper->field_newsletter_articles->set($articles);
  $wrapper->field_newsletter_more_articles->set($more_articles);

  $wrapper->save();

  return $wrapper->getIdentifier();
}



/**
 * Implements hook_entity_info().
 */
function diy_newsletter_entity_info() {

  $info = array();

  $info['newsletter'] = array(
    'label' => t('Newsletter'),
    'base table' => 'diy_newsletter',
    'entity keys' => array(
      'id' => 'id',
      'label' => 'subject',
    ),
    'module' => 'diy_newsletter',
    'entity class' => 'NewsletterEntity',
    'controller class' => 'NewsletterEntityController',
    'access callback' => 'diy_newsletter_access_callback',
    'uri callback' => 'entity_class_uri',
    'admin ui' => array(
      'path' => 'admin/diy/newsletter',
      'controller class' => 'EntityDefaultUIController',
    ),
    'fieldable' => TRUE,
    'bundles' => array(
      'newsletter' => array(
        'label' => t('Newsletter'),
        'admin' => array(
          'path' => 'admin/diy/newsletter',
        ),
      ),
    ),
    'views controller class' => 'EntityDefaultViewsController',
  );

  return $info;
}

/**
 * Implements HOOK_entity_property_info().
 */
function diy_newsletter_entity_property_info() {

  $info = array();

  $info['newsletter']['properties']['id'] = array(
    'label' => t('Newsletter ID'),
    'description' => t('The ID of the newsletter.'),
    'type' => 'integer',
    'schema field' => 'id',
  );

  $info['newsletter']['properties']['subject'] = array(
    'label' => t('Newsletter subject'),
    'description' => t('Subject of the newsletter.'),
    'type' => 'text',
    'schema field' => 'subject',
  );

  $info['newsletter']['properties']['status'] = array(
    'label' => t('Newsletter status'),
    'description' => t('Newsletter status.'),
    'type' => 'integer',
    'schema field' => 'status',
  );

  $info['newsletter']['properties']['created'] = array(
    'label' => t('Newsletter created date'),
    'description' => t('Newsletter created date.'),
    'type' => 'date',
    'schema field' => 'created',
  );
  return $info;
}

/**
 * Access callback for newsletter entities.
 */
function diy_newsletter_access_callback($op, $newsletter = NULL, $account = NULL) {
  if ($op == 'view') {
    return TRUE;
  }

  if (user_access('administer diy newsletter entites', $account) && ($op == 'update' || $op == 'create' || $op == 'delete')) {
    return TRUE;
  }

  return FALSE;
}

/**
 * Get all possible newsletter status option
 */
function diy_newsletter_get_status_options() {
  return array(
    0 => t('New'),
    1 => t('Approved'),
    2 => t('Sent')
  );
}

/**
 * Form definition for adding / editing a project.
 */
function newsletter_form($form, &$form_state, $newsletter = NULL) {

  $form['subject'] = array(
    '#title' => t('Subject'),
    '#type' => 'textfield',
    '#default_value' => isset($newsletter->subject) ? $newsletter->subject : '',
    '#required' => TRUE,
    '#weight' => -100,
  );

  $form['status'] = array(
    '#title' => t('Status'),
    '#type' => 'select',
    '#options' => diy_newsletter_get_status_options(),
    '#default_value' => isset($newsletter->status) ? $newsletter->status : 0,
    '#weight' => -99
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => isset($newsletter->id) ? t('Update newsletter') : t('Save newsletter'),
    '#weight' => 50,
  );

  field_attach_form('newsletter', $newsletter, $form, $form_state);

  return $form;
}

/**
 * Submit handler for the project add/edit form.
 */
function newsletter_form_submit($form, &$form_state) {
  $newsletter = entity_ui_form_submit_build_entity($form, $form_state);
  $newsletter->save();

  drupal_set_message(t('The newsletter: @subject has been saved.', array('@subject' => $newsletter->subject)));
  $form_state['redirect'] = 'admin/diy/newsletter';
}

/**
 * Implements HOOK_entity_presave().
 */
function diy_newsletter_entity_presave($entity, $type) {
  if($type == 'newsletter') {
    if(!isset($entity->status) || empty($entity->status)) {
      $entity->status = 0;
    }

    if(!isset($entity->created) || empty($entity->created)) {
      $entity->created = time();
    }
  }
}

/**
 * Implements hook_views_api_alter().
 *
 * Views api is specified by features but we want to add the views-template directory to it.
 */
function diy_newsletter_views_api_alter(&$apis) {
  if (!empty($apis['diy_newsletter'])) {
    $apis['diy_newsletter']['template path'] = drupal_get_path('module', 'diy_newsletter') . '/templates';
  }
}

