<?php

/**
 * @file
 * Internationalization (i18n) module - Commerce product handling.
 */

require_once dirname(__FILE__) . '/i18n_commerce_product.forms.inc';

/**
 * Implements hook_menu().
 */
function i18n_commerce_product_menu() {
  $items['admin/commerce/products/%commerce_product/translate'] = array(
    'title' => 'Translate',
    'page callback' => 'i18n_commerce_product_product_overview',
    'page arguments' => array(3),
    'access callback' => 'i18n_commerce_product_tab_access',
    'access arguments' => array(3),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );

  return $items;
}

/**
 * Implements hook_views_api().
 */
function i18n_commerce_product_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'i18n_commerce_product') . '/includes/views',
  );
}

/**
 * Access callback for "admin/commerce/products/%commerce_product/translate".
 */
function i18n_commerce_product_tab_access($commerce_product) {
  return commerce_product_access('create', commerce_product_new($commerce_product->type)) && user_access('translate content');
}

/**
 * Page callback for "admin/commerce/products/%commerce_product/translate".
 */
function i18n_commerce_product_product_overview($commerce_product) {
  require_once DRUPAL_ROOT . '/includes/language.inc';

  if (!empty($commerce_product->tproduct_id)) {
    // Already part of a set, grab that set.
    $tproduct_id = $commerce_product->tproduct_id;
    $translations = array(entity_language('commerce_product', $commerce_product) => $commerce_product);
    $translations += i18n_commerce_product_product_get_translations($commerce_product->tproduct_id, TRUE);
  }
  else {
    // We have no translation source nid, this could be a new set, emulate that.
    $tproduct_id = $commerce_product->product_id;
    $translations = array(entity_language('commerce_product', $commerce_product) => $commerce_product);
    $translations += i18n_commerce_product_product_get_translations($commerce_product->product_id);
  }

  $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
  $header = array(t('Language'), t('Title'), t('Status'), t('Operations'));

  foreach (language_list() as $langcode => $language) {
    if (empty($language->enabled)) {
      continue;
    }
    $options = array();
    $language_name = $language->name;
    if (isset($translations[$langcode])) {
      // Existing translation in the translation set: display status.
      // We load the full commerce product to check whether the user can edit it.
      $translation_commerce_product = commerce_product_load($translations[$langcode]->product_id);
      $path = 'admin/commerce/products/' . $translation_commerce_product->product_id;
      $links = language_negotiation_get_switch_links($type, $path);
      $title = empty($links->links[$langcode]['href']) ? l($translation_commerce_product->title, $path) : l($translation_commerce_product->title, $links->links[$langcode]['href'], $links->links[$langcode]);
      if (commerce_product_access('update', $translation_commerce_product)) {
        $text = t('edit');
        $path = 'admin/commerce/products/' . $translation_commerce_product->product_id;
        $links = language_negotiation_get_switch_links($type, $path);
        $options[] = empty($links->links[$langcode]['href']) ? l($text, $path) : l($text, $links->links[$langcode]['href'], $links->links[$langcode]);
      }
      $status = $translation_commerce_product->status ? t('Active') : t('Disabled');
      if ($translation_commerce_product->product_id == $tproduct_id) {
        $language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
      }
    }
    else {
      // No such translation in the set yet: help user to create it.
      $title = t('n/a');
      if (commerce_product_access('create', $commerce_product)) {
        $text = t('add translation');
        $path = 'admin/commerce/products/add/' . str_replace('_', '-', $commerce_product->type);
        $links = language_negotiation_get_switch_links($type, $path);
        $query = array('query' => array('translation' => $commerce_product->product_id, 'target' => $langcode));
        $options[] = empty($links->links[$langcode]['href']) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query));
      }
      $status = t('Not translated');
    }
    $rows[] = array($language_name, $title, $status, implode(" | ", $options));
  }

  drupal_set_title(t('Translations of %title', array('%title' => $commerce_product->title)), PASS_THROUGH);

  $build['translation_commerce_product_overview'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
  );

  return $build;
}

/**
 * Get translations of commerce product.
 */
function i18n_commerce_product_product_get_translations($tproduct_id, $source = FALSE) {
  if (is_numeric($tproduct_id) && $tproduct_id) {
    $translations = &drupal_static(__FUNCTION__, array());

    if (!isset($translations[$tproduct_id])) {
      $translations[$tproduct_id] = array();
      $query = db_select('commerce_product', 'cp')
        ->fields('cp', array('product_id', 'type', 'uid', 'status', 'title', 'language'));
      if ($source) {
        $query->condition('cp.product_id', $tproduct_id);
      }
      else {
        $query->condition('cp.tproduct_id', $tproduct_id);
      }
      $result = $query->execute();
      foreach ($result as $commerce_product) {
        $langcode = entity_language('commerce_product', $commerce_product);
        $translations[$tproduct_id][$langcode] = $commerce_product;
      }
    }
    return $translations[$tproduct_id];
  }
}

/**
 * Get product for current language.
 */
function i18n_commerce_product_product_get_current_by_language($commerce_product, $langcode = NULL) {
  global $language;

  if (empty($langcode)) {
    $langcode = $language->language;
  }
  if ($commerce_product->language != $langcode) {
    if (!empty($commerce_product->tproduct_id)) {
      $translated_product = i18n_commerce_product_product_get_translations($commerce_product->tproduct_id, TRUE);
    }
    else {
      $translated_product = i18n_commerce_product_product_get_translations($commerce_product->product_id);
    }
    if (!empty($translated_product[$langcode])) {
      return $translated_product[$langcode];
    }
  }

  return $commerce_product;
}

/**
 * Override function commerce_cart_product_add().
 * @see commerce_cart_product_add()
 */
function i18n_commerce_product_commerce_cart_product_add($uid, $line_item, $combine = TRUE) {
  // Do not add the line item if it doesn't have a unit price.
  $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);

  if (is_null($line_item_wrapper->commerce_unit_price->value())) {
    return FALSE;
  }

  // First attempt to load the customer's shopping cart order.
  $order = commerce_cart_order_load($uid);

  // If no order existed, create one now.
  if (empty($order)) {
    $order = commerce_cart_order_new($uid);
    $order->data['last_cart_refresh'] = REQUEST_TIME;
  }

  // Set the incoming line item's order_id.
  $line_item->order_id = $order->order_id;

  // Wrap the order for easy access to field data.
  $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

  // Extract the product and quantity we're adding from the incoming line item.
  $product = $line_item_wrapper->commerce_product->value();
  $quantity = $line_item->quantity;

  // Invoke the product prepare event with the shopping cart order.
  rules_invoke_all('commerce_cart_product_prepare', $order, $product, $line_item->quantity);

  // Determine if the product already exists on the order and increment its
  // quantity instead of adding a new line if it does.
  $matching_line_item = NULL;

  // If we are supposed to look for a line item to combine into...
  if ($combine) {
    // Generate an array of properties and fields to compare.
    $comparison_properties = array('type', 'commerce_product');

    // Add any field that was exposed on the Add to Cart form to the array.
    // TODO: Bypass combination when an exposed field is no longer available but
    // the same base product is added to the cart.
    foreach (field_info_instances('commerce_line_item', $line_item->type) as $info) {
      if (!empty($info['commerce_cart_settings']['field_access'])) {
        $comparison_properties[] = $info['field_name'];
      }
    }

    // Allow other modules to specify what properties should be compared when
    // determining whether or not to combine line items.
    $cloned_line_item = clone($line_item); drupal_alter("commerce_cart_product_comparison_properties", $comparison_properties, $cloned_line_item);

    // Loop over each line item on the order.
    foreach ($order_wrapper->commerce_line_items as $matching_line_item_wrapper) {
      // Examine each of the comparison properties on the line item.
      foreach ($comparison_properties as $property) {
        // If the property is not present on either line item, bypass it.
        if (!isset($matching_line_item_wrapper->value()->{$property}) && !isset($line_item_wrapper->value()->{$property})) {
          continue;
        }

        // If any property does not match the same property on the incoming line
        // item or exists on one line item but not the other...
        if ((!isset($matching_line_item_wrapper->value()->{$property}) && isset($line_item_wrapper->value()->{$property})) ||
          (isset($matching_line_item_wrapper->value()->{$property}) && !isset($line_item_wrapper->value()->{$property}))) {
          // Continue the loop with the next line item.
          continue 2;
        }
        // It's allow to match products by SKU (it's unique, but the same for translations of product).
        elseif ($matching_line_item_wrapper->{$property}->raw() != $line_item_wrapper->{$property}->raw()) {
          if ($property == 'commerce_product') {
            $product = $line_item_wrapper->{$property}->value();
            $matching_product = $matching_line_item_wrapper->{$property}->value();
            if (!empty($product->sku) && empty($matching_product->sku)
              || empty($product->sku) && !empty($matching_product->sku)
              || $product->sku != $matching_product->sku) {
              continue 2;
            }
          }
        }
      }

      // If every comparison line item matched, combine into this line item.
      $matching_line_item = $matching_line_item_wrapper->value();
      break;
    }
  }

  // If no matching line item was found...
  if (empty($matching_line_item)) {
    // Save the incoming line item now so we get its ID.
    commerce_line_item_save($line_item);

    // Add it to the order's line item reference value.
    $order_wrapper->commerce_line_items[] = $line_item;
  }
  else {
    // Increment the quantity of the matching line item, update the data array,
    // and save it.
    $matching_line_item->quantity += $quantity;
    $matching_line_item->data = array_merge($line_item->data, $matching_line_item->data);

    commerce_line_item_save($matching_line_item);

    // Clear the line item cache so the updated quantity will be available to
    // the ensuing load instead of the original quantity as loaded above.
    entity_get_controller('commerce_line_item')->resetCache(array($matching_line_item->line_item_id));

    // Update the line item variable for use in the invocation and return value.
    $line_item = $matching_line_item;
  }

  // Save the updated order.
  commerce_order_save($order);

  // Invoke the product add event with the newly saved or updated line item.
  rules_invoke_all('commerce_cart_product_add', $order, $product, $quantity, $line_item);

  // Return the line item.
  return $line_item;
}

/**
 * Return translated title of line item.
 */
function i18n_commerce_product_line_item_title($line_item) {
  global $language;

  $wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
  if (!empty($line_item->commerce_product)) {
    $product = $wrapper->commerce_product->value();
    $title = $product->title;
    if ($language->language != $product->language) {
      if (!empty($product->tproduct_id)) {
        $translations = i18n_commerce_product_product_get_translations($product->tproduct_id, TRUE);
      }
      else {
        // We have no translation source nid, this could be a new set, emulate that.
        $translations = i18n_commerce_product_product_get_translations($product->product_id);
      }
      if (!empty($translations[$language->language])) {
        $title = $translations[$language->language]->title;
      }
    }
    return $title;
  }
}
