<?php
/**
 * @author Jaap Jansma <jaap.jansma@civicoop.org>
 * @license AGPL-3.0
 */

namespace Civi\DataProcessor\DataFlow\SqlDataFlow;

use CRM_Core_Exception;
use CRM_Utils_Type;

class SimpleWhereClause extends AbstractWhereClause implements WhereClauseInterface {

  protected $table_alias;

  protected $field;

  protected $operator;

  protected $value;

  protected $valueType;

  protected $sqlFunction = null;

  public function __construct($table_alias, $field, $operator, $value, $valueType = 'String', $isJoinClause=FALSE, $sqlFunction=null) {
    $this->valueType = $valueType;
    if (is_array($value)) {
      switch ($operator) {
        case '=':
          $operator = 'IN';
          break;
        case '!=':
          $operator = 'NOT IN';
          break;

        case 'IS NULL':
          $operator = 'IS NULL';
          break;
        case 'IS NOT NULL':
          $operator = 'IS NOT NULL';
          break;
      }
    }

    $this->isJoinClause = $isJoinClause;
    $this->table_alias = $table_alias;
    $this->field = $field;
    $this->operator = $operator;

    if ($operator == 'IS NULL' || $operator == 'IS NOT NULL') {
      $this->value = NULL;
      return;
    }

    if (is_array($value)) {
      $esacpedValues = array();
      foreach($value as $val) {
        switch ($valueType) {
          case 'String':
          case 'Text':
          case 'Memo':
            try {
              $esacpedValues[] = "'" . CRM_Utils_Type::escape($val, $valueType) . "'";
            } catch (CRM_Core_Exception $e) {
            }
            break;
          default:
            try {
              $esacpedValues[] = CRM_Utils_Type::escape($val, $valueType);
            } catch (CRM_Core_Exception $e) {
            }
            break;
        }
      }
      if ($operator == 'BETWEEN' || $operator == 'NOT BETWEEN') {
        $this->value = implode(" AND ", $esacpedValues);
      }
      else {
        $this->value = "(" . implode(", ", $esacpedValues) . ")";
      }
    } else {
      switch ($valueType) {
        case 'String':
        case 'Text':
        case 'Memo':
          try {
            $this->value = "'" . CRM_Utils_Type::escape($value, $valueType) . "'";
          } catch (CRM_Core_Exception $e) {
          }
          break;
        default:
          try {
            $this->value = CRM_Utils_Type::escape($value, $valueType);
          } catch (CRM_Core_Exception $e) {
          }
          break;
      }
    }

    if ($sqlFunction) {
      $this->sqlFunction = $sqlFunction;
    }
  }

  /**
   * Returns the where clause
   * E.g. contact_type = 'Individual'
   *
   * @return string
   */
  public function getWhereClause(): string {
    if ($this->isJoinClause()) {
      return "`$this->table_alias`.`$this->field` $this->operator $this->value";
    }
    $fieldStatement = "`$this->table_alias`.`$this->field`";
    if ($this->sqlFunction) {
      $fieldStatement = sprintf($this->sqlFunction, $fieldStatement);
    }
    switch ($this->operator) {
      case 'NOT IN':
      case 'NOT LIKE':
      case 'NOT BETWEEN':
      case '!=':
        return "($fieldStatement $this->operator $this->value OR `$this->table_alias`.`$this->field` IS NULL)";
      case 'IS NULL':
        if ($this->valueType == 'Timestamp' || $this->valueType == 'Date') {
          return "$fieldStatement $this->operator $this->value";
        }
        return "(`$this->table_alias`.`$this->field` $this->operator OR `$this->table_alias`.`$this->field` = '')";
      case 'IS NOT NULL':
        if ($this->valueType == 'Timestamp' || $this->valueType == 'Date') {
          return "$fieldStatement $this->operator $this->value";
        }
        return "(`$this->table_alias`.`$this->field` $this->operator AND `$this->table_alias`.`$this->field` != '')";
      default:
        return "$fieldStatement $this->operator $this->value";
    }
  }

}
