<?php

/**
 * @file
 * Commerce Billy module.
 */

// One single invoice number, never regenerated.
define('COMMERCE_BILLY_INVOICE_METHOD_INFINITE', 'infinite');
// Invoice number is regenerated every year.
define('COMMERCE_BILLY_INVOICE_METHOD_YEARLY', 'yearly');
// Invoice number is regenerated every month.
define('COMMERCE_BILLY_INVOICE_METHOD_MONTHLY', 'monthly');


/**
 * Implements hook_commerce_order_state_info().
 */
function commerce_billy_commerce_order_state_info() {
  return array(
    'invoiced' => array(
      'name' => 'invoiced',
      'title' => t('Invoiced'),
      'description' => t('Orders in this state have been completed and an invoice number + pdf is generated.'),
      'weight' => 15,
      'default_status' => 'invoiced',
    ),
  );
}

/**
 * Implements hook_commerce_order_status_info().
 */
function commerce_billy_commerce_order_status_info() {
  return array(
    'invoiced' => array(
      'name' => 'invoiced',
      'title' => t('Invoiced'),
      'state' => 'invoiced',
    ),
  );
}

/**
 * Implements hook_menu_alter().
 */
function commerce_billy_menu_alter(&$items) {
  $items['admin/commerce/orders/%commerce_order/delete']['access callback'] = 'commerce_billy_order_delete_access';
}

/**
 * Access callback for deleting orders.
 */
function commerce_billy_order_delete_access($op, $order) {
  // Deletion of orders in state 'invoiced' is not allowed.
  if ($order->status == 'invoiced') {
    return FALSE;
  }
  return commerce_order_access($op, $order);
}

/**
 * Sets invoice number on order.
 *
 * Used as Rules action callback.
 *
 * @see commerce_billy_rules_action_info()
 */
function commerce_billy_invoice_nr($order) {
  // Lock down this function so that other requests do not interfere.
  $lock_name = 'commerce_billy_invoice_nr';
  while (!lock_acquire($lock_name)) {
    lock_wait($lock_name);
  }

  $method = variable_get('commerce_billy_invoice_nr_method', COMMERCE_BILLY_INVOICE_METHOD_YEARLY);
  switch ($method) {
    case COMMERCE_BILLY_INVOICE_METHOD_MONTHLY:
      $new_nr = commerce_billy_invoice_nr_monthly();
      break;

    case COMMERCE_BILLY_INVOICE_METHOD_YEARLY:
      $new_nr = commerce_billy_invoice_nr_yearly();
      break;

    case COMMERCE_BILLY_INVOICE_METHOD_INFINITE:
      $new_nr = commerce_billy_invoice_nr_infinite();
      break;
  }

  $pattern = variable_get('commerce_billy_invoice_nr_pattern', '[invoice_nr]');
  $order->order_number = str_replace('[invoice_nr]', $new_nr, $pattern);

  lock_release($lock_name);
}

/**
 * Generated monthly invoice number.
 */
function commerce_billy_invoice_nr_monthly() {
  $var_name = 'commerce_billy_invoice_nr_last_monthly';
  $last_number = commerce_billy_query_variable($var_name);

  $id = 1;
  if ($last_number) {
    $parts = explode('-', $last_number);
    $last_year = $parts[0];
    $last_month = $parts[1];
    $last_id = $parts[2];
    $year = date('Y');
    $month = date('m');
    if ($last_year == $year) {
      if ($last_month == $month) {
        $id = $last_id + 1;
      }
    }
  }
  $new_nr = date('Y') . '-' . date('m') . '-' . $id;
  variable_set($var_name, $new_nr);
  return $new_nr;
}

/**
 * Generated yearly invoice number.
 */
function commerce_billy_invoice_nr_yearly() {
  $var_name = 'commerce_billy_invoice_nr_last_yearly';
  $last_number = commerce_billy_query_variable($var_name);

  $id = 1;
  if ($last_number) {
    $parts = explode('-', $last_number);
    $last_year = $parts[0];
    $last_id = $parts[1];
    $year = date('Y');
    if ($last_year == $year) {
      $id = $last_id + 1;
    }
  }
  $new_nr = date('Y') . '-' . $id;
  variable_set($var_name, $new_nr);
  return $new_nr;
}

/**
 * Generated infinite invoice number.
 */
function commerce_billy_invoice_nr_infinite() {
  $var_name = 'commerce_billy_invoice_nr_last_infinite';
  $last_number = commerce_billy_query_variable($var_name);

  $id = 1;
  if ($last_number) {
    $id = $last_number + 1;
  }
  $new_nr = $id;
  variable_set($var_name, $new_nr);
  return $new_nr;
}

/**
 * Helper function that directly queries variable values from the database.
 *
 * In certain situations variable_get() cannot be used, as it statically caches
 * the value. e.g. we always need to most recent invoice number.
 *
 * @param string $var_name
 *   The name of the variable.
 */
function commerce_billy_query_variable($var_name) {
  return unserialize(db_select('variable', 'v')
    ->fields('v')
    ->condition('name', $var_name)
    ->execute()
    ->fetchField(1));
}

/**
 * Implements hook_menu().
 */
function commerce_billy_menu() {
  $items['admin/commerce/config/billy-invoice'] = array(
    'title' => 'Billy invoice settings.',
    'description' => 'Configure the Billy invoicing settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('commerce_billy_admin_form'),
    'access arguments' => array('configure order settings'),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'commerce_billy.admin.inc',
  );
  $items['admin/commerce/config/billy-invoice/settings'] = array(
    'title' => 'Settings',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  return $items;
}
