<?php

  /**
   * Invoice payments implementation
   *
   * @package activeCollab.modules.invoicing
   * @subpackage models
   */
  class IInvoicePaymentsImplementation extends IPaymentsImplementation {
    
    /**
     * Construct invoice payment implementation
     * 
     * @param Invoice $object
     */
    function __construct(Invoice $object) {
      if($object instanceof Invoice) {
        parent::__construct($object);
      } else {
        throw new InvalidInstanceError('object', $object, 'Invoice');
      } // if
    } // __construct
    
    
    /**
     * Notify financial managers about new payment depending of config options
     * 
     * @param INotifierContext $context
  	 * @param NotifierEvent $event
  	 * @param mixed $event_params
  	 * @param mixed $additional
     */
    function notifyFinancialManagers(INotifierContext $context, $event, $event_params = null, $additional = null) {
      $notify_managers = ConfigOptions::getValue('invoice_notify_financial_managers');
      
      if($notify_managers == Invoice::INVOICE_NOTIFY_FINANCIAL_MANAGERS_ALL) {
        ApplicationMailer::notifier()->notifyFinancialManagers($context, $event, $event_params,$additional);
      } elseif ($notify_managers == Invoice::INVOICE_NOTIFY_FINANCIAL_MANAGERS_SELECTED) {
        $notify_manager_ids = ConfigOptions::getValue('invoice_notify_financial_manager_ids');
        if(is_foreachable($notify_manager_ids)) {
          //check is user still financial manager
          $notify_people = array();
          foreach($notify_manager_ids as $user_id) {
            $user = DataObjectPool::get('User', $user_id);
            if($user instanceof User && $user->isFinancialManager()) {
              $notify_people[] = $user;
            }//if
          }//foreach
          ApplicationMailer::notifier()->notifyUsers($notify_people, $context, $event, $event_params, $additional);
        }//if
      }//if
    }//notifyFinancialManager
    
    
     
    /**
     * Return amount left for paying
     * 
     * @return float
     */
    function getAmountToPay() {
      $taxed_total = str_replace(',','.',strval($this->object->getTaxedTotal()));
      $paid_amount = str_replace(',','.',strval($this->getPaidAmount()));
      
      if(function_exists('bcsub')) {
        $left_to_pay = bcsub($taxed_total,$paid_amount,3);
      } else {
        $left_to_pay = $taxed_total - $paid_amount;
      }//if
     
      if($left_to_pay < 0) {
        return 0; 
      } else {
        return $left_to_pay;
      } // if
    } // getAmountToPay
    
    /**
     * Return % amount left for paying
     * 
     * @return float
     */
    function getPercentPaid() {
      return (float) number_format(($this->getPaidAmount() * 100) / $this->object->getTaxedTotal(), 2, '.', '');
    } // getPercentPaid
    
    /**
     * Change invoice status
     * 
     * @param User $user
     * @param Payment $payment
     */
    function changeStatus(User $by, $payment = null, $additional_params = null) {
      try {
        DB::beginWork('Change invoice status @ ' . __CLASS__);
        
        if($this->getAmountToPay() == 0 && $this->object->getStatus() == INVOICE_STATUS_ISSUED) {
          $this->gag(); // Make sure that no notifications are sent, we'll send notifications with markAsPaid() invoice method
          $this->object->markAsPaid($by, $payment, $additional_params); // Mark as paid
        } elseif($this->getAmountToPay() > 0 && $this->object->getStatus() == INVOICE_STATUS_PAID) {
          $this->object->setStatus(INVOICE_STATUS_ISSUED, $this->object->getIssuedBy(), $this->object->getIssuedOn()); // Revert to issued
          $this->object->save();
        } // if
        
        DB::commit('Invoice status changed @ ' . __CLASS__);
      } catch(Exception $e) {
        DB::rollback('Failed to update invoice status @ ' . __CLASS__);
        throw $e;
      } // try
    } // changeStatus
    
    /**
     * Check can payment be paid
     * 
     * @param float $amount_to_pay
     * @return boolean
     */
    function canMarkAsPaid($amount_to_pay) {
      $will_be_paid = $this->getPaidAmount() + $amount_to_pay;
      if($this->getAmountToPay() == 0 || $this->object->getTaxedTotal() < $will_be_paid) {
        throw new Error(lang("If you add this payment you will run over maximum payment amount. No payment added"));
      } // if
      
      return true;
    } // canMarkAsPaid
    
  }