<?php

class DiyProduct {
  var $pid;
  var $reference_nid; # tool or material nid
  var $data;
  var $priceItems;
  var $product_nid;
  var $domains;
  var $mu;
  var $su;

  public function __construct() {

  }

  public function populate() {
    $this->data = $this->getProduct($this->pid);
  }

  public function getProduct($pid) {

    $result = db_select('diy_product', 'd')
      ->fields('d')
      ->condition('d.pid', $pid,'=')
      ->execute()
      ->fetchAssoc();

    return $result;
  }

  public function setPriceItems($priceItems) {
    $this->priceItems = $priceItems;
  }

  public function handleEntity($pid, $reference_nid) {
    $this->pid = $pid;
    $this->reference_nid = $reference_nid;

    $this->populate();

    $query = new EntityFieldQuery();

    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', 'product')
      ->fieldCondition('field_external_id', 'value', $this->data['external_id'], '=')
      ->fieldCondition('field_source', 'value', $this->data['source'], '=')
      ->fieldCondition('field_shop_id', 'value', $this->data['shop_nid'], '=')
      ->fieldCondition('field_tool_material', 'nid', $this->reference_nid, '=')
      ->range(0, 1)
      ->addMetaData('account', user_load(1));
    $result = $query->execute();

    if(isset($result['node'])) {

      $keys = array_keys($result['node']);
      $first = reset($keys);

      $product_node = node_load($first);

      $field_last_change = field_get_items('node', $product_node, 'field_last_change');

      if($this->data['updated'] > $field_last_change[0]['value']) {
        $this->updateProduct($product_node);
      }
      $entity = $product_node;
    } else {
      $entity = $this->insertProduct();
    }

    $this->product_nid = $entity->nid;

    return true;
  }

  /*
   * Updates given product node. Requires $this->data to be set.
   */
  public function updateProduct($product) {
    #drupal_set_message('Update product');
    return $this->saveProduct($product);
  }

  /*
   * Insert new product node. Requires $this->data and further fields set.
   */
  public function insertProduct() {
    global $user;

    #drupal_set_message('Insert product');

    $values = array(
      'type' => 'product',
      'uid' => $user->uid,
      'status' => 1,
      'promote' => 0,
      'language' => 'de'
    );

    $entity = entity_create('node', $values);

    return $this->saveProduct($entity);
  }

  public function saveProduct($entity) {
    $ewrapper = entity_metadata_wrapper('node', $entity);

    $ewrapper->title->set($this->data['title']);
    $ewrapper->field_product_number->set($this->data['article_number']);
    $ewrapper->field_external_id->set($this->data['external_id']);
    $ewrapper->field_shop_id->set($this->data['shop_nid']);
    $ewrapper->field_last_change->set($this->data['updated']);
    $ewrapper->field_source->set($this->data['source']);

    if(!empty($this->data['description'])) {
      $ewrapper->body->set(array('value' => $this->data['description']));
    }

    if(!empty($this->data['image_url'])) {
      $file_info = system_retrieve_file($this->data['image_url'], 'public://product/product' . $this->data['external_id'], TRUE);
      if($file_info->fid) {
        $ewrapper->field_image->set(array('fid' => $file_info->fid));
      }
    }

    $producer_id = $this->handleProducer($this->data['producer']);
    $ewrapper->field_producer->set($producer_id);

    if(!empty($this->data['ean'])) {
      $ewrapper->field_ean_number->set($this->data['ean']);
    }

    // when we just update our product from a affilinet cron run
    // we dont need to set reference_nid (and we dont got it out of the db)
    if(!empty($this->reference_nid)) {
      $ewrapper->field_tool_material->set($this->reference_nid);
    }
    if(!empty($this->mu)) {
      $ewrapper->field_tools_mu->set($this->mu);
    }
    if(!empty($this->su)) {
      $ewrapper->field_tools_su->set($this->su);
    }

    $ewrapper->save();
    $node = $ewrapper->value();

    // thats only needed on creaton
    if(!empty($this->domains)) {
      $node->domains = $this->domains;
      $node->domain_site = 0;
      $node->domain_source = DOMAIN_SOURCE_USE_ACTIVE;
      node_save($node);
    }

    return $node;
  }

  public function handleProducer($producer) {
    if($terms = taxonomy_get_term_by_name($producer, 'producer')) {
      $first = reset($terms);
      return $first->tid;
    } else {
      $data = array(
        'name' => $producer,
        'vid' => 14,
        'parent' => array(0),
      );

      $term = entity_create('taxonomy_term', $data);
      $wrapper = entity_metadata_wrapper('taxonomy_term', $term);
      $wrapper->save();
      $entity = $wrapper->value();

      return $entity->tid;
    }
  }

  public function handleProductPriceItems() {
    foreach($this->priceItems as $ProductId) {
      $ProductRow = $this->getProduct($ProductId);

      $ProductPriceItem = new DiyProductPrice($this->product_nid);
      $ProductPriceItem->skipConfirmationStep = TRUE;
      $ProductPriceItem->handleProductPriceItem($ProductRow);
    }
  }
}

class DiyProductPrice {
  var $product_nid;
  var $skipConfirmationStep = FALSE;
  var $ignoreUpdatedCheck = FALSE;

  public function __construct($product_nid) {
    $this->product_nid = $product_nid;
  }

  public function handleProductPriceItem($ProductRow) {
    $query = new EntityFieldQuery();

    $query->entityCondition('entity_type', 'diy_product_price')
      ->propertyCondition('product_nid', $this->product_nid, '=')
      ->propertyCondition('external_id', $ProductRow['external_id'], '=')
      ->propertyCondition('source', $ProductRow['source'], '=')
      ->range(0, 1)
      ->addMetaData('account', user_load(1));
    $result = $query->execute();

    if(isset($result['diy_product_price'])) {

      $keys = array_keys($result['diy_product_price']);
      $first = reset($keys);

      $price_entities = entity_load('diy_product_price', array($first));
      $price_entity = reset($price_entities);

      if($ProductRow['updated'] > $price_entity->updated || $price_entity->status == 3 || $this->ignoreUpdatedCheck) {
        $this->updateProductPriceItem($price_entity, $ProductRow);
      }

    } else {
      $this->insertProductPriceItem($ProductRow);
    }
  }

  public function updateProductPriceItem($pp, $ProductRow) {
    $this->saveProductPriceItem($pp, $ProductRow);
  }

  public function insertProductPriceItem($ProductRow) {
    $data = array(
      'product_nid' => $this->product_nid,
      'external_id' => $ProductRow['external_id'],
      'status' => 0, # show
      'created' => time(),
      'source' => $ProductRow['source']
    );

    if($this->skipConfirmationStep) {
      $data['status'] = 1;
    }

    $data += array('shop_nid' => $ProductRow['shop_nid']);

    $pp = entity_create('diy_product_price', $data);
    $this->saveProductPriceItem($pp, $ProductRow);
  }

  public function saveProductPriceItem($pp, $ProductRow) {

    $ewrapper = entity_metadata_wrapper('diy_product_price', $pp);

    $ewrapper->updated->set($ProductRow['updated']);

    if(!empty($ProductRow['deeplink'])) {
      $ewrapper->deeplink->set($ProductRow['deeplink']);
    }

    if(!empty($ProductRow['price'])) {
      $ewrapper->price->set($ProductRow['price']);
    }

    if(!empty($ProductRow['delivery_costs'])) {
      $ewrapper->delivery_costs->set($ProductRow['delivery_costs']);
    }

    if(!empty($ProductRow['delivery_time'])) {
      $ewrapper->delivery_time->set($ProductRow['delivery_time']);
    }

    // update a product state, if it had been deleted and reappears in api
    if($ewrapper->status->value() == 3) {
      $ewrapper->status->set(1);
    }

    $ewrapper->save();
  }
}