<?php

class BudgetOperation extends \Eloquent {

	use SoftDeletingTrait;

  public static function boot() {
		parent::boot();

		BudgetOperation::observe(new BudgetOperationObserver);
	}
  
	protected $guarded		 = array();
	public static $rules	 = array();

	const TYPE_INCOMING					 = 2;
	const TYPE_OUTCOMING				 = 1;
	const TYPE_EXCHANGE					 = 3;
	const TYPE_OPENING_BALANCE	 = 500;
	const TYPE_OPENING_DEBT_IN	 = 150;
	const TYPE_OPENING_DEBT_OUT	 = 151;

	protected static $typeNames = array(
			BudgetOperation::TYPE_INCOMING				 => 'Приход',
			BudgetOperation::TYPE_OUTCOMING				 => 'Расход',
			BudgetOperation::TYPE_EXCHANGE				 => 'Перевод',
			BudgetOperation::TYPE_OPENING_BALANCE	 => 'Остатки на начало месяца',
			BudgetOperation::TYPE_OPENING_DEBT_IN	 => 'Мы должны на начало месяца',
			BudgetOperation::TYPE_OPENING_DEBT_OUT => 'Долг нам на начало месяца',
	);
  
  /** 
   *  История операции пишется только для полей из этого массива 
   */
	public $tableNames = array(
//			'user_id'				        => 'Пользователь',
//			'project_id'				    => 'Проект',
			'budget_upload_id'			=> 'Выгрузка',
			'date'				          => 'Дата',
			'type'				          => 'Тип',
			'amount'			          => 'Сумма',
			'budget_cost_id'				=> 'Статья расхода',
			'is_salary'				      => 'З/п операция',
			'budget_partner_id'	    => 'Контрагент',
			'budget_in_account_id'  => 'Счет для зачисления',
			'budget_out_account_id' => 'Счет для списания',
			'comment'				        => 'Комментарий',
//			'delete_user_id'				=> 'Удаливший пользователь',
			'isarchived'				    => 'Архивная',
//			'archived_at'				    => 'Заархивировано',
			'isdebt'				        => 'Долговая',
			'debt_partner_id'				=> 'Долговой контрагент',
			'debt_comment'				  => 'Комментарий к долгу',
			'isnoincome'				    => 'Не является доходом',
			'isnooutcome'				    => 'Не является расходом',
			'debt_parent_id'				=> 'Связанная долговая операция №',
	);
  
  /** 
   *  'is_' поля.
   */
  public $checkableFields = array(
			'is_salary',
			'isarchived',
			'isdebt',
			'isnoincome',
			'isnooutcome'
	);

  /** 
   *  '_id' поля.
   *  Используется для получения названия параметра. Таблица должна иметь поле name.
   */
  public $idFields = array(
			'budget_cost_id'				=> 'cost',
			'budget_partner_id'	    => 'partner',
			'budget_in_account_id'  => 'inAccount',
			'budget_out_account_id' => 'outAccount',
			'debt_partner_id'				=> 'debtPartner'
	);

	public function project() {
		return $this->belongsTo('Project');
	}

	public function user() {
		return $this->belongsTo('User')->withTrashed()->remember(60);
	}

	public function budgetUpload() {
		return $this->belongsTo('BudgetUpload')->withTrashed()->remember(60);
	}

	public function inAccount() {
		return $this->belongsTo('BudgetAccount', 'budget_in_account_id')->withTrashed();
	}

	public function outAccount() {
		return $this->belongsTo('BudgetAccount', 'budget_out_account_id')->withTrashed();
	}

	public function cost() {
		return $this->belongsTo('BudgetCost', 'budget_cost_id')->withTrashed();
	}

	public function partner() {
		return $this->belongsTo('BudgetPartner', 'budget_partner_id')->withTrashed();
	}

	public function debtPartner() {
		return $this->belongsTo('BudgetDebtPartner', 'debt_partner_id')->withTrashed();
	}
  
	public function budgetOperationHistory() {
		return $this->hasMany('BudgetOperationHistory');
	}

	public function setAmountAttribute($value) {
		$value											 = str_replace(',', '.', $value);
		$value											 = str_replace(' ', '', $value);
		$this->attributes['amount']	 = round($value * 100, 0);
	}

	public function getAmountAttribute() {
		return round($this->attributes['amount'] / 100, 2);
	}

	public function getFormattedDate() {
		$date = explode('-', $this->date);
		return "{$date[2]}.{$date[1]}.{$date[0]}";
	}

	public function getTypeName() {
		return self::$typeNames[$this->type];
	}

	public function getTrClassName() {
		$className = '';
		if ($this->isuploaded) {
			$className .= ' isuploaded';
		}
		if ($this->deleted_at) {
			$className .= ' danger';
		}
		if ($this->type == BudgetOperation::TYPE_OUTCOMING && !$this->isdebt && !$this->budget_cost_id) {
			$className .= ' nocostid';
		}
		if ($this->isdebt && $this->debt_partner_id) {
			$className .= ' debt-partner-id-' . $this->debt_partner_id;
		}
		if ($this->budget_in_account_id) {
			if ($this->type == BudgetOperation::TYPE_INCOMING || $this->type == BudgetOperation::TYPE_EXCHANGE || $this->type == BudgetOperation::TYPE_OPENING_BALANCE) {
				$className .= ' budget-account-'.$this->budget_in_account_id;
			}
		}
		if ($this->budget_out_account_id) {
			if ($this->type == BudgetOperation::TYPE_EXCHANGE || $this->type == BudgetOperation::TYPE_OUTCOMING) {
				$className .= ' budget-account-'.$this->budget_out_account_id;
			}
		}
		if ($this->budget_cost_id && !$this->isdebt) {
			if ($this->type == BudgetOperation::TYPE_OUTCOMING) {
				$className .= ' budget-cost-'.$this->budget_cost_id;
			}
		}
		return $className;
	}

	public function getClassName() {
		if ($this->deleted_at) {
			return 'text-active';
		}
		elseif ($this->type == BudgetOperation::TYPE_INCOMING) {
			return 'text-success';
		}
		elseif ($this->type == BudgetOperation::TYPE_OUTCOMING) {
			return 'text-info';
		}
		elseif ($this->type == BudgetOperation::TYPE_EXCHANGE) {
			return 'text-warning';
		}
		elseif ($this->type == BudgetOperation::TYPE_OPENING_BALANCE) {
			return 'text-success';
		}
		elseif ($this->type == BudgetOperation::TYPE_OPENING_DEBT_IN) {
			return 'text-danger';
		}
		elseif ($this->type == BudgetOperation::TYPE_OPENING_DEBT_OUT) {
			return 'text-info';
		}
	}

	public function getSalaryCosts() {
		$salaryCosts = BudgetCost::select(DB::raw('id'))
														  ->whereBudgetCostGroupId(6)
														  ->remember(60)
														  ->get();
		$costsList = [];

		foreach ($salaryCosts as $salaryCost){
			$costsList[] = $salaryCost->id;
		}

		return $costsList;
	}

  public function humanizeVal($key, $value){
      $checkableFields = $this->checkableFields;
      $idFields = $this->idFields;
      $typeNames = self::$typeNames;
      
      if($key == 'amount'){
        $value = "<span class='log-amount' data-val='$value'>".($value/100).'</span>';
      }
      else if($key == 'date'){
        $date = explode('-', $value);
		    $value = $date[2].'.'.$date[1].'.'.$date[0];
      }
      else if($key == 'type'){
		    $value = $typeNames[$value];
      }
      else if(in_array($key, $checkableFields)){
        if($value == 1){
          $value = 'Да';
        }
        else if($value == 0 || $value == null){
          $value = 'Нет';
        }
      }
      else if(array_key_exists($key, $idFields)){
        $value = '<span data-id="'.$value.'">'.$this->$idFields[$key]->name.'</span>';
      }

      return $value;
  }

  public function getChanges(){
    $changes = array();
    $idFields = $this->idFields;
    
		foreach ($this->attributes as $key => $value) {
       
      if ( ! array_key_exists($key, $this->original) )
			{
        $value = $this->humanizeVal($key, $value);
				$changes[$key] = [
                    'new' => $value,
                    'old' => ''
                ];
			}
      else if ($value !== $this->original[$key] && !$this->originalIsNumericallyEquivalent($key))
			{
        $value = $this->humanizeVal($key, $value);
        if(array_key_exists($key, $idFields)){
          $oldValue = "<span class='log-$key' data-old-id='".$this->original[$key]."'></span>";
        } else {
          $oldValue = $this->humanizeVal($key, $this->original[$key]); 
        }
				$changes[$key] = [
                    'new' => $value,
                    'old' => $oldValue
                ];
			}
		}

		return $changes;
  }
  
	/**
	 * Массив сумм поступлений и расходов за период по каждому бюджетному проекту
	 * @return Array
	 * @Example:   Array (   [3] => Array ( [1] => 158718.9300 [2] => 216098.0000 )
	 * @Example:     [13] => Array ( [2] => 550550.1700 )   )
	 */
	public static function getBudgetProjectsBalance($date) {
		$budgetProjectsBalance = BudgetOperation::select(DB::raw('sum(amount)/100 as sum, project_id, type'))
																						->whereIn('type', array(BudgetOperation::TYPE_OUTCOMING, BudgetOperation::TYPE_INCOMING))
																						->whereIsnooutcome(0)
																						->whereIsnoincome(0)
																						->where('date', '>=', $date)
																						->where('date', '<=', $date)
																						->groupBy('project_id')
																						->groupBy('type')
																						->get();

		$balances = [];
		foreach ($budgetProjectsBalance as $projectBalance){
			$balances[$projectBalance->project_id][$projectBalance->type] = $projectBalance->sum;
		}

    return $balances;
	}
  
  /**
	 * Массив сумм остатков на счетах по каждому бюджетному проекту на указанную дату
	 * @return Array
	 * @Example:   Array (   [3] => Array ( [in] => 158718.9300 [out] => 216098.0000 )
	 * @Example:     [13] => Array ( [in] => 0 [out] => 550550.1700 )   )
	 */
	public static function getBudgetProjectsMoney() {
		$budgetProjectsMoneyIn = BudgetOperation::select(DB::raw('sum(amount)/100 as sum, project_id'))
																						->whereIn('type', array(BudgetOperation::TYPE_INCOMING, BudgetOperation::TYPE_EXCHANGE, BudgetOperation::TYPE_OPENING_BALANCE))
																						->groupBy('project_id')
																						->get();
    
    $budgetProjectsMoneyOut = BudgetOperation::select(DB::raw('sum(amount)/100 as sum, project_id, type'))
																						->whereIn('type', array(BudgetOperation::TYPE_OUTCOMING, BudgetOperation::TYPE_EXCHANGE))
																						->groupBy('project_id')
																						->get();
    // записываем в общий массив входящие остатки проектов
    $budgetProjectsMoney = [];
		foreach ($budgetProjectsMoneyIn as $projectMoneyIn){
			$budgetProjectsMoney[$projectMoneyIn->project_id]['in'] = $projectMoneyIn->sum;
      // заполняем Out нулями, чтобы не проверять потом на существование такой ключ - он перепишется дальше или останется 0
			$budgetProjectsMoney[$projectMoneyIn->project_id]['out'] = $projectMoneyIn->sum; 
		}
    // добавляем в этот же массив исходящие остатки
		foreach ($budgetProjectsMoneyOut as $projectMoneyOut){
			$budgetProjectsMoney[$projectMoneyOut->project_id]['out'] = $projectMoneyOut->sum;
        // если в этом массиве появятся новые проекты, то заполнить нулем соотв. In ключ, чтобы не проверять на существование ключа дальше
      if(!isset($budgetProjectsMoney[$projectMoneyOut->project_id]['in'])){
			  $budgetProjectsMoney[$projectMoneyOut->project_id]['in'] = 0;
      }
		}
    
    return $budgetProjectsMoney;
	}
}
